├── .browserslistrc
├── .changeset
├── README.md
├── config.json
└── getChangelogEntry.js
├── .circleci
└── config.yml
├── .codesandbox
└── ci.json
├── .coveralls.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── config.yml
├── dependabot.yml
└── workflows
│ └── release.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── cypress.json
├── cypress
├── fixtures
│ └── selectors.json
├── integration
│ ├── multi-select.spec.ts
│ └── single-select.spec.ts
└── tsconfig.json
├── docs
├── App
│ ├── Footer.tsx
│ ├── GitHubButton.tsx
│ ├── Header.tsx
│ ├── PageNav.tsx
│ ├── ScrollSpy.tsx
│ ├── Section.tsx
│ ├── Sticky.tsx
│ ├── TwitterButton.tsx
│ ├── components.tsx
│ ├── index.tsx
│ └── routes.ts
├── CHANGELOG.md
├── ExampleWrapper.tsx
├── NoMatch.tsx
├── PropTypes
│ ├── Async.ts
│ ├── Creatable.ts
│ ├── Select.ts
│ ├── components
│ │ ├── ClearIndicator.ts
│ │ ├── Control.ts
│ │ ├── DropdownIndicator.ts
│ │ ├── Group.ts
│ │ ├── IndicatorsContainer.ts
│ │ ├── IndicatorsSeparator.ts
│ │ ├── Input.ts
│ │ ├── LoadingIndicator.ts
│ │ ├── LoadingMessage.ts
│ │ ├── Menu.ts
│ │ ├── MenuList.ts
│ │ ├── MultiValue.ts
│ │ ├── MultiValueContainer.ts
│ │ ├── MultiValueLabel.ts
│ │ ├── MultiValueRemove.ts
│ │ ├── NoOptionsMessage.ts
│ │ ├── Option.ts
│ │ ├── Placeholder.ts
│ │ ├── SelectContainer.ts
│ │ ├── SingleValue.ts
│ │ └── ValueContainer.ts
│ └── stateManager.ts
├── Svg.tsx
├── Table.tsx
├── Tests.tsx
├── _redirects
├── data.ts
├── examples
│ ├── AccessingInternals.tsx
│ ├── AnimatedMulti.tsx
│ ├── AsyncCallbacks.tsx
│ ├── AsyncCreatable.tsx
│ ├── AsyncMulti.tsx
│ ├── AsyncPromises.tsx
│ ├── BasicGrouped.tsx
│ ├── BasicMulti.tsx
│ ├── BasicSingle.tsx
│ ├── ControlledMenu.tsx
│ ├── CreatableAdvanced.tsx
│ ├── CreatableInputOnly.tsx
│ ├── CreatableMulti.tsx
│ ├── CreatableSingle.tsx
│ ├── CreateFilter.tsx
│ ├── CustomAriaLive.tsx
│ ├── CustomClearIndicator.tsx
│ ├── CustomControl.tsx
│ ├── CustomDropdownIndicator.tsx
│ ├── CustomFilterOptions.tsx
│ ├── CustomGetOptionLabel.tsx
│ ├── CustomGetOptionValue.tsx
│ ├── CustomGroup.tsx
│ ├── CustomGroupHeading.tsx
│ ├── CustomIndicatorSeparator.tsx
│ ├── CustomIndicatorsContainer.tsx
│ ├── CustomInput.tsx
│ ├── CustomIsOptionDisabled.tsx
│ ├── CustomLoadingIndicator.tsx
│ ├── CustomLoadingMessage.tsx
│ ├── CustomMenu.tsx
│ ├── CustomMenuList.tsx
│ ├── CustomMultiValueContainer.tsx
│ ├── CustomMultiValueLabel.tsx
│ ├── CustomMultiValueRemove.tsx
│ ├── CustomNoOptionsMessage.tsx
│ ├── CustomOption.tsx
│ ├── CustomPlaceholder.tsx
│ ├── CustomSelectContainer.tsx
│ ├── CustomSelectProps.tsx
│ ├── CustomSingleValue.tsx
│ ├── CustomValueContainer.tsx
│ ├── DefaultOptions.tsx
│ ├── Experimental.tsx
│ ├── FixedOptions.tsx
│ ├── MenuBuffer.tsx
│ ├── MenuPortal.tsx
│ ├── MultiSelectSort.tsx
│ ├── OnSelectResetsInput.tsx
│ ├── Popout.tsx
│ ├── StyleCompositionExample.tsx
│ ├── StyledMulti.tsx
│ ├── StyledSingle.tsx
│ ├── Theme.tsx
│ └── index.tsx
├── favicon.ico
├── generate-magical-types
│ ├── generate
│ │ └── package.json
│ ├── package.json
│ ├── serialize
│ │ └── package.json
│ └── src
│ │ ├── generate.ts
│ │ ├── serialize.ts
│ │ └── types.ts
├── index.css
├── index.html
├── index.tsx
├── isArray.ts
├── markdown
│ ├── renderer.tsx
│ └── store.ts
├── package.json
├── pages
│ ├── advanced
│ │ └── index.tsx
│ ├── async
│ │ └── index.tsx
│ ├── components
│ │ └── index.tsx
│ ├── creatable
│ │ └── index.tsx
│ ├── home
│ │ └── index.tsx
│ ├── props
│ │ └── index.tsx
│ ├── styles
│ │ └── index.tsx
│ ├── typescript
│ │ └── index.tsx
│ ├── upgrade-to-v2
│ │ ├── index.tsx
│ │ └── props.tsx
│ └── upgrade
│ │ └── index.tsx
├── styled-components.tsx
├── tsconfig.json
├── utils.ts
└── webpack.config.ts
├── netlify.toml
├── package.json
├── packages
└── react-select
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── animated
│ └── package.json
│ ├── async-creatable
│ └── package.json
│ ├── async
│ └── package.json
│ ├── base
│ └── package.json
│ ├── creatable
│ └── package.json
│ ├── package.json
│ ├── src
│ ├── Async.tsx
│ ├── AsyncCreatable.tsx
│ ├── Creatable.tsx
│ ├── NonceProvider.tsx
│ ├── Select.tsx
│ ├── __tests__
│ │ ├── Async.test.tsx
│ │ ├── AsyncCreatable.test.tsx
│ │ ├── Creatable.test.tsx
│ │ ├── Select.test.tsx
│ │ ├── StateManaged.test.tsx
│ │ ├── __snapshots__
│ │ │ ├── Async.test.tsx.snap
│ │ │ ├── AsyncCreatable.test.tsx.snap
│ │ │ ├── Creatable.test.tsx.snap
│ │ │ ├── Select.test.tsx.snap
│ │ │ └── StateManaged.test.tsx.snap
│ │ ├── constants.ts
│ │ └── tsconfig.json
│ ├── accessibility
│ │ ├── helpers.ts
│ │ └── index.ts
│ ├── animated
│ │ ├── Input.tsx
│ │ ├── MultiValue.tsx
│ │ ├── Placeholder.tsx
│ │ ├── SingleValue.tsx
│ │ ├── ValueContainer.tsx
│ │ ├── index.ts
│ │ └── transitions.tsx
│ ├── async-creatable
│ │ └── index.ts
│ ├── async
│ │ └── index.ts
│ ├── base
│ │ └── index.ts
│ ├── builtins.ts
│ ├── components
│ │ ├── Control.tsx
│ │ ├── Group.tsx
│ │ ├── Input.tsx
│ │ ├── LiveRegion.tsx
│ │ ├── Menu.tsx
│ │ ├── MultiValue.tsx
│ │ ├── Option.tsx
│ │ ├── Placeholder.tsx
│ │ ├── SingleValue.tsx
│ │ ├── containers.tsx
│ │ ├── index.ts
│ │ └── indicators.tsx
│ ├── creatable
│ │ └── index.ts
│ ├── diacritics.ts
│ ├── filters.ts
│ ├── index.ts
│ ├── internal
│ │ ├── A11yText.tsx
│ │ ├── DummyInput.tsx
│ │ ├── RequiredInput.tsx
│ │ ├── ScrollManager.tsx
│ │ ├── index.ts
│ │ ├── useScrollCapture.ts
│ │ └── useScrollLock.ts
│ ├── stateManager.tsx
│ ├── styles.ts
│ ├── theme.ts
│ ├── types.ts
│ ├── useAsync.ts
│ ├── useCreatable.ts
│ ├── useStateManager.ts
│ └── utils.ts
│ └── tsconfig.json
├── storybook
├── .gitignore
├── .storybook
│ ├── .babelrc
│ ├── main.ts
│ └── preview.tsx
├── components
│ ├── field.tsx
│ ├── index.ts
│ ├── inline.tsx
│ ├── stack.tsx
│ └── svg.tsx
├── data.ts
├── package.json
├── postcss.config.js
├── stories
│ ├── AccessingInternalsViaRef.stories.tsx
│ ├── AnimatedMulti.stories.tsx
│ ├── AsyncCallbacks.stories.tsx
│ ├── AsyncCreatable.stories.tsx
│ ├── AsyncMulti.stories.tsx
│ ├── AsyncPromises.stories.tsx
│ ├── AsyncSelectWithDefaultOptions.stories.tsx
│ ├── BasicGrouped.stories.tsx
│ ├── BasicMulti.stories.tsx
│ ├── BasicSingle.stories.tsx
│ ├── ClassNamesWithTailwind.stories.tsx
│ ├── ControlledMenu.stories.tsx
│ ├── Creatable.stories.tsx
│ ├── CreatableAdvanced.stories.tsx
│ ├── CreatableInputOnly.stories.tsx
│ ├── CreateFilter.stories.tsx
│ ├── CustomAriaLive.stories.tsx
│ ├── CustomClearIndicator.stories.tsx
│ ├── CustomControl.stories.tsx
│ ├── CustomDropdownIndicator.stories.tsx
│ ├── CustomFilterOptions.stories.tsx
│ ├── CustomFormatOptionLabel.stories.tsx
│ ├── CustomGetOptionLabel.stories.tsx
│ ├── CustomGetOptionValue.stories.tsx
│ ├── CustomGroup.stories.tsx
│ ├── CustomGroupHeading.stories.tsx
│ ├── CustomIndicatorSeparator.stories.tsx
│ ├── CustomIndicatorsContainer.stories.tsx
│ ├── CustomInput.stories.tsx
│ ├── CustomIsOptionDisabled.stories.tsx
│ ├── CustomLoadingIndicator.stories.tsx
│ ├── CustomLoadingMessage.stories.tsx
│ ├── CustomMenu.stories.tsx
│ ├── CustomMenuList.stories.tsx
│ ├── CustomMultiValueContainer.stories.tsx
│ ├── CustomMultiValueLabel.stories.tsx
│ ├── CustomMultiValueRemove.stories.tsx
│ ├── CustomNoOptionsMessage.stories.tsx
│ ├── CustomOption.stories.tsx
│ ├── CustomPlaceholder.stories.tsx
│ ├── CustomSelectContainer.stories.tsx
│ ├── CustomSelectProps.stories.tsx
│ ├── CustomSingleValue.stories.tsx
│ ├── CustomValueContainer.stories.tsx
│ ├── ExperimentalDatePicker.stories.tsx
│ ├── FixedOptions.stories.tsx
│ ├── Grouped.stories.tsx
│ ├── MenuBuffer.stories.tsx
│ ├── MenuPortal.stories.tsx
│ ├── MultiSelectSort.stories.tsx
│ ├── OnSelectKeepsInput.stories.tsx
│ ├── Popout.stories.tsx
│ ├── StyleCompositionExample.stories.tsx
│ ├── StyledMulti.stories.tsx
│ ├── StyledSingle.stories.tsx
│ ├── Tailwind.stories.tsx
│ ├── Theme.stories.tsx
│ └── UnstyledWithTailwind.stories.tsx
├── styles
│ └── tailwind.css
└── tailwind.config.js
├── test-setup.js
├── tsconfig.json
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 0.25%
2 | ie 11
3 | not op_mini all
4 |
--------------------------------------------------------------------------------
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with `bolt` to help you release components from a mono-repository. You can find the full documentation for it [here](https://www.npmjs.com/package/@changesets/cli)
4 |
5 | To help you get started though, here are some things you should know about this folder:
6 |
7 | ## Changesets are automatically generated
8 |
9 | Changesets are generated by the `yarn changeset` or `npx changeset` command. As long as you are following a changeset release flow, you shouldn't have any problems.
10 |
11 | ## Each changeset is its own folder
12 |
13 | We use hashes by default for these folder names to avoid collisions when generating them, but there's no harm that will come from renaming them.
14 |
15 | ## Changesets are automatically removed
16 |
17 | When `changeset bump` or equivalent command is run, all the changeset folders are removed. This is so we only ever use a changeset once. This makes this a very bad place to store any other information.
18 |
19 | ## Changesets come in two parts
20 |
21 | You should treat these parts quite differently:
22 |
23 | - `changes.md` is a file you should feel free to edit as much as you want. It will be prepended to your changelog when you next run your version command.
24 | - `changes.json` is a file that includes information about releases, what should be versioned by the version command. We strongly recommend against editing this directly, as you may make a new changeset that puts your bolt repository into an invalid state.
25 |
26 | ## I want to edit the information in a `changes.json` - how do I do it safely?
27 |
28 | The best option is to make a new changeset using the changeset command, copy over the `changes.md`, then delete the old changeset.
29 |
30 | ## Can I rename the folder for my changeset?
31 |
32 | Absolutely! We need unique hashes to make changesets play nicely with git, but changing your folder from our hash to your own name isn't going to cause any problems.
33 |
34 | ## Can I manually delete changesets?
35 |
36 | You can, but you should be aware this will remove the intent to release communicated by the changeset, and should be done with caution.
37 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@0.2.1/schema.json",
3 | "changelog": "./getChangelogEntry",
4 | "commit": false,
5 | "linked": [],
6 | "access": "public"
7 | }
8 |
--------------------------------------------------------------------------------
/.changeset/getChangelogEntry.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const { getInfo } = require('@changesets/get-github-info');
3 |
4 | const getReleaseLine = async (changeset, type) => {
5 | const [firstLine, ...futureLines] = changeset.summary
6 | .split('\n')
7 | .map((l) => l.trimRight());
8 | let { links } = await getInfo({
9 | repo: 'JedWatson/react-select',
10 | commit: changeset.commit,
11 | });
12 | return `- ${links.commit}${links.pull === null ? '' : ` ${links.pull}`}${
13 | links.user === null ? '' : ` Thanks ${links.user}!`
14 | } - ${firstLine}\n${futureLines.map((l) => ` ${l}`).join('\n')}`;
15 | };
16 |
17 | const getDependencyReleaseLine = async (changesets, dependenciesUpdated) => {
18 | if (dependenciesUpdated.length === 0) return '';
19 |
20 | const changesetLinks = changesets.map(
21 | (changeset) => `- Updated dependencies [${changeset.commit}]:`
22 | );
23 |
24 | const updatedDepenenciesList = dependenciesUpdated.map(
25 | (dependency) => ` - ${dependency.name}@${dependency.version}`
26 | );
27 |
28 | return [...changesetLinks, ...updatedDepenenciesList].join('\n');
29 | };
30 |
31 | module.exports = {
32 | getReleaseLine,
33 | getDependencyReleaseLine,
34 | };
35 |
--------------------------------------------------------------------------------
/.codesandbox/ci.json:
--------------------------------------------------------------------------------
1 | {
2 | "buildCommand": "build",
3 | "packages": ["packages/*"],
4 | "sandboxes": ["nfmxw"],
5 | "node": "20"
6 | }
7 |
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service-name: travis-ci
2 | repo_token: itdMRdBNgDK8Gb5nIA63zVMEryaxTQxkR
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 | root = true
4 |
5 | [*]
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | indent_style = space
11 | indent_size = 2
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
16 | [.circleci/config.yml]
17 | indent_size = 4
18 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage/*
2 | cypress/plugins/*
3 | cypress/support/*
4 | **/dist/*
5 | lib/*
6 | node_modules/*
7 | **/node_modules/*
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['plugin:react-hooks/recommended', 'plugin:@typescript-eslint/base'],
3 | parser: '@typescript-eslint/parser',
4 | env: {
5 | browser: true,
6 | es6: true,
7 | node: true,
8 | },
9 | plugins: ['react', '@typescript-eslint'],
10 | rules: {
11 | '@typescript-eslint/no-unused-vars': [
12 | 'error',
13 | {
14 | args: 'after-used',
15 | argsIgnorePattern: '^event$',
16 | ignoreRestSiblings: true,
17 | vars: 'all',
18 | varsIgnorePattern: 'jsx|emotionJSX',
19 | },
20 | ],
21 | curly: [2, 'multi-line'],
22 | 'jsx-quotes': 1,
23 | 'no-shadow': 0,
24 | '@typescript-eslint/no-shadow': 2,
25 | 'no-trailing-spaces': 1,
26 | 'no-underscore-dangle': 1,
27 | '@typescript-eslint/no-unused-expressions': 1,
28 | 'object-curly-spacing': [1, 'always'],
29 | '@typescript-eslint/quotes': [2, 'single', 'avoid-escape'],
30 | 'react/jsx-boolean-value': 1,
31 | 'react/jsx-no-undef': 1,
32 | 'react/jsx-uses-react': 1,
33 | 'react/jsx-uses-vars': 1,
34 | 'react/jsx-wrap-multilines': 1,
35 | 'react/no-did-mount-set-state': 1,
36 | 'react/no-did-update-set-state': 1,
37 | 'react/no-unknown-property': 1,
38 | 'react/react-in-jsx-scope': 1,
39 | 'react/self-closing-comp': 1,
40 | 'react/sort-prop-types': 1,
41 | '@typescript-eslint/semi': 2,
42 | '@typescript-eslint/no-inferrable-types': 2,
43 | strict: 0,
44 | },
45 | settings: {
46 | react: {
47 | version: 'detect',
48 | },
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thanks for your interest in React-Select. All forms of contribution are
4 | welcome, from issue reports to PRs and documentation / write-ups.
5 |
6 | Before you open a PR:
7 |
8 | - In development, run `yarn start` to build (+watch) the project source, and run
9 | the [development server](http://localhost:8000).
10 | - Please ensure all the examples work correctly after your change. If you're
11 | adding a major new use-case, add a new example demonstrating its use.
12 | - Be careful to follow the code style of the project. Run `yarn lint` after
13 | your changes and ensure you do not introduce any new errors or warnings.
14 | - This repository uses TypeScript, please run `yarn type-check` after your changes to ensure
15 | that you do not introduce any new type errors.
16 |
17 | - Ensure that your effort is aligned with the project's roadmap by talking to
18 | the maintainers, especially if you are going to spend a lot of time on it.
19 | - Make sure there's an issue open for any work you take on and intend to submit
20 | as a pull request - it helps core members review your concept and direction
21 | early and is a good way to discuss what you're planning to do.
22 | - If you open an issue and are interested in working on a fix, please let us
23 | know. We'll help you get started, rather than adding it to the queue.
24 | - Make sure you do not add regressions by running `yarn test`.
25 | - Where possible, include tests with your changes, either that demonstrates the
26 | bug, or tests the new functionality. If you're not sure how to test your
27 | changes, feel free to ping @gwyneplaine or @JedWatson
28 | - Run `yarn coveralls` to check that the coverage hasn't dropped, and look at the
29 | report (under the generated `coverage` directory) to check that your changes are
30 | covered
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: File a bug report
4 | title: '
'
5 | labels: [issue/bug-unconfirmed]
6 | assignees: ''
7 | ---
8 |
9 | **Thanks for using react-select!**
10 |
11 | If you are going to ask a question or want to propose a change or a new feature, then please don't file an issue for this.
12 | Questions and feature requests have their own place in our discussions section.
13 |
14 | ## Are you reporting a bug or runtime error?
15 |
16 | Please include a test case that demonstrates the issue you're reporting!
17 |
18 | This is very helpful to maintainers in order to help us see the issue you're seeing.
19 |
20 | Please note we are currently only directing our efforts towards the current major (v5) version and beyond.
21 |
22 | We understand this might be inconvenient but it is in the best interest of supporting the broader community and to sustain the `react-select` project going forward.
23 |
24 | To report bugs against react-select v5 please fork the following code-sandbox:
25 | https://codesandbox.io/s/react-select-v5-sandbox-y5jtm
26 |
27 | You may also find the [online Babel tool](https://babeljs.io/repl/) quite helpful if you wish to use ES6/ES7 syntax not yet supported by the browser you are using.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Feature request
4 | url: https://github.com/JedWatson/react-select/discussions/categories/ideas
5 | about: Got an idea for a feature or want to propose a change? Then this is the place for you.
6 | - name: Question on usage
7 | url: https://github.com/JedWatson/react-select/discussions/categories/q-a
8 | about: If you have a question regarding the usage of the library.
9 | - name: StackOverflow
10 | url: https://stackoverflow.com/questions/tagged/react-select
11 | about: Alternatively you can visit StackOverflow with the `[react-select]` tag
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'npm'
4 | directory: '/'
5 | schedule:
6 | interval: 'weekly'
7 | ignore:
8 | - dependency-name: '*'
9 | update-types:
10 | ['version-update:semver-minor', 'version-update:semver-patch']
11 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | permissions:
9 | contents: read
10 |
11 | jobs:
12 | release:
13 | permissions:
14 | # for changesets/action
15 | contents: write
16 | pull-requests: write
17 | name: Release
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout Repo
21 | uses: actions/checkout@v3
22 | with:
23 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
24 | fetch-depth: 0
25 |
26 | - name: Setup Node.js 22.x
27 | uses: actions/setup-node@v4
28 | with:
29 | node-version: 22.x
30 |
31 | - name: Install Dependencies
32 | run: yarn
33 |
34 | - name: Create Release Pull Request or Publish to npm
35 | uses: changesets/action@v1
36 | with:
37 | publish: yarn release
38 | env:
39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build
2 | lib
3 | dist
4 | docs/dist
5 | .env
6 |
7 | # Logs
8 | logs
9 | *.log
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 |
16 | # Coverage tools
17 | lib-cov
18 | coverage
19 | .nyc_output
20 |
21 | # Cypress
22 | cypress/videos
23 | cypress/screenshots
24 | cypress/support
25 | cypress/plugins
26 |
27 | # Dependency directory
28 | node_modules
29 | bower_components
30 |
31 | # Publish directory
32 | .publish
33 |
34 | # Editor artefacts
35 | .idea
36 |
37 | # Other
38 | .DS_Store
39 | .env
40 | package-lock.json
41 |
42 | # Notes
43 | .NOTES.md
44 |
45 | magical-types
46 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 22
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | coverage/*
2 | cypress/plugins/*
3 | cypress/support/*
4 | **/dist/*
5 | lib/*
6 | node_modules/*
7 | **/node_modules/*
8 | **/magical-types/*
9 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | singleQuote: true,
3 | trailingComma: 'es5',
4 | overrides: [
5 | {
6 | files: '.changeset/pre.json',
7 | options: { parser: 'json-stringify' },
8 | },
9 | ],
10 | };
11 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thanks for your interest in React-Select. All forms of contribution are
4 | welcome, from issue reports to PRs and documentation / write-ups.
5 |
6 | Before you open a PR:
7 |
8 | - In development, run `yarn start` to build (and watch) the project source, and run
9 | the [development server](http://localhost:8000).
10 | - Please ensure all the examples work correctly after your change. If you're
11 | adding a major new use-case, add a new example `/docs/examples` and subsequent documentation demonstrating its use `/docs/pages`.
12 | - Ensure that your effort is aligned with the project's roadmap by talking to
13 | the maintainers, especially if you are going to spend a lot of time on it.
14 | - Make sure there's an issue open for any work you take on and intend to submit
15 | as a pull request - it helps core members review your concept and direction
16 | early and is a good way to discuss what you're planning to do.
17 | - If you open an issue and are interested in working on a fix, please let us
18 | know. We'll help you get started, rather than inadvertently doubling up on your hard work.
19 | - Make sure you do not add regressions by running `yarn test`.
20 | - Where possible, include tests with your changes, either that demonstrates the
21 | bug, or tests the new functionality.
22 | - All new features and changes need documentation.
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Jed Watson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | '@emotion/babel-plugin',
4 | ['@babel/plugin-proposal-class-properties', { loose: true }],
5 | ['@babel/plugin-proposal-private-methods', { loose: true }],
6 | '@babel/plugin-transform-runtime',
7 | ],
8 | presets: [
9 | '@babel/preset-env',
10 | '@babel/preset-react',
11 | '@babel/preset-typescript',
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:8000/cypress-tests",
3 | "video": false
4 | }
5 |
--------------------------------------------------------------------------------
/cypress/fixtures/selectors.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleBasic": "#cypress-single",
3 | "singleBasicSelect": "#basic-select-single",
4 | "singleClearable": "#cypress-single-clearable",
5 | "singleClearableSelect": "#clearable-select-single",
6 | "singleGroupedSelect": "#grouped-options-single",
7 | "checkboxDisable": ".disable-checkbox",
8 | "checkboxEscapeClearsValue": ".escape-clears-value-checkbox",
9 | "groupHeading": ".react-select__group-heading",
10 | "indicatorClear": ".react-select__clear-indicator",
11 | "indicatorDropdown": ".react-select__dropdown-indicator",
12 | "menu": ".react-select__menu",
13 | "control": ".react-select__control",
14 | "menuOption": ".react-select__option",
15 | "noOptionsValue": ".react-select__menu-notice--no-options",
16 | "placeholder": ".react-select__placeholder",
17 | "singleValue": ".react-select__single-value",
18 | "menuSingle": "#basic-select-single .react-select__menu",
19 | "singleSelectSingleInput": "#react-select-basic-select-single-input",
20 | "toggleMenuSingle": "#basic-select-single .react-select__dropdown-indicator",
21 | "firstMultiValueRemove": "#multi-select .react-select__multi-value__remove:first",
22 | "menuMulti": "#multi-select .react-select__menu",
23 | "multiSelectDefaultValues": "#multi-select .react-select__multi-value",
24 | "multiSelectInput": "#react-select-multi-select-input",
25 | "placeHolderMulti": "#multi-select .react-select__placeholder",
26 | "toggleMenuMulti": "#multi-select .react-select__dropdown-indicator",
27 | "focusedOption": ".react-select__option--is-focused"
28 | }
29 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "noEmit": true,
6 | "strict": true,
7 | "types": ["cypress"],
8 | "esModuleInterop": true,
9 | "resolveJsonModule": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/docs/App/Footer.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 |
4 | // const smallDevice = '@media (max-width: 769px)';
5 | const largeDevice = '@media (min-width: 770px)';
6 |
7 | const Wrapper = (props: JSX.IntrinsicElements['div']) => (
8 |
18 | );
19 | const Container = (props: JSX.IntrinsicElements['div']) => (
20 |
39 | );
40 | const A = (props: JSX.IntrinsicElements['a']) => (
41 |
56 | );
57 |
58 | export default function Footer() {
59 | return (
60 |
61 |
62 |
63 | Copyright © Jed Watson ,
64 | 2022. MIT Licensed.
65 |
66 |
67 | Thanks to Thinkmill and{' '}
68 | Atlassian for supporting this
69 | project.
70 |
71 |
72 |
73 | );
74 | }
75 |
--------------------------------------------------------------------------------
/docs/App/Section.tsx:
--------------------------------------------------------------------------------
1 | import React, { FunctionComponent } from 'react';
2 | import { Redirect, Route, RouteComponentProps, Switch } from 'react-router-dom';
3 |
4 | import routes from './routes';
5 |
6 | const Section: FunctionComponent = () => {
7 | const routeKeys = Object.keys(routes);
8 | return (
9 |
10 | {routeKeys.map((r) => (
11 | } />
12 | ))}
13 |
14 |
15 | );
16 | };
17 |
18 | const Content = ({ location, match }: RouteComponentProps) => {
19 | const page = routes[match.path];
20 |
21 | return (
22 | (
25 |
26 |
27 |
28 | )}
29 | />
30 | );
31 | };
32 |
33 | export default Section;
34 |
--------------------------------------------------------------------------------
/docs/App/TwitterButton.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 |
4 | const TwitterButton = () => (
5 |
44 | );
45 |
46 | export default TwitterButton;
47 |
--------------------------------------------------------------------------------
/docs/App/routes.ts:
--------------------------------------------------------------------------------
1 | import { ComponentType } from 'react';
2 | import Home from '../pages/home';
3 | import Props from '../pages/props';
4 | import Styles from '../pages/styles';
5 | import Components from '../pages/components';
6 | import Async from '../pages/async';
7 | import Creatable from '../pages/creatable';
8 | import Advanced from '../pages/advanced';
9 | import TypeScript from '../pages/typescript';
10 | import Upgrade from '../pages/upgrade';
11 | import UpgradeToV2 from '../pages/upgrade-to-v2';
12 |
13 | const routes: { readonly [key: string]: ComponentType } = {
14 | '/home': Home,
15 | '/props': Props,
16 | '/styles': Styles,
17 | '/components': Components,
18 | '/async': Async,
19 | '/creatable': Creatable,
20 | '/advanced': Advanced,
21 | '/typescript': TypeScript,
22 | '/upgrade': Upgrade,
23 | '/upgrade-to-v2': UpgradeToV2,
24 | };
25 |
26 | export default routes;
27 |
--------------------------------------------------------------------------------
/docs/NoMatch.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { H1 } from './styled-components';
4 |
5 | export default function NoMatch() {
6 | return (
7 |
8 |
Oops!
9 |
Couldn't find this page.
10 |
Back home
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/docs/PropTypes/Async.ts:
--------------------------------------------------------------------------------
1 | export { AsyncAdditionalProps } from 'react-select/src/useAsync';
2 |
--------------------------------------------------------------------------------
/docs/PropTypes/Creatable.ts:
--------------------------------------------------------------------------------
1 | export { CreatableAdditionalProps } from 'react-select/src/useCreatable';
2 |
--------------------------------------------------------------------------------
/docs/PropTypes/Select.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 |
3 | import { Props, defaultProps } from 'react-select/src/Select';
4 | import { GroupBase } from 'react-select';
5 |
6 | export default class Select extends Component<
7 | Props>
8 | > {
9 | defaultProps = defaultProps;
10 | }
11 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/ClearIndicator.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, ClearIndicatorProps } from 'react-select';
3 |
4 | export default class ClearIndicator<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Control.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { ControlProps, GroupBase } from 'react-select';
3 |
4 | export default class Control<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/DropdownIndicator.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, DropdownIndicatorProps } from 'react-select';
3 |
4 | export default class DropdownIndicator<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Group.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, GroupProps } from 'react-select';
3 |
4 | export default class Group<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/IndicatorsContainer.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, IndicatorsContainerProps } from 'react-select';
3 |
4 | export default class IndicatorsContainer<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/IndicatorsSeparator.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { DropdownIndicatorProps, GroupBase } from 'react-select';
3 |
4 | export default class DropdownIndicator<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Input.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, InputProps } from 'react-select';
3 |
4 | export default class Input<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/LoadingIndicator.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, LoadingIndicatorProps } from 'react-select';
3 |
4 | export default class LoadingIndicator<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/LoadingMessage.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, NoticeProps } from 'react-select';
3 |
4 | export default class LoadingMessage<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Menu.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MenuProps } from 'react-select';
3 |
4 | export default class Menu<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/MenuList.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MenuListProps } from 'react-select';
3 |
4 | export default class MenuList<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/MultiValue.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MultiValueProps } from 'react-select';
3 |
4 | export default class MultiValue<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/MultiValueContainer.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MultiValueGenericProps } from 'react-select';
3 |
4 | export default class MultiValueContainer<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/MultiValueLabel.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MultiValueGenericProps } from 'react-select';
3 |
4 | export default class MultiValueLabel<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/MultiValueRemove.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, MultiValueGenericProps } from 'react-select';
3 |
4 | export default class MultiValueRemove<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/NoOptionsMessage.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, NoticeProps } from 'react-select';
3 |
4 | export default class NoOptionsMessage<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Option.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, OptionProps } from 'react-select';
3 |
4 | export default class Option<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/Placeholder.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, PlaceholderProps } from 'react-select';
3 |
4 | export default class Placeholder<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/SelectContainer.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { ContainerProps, GroupBase } from 'react-select';
3 |
4 | export default class SelectContainer<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/SingleValue.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, SingleValueProps } from 'react-select';
3 |
4 | export default class SingleValue<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/components/ValueContainer.ts:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { GroupBase, ValueContainerProps } from 'react-select';
3 |
4 | export default class ValueContainer<
5 | Option,
6 | IsMulti extends boolean,
7 | Group extends GroupBase
8 | > extends Component> {}
9 |
--------------------------------------------------------------------------------
/docs/PropTypes/stateManager.ts:
--------------------------------------------------------------------------------
1 | export { StateManagerAdditionalProps } from 'react-select/src/useStateManager';
2 |
--------------------------------------------------------------------------------
/docs/Svg.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 |
4 | export type SvgProps = { readonly size: number } & JSX.IntrinsicElements['svg'];
5 |
6 | const Svg = ({ size, ...props }: SvgProps) => (
7 |
23 | );
24 |
25 | export default Svg;
26 |
--------------------------------------------------------------------------------
/docs/Table.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { FunctionComponent } from 'react';
3 | import { jsx } from '@emotion/react';
4 |
5 | export const Table: FunctionComponent = ({ children }) => (
6 |
15 | );
16 |
17 | export const Header: FunctionComponent = ({ children }) => (
18 |
25 | {children}
26 |
27 | );
28 |
29 | export const Cell: FunctionComponent = ({ children }) => (
30 |
38 | {children}
39 |
40 | );
41 |
--------------------------------------------------------------------------------
/docs/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 |
--------------------------------------------------------------------------------
/docs/examples/AnimatedMulti.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select from 'react-select';
4 | import makeAnimated from 'react-select/animated';
5 | import { colourOptions } from '../data';
6 |
7 | const animatedComponents = makeAnimated();
8 |
9 | export default function AnimatedMulti() {
10 | return (
11 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/docs/examples/AsyncCallbacks.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import AsyncSelect from 'react-select/async';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const filterColors = (inputValue: string) => {
7 | return colourOptions.filter((i) =>
8 | i.label.toLowerCase().includes(inputValue.toLowerCase())
9 | );
10 | };
11 |
12 | const loadOptions = (
13 | inputValue: string,
14 | callback: (options: ColourOption[]) => void
15 | ) => {
16 | setTimeout(() => {
17 | callback(filterColors(inputValue));
18 | }, 1000);
19 | };
20 |
21 | export default () => (
22 |
23 | );
24 |
--------------------------------------------------------------------------------
/docs/examples/AsyncCreatable.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import AsyncCreatableSelect from 'react-select/async-creatable';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const filterColors = (inputValue: string) => {
7 | return colourOptions.filter((i) =>
8 | i.label.toLowerCase().includes(inputValue.toLowerCase())
9 | );
10 | };
11 |
12 | const promiseOptions = (inputValue: string) =>
13 | new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(filterColors(inputValue));
16 | }, 1000);
17 | });
18 |
19 | export default () => (
20 |
25 | );
26 |
--------------------------------------------------------------------------------
/docs/examples/AsyncMulti.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import AsyncSelect from 'react-select/async';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const filterColors = (inputValue: string) => {
7 | return colourOptions.filter((i) =>
8 | i.label.toLowerCase().includes(inputValue.toLowerCase())
9 | );
10 | };
11 |
12 | const promiseOptions = (inputValue: string) =>
13 | new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(filterColors(inputValue));
16 | }, 1000);
17 | });
18 |
19 | export default () => (
20 |
26 | );
27 |
--------------------------------------------------------------------------------
/docs/examples/AsyncPromises.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import AsyncSelect from 'react-select/async';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const filterColors = (inputValue: string) => {
7 | return colourOptions.filter((i) =>
8 | i.label.toLowerCase().includes(inputValue.toLowerCase())
9 | );
10 | };
11 |
12 | const promiseOptions = (inputValue: string) =>
13 | new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(filterColors(inputValue));
16 | }, 1000);
17 | });
18 |
19 | export default () => (
20 |
21 | );
22 |
--------------------------------------------------------------------------------
/docs/examples/BasicGrouped.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties } from 'react';
2 |
3 | import Select from 'react-select';
4 | import {
5 | ColourOption,
6 | colourOptions,
7 | FlavourOption,
8 | GroupedOption,
9 | groupedOptions,
10 | } from '../data';
11 |
12 | const groupStyles = {
13 | display: 'flex',
14 | alignItems: 'center',
15 | justifyContent: 'space-between',
16 | };
17 | const groupBadgeStyles: CSSProperties = {
18 | backgroundColor: '#EBECF0',
19 | borderRadius: '2em',
20 | color: '#172B4D',
21 | display: 'inline-block',
22 | fontSize: 12,
23 | fontWeight: 'normal',
24 | lineHeight: '1',
25 | minWidth: 1,
26 | padding: '0.16666666666667em 0.5em',
27 | textAlign: 'center',
28 | };
29 |
30 | const formatGroupLabel = (data: GroupedOption) => (
31 |
32 | {data.label}
33 | {data.options.length}
34 |
35 | );
36 |
37 | export default () => (
38 |
39 | defaultValue={colourOptions[1]}
40 | options={groupedOptions}
41 | formatGroupLabel={formatGroupLabel}
42 | />
43 | );
44 |
--------------------------------------------------------------------------------
/docs/examples/BasicMulti.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select from 'react-select';
4 | import { colourOptions } from '../data';
5 |
6 | export default () => (
7 |
15 | );
16 |
--------------------------------------------------------------------------------
/docs/examples/BasicSingle.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import Select from 'react-select';
4 | import { colourOptions } from '../data';
5 |
6 | const Checkbox = ({ children, ...props }: JSX.IntrinsicElements['input']) => (
7 |
8 |
9 | {children}
10 |
11 | );
12 |
13 | export default () => {
14 | const [isClearable, setIsClearable] = useState(true);
15 | const [isSearchable, setIsSearchable] = useState(true);
16 | const [isDisabled, setIsDisabled] = useState(false);
17 | const [isLoading, setIsLoading] = useState(false);
18 | const [isRtl, setIsRtl] = useState(false);
19 |
20 | return (
21 | <>
22 |
34 |
35 |
44 | setIsClearable((state) => !state)}
47 | >
48 | Clearable
49 |
50 | setIsSearchable((state) => !state)}
53 | >
54 | Searchable
55 |
56 | setIsDisabled((state) => !state)}
59 | >
60 | Disabled
61 |
62 | setIsLoading((state) => !state)}
65 | >
66 | Loading
67 |
68 | setIsRtl((state) => !state)}>
69 | RTL
70 |
71 |
72 | >
73 | );
74 | };
75 |
--------------------------------------------------------------------------------
/docs/examples/ControlledMenu.tsx:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from 'react';
2 |
3 | import Select, { SelectInstance } from 'react-select';
4 | import { colourOptions } from '../data';
5 | import { Note } from '../styled-components';
6 |
7 | const Checkbox = (props: JSX.IntrinsicElements['input']) => (
8 |
9 | );
10 |
11 | export default () => {
12 | const ref = useRef(null);
13 | const [menuIsOpen, setMenuIsOpen] = useState(false);
14 |
15 | const toggleMenuIsOpen = () => {
16 | setMenuIsOpen((value) => !value);
17 | const selectEl = ref.current;
18 | if (!selectEl) return;
19 | if (menuIsOpen) selectEl.blur();
20 | else selectEl.focus();
21 | };
22 |
23 | return (
24 | <>
25 | ({ ...base, position: 'relative' }) }}
31 | name="color"
32 | options={colourOptions}
33 | />
34 |
35 |
40 | menuIsOpen
41 |
42 | >
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/docs/examples/CreatableAdvanced.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import CreatableSelect from 'react-select/creatable';
4 |
5 | interface Option {
6 | readonly label: string;
7 | readonly value: string;
8 | }
9 |
10 | const createOption = (label: string) => ({
11 | label,
12 | value: label.toLowerCase().replace(/\W/g, ''),
13 | });
14 |
15 | const defaultOptions = [
16 | createOption('One'),
17 | createOption('Two'),
18 | createOption('Three'),
19 | ];
20 |
21 | export default () => {
22 | const [isLoading, setIsLoading] = useState(false);
23 | const [options, setOptions] = useState(defaultOptions);
24 | const [value, setValue] = useState();
25 |
26 | const handleCreate = (inputValue: string) => {
27 | setIsLoading(true);
28 | setTimeout(() => {
29 | const newOption = createOption(inputValue);
30 | setIsLoading(false);
31 | setOptions((prev) => [...prev, newOption]);
32 | setValue(newOption);
33 | }, 1000);
34 | };
35 |
36 | return (
37 | setValue(newValue)}
42 | onCreateOption={handleCreate}
43 | options={options}
44 | value={value}
45 | />
46 | );
47 | };
48 |
--------------------------------------------------------------------------------
/docs/examples/CreatableInputOnly.tsx:
--------------------------------------------------------------------------------
1 | import React, { KeyboardEventHandler } from 'react';
2 |
3 | import CreatableSelect from 'react-select/creatable';
4 |
5 | const components = {
6 | DropdownIndicator: null,
7 | };
8 |
9 | interface Option {
10 | readonly label: string;
11 | readonly value: string;
12 | }
13 |
14 | const createOption = (label: string) => ({
15 | label,
16 | value: label,
17 | });
18 |
19 | export default () => {
20 | const [inputValue, setInputValue] = React.useState('');
21 | const [value, setValue] = React.useState([]);
22 |
23 | const handleKeyDown: KeyboardEventHandler = (event) => {
24 | if (!inputValue) return;
25 | switch (event.key) {
26 | case 'Enter':
27 | case 'Tab':
28 | setValue((prev) => [...prev, createOption(inputValue)]);
29 | setInputValue('');
30 | event.preventDefault();
31 | }
32 | };
33 |
34 | return (
35 | setValue(newValue)}
42 | onInputChange={(newValue) => setInputValue(newValue)}
43 | onKeyDown={handleKeyDown}
44 | placeholder="Type something and press enter..."
45 | value={value}
46 | />
47 | );
48 | };
49 |
--------------------------------------------------------------------------------
/docs/examples/CreatableMulti.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import CreatableSelect from 'react-select/creatable';
4 | import { colourOptions } from '../data';
5 |
6 | export default () => ;
7 |
--------------------------------------------------------------------------------
/docs/examples/CreatableSingle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import CreatableSelect from 'react-select/creatable';
4 | import { colourOptions } from '../data';
5 |
6 | export default () => ;
7 |
--------------------------------------------------------------------------------
/docs/examples/CreateFilter.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import Select, { createFilter } from 'react-select';
3 | import { colourOptions } from '../data';
4 | import { Note } from '../styled-components';
5 |
6 | const Checkbox = (props: JSX.IntrinsicElements['input']) => (
7 |
8 | );
9 |
10 | export default () => {
11 | const [ignoreCase, setIgnoreCase] = useState(false);
12 | const [ignoreAccents, setIgnoreAccents] = useState(false);
13 | const [trim, setTrim] = useState(false);
14 | const [matchFromStart, setMatchFromStart] = useState(false);
15 |
16 | const filterConfig = {
17 | ignoreCase,
18 | ignoreAccents,
19 | trim,
20 | matchFrom: matchFromStart ? ('start' as const) : ('any' as const),
21 | };
22 |
23 | return (
24 | <>
25 |
33 |
34 | setIgnoreCase((prev) => !prev)}
37 | id="cypress-single__clearable-checkbox"
38 | />
39 | Ignore Case
40 |
41 |
42 | setIgnoreAccents((prev) => !prev)}
45 | id="cypress-single__clearable-checkbox"
46 | />
47 | Ignore Accents
48 |
49 |
50 | setTrim((prev) => !prev)}
53 | id="cypress-single__clearable-checkbox"
54 | />
55 | Trim
56 |
57 |
58 | setMatchFromStart((prev) => !prev)}
61 | id="cypress-single__clearable-checkbox"
62 | />
63 | Match from the start
64 |
65 | >
66 | );
67 | };
68 |
--------------------------------------------------------------------------------
/docs/examples/CustomAriaLive.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties, useState } from 'react';
2 |
3 | import Select, { AriaOnFocus } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | export default function CustomAriaLive() {
7 | const [ariaFocusMessage, setAriaFocusMessage] = useState('');
8 | const [isMenuOpen, setIsMenuOpen] = useState(false);
9 |
10 | const style: { [key: string]: CSSProperties } = {
11 | blockquote: {
12 | fontStyle: 'italic',
13 | fontSize: '.75rem',
14 | margin: '1rem 0',
15 | },
16 | label: {
17 | fontSize: '.75rem',
18 | fontWeight: 'bold',
19 | lineHeight: 2,
20 | },
21 | };
22 |
23 | const onFocus: AriaOnFocus = ({ focused, isDisabled }) => {
24 | const msg = `You are currently focused on option ${focused.label}${
25 | isDisabled ? ', disabled' : ''
26 | }`;
27 | setAriaFocusMessage(msg);
28 | return msg;
29 | };
30 |
31 | const onMenuOpen = () => setIsMenuOpen(true);
32 | const onMenuClose = () => setIsMenuOpen(false);
33 |
34 | return (
35 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/docs/examples/CustomClearIndicator.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties, FunctionComponent } from 'react';
2 |
3 | import Select, { ClearIndicatorProps } from 'react-select';
4 | import { CSSObject } from '@emotion/serialize';
5 | import { ColourOption, colourOptions } from '../data';
6 |
7 | const CustomClearText: FunctionComponent = () => <>clear all>;
8 | const ClearIndicator = (props: ClearIndicatorProps) => {
9 | const {
10 | children = ,
11 | getStyles,
12 | innerProps: { ref, ...restInnerProps },
13 | } = props;
14 | return (
15 |
22 | );
23 | };
24 |
25 | const ClearIndicatorStyles = (
26 | base: CSSObject,
27 | state: ClearIndicatorProps
28 | ): CSSObject => ({
29 | ...base,
30 | cursor: 'pointer',
31 | color: state.isFocused ? 'blue' : 'black',
32 | });
33 |
34 | export default function CustomClearIndicator() {
35 | return (
36 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/docs/examples/CustomControl.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select, { components, ControlProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 | const controlStyles = {
6 | border: '1px solid black',
7 | padding: '5px',
8 | background: colourOptions[2].color,
9 | color: 'white',
10 | };
11 |
12 | const ControlComponent = (props: ControlProps) => (
13 |
14 |
Custom Control
15 |
16 |
17 | );
18 |
19 | export default () => (
20 |
28 | );
29 |
--------------------------------------------------------------------------------
/docs/examples/CustomDropdownIndicator.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import EmojiIcon from '@atlaskit/icon/glyph/emoji';
3 | import Select, { components, DropdownIndicatorProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const DropdownIndicator = (
7 | props: DropdownIndicatorProps
8 | ) => {
9 | return (
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | export default () => (
17 |
24 | );
25 |
--------------------------------------------------------------------------------
/docs/examples/CustomFilterOptions.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select from 'react-select';
3 | import { colourOptions } from '../data';
4 |
5 | const filterOptions = (
6 | candidate: { label: string; value: string; data: any },
7 | input: string
8 | ) => {
9 | if (input) {
10 | return candidate.value === customOptions[0].value;
11 | }
12 | return true;
13 | };
14 |
15 | const customOptions = [
16 | {
17 | value: 'custom',
18 | label: 'Using a custom filter to always display this option on search',
19 | },
20 | ...colourOptions,
21 | ];
22 |
23 | export default () => (
24 |
32 | );
33 |
--------------------------------------------------------------------------------
/docs/examples/CustomGetOptionLabel.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select from 'react-select';
3 | import { flavourOptions } from '../data';
4 |
5 | export default () => (
6 | <>
7 |
8 | Composing a display label from the label property and rating property in
9 | the options object
10 |
11 | `${option.label}: ${option.rating}`}
18 | />
19 | >
20 | );
21 |
--------------------------------------------------------------------------------
/docs/examples/CustomGetOptionValue.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import Select from 'react-select';
3 | import { dogOptions } from '../data';
4 |
5 | export default function CustomGetOptionValue() {
6 | return (
7 |
8 | Using id property, instead of value property.
9 | `${option['id']}`}
16 | />
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/docs/examples/CustomGroup.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select, { components, GroupProps } from 'react-select';
4 | import {
5 | ColourOption,
6 | colourOptions,
7 | FlavourOption,
8 | groupedOptions,
9 | } from '../data';
10 |
11 | const groupStyles = {
12 | border: `2px dotted ${colourOptions[2].color}`,
13 | borderRadius: '5px',
14 | background: '#f2fcff',
15 | };
16 |
17 | const Group = (props: GroupProps) => (
18 |
19 |
20 |
21 | );
22 |
23 | export default () => (
24 |
25 | defaultValue={colourOptions[1]}
26 | options={groupedOptions}
27 | components={{ Group }}
28 | />
29 | );
30 |
--------------------------------------------------------------------------------
/docs/examples/CustomGroupHeading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select, { components, GroupHeadingProps } from 'react-select';
4 | import {
5 | ColourOption,
6 | colourOptions,
7 | FlavourOption,
8 | groupedOptions,
9 | } from '../data';
10 | import EditorPanelIcon from '@atlaskit/icon/glyph/editor/panel';
11 | import Tooltip from '@atlaskit/tooltip';
12 |
13 | const groupStyles = {
14 | border: `2px dotted ${colourOptions[2].color}`,
15 | color: 'white',
16 | background: colourOptions[2].color,
17 | padding: '5px 0px',
18 | display: 'flex',
19 | };
20 |
21 | const GroupHeading = (
22 | props: GroupHeadingProps
23 | ) => (
24 |
25 |
26 |
27 |
28 |
29 |
30 | );
31 |
32 | export default () => (
33 |
34 | defaultValue={colourOptions[1]}
35 | options={groupedOptions}
36 | components={{ GroupHeading }}
37 | styles={{
38 | groupHeading: (base) => ({
39 | ...base,
40 | flex: '1 1',
41 | color: 'white',
42 | margin: 0,
43 | }),
44 | }}
45 | />
46 | );
47 |
--------------------------------------------------------------------------------
/docs/examples/CustomIndicatorSeparator.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { IndicatorSeparatorProps } from 'react-select';
3 | import { ColourOption, colourOptions } from '../data';
4 |
5 | const indicatorSeparatorStyle = {
6 | alignSelf: 'stretch',
7 | backgroundColor: colourOptions[2].color,
8 | marginBottom: 8,
9 | marginTop: 8,
10 | width: 1,
11 | };
12 |
13 | const IndicatorSeparator = ({
14 | innerProps,
15 | }: IndicatorSeparatorProps) => {
16 | return ;
17 | };
18 |
19 | export default () => (
20 |
27 | );
28 |
--------------------------------------------------------------------------------
/docs/examples/CustomIndicatorsContainer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { components, IndicatorsContainerProps } from 'react-select';
3 | import { ColourOption, colourOptions } from '../data';
4 |
5 | const IndicatorsContainer = (
6 | props: IndicatorsContainerProps
7 | ) => {
8 | return (
9 |
10 |
11 |
12 | );
13 | };
14 |
15 | export default () => (
16 |
23 | );
24 |
--------------------------------------------------------------------------------
/docs/examples/CustomInput.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import Select, { components, InputProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const Input = (props: InputProps) => {
7 | if (props.isHidden) {
8 | return ;
9 | }
10 | return (
11 |
12 |
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | export default () => (
20 |
27 | );
28 |
--------------------------------------------------------------------------------
/docs/examples/CustomIsOptionDisabled.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select from 'react-select';
3 | import { flavourOptions } from '../data';
4 |
5 | export default () => (
6 | <>
7 |
8 | Disable all options that do not have a 'safe' rating, via the
9 | isOptionsDisabled fn prop
10 |
11 | option.rating !== 'safe'}
18 | />
19 | >
20 | );
21 |
--------------------------------------------------------------------------------
/docs/examples/CustomLoadingIndicator.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Spinner from '@atlaskit/spinner';
3 | import Tooltip from '@atlaskit/tooltip';
4 | import AsyncSelect from 'react-select/async';
5 | import { LoadingIndicatorProps } from 'react-select';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | const LoadingIndicator = (props: LoadingIndicatorProps) => {
9 | return (
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | const filterColors = (inputValue: string) =>
17 | colourOptions.filter((i) =>
18 | i.label.toLowerCase().includes(inputValue.toLowerCase())
19 | );
20 |
21 | const promiseOptions = (inputValue: string) =>
22 | new Promise((resolve) => {
23 | setTimeout(() => {
24 | resolve(filterColors(inputValue));
25 | }, 1000);
26 | });
27 |
28 | const CustomLoadingIndicator = () => {
29 | return (
30 |
36 | );
37 | };
38 |
39 | export default CustomLoadingIndicator;
40 |
--------------------------------------------------------------------------------
/docs/examples/CustomLoadingMessage.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties } from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import AsyncSelect from 'react-select/async';
4 | import { NoticeProps } from 'react-select';
5 | import { ColourOption, colourOptions } from '../data';
6 |
7 | const LoadingMessage = (props: NoticeProps) => {
8 | return (
9 |
10 |
14 | {props.children}
15 |
16 |
17 | );
18 | };
19 |
20 | const filterColors = (inputValue: string) =>
21 | colourOptions.filter((i) =>
22 | i.label.toLowerCase().includes(inputValue.toLowerCase())
23 | );
24 |
25 | const promiseOptions = (inputValue: string) =>
26 | new Promise((resolve) => {
27 | setTimeout(() => {
28 | resolve(filterColors(inputValue));
29 | }, 1000);
30 | });
31 |
32 | const CustomLoadingMessage = () => {
33 | return (
34 | ({
40 | ...base,
41 | backgroundColor: colourOptions[2].color,
42 | color: 'white',
43 | }),
44 | }}
45 | components={{ LoadingMessage }}
46 | />
47 | );
48 | };
49 |
50 | export default CustomLoadingMessage;
51 |
--------------------------------------------------------------------------------
/docs/examples/CustomMenu.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 |
3 | import Select, { components, MenuProps } from 'react-select';
4 | import {
5 | ColourOption,
6 | colourOptions,
7 | FlavourOption,
8 | GroupedOption,
9 | groupedOptions,
10 | } from '../data';
11 |
12 | function getLength(
13 | options: readonly (GroupedOption | ColourOption | FlavourOption)[]
14 | ): number {
15 | return options.reduce((acc, curr) => {
16 | if ('options' in curr) return acc + getLength(curr.options);
17 | return acc + 1;
18 | }, 0);
19 | }
20 |
21 | const menuHeaderStyle = {
22 | padding: '8px 12px',
23 | };
24 |
25 | const Menu = (
26 | props: MenuProps
27 | ) => {
28 | const optionsLength = getLength(props.options);
29 | return (
30 |
31 |
32 | Custom Menu with {optionsLength} options
33 |
34 |
35 | {...props}
36 | >
37 | {props.children}
38 |
39 |
40 | );
41 | };
42 |
43 | export default () => (
44 |
45 | defaultValue={colourOptions[1]}
46 | options={groupedOptions}
47 | components={{ Menu }}
48 | />
49 | );
50 |
--------------------------------------------------------------------------------
/docs/examples/CustomMenuList.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Select, { components, MenuListProps } from 'react-select';
4 | import {
5 | ColourOption,
6 | colourOptions,
7 | FlavourOption,
8 | GroupedOption,
9 | groupedOptions,
10 | } from '../data';
11 |
12 | const menuHeaderStyle = {
13 | padding: '8px 12px',
14 | background: colourOptions[2].color,
15 | color: 'white',
16 | };
17 |
18 | const MenuList = (
19 | props: MenuListProps
20 | ) => {
21 | return (
22 |
23 | Custom Menu List
24 | {props.children}
25 |
26 | );
27 | };
28 |
29 | export default () => (
30 |
31 | defaultValue={colourOptions[1]}
32 | options={groupedOptions}
33 | components={{ MenuList }}
34 | />
35 | );
36 |
--------------------------------------------------------------------------------
/docs/examples/CustomMultiValueContainer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import Select, { components, MultiValueGenericProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const MultiValueContainer = (props: MultiValueGenericProps) => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default () => (
15 | ({
20 | ...base,
21 | border: `2px dotted ${colourOptions[2].color}`,
22 | }),
23 | }}
24 | defaultValue={[colourOptions[4], colourOptions[5]]}
25 | isMulti
26 | options={colourOptions}
27 | />
28 | );
29 |
--------------------------------------------------------------------------------
/docs/examples/CustomMultiValueLabel.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import Select, { components, MultiValueGenericProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const MultiValueLabel = (props: MultiValueGenericProps) => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default () => (
15 | ({
20 | ...base,
21 | backgroundColor: colourOptions[2].color,
22 | color: 'white',
23 | }),
24 | }}
25 | defaultValue={[colourOptions[4], colourOptions[5]]}
26 | isMulti
27 | options={colourOptions}
28 | />
29 | );
30 |
--------------------------------------------------------------------------------
/docs/examples/CustomMultiValueRemove.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import EmojiIcon from '@atlaskit/icon/glyph/emoji';
3 | import Tooltip from '@atlaskit/tooltip';
4 | import Select, { components, MultiValueRemoveProps } from 'react-select';
5 | import { ColourOption, colourOptions } from '../data';
6 |
7 | const MultiValueRemove = (props: MultiValueRemoveProps) => {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | export default () => (
18 | ({
23 | ...base,
24 | border: `1px dotted ${colourOptions[2].color}`,
25 | height: '100%',
26 | }),
27 | }}
28 | defaultValue={[colourOptions[4], colourOptions[5]]}
29 | isMulti
30 | options={colourOptions}
31 | />
32 | );
33 |
--------------------------------------------------------------------------------
/docs/examples/CustomNoOptionsMessage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import Select, { components, NoticeProps } from 'react-select';
4 | import { colourOptions } from '../data';
5 |
6 | const msgStyles = {
7 | background: colourOptions[2].color,
8 | color: 'white',
9 | };
10 |
11 | const NoOptionsMessage = (props: NoticeProps) => {
12 | return (
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | const CustomNoOptionsMessage = () => {
20 | return (
21 | ({ ...base, ...msgStyles }) }}
25 | isSearchable
26 | name="color"
27 | options={[]}
28 | />
29 | );
30 | };
31 |
32 | export default CustomNoOptionsMessage;
33 |
--------------------------------------------------------------------------------
/docs/examples/CustomOption.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import Select, { components, OptionProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const Option = (props: OptionProps) => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default () => (
15 | ({
20 | ...base,
21 | border: `1px dotted ${colourOptions[2].color}`,
22 | height: '100%',
23 | }),
24 | }}
25 | defaultValue={colourOptions[4]}
26 | options={colourOptions}
27 | />
28 | );
29 |
--------------------------------------------------------------------------------
/docs/examples/CustomPlaceholder.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { components, PlaceholderProps } from 'react-select';
3 | import { ColourOption, colourOptions } from '../data';
4 |
5 | const Placeholder = (props: PlaceholderProps) => {
6 | return ;
7 | };
8 |
9 | export default () => (
10 | ({
16 | ...base,
17 | fontSize: '1em',
18 | color: colourOptions[2].color,
19 | fontWeight: 400,
20 | }),
21 | }}
22 | options={colourOptions}
23 | />
24 | );
25 |
--------------------------------------------------------------------------------
/docs/examples/CustomSelectContainer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { components, ContainerProps } from 'react-select';
3 | import Tooltip from '@atlaskit/tooltip';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const SelectContainer = ({
7 | children,
8 | ...props
9 | }: ContainerProps) => {
10 | return (
11 |
12 |
13 | {children}
14 |
15 |
16 | );
17 | };
18 |
19 | export default () => (
20 | ({
25 | ...base,
26 | backgroundColor: colourOptions[2].color,
27 | padding: 5,
28 | }),
29 | }}
30 | options={colourOptions}
31 | />
32 | );
33 |
--------------------------------------------------------------------------------
/docs/examples/CustomSelectProps.tsx:
--------------------------------------------------------------------------------
1 | import React, { MouseEventHandler, useState } from 'react';
2 | import Select, {
3 | components,
4 | ControlProps,
5 | Props,
6 | StylesConfig,
7 | } from 'react-select';
8 | import { ColourOption, colourOptions } from '../data';
9 |
10 | const EMOJIS = ['👍', '🤙', '👏', '👌', '🙌', '✌️', '🖖', '👐'];
11 |
12 | const Control = ({ children, ...props }: ControlProps) => {
13 | // @ts-ignore
14 | const { emoji, onEmojiClick } = props.selectProps;
15 | const style = { cursor: 'pointer' };
16 |
17 | return (
18 |
19 |
20 | {emoji}
21 |
22 | {children}
23 |
24 | );
25 | };
26 |
27 | const CustomSelectProps = (props: Props) => {
28 | const [clickCount, setClickCount] = useState(0);
29 |
30 | const onClick: MouseEventHandler = (e) => {
31 | setClickCount(clickCount + 1);
32 | e.preventDefault();
33 | e.stopPropagation();
34 | };
35 |
36 | const styles: StylesConfig = {
37 | control: (css) => ({ ...css, paddingLeft: '1rem' }),
38 | };
39 |
40 | const emoji = EMOJIS[clickCount % EMOJIS.length];
41 |
42 | return (
43 |
54 | );
55 | };
56 |
57 | export default CustomSelectProps;
58 |
--------------------------------------------------------------------------------
/docs/examples/CustomSingleValue.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { components, SingleValueProps } from 'react-select';
3 | import { ColourOption, colourOptions } from '../data';
4 |
5 | const SingleValue = ({
6 | children,
7 | ...props
8 | }: SingleValueProps) => (
9 | {children}
10 | );
11 |
12 | export default () => (
13 | ({
18 | ...base,
19 | padding: 5,
20 | borderRadius: 5,
21 | background: colourOptions[2].color,
22 | color: 'white',
23 | display: 'flex',
24 | }),
25 | }}
26 | components={{ SingleValue }}
27 | isSearchable
28 | name="color"
29 | options={colourOptions}
30 | />
31 | );
32 |
--------------------------------------------------------------------------------
/docs/examples/CustomValueContainer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { components, ValueContainerProps } from 'react-select';
3 | import { ColourOption, colourOptions } from '../data';
4 |
5 | const ValueContainer = ({
6 | children,
7 | ...props
8 | }: ValueContainerProps) => (
9 | {children}
10 | );
11 |
12 | export default () => (
13 | ({ ...base, color: 'white' }),
18 | valueContainer: (base) => ({
19 | ...base,
20 | background: colourOptions[2].color,
21 | color: 'white',
22 | width: '100%',
23 | }),
24 | }}
25 | components={{ ValueContainer }}
26 | isSearchable
27 | name="color"
28 | options={colourOptions}
29 | />
30 | );
31 |
--------------------------------------------------------------------------------
/docs/examples/DefaultOptions.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import AsyncSelect from 'react-select/async';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const filterColors = (inputValue: string) => {
7 | return colourOptions.filter((i) =>
8 | i.label.toLowerCase().includes(inputValue.toLowerCase())
9 | );
10 | };
11 |
12 | const promiseOptions = (inputValue: string) =>
13 | new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(filterColors(inputValue));
16 | }, 1000);
17 | });
18 |
19 | export default () => (
20 |
25 | );
26 |
--------------------------------------------------------------------------------
/docs/examples/FixedOptions.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import Select, { ActionMeta, OnChangeValue, StylesConfig } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const styles: StylesConfig = {
7 | multiValue: (base, state) => {
8 | return state.data.isFixed ? { ...base, backgroundColor: 'gray' } : base;
9 | },
10 | multiValueLabel: (base, state) => {
11 | return state.data.isFixed
12 | ? { ...base, fontWeight: 'bold', color: 'white', paddingRight: 6 }
13 | : base;
14 | },
15 | multiValueRemove: (base, state) => {
16 | return state.data.isFixed ? { ...base, display: 'none' } : base;
17 | },
18 | };
19 |
20 | const orderOptions = (values: readonly ColourOption[]) => {
21 | return values
22 | .filter((v) => v.isFixed)
23 | .concat(values.filter((v) => !v.isFixed));
24 | };
25 |
26 | export default () => {
27 | const [value, setValue] = useState(
28 | orderOptions([colourOptions[0], colourOptions[1], colourOptions[3]])
29 | );
30 |
31 | const onChange = (
32 | newValue: OnChangeValue,
33 | actionMeta: ActionMeta
34 | ) => {
35 | switch (actionMeta.action) {
36 | case 'remove-value':
37 | case 'pop-value':
38 | if (actionMeta.removedValue.isFixed) {
39 | return;
40 | }
41 | break;
42 | case 'clear':
43 | newValue = colourOptions.filter((v) => v.isFixed);
44 | break;
45 | }
46 |
47 | setValue(orderOptions(newValue));
48 | };
49 |
50 | return (
51 | !v.isFixed)}
56 | name="colors"
57 | className="basic-multi-select"
58 | classNamePrefix="select"
59 | onChange={onChange}
60 | options={colourOptions}
61 | />
62 | );
63 | };
64 |
--------------------------------------------------------------------------------
/docs/examples/MenuBuffer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select from 'react-select';
3 |
4 | import { colourOptions } from '../data';
5 |
6 | export default () => (
7 | ({ ...base, marginBottom: 76 }) }}
11 | />
12 | );
13 |
--------------------------------------------------------------------------------
/docs/examples/OnSelectResetsInput.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Select, { InputActionMeta } from 'react-select';
3 | import { colourOptions } from '../data';
4 |
5 | export default () => {
6 | const [menuIsOpen, setMenuIsOpen] = React.useState();
7 |
8 | const onInputChange = (
9 | inputValue: string,
10 | { action, prevInputValue }: InputActionMeta
11 | ) => {
12 | if (action === 'input-change') return inputValue;
13 | if (action === 'menu-close') {
14 | if (prevInputValue) setMenuIsOpen(true);
15 | else setMenuIsOpen(undefined);
16 | }
17 | return prevInputValue;
18 | };
19 |
20 | return (
21 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/docs/examples/StyleCompositionExample.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 | import Select, { OptionProps } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | const Option = (props: OptionProps) => {
7 | const {
8 | children,
9 | className,
10 | cx,
11 | getStyles,
12 | isDisabled,
13 | isFocused,
14 | isSelected,
15 | innerRef,
16 | innerProps,
17 | } = props;
18 | return (
19 |
33 | {children}
34 |
35 | );
36 | };
37 |
38 | export default () => (
39 | ({
44 | ...base,
45 | border: `1px dotted ${colourOptions[2].color}`,
46 | height: '100%',
47 | }),
48 | }}
49 | defaultValue={colourOptions[4]}
50 | options={colourOptions}
51 | />
52 | );
53 |
--------------------------------------------------------------------------------
/docs/examples/StyledMulti.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import chroma from 'chroma-js';
3 |
4 | import { ColourOption, colourOptions } from '../data';
5 | import Select, { StylesConfig } from 'react-select';
6 |
7 | const colourStyles: StylesConfig = {
8 | control: (styles) => ({ ...styles, backgroundColor: 'white' }),
9 | option: (styles, { data, isDisabled, isFocused, isSelected }) => {
10 | const color = chroma(data.color);
11 | return {
12 | ...styles,
13 | backgroundColor: isDisabled
14 | ? undefined
15 | : isSelected
16 | ? data.color
17 | : isFocused
18 | ? color.alpha(0.1).css()
19 | : undefined,
20 | color: isDisabled
21 | ? '#ccc'
22 | : isSelected
23 | ? chroma.contrast(color, 'white') > 2
24 | ? 'white'
25 | : 'black'
26 | : data.color,
27 | cursor: isDisabled ? 'not-allowed' : 'default',
28 |
29 | ':active': {
30 | ...styles[':active'],
31 | backgroundColor: !isDisabled
32 | ? isSelected
33 | ? data.color
34 | : color.alpha(0.3).css()
35 | : undefined,
36 | },
37 | };
38 | },
39 | multiValue: (styles, { data }) => {
40 | const color = chroma(data.color);
41 | return {
42 | ...styles,
43 | backgroundColor: color.alpha(0.1).css(),
44 | };
45 | },
46 | multiValueLabel: (styles, { data }) => ({
47 | ...styles,
48 | color: data.color,
49 | }),
50 | multiValueRemove: (styles, { data }) => ({
51 | ...styles,
52 | color: data.color,
53 | ':hover': {
54 | backgroundColor: data.color,
55 | color: 'white',
56 | },
57 | }),
58 | };
59 |
60 | export default () => (
61 |
68 | );
69 |
--------------------------------------------------------------------------------
/docs/examples/StyledSingle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import chroma from 'chroma-js';
3 |
4 | import { ColourOption, colourOptions } from '../data';
5 | import Select, { StylesConfig } from 'react-select';
6 |
7 | const dot = (color = 'transparent') => ({
8 | alignItems: 'center',
9 | display: 'flex',
10 |
11 | ':before': {
12 | backgroundColor: color,
13 | borderRadius: 10,
14 | content: '" "',
15 | display: 'block',
16 | marginRight: 8,
17 | height: 10,
18 | width: 10,
19 | },
20 | });
21 |
22 | const colourStyles: StylesConfig = {
23 | control: (styles) => ({ ...styles, backgroundColor: 'white' }),
24 | option: (styles, { data, isDisabled, isFocused, isSelected }) => {
25 | const color = chroma(data.color);
26 | return {
27 | ...styles,
28 | backgroundColor: isDisabled
29 | ? undefined
30 | : isSelected
31 | ? data.color
32 | : isFocused
33 | ? color.alpha(0.1).css()
34 | : undefined,
35 | color: isDisabled
36 | ? '#ccc'
37 | : isSelected
38 | ? chroma.contrast(color, 'white') > 2
39 | ? 'white'
40 | : 'black'
41 | : data.color,
42 | cursor: isDisabled ? 'not-allowed' : 'default',
43 |
44 | ':active': {
45 | ...styles[':active'],
46 | backgroundColor: !isDisabled
47 | ? isSelected
48 | ? data.color
49 | : color.alpha(0.3).css()
50 | : undefined,
51 | },
52 | };
53 | },
54 | input: (styles) => ({ ...styles, ...dot() }),
55 | placeholder: (styles) => ({ ...styles, ...dot('#ccc') }),
56 | singleValue: (styles, { data }) => ({ ...styles, ...dot(data.color) }),
57 | };
58 |
59 | export default () => (
60 |
65 | );
66 |
--------------------------------------------------------------------------------
/docs/examples/Theme.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { flavourOptions } from '../data';
4 | import Select from 'react-select';
5 |
6 | export default () => (
7 | ({
11 | ...theme,
12 | borderRadius: 0,
13 | colors: {
14 | ...theme.colors,
15 | primary25: 'hotpink',
16 | primary: 'black',
17 | },
18 | })}
19 | />
20 | );
21 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JedWatson/react-select/2a913698ad3d7759fb8e6bc5dd8a7d839227da2f/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/generate-magical-types/generate/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-generate-magical-types-generate.cjs.js",
3 | "module": "dist/react-select-generate-magical-types-generate.esm.js"
4 | }
5 |
--------------------------------------------------------------------------------
/docs/generate-magical-types/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@react-select/generate-magical-types",
3 | "main": "dist/generate-magical-types.cjs.js",
4 | "exports": {
5 | "./generate": {
6 | "module": "./generate/dist/react-select-generate-magical-types-generate.esm.js",
7 | "import": "./generate/dist/react-select-generate-magical-types-generate.cjs.mjs",
8 | "default": "./generate/dist/react-select-generate-magical-types-generate.cjs.js"
9 | },
10 | "./serialize": {
11 | "module": "./serialize/dist/react-select-generate-magical-types-serialize.esm.js",
12 | "import": "./serialize/dist/react-select-generate-magical-types-serialize.cjs.mjs",
13 | "default": "./serialize/dist/react-select-generate-magical-types-serialize.cjs.js"
14 | },
15 | "./package.json": "./package.json"
16 | },
17 | "//": "these deps aren't real, they're just to appease preconstruct",
18 | "dependencies": {
19 | "@babel/runtime": "*",
20 | "@magical-types/convert-type": "*",
21 | "@magical-types/serialization": "*",
22 | "ts-morph": "*",
23 | "fs-extra": "*",
24 | "flatted": "*"
25 | },
26 | "preconstruct": {
27 | "entrypoints": [
28 | "generate.ts",
29 | "serialize.ts"
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/generate-magical-types/serialize/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-generate-magical-types-serialize.cjs.js",
3 | "module": "dist/react-select-generate-magical-types-serialize.esm.js"
4 | }
5 |
--------------------------------------------------------------------------------
/docs/generate-magical-types/src/types.ts:
--------------------------------------------------------------------------------
1 | import { MagicalNode, MagicalNodeIndex } from '@magical-types/types';
2 |
3 | export type MagicalNodeMetadata = Record<
4 | string,
5 | Record
6 | >;
7 |
8 | export type MagicalNodeRecord = {
9 | type: 'component' | 'other';
10 | index: MagicalNodeIndex;
11 | };
12 |
13 | export type MagicalNodesForPackage = Record<
14 | string,
15 | { type: 'component' | 'other'; node: MagicalNode }
16 | >;
17 |
18 | export type MagicalNodes = Record;
19 |
--------------------------------------------------------------------------------
/docs/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto:400,500,700');
2 |
3 | body {
4 | -moz-font-feature-settings: 'liga' on;
5 | -moz-osx-font-smoothing: grayscale;
6 | -webkit-font-smoothing: antialiased;
7 | color: #253858;
8 | font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
9 | Helvetica, sans-serif;
10 | font-style: normal;
11 | font-weight: 400;
12 | margin: 0;
13 | padding: 0;
14 | text-rendering: optimizeLegibility;
15 | }
16 | p > a,
17 | p > a:hover,
18 | p > a:visited,
19 | li > a,
20 | li > a:hover,
21 | li > a:visited {
22 | color: #2684ff;
23 | }
24 | code {
25 | font-family: Roboto Mono, Monaco, monospace;
26 | }
27 | p > code {
28 | white-space: nowrap;
29 | }
30 | p,
31 | ul,
32 | ol {
33 | line-height: 1.5;
34 | }
35 | td p {
36 | margin: 0;
37 | }
38 | h1,
39 | h2,
40 | h3,
41 | h4,
42 | h5 {
43 | color: #091e42;
44 | }
45 | h6 {
46 | color: #777;
47 | margin-bottom: 0.25em;
48 | text-transform: uppercase;
49 | }
50 | @keyframes dropIn {
51 | from,
52 | 60%,
53 | 75%,
54 | 90%,
55 | to {
56 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
57 | }
58 | 0% {
59 | opacity: 0;
60 | transform: translate3d(0, -1666px, 0);
61 | }
62 | 60% {
63 | opacity: 1;
64 | transform: translate3d(0, 26px, 0);
65 | }
66 | 75% {
67 | transform: translate3d(0, -10px, 0);
68 | }
69 | 90% {
70 | transform: translate3d(0, 6px, 0);
71 | }
72 | to {
73 | transform: translate3d(0, 0, 0);
74 | }
75 | }
76 | .animate-dropin {
77 | animation: dropIn 0.66s;
78 | }
79 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React-Select
5 |
9 |
13 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/docs/index.tsx:
--------------------------------------------------------------------------------
1 | import '@babel/polyfill';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import App from './App';
5 |
6 | ReactDOM.render( , document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/docs/isArray.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Alternative to Array.isArray that correctly narrows the type for readonly arrays.
3 | */
4 | export default function isArray(arg: unknown): arg is readonly T[] {
5 | return Array.isArray(arg);
6 | }
7 |
--------------------------------------------------------------------------------
/docs/markdown/store.ts:
--------------------------------------------------------------------------------
1 | export interface Data {
2 | key: string;
3 | label: string;
4 | level: number;
5 | path: string;
6 | }
7 |
8 | class HeadingStore {
9 | store: { [key: string]: Data } = {};
10 | headings: { [key: string]: Data[] } = {};
11 |
12 | add(key: string, data: Data) {
13 | console.log('add being called with', data.label);
14 | if (!this.headings[location.pathname]) {
15 | this.headings[location.pathname] = [];
16 | }
17 |
18 | if (!this.store[key]) {
19 | this.store[key] = data;
20 | this.headings[location.pathname].push(data);
21 | }
22 | }
23 | getStore() {
24 | return this.store;
25 | }
26 | getPageHeadings(page: string) {
27 | return this.headings[page];
28 | }
29 | getAllHeadings() {
30 | return this.headings;
31 | }
32 | getHeadingByKey(key: string) {
33 | return this.store[key];
34 | }
35 | }
36 |
37 | // global heading store
38 | const store = new HeadingStore();
39 |
40 | export default store;
41 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "jsx": "react",
6 | "noEmit": true,
7 | "strict": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "resolveJsonModule": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/docs/utils.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { MagicalNode, MagicalNodeIndex } from '@magical-types/types';
3 | import { deserialize } from '@magical-types/serialization/deserialize';
4 |
5 | import type { MagicalNodeMetadata } from './generate-magical-types/src/types';
6 | // @ts-ignore
7 | import manifest from './magical-types/magical-types-manifest.json';
8 |
9 | export type getNodeType =
10 | | ((index: MagicalNodeIndex) => MagicalNode)
11 | | undefined;
12 |
13 | let getNode: getNodeType;
14 |
15 | export const metadata: MagicalNodeMetadata = (manifest as any).types;
16 |
17 | export function useMagicalNodes() {
18 | let [, forceUpdate] = useState(0);
19 |
20 | useEffect(() => {
21 | if (!getNode) {
22 | fetch(manifest.paths[0])
23 | .then((x) => x.json())
24 | .then((firstNodeGroup) => {
25 | getNode = deserialize([
26 | firstNodeGroup,
27 | ...(manifest.paths as string[])
28 | .slice(1)
29 | .map((path) => () => fetch(path).then((x) => x.json())),
30 | ]);
31 | forceUpdate(1);
32 | });
33 | }
34 | }, []);
35 | return getNode;
36 | }
37 |
--------------------------------------------------------------------------------
/docs/webpack.config.ts:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import * as webpack from 'webpack';
3 | import CopyWebpackPlugin from 'copy-webpack-plugin';
4 | import HtmlWebpackPlugin from 'html-webpack-plugin';
5 | import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
6 | import { config } from 'dotenv';
7 | import { CleanWebpackPlugin } from 'clean-webpack-plugin';
8 |
9 | config();
10 |
11 | const webpackConfig: webpack.Configuration = {
12 | context: __dirname,
13 | entry: {
14 | index: './index',
15 | },
16 | output: {
17 | path: path.resolve(__dirname, 'dist'),
18 | filename: '[name].js',
19 | publicPath: '/',
20 | },
21 | devServer: {
22 | port: 8000,
23 | historyApiFallback: true,
24 | },
25 | // devtool: 'source-map',
26 | devtool: 'cheap-module-eval-source-map',
27 | resolve: {
28 | extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
29 | },
30 | module: {
31 | rules: [
32 | {
33 | test: /\.(ts|js)x?$/,
34 | exclude: [/node_modules/],
35 | use: [
36 | {
37 | loader: 'babel-loader',
38 | options: {
39 | root: path.join(__dirname, '..'),
40 | },
41 | },
42 | ],
43 | },
44 | {
45 | test: /\.css$/,
46 | use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
47 | },
48 | ],
49 | },
50 | plugins: [
51 | // new webpack.DefinePlugin({
52 | // 'process.env.CLIENT_ID': `'${process.env.CLIENT_ID}'`,
53 | // 'process.env.CLIENT_SECRET': `'${process.env.CLIENT_SECRET}'`,
54 | // }),
55 | new CleanWebpackPlugin(),
56 | new HtmlWebpackPlugin({
57 | filename: 'index.html',
58 | inject: false,
59 | template: path.resolve(__dirname, 'index.html'),
60 | }),
61 | new CopyWebpackPlugin([
62 | '_redirects',
63 | 'favicon.ico',
64 | 'index.css',
65 | 'magical-types/*',
66 | ]),
67 | new ForkTsCheckerWebpackPlugin({
68 | async: false,
69 | typescript: {
70 | configFile: './tsconfig.json',
71 | },
72 | }),
73 | ],
74 | };
75 |
76 | export default webpackConfig;
77 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | command = "yarn build:docs"
3 | publish = "docs/dist"
4 |
5 | [build.environment]
6 | YARN_VERSION = "1.22.22"
7 |
--------------------------------------------------------------------------------
/packages/react-select/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Jed Watson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/react-select/animated/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-animated.cjs.js",
3 | "module": "dist/react-select-animated.esm.js",
4 | "types": "dist/react-select-animated.cjs.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-select/async-creatable/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-async-creatable.cjs.js",
3 | "module": "dist/react-select-async-creatable.esm.js",
4 | "types": "dist/react-select-async-creatable.cjs.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-select/async/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-async.cjs.js",
3 | "module": "dist/react-select-async.esm.js",
4 | "types": "dist/react-select-async.cjs.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-select/base/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-base.cjs.js",
3 | "module": "dist/react-select-base.esm.js",
4 | "types": "dist/react-select-base.cjs.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-select/creatable/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "dist/react-select-creatable.cjs.js",
3 | "module": "dist/react-select-creatable.esm.js",
4 | "types": "dist/react-select-creatable.cjs.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-select/src/Async.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | forwardRef,
4 | MutableRefObject,
5 | ReactElement,
6 | RefAttributes,
7 | } from 'react';
8 | import Select from './Select';
9 | import { GroupBase } from './types';
10 | import useStateManager from './useStateManager';
11 | import useAsync from './useAsync';
12 | import type { AsyncProps } from './useAsync';
13 | export type { AsyncProps };
14 |
15 | type AsyncSelect = <
16 | Option = unknown,
17 | IsMulti extends boolean = false,
18 | Group extends GroupBase = GroupBase
19 | >(
20 | props: AsyncProps &
21 | RefAttributes>
22 | ) => ReactElement;
23 |
24 | const AsyncSelect = forwardRef(
25 | >(
26 | props: AsyncProps ,
27 | ref:
28 | | ((instance: Select | null) => void)
29 | | MutableRefObject | null>
30 | | null
31 | ) => {
32 | const stateManagedProps = useAsync(props);
33 | const selectProps = useStateManager(stateManagedProps);
34 |
35 | return ;
36 | }
37 | ) as AsyncSelect;
38 |
39 | export { useAsync };
40 | export default AsyncSelect;
41 |
--------------------------------------------------------------------------------
/packages/react-select/src/AsyncCreatable.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | forwardRef,
4 | MutableRefObject,
5 | ReactElement,
6 | RefAttributes,
7 | } from 'react';
8 | import Select from './Select';
9 | import { GroupBase } from './types';
10 | import useAsync, { AsyncAdditionalProps } from './useAsync';
11 | import useStateManager, { StateManagerProps } from './useStateManager';
12 | import useCreatable, { CreatableAdditionalProps } from './useCreatable';
13 |
14 | export type AsyncCreatableProps<
15 | Option,
16 | IsMulti extends boolean,
17 | Group extends GroupBase
18 | > = StateManagerProps &
19 | CreatableAdditionalProps &
20 | AsyncAdditionalProps ;
21 |
22 | type AsyncCreatableSelect = <
23 | Option = unknown,
24 | IsMulti extends boolean = false,
25 | Group extends GroupBase = GroupBase
26 | >(
27 | props: AsyncCreatableProps &
28 | RefAttributes>
29 | ) => ReactElement;
30 |
31 | const AsyncCreatableSelect = forwardRef(
32 | >(
33 | props: AsyncCreatableProps ,
34 | ref:
35 | | ((instance: Select | null) => void)
36 | | MutableRefObject | null>
37 | | null
38 | ) => {
39 | const stateManagerProps = useAsync(props);
40 | const creatableProps = useStateManager(stateManagerProps);
41 | const selectProps = useCreatable(creatableProps);
42 |
43 | return ;
44 | }
45 | ) as AsyncCreatableSelect;
46 |
47 | export default AsyncCreatableSelect;
48 |
--------------------------------------------------------------------------------
/packages/react-select/src/Creatable.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | forwardRef,
4 | MutableRefObject,
5 | ReactElement,
6 | RefAttributes,
7 | } from 'react';
8 | import Select from './Select';
9 | import { GroupBase } from './types';
10 | import useStateManager, { StateManagerProps } from './useStateManager';
11 | import useCreatable, { CreatableAdditionalProps } from './useCreatable';
12 |
13 | export type CreatableProps<
14 | Option,
15 | IsMulti extends boolean,
16 | Group extends GroupBase
17 | > = StateManagerProps &
18 | CreatableAdditionalProps ;
19 |
20 | type CreatableSelect = <
21 | Option = unknown,
22 | IsMulti extends boolean = false,
23 | Group extends GroupBase = GroupBase
24 | >(
25 | props: CreatableProps &
26 | RefAttributes>
27 | ) => ReactElement;
28 |
29 | const CreatableSelect = forwardRef(
30 | >(
31 | props: CreatableProps ,
32 | ref:
33 | | ((instance: Select | null) => void)
34 | | MutableRefObject | null>
35 | | null
36 | ) => {
37 | const creatableProps = useStateManager(props);
38 | const selectProps = useCreatable(creatableProps);
39 |
40 | return ;
41 | }
42 | ) as CreatableSelect;
43 |
44 | export { useCreatable };
45 | export default CreatableSelect;
46 |
--------------------------------------------------------------------------------
/packages/react-select/src/NonceProvider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useMemo } from 'react';
3 | import { ReactNode } from 'react';
4 | import { CacheProvider } from '@emotion/react';
5 | import createCache from '@emotion/cache';
6 |
7 | interface NonceProviderProps {
8 | nonce: string;
9 | children: ReactNode;
10 | cacheKey: string;
11 | }
12 |
13 | export default ({ nonce, children, cacheKey }: NonceProviderProps) => {
14 | const emotionCache = useMemo(
15 | () => createCache({ key: cacheKey, nonce }),
16 | [cacheKey, nonce]
17 | );
18 | return {children} ;
19 | };
20 |
--------------------------------------------------------------------------------
/packages/react-select/src/__tests__/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "jsx": "react",
6 | "noEmit": true,
7 | "strict": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "resolveJsonModule": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/react-select/src/accessibility/helpers.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | function testPlatform(re: RegExp) {
4 | return typeof window !== 'undefined' && window.navigator != null
5 | ? re.test(
6 | window.navigator['userAgentData']?.platform || window.navigator.platform
7 | )
8 | : false;
9 | }
10 |
11 | export function isIPhone() {
12 | return testPlatform(/^iPhone/i);
13 | }
14 |
15 | export function isMac() {
16 | return testPlatform(/^Mac/i);
17 | }
18 |
19 | export function isIPad() {
20 | return (
21 | testPlatform(/^iPad/i) ||
22 | // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
23 | (isMac() && navigator.maxTouchPoints > 1)
24 | );
25 | }
26 |
27 | export function isIOS() {
28 | return isIPhone() || isIPad();
29 | }
30 |
31 | export function isAppleDevice() {
32 | return isMac() || isIOS();
33 | }
34 |
--------------------------------------------------------------------------------
/packages/react-select/src/animated/Input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ReactElement } from 'react';
3 | import { TransitionProps } from 'react-transition-group/Transition';
4 | import { InputProps } from '../components/Input';
5 | import { GroupBase } from '../types';
6 |
7 | export type InputComponent = <
8 | Option,
9 | IsMulti extends boolean,
10 | Group extends GroupBase
11 | >(
12 | props: InputProps
13 | ) => ReactElement;
14 |
15 | export type AnimatedInputProps<
16 | Option,
17 | IsMulti extends boolean,
18 | Group extends GroupBase
19 | > = InputProps & Partial;
20 |
21 | // strip transition props off before spreading onto select component
22 | const AnimatedInput = (WrappedComponent: InputComponent): InputComponent => {
23 | return >({
24 | in: inProp,
25 | onExited,
26 | appear,
27 | enter,
28 | exit,
29 | ...props
30 | }: AnimatedInputProps ) => (
31 |
32 | );
33 | };
34 |
35 | export default AnimatedInput;
36 |
--------------------------------------------------------------------------------
/packages/react-select/src/animated/MultiValue.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ReactElement } from 'react';
3 | import { TransitionProps } from 'react-transition-group/Transition';
4 | import { MultiValueProps } from '../components/MultiValue';
5 | import { Collapse } from './transitions';
6 | import { GroupBase } from '../types';
7 |
8 | export type MultiValueComponent = <
9 | Option,
10 | IsMulti extends boolean,
11 | Group extends GroupBase
12 | >(
13 | props: MultiValueProps
14 | ) => ReactElement;
15 |
16 | export type AnimatedMultiValueProps<
17 | Option,
18 | IsMulti extends boolean,
19 | Group extends GroupBase
20 | > = MultiValueProps & Partial;
21 |
22 | // strip transition props off before spreading onto actual component
23 |
24 | const AnimatedMultiValue = (WrappedComponent: MultiValueComponent) => {
25 | return >({
26 | in: inProp,
27 | onExited,
28 | ...props
29 | }: AnimatedMultiValueProps ) => (
30 |
31 |
32 |
33 | );
34 | };
35 |
36 | export default AnimatedMultiValue;
37 |
--------------------------------------------------------------------------------
/packages/react-select/src/animated/Placeholder.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ReactElement } from 'react';
3 | import { PlaceholderProps } from '../components/Placeholder';
4 | import { Fade, collapseDuration } from './transitions';
5 | import { GroupBase } from '../types';
6 |
7 | export type PlaceholderComponent = <
8 | Option,
9 | IsMulti extends boolean,
10 | Group extends GroupBase
11 | >(
12 | props: PlaceholderProps
13 | ) => ReactElement;
14 |
15 | // fade in when last multi-value removed, otherwise instant
16 | const AnimatedPlaceholder =
17 | (WrappedComponent: PlaceholderComponent) =>
18 | >(
19 | props: PlaceholderProps
20 | ) =>
21 | (
22 | >
23 | component={WrappedComponent}
24 | duration={props.isMulti ? collapseDuration : 1}
25 | {...props}
26 | />
27 | );
28 |
29 | export default AnimatedPlaceholder;
30 |
--------------------------------------------------------------------------------
/packages/react-select/src/animated/SingleValue.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ReactElement } from 'react';
3 | import { SingleValueProps } from '../components/SingleValue';
4 | import { Fade } from './transitions';
5 | import { GroupBase } from '../types';
6 |
7 | export type SingleValueComponent = <
8 | Option,
9 | IsMulti extends boolean,
10 | Group extends GroupBase
11 | >(
12 | props: SingleValueProps
13 | ) => ReactElement;
14 |
15 | // instant fade; all transition-group children must be transitions
16 |
17 | const AnimatedSingleValue =
18 | (WrappedComponent: SingleValueComponent) =>
19 | >(
20 | props: SingleValueProps
21 | ) =>
22 | (
23 | >
24 | component={WrappedComponent}
25 | {...props}
26 | />
27 | );
28 |
29 | export default AnimatedSingleValue;
30 |
--------------------------------------------------------------------------------
/packages/react-select/src/animated/index.ts:
--------------------------------------------------------------------------------
1 | import memoize from 'memoize-one';
2 | import {
3 | defaultComponents,
4 | SelectComponentsGeneric,
5 | } from '../components/index';
6 | import { default as AnimatedInput } from './Input';
7 | import { default as AnimatedMultiValue } from './MultiValue';
8 | import { default as AnimatedPlaceholder } from './Placeholder';
9 | import { default as AnimatedSingleValue } from './SingleValue';
10 | import { default as AnimatedValueContainer } from './ValueContainer';
11 |
12 | const makeAnimated = (
13 | externalComponents: Partial = {}
14 | ): Partial => {
15 | const components = defaultComponents({ components: externalComponents });
16 | const {
17 | Input,
18 | MultiValue,
19 | Placeholder,
20 | SingleValue,
21 | ValueContainer,
22 | ...rest
23 | } = components;
24 | return {
25 | Input: AnimatedInput(Input),
26 | MultiValue: AnimatedMultiValue(MultiValue),
27 | Placeholder: AnimatedPlaceholder(Placeholder),
28 | SingleValue: AnimatedSingleValue(SingleValue),
29 | ValueContainer: AnimatedValueContainer(ValueContainer),
30 | ...rest,
31 | };
32 | };
33 |
34 | const AnimatedComponents = makeAnimated();
35 |
36 | export const Input = AnimatedComponents.Input;
37 | export const MultiValue = AnimatedComponents.MultiValue;
38 | export const Placeholder = AnimatedComponents.Placeholder;
39 | export const SingleValue = AnimatedComponents.SingleValue;
40 | export const ValueContainer = AnimatedComponents.ValueContainer;
41 |
42 | export default memoize(makeAnimated);
43 |
--------------------------------------------------------------------------------
/packages/react-select/src/async-creatable/index.ts:
--------------------------------------------------------------------------------
1 | export * from '../AsyncCreatable';
2 | export { default } from '../AsyncCreatable';
3 |
--------------------------------------------------------------------------------
/packages/react-select/src/async/index.ts:
--------------------------------------------------------------------------------
1 | export * from '../Async';
2 | export { default } from '../Async';
3 |
--------------------------------------------------------------------------------
/packages/react-select/src/base/index.ts:
--------------------------------------------------------------------------------
1 | export * from '../Select';
2 | export { default } from '../Select';
3 |
--------------------------------------------------------------------------------
/packages/react-select/src/builtins.ts:
--------------------------------------------------------------------------------
1 | import { GroupBase } from './types';
2 |
3 | export const formatGroupLabel = >(
4 | group: Group
5 | ): string => group.label as string;
6 |
7 | export const getOptionLabel = (option: Option): string =>
8 | (option as { label?: unknown }).label as string;
9 |
10 | export const getOptionValue = (option: Option): string =>
11 | (option as { value?: unknown }).value as string;
12 |
13 | export const isOptionDisabled = (option: Option): boolean =>
14 | !!(option as { isDisabled?: unknown }).isDisabled;
15 |
--------------------------------------------------------------------------------
/packages/react-select/src/components/Placeholder.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { JSX, ReactNode } from 'react';
3 | import { jsx } from '@emotion/react';
4 | import {
5 | CommonPropsAndClassName,
6 | CSSObjectWithLabel,
7 | GroupBase,
8 | } from '../types';
9 | import { getStyleProps } from '../utils';
10 |
11 | export interface PlaceholderProps<
12 | Option = unknown,
13 | IsMulti extends boolean = boolean,
14 | Group extends GroupBase = GroupBase
15 | > extends CommonPropsAndClassName {
16 | /** The children to be rendered. */
17 | children: ReactNode;
18 | /** props passed to the wrapping element for the group. */
19 | innerProps: JSX.IntrinsicElements['div'];
20 | isDisabled: boolean;
21 | isFocused: boolean;
22 | }
23 |
24 | export const placeholderCSS = <
25 | Option,
26 | IsMulti extends boolean,
27 | Group extends GroupBase
28 | >(
29 | { theme: { spacing, colors } }: PlaceholderProps ,
30 | unstyled: boolean
31 | ): CSSObjectWithLabel => ({
32 | label: 'placeholder',
33 | gridArea: '1 / 1 / 2 / 3',
34 | ...(unstyled
35 | ? {}
36 | : {
37 | color: colors.neutral50,
38 | marginLeft: spacing.baseUnit / 2,
39 | marginRight: spacing.baseUnit / 2,
40 | }),
41 | });
42 |
43 | const Placeholder = <
44 | Option,
45 | IsMulti extends boolean,
46 | Group extends GroupBase
47 | >(
48 | props: PlaceholderProps
49 | ) => {
50 | const { children, innerProps } = props;
51 | return (
52 |
58 | {children}
59 |
60 | );
61 | };
62 |
63 | export default Placeholder;
64 |
--------------------------------------------------------------------------------
/packages/react-select/src/components/SingleValue.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { JSX, ReactNode } from 'react';
3 | import { jsx } from '@emotion/react';
4 | import {
5 | CommonPropsAndClassName,
6 | CSSObjectWithLabel,
7 | GroupBase,
8 | } from '../types';
9 | import { getStyleProps } from '../utils';
10 |
11 | export interface SingleValueProps<
12 | Option = unknown,
13 | IsMulti extends boolean = boolean,
14 | Group extends GroupBase = GroupBase
15 | > extends CommonPropsAndClassName {
16 | /** The children to be rendered. */
17 | children: ReactNode;
18 | /** The data of the selected option rendered in the Single Value component. */
19 | data: Option;
20 | /** Props passed to the wrapping element for the group. */
21 | innerProps: JSX.IntrinsicElements['div'];
22 | /** Whether this is disabled. */
23 | isDisabled: boolean;
24 | }
25 |
26 | export const css = <
27 | Option,
28 | IsMulti extends boolean,
29 | Group extends GroupBase
30 | >(
31 | {
32 | isDisabled,
33 | theme: { spacing, colors },
34 | }: SingleValueProps ,
35 | unstyled: boolean
36 | ): CSSObjectWithLabel => ({
37 | label: 'singleValue',
38 | gridArea: '1 / 1 / 2 / 3',
39 | maxWidth: '100%',
40 | overflow: 'hidden',
41 | textOverflow: 'ellipsis',
42 | whiteSpace: 'nowrap',
43 | ...(unstyled
44 | ? {}
45 | : {
46 | color: isDisabled ? colors.neutral40 : colors.neutral80,
47 | marginLeft: spacing.baseUnit / 2,
48 | marginRight: spacing.baseUnit / 2,
49 | }),
50 | });
51 |
52 | const SingleValue = <
53 | Option,
54 | IsMulti extends boolean,
55 | Group extends GroupBase
56 | >(
57 | props: SingleValueProps
58 | ) => {
59 | const { children, isDisabled, innerProps } = props;
60 | return (
61 |
68 | {children}
69 |
70 | );
71 | };
72 |
73 | export default SingleValue;
74 |
--------------------------------------------------------------------------------
/packages/react-select/src/creatable/index.ts:
--------------------------------------------------------------------------------
1 | export * from '../Creatable';
2 | export { default } from '../Creatable';
3 |
--------------------------------------------------------------------------------
/packages/react-select/src/filters.ts:
--------------------------------------------------------------------------------
1 | import memoizeOne from 'memoize-one';
2 | import { stripDiacritics } from './diacritics';
3 |
4 | export interface FilterOptionOption {
5 | readonly label: string;
6 | readonly value: string;
7 | readonly data: Option;
8 | }
9 |
10 | interface Config {
11 | readonly ignoreCase?: boolean;
12 | readonly ignoreAccents?: boolean;
13 | readonly stringify?: (option: FilterOptionOption ) => string;
14 | readonly trim?: boolean;
15 | readonly matchFrom?: 'any' | 'start';
16 | }
17 |
18 | const memoizedStripDiacriticsForInput = memoizeOne(stripDiacritics);
19 |
20 | const trimString = (str: string) => str.replace(/^\s+|\s+$/g, '');
21 | const defaultStringify = (option: FilterOptionOption ) =>
22 | `${option.label} ${option.value}`;
23 |
24 | export const createFilter =
25 | (config?: Config ) =>
26 | (option: FilterOptionOption , rawInput: string): boolean => {
27 | // eslint-disable-next-line no-underscore-dangle
28 | if ((option.data as { __isNew__?: unknown }).__isNew__) return true;
29 | const { ignoreCase, ignoreAccents, stringify, trim, matchFrom } = {
30 | ignoreCase: true,
31 | ignoreAccents: true,
32 | stringify: defaultStringify,
33 | trim: true,
34 | matchFrom: 'any',
35 | ...config,
36 | };
37 | let input = trim ? trimString(rawInput) : rawInput;
38 | let candidate = trim ? trimString(stringify(option)) : stringify(option);
39 | if (ignoreCase) {
40 | input = input.toLowerCase();
41 | candidate = candidate.toLowerCase();
42 | }
43 | if (ignoreAccents) {
44 | input = memoizedStripDiacriticsForInput(input);
45 | candidate = stripDiacritics(candidate);
46 | }
47 | return matchFrom === 'start'
48 | ? candidate.substr(0, input.length) === input
49 | : candidate.indexOf(input) > -1;
50 | };
51 |
--------------------------------------------------------------------------------
/packages/react-select/src/index.ts:
--------------------------------------------------------------------------------
1 | import Select from './Select';
2 | import type { GroupBase } from './types';
3 | export type { FilterOptionOption } from './filters';
4 | import useStateManager from './useStateManager';
5 |
6 | export { default } from './stateManager';
7 | export { default as NonceProvider } from './NonceProvider';
8 | export { mergeStyles } from './styles';
9 | export { defaultTheme } from './theme';
10 | export { createFilter } from './filters';
11 | export { components } from './components';
12 | export type SelectInstance<
13 | Option = unknown,
14 | IsMulti extends boolean = false,
15 | Group extends GroupBase = GroupBase
16 | > = Select ;
17 | export type { StateManagerProps as Props } from './useStateManager';
18 | export { useStateManager };
19 |
20 | export type { SelectComponentsConfig } from './components';
21 | export type {
22 | ContainerProps,
23 | IndicatorsContainerProps,
24 | ValueContainerProps,
25 | } from './components/containers';
26 | export type { ControlProps } from './components/Control';
27 | export type { GroupProps, GroupHeadingProps } from './components/Group';
28 | export type {
29 | ClearIndicatorProps,
30 | DropdownIndicatorProps,
31 | IndicatorSeparatorProps,
32 | LoadingIndicatorProps,
33 | } from './components/indicators';
34 | export type { InputProps } from './components/Input';
35 | export type { MenuListProps, MenuProps, NoticeProps } from './components/Menu';
36 | export type {
37 | MultiValueGenericProps,
38 | MultiValueProps,
39 | MultiValueRemoveProps,
40 | } from './components/MultiValue';
41 | export type { OptionProps } from './components/Option';
42 | export type { PlaceholderProps } from './components/Placeholder';
43 | export type { SingleValueProps } from './components/SingleValue';
44 | export type { ThemeConfig } from './theme';
45 | export type { ClassNamesConfig, StylesConfig } from './styles';
46 | export * from './types';
47 | export type {
48 | OptionContext,
49 | GuidanceContext,
50 | AriaGuidanceProps,
51 | AriaOnChangeProps,
52 | AriaOnFilterProps,
53 | AriaOnFocusProps,
54 | AriaLiveMessages,
55 | AriaGuidance,
56 | AriaOnChange,
57 | AriaOnFilter,
58 | AriaOnFocus,
59 | } from './accessibility';
60 | export type { FormatOptionLabelContext, FormatOptionLabelMeta } from './Select';
61 |
--------------------------------------------------------------------------------
/packages/react-select/src/internal/A11yText.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { JSX } from 'react';
3 | import { jsx } from '@emotion/react';
4 |
5 | // Assistive text to describe visual elements. Hidden for sighted users.
6 | const A11yText = (props: JSX.IntrinsicElements['span']) => (
7 |
22 | );
23 |
24 | export default A11yText;
25 |
--------------------------------------------------------------------------------
/packages/react-select/src/internal/DummyInput.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { JSX, Ref } from 'react';
3 | import { jsx } from '@emotion/react';
4 | import { removeProps } from '../utils';
5 |
6 | export default function DummyInput({
7 | innerRef,
8 | ...props
9 | }: JSX.IntrinsicElements['input'] & {
10 | readonly innerRef: Ref;
11 | }) {
12 | // Remove animation props not meant for HTML elements
13 | const filteredProps = removeProps(
14 | props,
15 | 'onExited',
16 | 'in',
17 | 'enter',
18 | 'exit',
19 | 'appear'
20 | );
21 |
22 | return (
23 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/packages/react-select/src/internal/RequiredInput.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { FocusEventHandler, FunctionComponent } from 'react';
3 | import { jsx } from '@emotion/react';
4 |
5 | const RequiredInput: FunctionComponent<{
6 | readonly name?: string;
7 | readonly onFocus: FocusEventHandler;
8 | }> = ({ name, onFocus }) => (
9 | {}}
28 | />
29 | );
30 |
31 | export default RequiredInput;
32 |
--------------------------------------------------------------------------------
/packages/react-select/src/internal/ScrollManager.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 | import { Fragment, ReactElement, RefCallback, MouseEvent } from 'react';
4 | import useScrollCapture from './useScrollCapture';
5 | import useScrollLock from './useScrollLock';
6 |
7 | interface Props {
8 | readonly children: (ref: RefCallback) => ReactElement;
9 | readonly lockEnabled: boolean;
10 | readonly captureEnabled: boolean;
11 | readonly onBottomArrive?: (event: WheelEvent | TouchEvent) => void;
12 | readonly onBottomLeave?: (event: WheelEvent | TouchEvent) => void;
13 | readonly onTopArrive?: (event: WheelEvent | TouchEvent) => void;
14 | readonly onTopLeave?: (event: WheelEvent | TouchEvent) => void;
15 | }
16 |
17 | const blurSelectInput = (event: MouseEvent) => {
18 | const element = event.target as HTMLDivElement;
19 | return (
20 | element.ownerDocument.activeElement &&
21 | (element.ownerDocument.activeElement as HTMLElement).blur()
22 | );
23 | };
24 |
25 | export default function ScrollManager({
26 | children,
27 | lockEnabled,
28 | captureEnabled = true,
29 | onBottomArrive,
30 | onBottomLeave,
31 | onTopArrive,
32 | onTopLeave,
33 | }: Props) {
34 | const setScrollCaptureTarget = useScrollCapture({
35 | isEnabled: captureEnabled,
36 | onBottomArrive,
37 | onBottomLeave,
38 | onTopArrive,
39 | onTopLeave,
40 | });
41 | const setScrollLockTarget = useScrollLock({ isEnabled: lockEnabled });
42 |
43 | const targetRef: RefCallback = (element) => {
44 | setScrollCaptureTarget(element);
45 | setScrollLockTarget(element);
46 | };
47 |
48 | return (
49 |
50 | {lockEnabled && (
51 |
55 | )}
56 | {children(targetRef)}
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/packages/react-select/src/internal/index.ts:
--------------------------------------------------------------------------------
1 | export { default as A11yText } from './A11yText';
2 | export { default as DummyInput } from './DummyInput';
3 | export { default as ScrollManager } from './ScrollManager';
4 | export { default as RequiredInput } from './RequiredInput';
5 |
--------------------------------------------------------------------------------
/packages/react-select/src/stateManager.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | forwardRef,
4 | MutableRefObject,
5 | ReactElement,
6 | RefAttributes,
7 | } from 'react';
8 |
9 | import { GroupBase } from './types';
10 | import Select from './Select';
11 | import useStateManager from './useStateManager';
12 | import type { StateManagerProps } from './useStateManager';
13 | export type { StateManagerProps };
14 |
15 | type StateManagedSelect = <
16 | Option = unknown,
17 | IsMulti extends boolean = false,
18 | Group extends GroupBase = GroupBase
19 | >(
20 | props: StateManagerProps &
21 | RefAttributes>
22 | ) => ReactElement;
23 |
24 | const StateManagedSelect = forwardRef(
25 | >(
26 | props: StateManagerProps ,
27 | ref:
28 | | ((instance: Select | null) => void)
29 | | MutableRefObject | null>
30 | | null
31 | ) => {
32 | const baseSelectProps = useStateManager(props);
33 |
34 | return ;
35 | }
36 | ) as StateManagedSelect;
37 |
38 | export default StateManagedSelect;
39 |
--------------------------------------------------------------------------------
/packages/react-select/src/theme.ts:
--------------------------------------------------------------------------------
1 | import { Theme } from './types';
2 |
3 | export const colors = {
4 | primary: '#2684FF',
5 | primary75: '#4C9AFF',
6 | primary50: '#B2D4FF',
7 | primary25: '#DEEBFF',
8 |
9 | danger: '#DE350B',
10 | dangerLight: '#FFBDAD',
11 |
12 | neutral0: 'hsl(0, 0%, 100%)',
13 | neutral5: 'hsl(0, 0%, 95%)',
14 | neutral10: 'hsl(0, 0%, 90%)',
15 | neutral20: 'hsl(0, 0%, 80%)',
16 | neutral30: 'hsl(0, 0%, 70%)',
17 | neutral40: 'hsl(0, 0%, 60%)',
18 | neutral50: 'hsl(0, 0%, 50%)',
19 | neutral60: 'hsl(0, 0%, 40%)',
20 | neutral70: 'hsl(0, 0%, 30%)',
21 | neutral80: 'hsl(0, 0%, 20%)',
22 | neutral90: 'hsl(0, 0%, 10%)',
23 | };
24 |
25 | const borderRadius = 4;
26 | // Used to calculate consistent margin/padding on elements
27 | const baseUnit = 4;
28 | // The minimum height of the control
29 | const controlHeight = 38;
30 | // The amount of space between the control and menu */
31 | const menuGutter = baseUnit * 2;
32 |
33 | export const spacing = {
34 | baseUnit,
35 | controlHeight,
36 | menuGutter,
37 | };
38 |
39 | export const defaultTheme: Theme = {
40 | borderRadius,
41 | colors,
42 | spacing,
43 | };
44 |
45 | export type ThemeConfig = Theme | ((theme: Theme) => Theme);
46 |
--------------------------------------------------------------------------------
/packages/react-select/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "jsx": "react",
6 | "noEmit": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "resolveJsonModule": true
10 | },
11 | "exclude": ["src/__tests__"]
12 | }
13 |
--------------------------------------------------------------------------------
/storybook/.gitignore:
--------------------------------------------------------------------------------
1 | # Storybook
2 | storybook-static
3 |
--------------------------------------------------------------------------------
/storybook/.storybook/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-typescript",
5 | "@emotion/babel-preset-css-prop"
6 | ],
7 | "plugins": ["@emotion"]
8 | }
9 |
--------------------------------------------------------------------------------
/storybook/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from '@storybook/core-common';
2 | import postcss from 'postcss';
3 |
4 | const config: StorybookConfig = {
5 | addons: [
6 | '@storybook/addon-a11y',
7 | '@storybook/addon-essentials',
8 | {
9 | name: '@storybook/addon-postcss',
10 | options: {
11 | postcssLoaderOptions: {
12 | implementation: postcss,
13 | },
14 | },
15 | },
16 | ],
17 | core: {
18 | builder: 'webpack4',
19 | },
20 | features: {
21 | /**
22 | * Enable code splitting
23 | * @see https://storybook.js.org/docs/react/builders/webpack#code-splitting
24 | */
25 | storyStoreV7: true,
26 | },
27 | framework: '@storybook/react',
28 | stories: ['../stories/**/*.stories.@(js|jsx|ts|tsx)'],
29 | };
30 |
31 | export default config;
32 |
--------------------------------------------------------------------------------
/storybook/.storybook/preview.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx, Global, css } from '@emotion/react';
3 | import type { DecoratorFn } from '@storybook/react';
4 | import { Fragment } from 'react';
5 |
6 | export const parameters = {
7 | options: {
8 | storySort: {
9 | order: [
10 | 'Select',
11 | ['BasicSingle', 'BasicMulti', 'AnimatedMulti', 'Grouped', 'Creatable'],
12 | ],
13 | },
14 | },
15 | docs: {
16 | source: {
17 | type: 'code',
18 | },
19 | },
20 | };
21 |
22 | const globalStyles = css`
23 | *,
24 | *::before,
25 | *::after {
26 | box-sizing: border-box;
27 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
28 | 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
29 | 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
30 | 'Noto Color Emoji';
31 | }
32 | `;
33 |
34 | const withCssReset: DecoratorFn = (Story) => {
35 | return (
36 |
37 |
38 |
39 |
40 | );
41 | };
42 |
43 | export const decorators = [withCssReset];
44 |
--------------------------------------------------------------------------------
/storybook/components/field.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | type FieldProps = {
4 | label?: string;
5 | secondaryLabel?: string;
6 | children: React.ReactNode;
7 | htmlFor: string;
8 | };
9 |
10 | export function Field({
11 | children,
12 | htmlFor,
13 | label = 'Select',
14 | secondaryLabel,
15 | }: FieldProps) {
16 | return (
17 |
24 |
33 | {label}
34 | {secondaryLabel && (
35 |
36 | {secondaryLabel}
37 |
38 | )}
39 |
40 | {children}
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/storybook/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './field';
2 | export * from './inline';
3 | export * from './stack';
4 | export * from './svg';
5 |
--------------------------------------------------------------------------------
/storybook/components/inline.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | type InlineProps = React.HTMLAttributes & {
4 | gap?: keyof typeof gapSize;
5 | };
6 |
7 | export function Inline({
8 | children,
9 | gap = 'small',
10 | style,
11 | ...consumerProps
12 | }: InlineProps) {
13 | return (
14 |
23 | {children}
24 |
25 | );
26 | }
27 |
28 | const gapSize = {
29 | small: '0.5rem',
30 | medium: '1rem',
31 | large: '2rem',
32 | };
33 |
--------------------------------------------------------------------------------
/storybook/components/stack.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | type StackProps = React.HTMLAttributes & {
4 | gap?: keyof typeof gapSize;
5 | };
6 |
7 | export function Stack({
8 | children,
9 | gap = 'small',
10 | style,
11 | ...consumerProps
12 | }: StackProps) {
13 | return (
14 |
23 | {children}
24 |
25 | );
26 | }
27 |
28 | const gapSize = {
29 | small: '0.5rem',
30 | medium: '1rem',
31 | large: '2rem',
32 | };
33 |
--------------------------------------------------------------------------------
/storybook/components/svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export function Svg(props: JSX.IntrinsicElements['svg']) {
4 | return (
5 |
13 | );
14 | }
15 |
16 | export function ChevronDown(props: JSX.IntrinsicElements['svg']) {
17 | return (
18 |
19 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/storybook/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storybook",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "MIT",
6 | "scripts": {
7 | "build": "build-storybook",
8 | "dev": "start-storybook -p 6006"
9 | },
10 | "dependencies": {
11 | "@atlaskit/button": "^15.1.4",
12 | "@atlaskit/icon": "^11.0.1",
13 | "@atlaskit/modal-dialog": "^11.2.5",
14 | "@atlaskit/tooltip": "^17.1.2",
15 | "@babel/core": "^7.19.6",
16 | "@babel/preset-env": "^7.19.4",
17 | "@babel/preset-typescript": "^7.18.6",
18 | "@emotion/babel-plugin": "^11.10.2",
19 | "@emotion/babel-preset-css-prop": "^11.10.0",
20 | "@emotion/react": "^11.8.1",
21 | "babel-loader": "^8.2.5",
22 | "chroma-js": "^2.4.2",
23 | "chrono-node": "^2.1.11",
24 | "classnames": "^2.3.2",
25 | "moment": "^2.29.4",
26 | "react": "^16.13.0",
27 | "react-dom": "^16.13.0",
28 | "react-select": "^5.5.9",
29 | "remeda": "^1.1.0",
30 | "webpack": "^4.30.0"
31 | },
32 | "devDependencies": {
33 | "@storybook/addon-a11y": "^6.5.13",
34 | "@storybook/addon-essentials": "^6.5.13",
35 | "@storybook/addon-postcss": "^2.0.0",
36 | "@storybook/builder-webpack4": "^6.5.13",
37 | "@storybook/manager-webpack4": "^6.5.13",
38 | "@storybook/react": "^6.5.13",
39 | "autoprefixer": "^10.4.12",
40 | "postcss": "^8.4.18",
41 | "tailwindcss": "^3.2.1",
42 | "typescript": "^4.1.3"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/storybook/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('tailwindcss'), require('autoprefixer')],
3 | };
4 |
--------------------------------------------------------------------------------
/storybook/stories/AnimatedMulti.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStory } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 | import makeAnimated from 'react-select/animated';
5 |
6 | import { Field } from '../components';
7 | import { colourOptions, defaultArgs } from '../data';
8 |
9 | export default {
10 | title: 'Select/AnimatedMulti',
11 | component: Select,
12 | } as ComponentMeta;
13 |
14 | const animatedComponents = makeAnimated();
15 |
16 | const Template: ComponentStory = ({
17 | inputId = 'react-select',
18 | ...props
19 | }) => {
20 | return (
21 |
26 |
27 |
28 | );
29 | };
30 |
31 | export const AnimatedMulti = Template.bind({});
32 | AnimatedMulti.args = {
33 | ...defaultArgs,
34 | defaultValue: [colourOptions[0], colourOptions[1], colourOptions[2]],
35 | isMulti: true,
36 | };
37 |
--------------------------------------------------------------------------------
/storybook/stories/AsyncCallbacks.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import AsyncSelect from 'react-select/async';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/AsyncCallbacks',
10 | component: AsyncSelect,
11 | } as ComponentMeta;
12 |
13 | export function AsyncCallbacks() {
14 | return (
15 |
16 |
22 |
23 | );
24 | }
25 |
26 | // =============================================================================
27 | // Utils
28 | // =============================================================================
29 |
30 | function filterColors(inputValue: string) {
31 | return colourOptions.filter((i) =>
32 | i.label.toLowerCase().includes(inputValue.toLowerCase())
33 | );
34 | }
35 |
36 | function loadOptions(
37 | inputValue: string,
38 | callback: (options: ColourOption[]) => void
39 | ) {
40 | setTimeout(() => {
41 | callback(filterColors(inputValue));
42 | }, 1000);
43 | }
44 |
--------------------------------------------------------------------------------
/storybook/stories/AsyncCreatable.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import AsyncCreatableSelect from 'react-select/async-creatable';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/AsyncCreatable',
10 | component: AsyncCreatableSelect,
11 | } as ComponentMeta;
12 |
13 | export function AsyncCreatable() {
14 | return (
15 |
16 |
22 |
23 | );
24 | }
25 |
26 | // =============================================================================
27 | // Utils
28 | // =============================================================================
29 |
30 | function filterColors(inputValue: string) {
31 | return colourOptions.filter((i) =>
32 | i.label.toLowerCase().includes(inputValue.toLowerCase())
33 | );
34 | }
35 |
36 | function promiseOptions(inputValue: string) {
37 | return new Promise((resolve) => {
38 | setTimeout(() => {
39 | resolve(filterColors(inputValue));
40 | }, 1000);
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/storybook/stories/AsyncMulti.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import AsyncSelect from 'react-select/async';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/AsyncMulti',
10 | component: AsyncSelect,
11 | } as ComponentMeta;
12 |
13 | export function AsyncMulti() {
14 | return (
15 |
16 |
23 |
24 | );
25 | }
26 |
27 | // =============================================================================
28 | // Utils
29 | // =============================================================================
30 |
31 | function filterColors(inputValue: string) {
32 | return colourOptions.filter((i) =>
33 | i.label.toLowerCase().includes(inputValue.toLowerCase())
34 | );
35 | }
36 |
37 | function promiseOptions(inputValue: string) {
38 | return new Promise((resolve) => {
39 | setTimeout(() => {
40 | resolve(filterColors(inputValue));
41 | }, 1000);
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/storybook/stories/AsyncPromises.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import AsyncSelect from 'react-select/async';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/AsyncPromises',
10 | component: AsyncSelect,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function AsyncPromises() {
15 | return (
16 |
17 |
23 |
24 | );
25 | }
26 |
27 | // =============================================================================
28 | // Utils
29 | // =============================================================================
30 |
31 | function filterColors(inputValue: string) {
32 | return colourOptions.filter((i) =>
33 | i.label.toLowerCase().includes(inputValue.toLowerCase())
34 | );
35 | }
36 |
37 | function promiseOptions(inputValue: string) {
38 | return new Promise((resolve) => {
39 | setTimeout(() => {
40 | resolve(filterColors(inputValue));
41 | }, 1000);
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/storybook/stories/AsyncSelectWithDefaultOptions.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import AsyncSelect from 'react-select/async';
4 | import { Field } from '../components';
5 |
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/AsyncSelectWithDefaultOptions',
10 | component: AsyncSelect,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function AsyncSelectWithDefaultOptions() {
15 | return (
16 |
20 |
26 |
27 | );
28 | }
29 |
30 | // =============================================================================
31 | // Utils
32 | // =============================================================================
33 |
34 | function filterColors(inputValue: string) {
35 | return colourOptions.filter((i) =>
36 | i.label.toLowerCase().includes(inputValue.toLowerCase())
37 | );
38 | }
39 |
40 | function promiseOptions(inputValue: string) {
41 | return new Promise((resolve) => {
42 | setTimeout(() => {
43 | resolve(filterColors(inputValue));
44 | }, 1000);
45 | });
46 | }
47 |
--------------------------------------------------------------------------------
/storybook/stories/BasicGrouped.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import {
7 | ColourOption,
8 | colourOptions,
9 | FlavourOption,
10 | GroupedOption,
11 | groupedOptions,
12 | } from '../data';
13 |
14 | export default {
15 | title: 'Select/BasicGrouped',
16 | component: Select,
17 | } as ComponentMeta;
18 |
19 | export function BasicGrouped() {
20 | return (
21 |
22 |
23 | inputId="basic-grouped-id"
24 | defaultValue={colourOptions[1]}
25 | options={groupedOptions}
26 | formatGroupLabel={FormatGroupLabel}
27 | />
28 |
29 | );
30 | }
31 |
32 | function FormatGroupLabel({ label, options }: GroupedOption) {
33 | return (
34 |
41 | {label}
42 |
56 | {options.length}
57 |
58 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/storybook/stories/BasicMulti.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStory } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { colourOptions, defaultArgs } from '../data';
7 |
8 | export default {
9 | title: 'Select/BasicMulti',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | const Template: ComponentStory = ({
15 | inputId = 'react-select',
16 | ...props
17 | }) => {
18 | return (
19 |
20 |
21 |
22 | );
23 | };
24 |
25 | export const BasicMulti = Template.bind({});
26 | BasicMulti.args = {
27 | ...defaultArgs,
28 | defaultValue: [colourOptions[0], colourOptions[1], colourOptions[2]],
29 | isMulti: true,
30 | };
31 |
--------------------------------------------------------------------------------
/storybook/stories/BasicSingle.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStory } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { defaultArgs } from '../data';
7 |
8 | /**
9 | * More on default export:
10 | * @see https://storybook.js.org/docs/react/writing-stories/introduction#default-export
11 | */
12 | export default {
13 | title: 'Select/BasicSingle',
14 | component: Select,
15 | /**
16 | * More on argTypes:
17 | * @see https://storybook.js.org/docs/react/api/argtypes
18 | */
19 | argTypes: {},
20 | } as ComponentMeta;
21 |
22 | /**
23 | * More on component templates:
24 | * @see https://storybook.js.org/docs/react/writing-stories/introduction#using-args
25 | */
26 | const Template: ComponentStory = ({
27 | inputId = 'react-select',
28 | ...props
29 | }) => {
30 | return (
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export const BasicSingle = Template.bind({});
38 | /**
39 | * More on args:
40 | * @see https://storybook.js.org/docs/react/writing-stories/args
41 | */
42 | BasicSingle.args = {
43 | ...defaultArgs,
44 | };
45 |
--------------------------------------------------------------------------------
/storybook/stories/ControlledMenu.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { SelectInstance, StylesConfig } from 'react-select';
4 |
5 | import { Field, Inline, Stack } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/ControlledMenu',
10 | component: Select,
11 | } as ComponentMeta;
12 |
13 | export function ControlledMenu() {
14 | const inputRef = React.useRef>(null);
15 | const [menuIsOpen, setMenuIsOpen] = React.useState(false);
16 |
17 | function toggleMenuIsOpen() {
18 | setMenuIsOpen((value) => !value);
19 | const selectEl = inputRef.current;
20 | if (!selectEl) return;
21 | if (menuIsOpen) selectEl.blur();
22 | else selectEl.focus();
23 | }
24 |
25 | return (
26 |
27 |
28 |
34 | Click to toggle menu
35 |
36 |
37 |
45 |
46 |
47 | );
48 | }
49 |
50 | // =============================================================================
51 | // Styles
52 | // =============================================================================
53 |
54 | const styles: StylesConfig = {
55 | menu: (base) => ({ ...base, position: 'relative' }),
56 | };
57 |
--------------------------------------------------------------------------------
/storybook/stories/CreatableAdvanced.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import CreatableSelect from 'react-select/creatable';
4 |
5 | import { Field } from '../components';
6 | import { NumberOption, numbers } from '../data';
7 |
8 | export default {
9 | title: 'Select/CreatableAdvanced',
10 | component: CreatableSelect,
11 | } as ComponentMeta;
12 |
13 | export function CreatableAdvanced() {
14 | const [isLoading, setIsLoading] = React.useState(false);
15 | const [options, setOptions] = React.useState(numbers);
16 | const [value, setValue] = React.useState(null);
17 |
18 | function handleCreate(inputValue: string) {
19 | setIsLoading(true);
20 | setTimeout(() => {
21 | const newOption = {
22 | label: inputValue,
23 | value: slugify(inputValue),
24 | };
25 | setIsLoading(false);
26 | setOptions((prev) => [...prev, newOption]);
27 | setValue(newOption);
28 | }, 1000);
29 | }
30 |
31 | return (
32 |
33 | setValue(newValue)}
38 | onCreateOption={handleCreate}
39 | options={options}
40 | value={value}
41 | />
42 |
43 | );
44 | }
45 |
46 | function slugify(text: string) {
47 | return text
48 | .toLowerCase()
49 | .replace(/[^a-z0-9 -]/g, '')
50 | .replace(/\s+/g, '-')
51 | .replace(/-+/g, '-');
52 | }
53 |
--------------------------------------------------------------------------------
/storybook/stories/CreatableInputOnly.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import CreatableSelect from 'react-select/creatable';
4 | import { Field } from '../components';
5 |
6 | export default {
7 | title: 'Select/CreatableInputOnly',
8 | component: CreatableSelect,
9 | } as ComponentMeta;
10 |
11 | export function CreatableInputOnly() {
12 | const [inputValue, setInputValue] = React.useState('');
13 | const [value, setValue] = React.useState([]);
14 |
15 | function handleKeyDown(event: React.KeyboardEvent) {
16 | if (!inputValue) return;
17 | switch (event.key) {
18 | case 'Enter':
19 | case 'Tab':
20 | setValue((prev) => [...prev, { label: inputValue, value: inputValue }]);
21 | setInputValue('');
22 | event.preventDefault();
23 | }
24 | }
25 |
26 | return (
27 |
28 | setValue(newValue)}
34 | onInputChange={(newValue) => setInputValue(newValue)}
35 | onKeyDown={handleKeyDown}
36 | placeholder="Type something and press enter..."
37 | value={value}
38 | />
39 |
40 | );
41 | }
42 |
43 | interface Option {
44 | readonly label: string;
45 | readonly value: string;
46 | }
47 |
--------------------------------------------------------------------------------
/storybook/stories/CustomAriaLive.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { AriaOnFocus } from 'react-select';
4 | import { ColourOption, colourOptions } from '../data';
5 |
6 | export default {
7 | title: 'Select/CustomAriaLive',
8 | component: Select,
9 | argTypes: {},
10 | } as ComponentMeta;
11 |
12 | export function CustomAriaLive() {
13 | const [isMenuOpen, setIsMenuOpen] = React.useState(false);
14 | const handleMenuOpen = () => setIsMenuOpen(true);
15 | const handleMenuClose = () => setIsMenuOpen(false);
16 |
17 | const [ariaFocusMessage, setAriaFocusMessage] = React.useState('');
18 | const onFocus: AriaOnFocus = ({ focused, isDisabled }) => {
19 | const message = `You are currently focused on option "${focused.label}"${
20 | isDisabled ? ', disabled' : ''
21 | }`;
22 | setAriaFocusMessage(message);
23 | return message;
24 | };
25 |
26 | return (
27 |
45 | );
46 | }
47 |
48 | // =============================================================================
49 | // Styles
50 | // =============================================================================
51 |
52 | const styles = {
53 | form: {
54 | display: 'flex',
55 | flexDirection: 'column',
56 | gap: '0.5rem',
57 | },
58 | blockquote: {
59 | fontStyle: 'italic',
60 | margin: 0,
61 | },
62 | label: {
63 | fontWeight: 500,
64 | display: 'flex',
65 | flexDirection: 'column',
66 | gap: '0.5rem',
67 | },
68 | } as const;
69 |
--------------------------------------------------------------------------------
/storybook/stories/CustomClearIndicator.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { ClearIndicatorProps, StylesConfig } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomClearIndicator',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomClearIndicator() {
15 | return (
16 |
17 |
25 |
26 | );
27 | }
28 |
29 | // =============================================================================
30 | // Styles
31 | // =============================================================================
32 |
33 | const styles: StylesConfig = {
34 | clearIndicator: (base, state) => ({
35 | ...base,
36 | cursor: 'pointer',
37 | color: state.isFocused ? 'blue' : 'black',
38 | }),
39 | };
40 |
41 | // =============================================================================
42 | // Components
43 | // =============================================================================
44 |
45 | function ClearIndicator(props: ClearIndicatorProps) {
46 | const {
47 | getStyles,
48 | innerProps: { ref, ...restInnerProps },
49 | } = props;
50 | return (
51 |
56 |
57 | clear all
58 |
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/storybook/stories/CustomControl.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { components, ControlProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomControl',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomControl() {
15 | return (
16 |
17 |
23 |
24 | );
25 | }
26 |
27 | // =============================================================================
28 | // Components
29 | // =============================================================================
30 |
31 | function ControlComponent(props: ControlProps) {
32 | return (
33 |
41 |
42 |
This is the Custom Control
43 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/storybook/stories/CustomDropdownIndicator.stories.tsx:
--------------------------------------------------------------------------------
1 | import EmojiIcon from '@atlaskit/icon/glyph/emoji';
2 | import type { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, { components, DropdownIndicatorProps } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { ColourOption, colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/CustomDropdownIndicator',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | export function CustomDropdownIndicator() {
16 | return (
17 |
18 |
23 |
24 | );
25 | }
26 |
27 | // =============================================================================
28 | // Components
29 | // =============================================================================
30 |
31 | function DropdownIndicator(props: DropdownIndicatorProps) {
32 | return (
33 |
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/storybook/stories/CustomFilterOptions.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 | import { Field } from '../components';
5 |
6 | import { colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomFilterOptions',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomFilterOptions() {
15 | return (
16 |
17 |
23 |
24 | );
25 | }
26 |
27 | const filterOptions = (
28 | candidate: { label: string; value: string },
29 | input: string
30 | ) => {
31 | if (input) {
32 | return candidate.value === customOptions[0].value;
33 | }
34 | return true;
35 | };
36 |
37 | const customOptions = [
38 | {
39 | value: 'custom',
40 | label: 'Using a custom filter to always display this option on search',
41 | },
42 | ...colourOptions,
43 | ];
44 |
--------------------------------------------------------------------------------
/storybook/stories/CustomFormatOptionLabel.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 | import { Field } from '../components';
5 |
6 | import { colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomFormatOptionLabel',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomFormatOptionLabel() {
15 | return (
16 |
20 |
26 |
27 | );
28 | }
29 |
30 | function formatOptionLabel(option: typeof colourOptions[number]) {
31 | return (
32 |
33 |
41 |
{option.label}
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/storybook/stories/CustomGetOptionLabel.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { flavourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomGetOptionLabel',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomGetOptionLabel() {
15 | return (
16 |
21 | `${option.label}: ${option.rating}`}
25 | />
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/storybook/stories/CustomGetOptionValue.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { dogOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomGetOptionValue',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomGetOptionValue() {
15 | return (
16 |
21 | `${option['id']}`}
25 | />
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/storybook/stories/CustomGroup.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { components, GroupProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import {
7 | ColourOption,
8 | colourOptions,
9 | FlavourOption,
10 | groupedOptions,
11 | } from '../data';
12 |
13 | export default {
14 | title: 'Select/CustomGroup',
15 | component: Select,
16 | argTypes: {},
17 | } as ComponentMeta;
18 |
19 | export function CustomGroup() {
20 | return (
21 |
22 |
23 | inputId="custom-group-id"
24 | defaultValue={colourOptions[1]}
25 | options={groupedOptions}
26 | components={{ Group }}
27 | />
28 |
29 | );
30 | }
31 |
32 | // =============================================================================
33 | // Components
34 | // =============================================================================
35 |
36 | function Group(props: GroupProps) {
37 | return (
38 |
45 |
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/storybook/stories/CustomGroupHeading.stories.tsx:
--------------------------------------------------------------------------------
1 | import EditorPanelIcon from '@atlaskit/icon/glyph/editor/panel';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import type { ComponentMeta } from '@storybook/react';
4 | import * as React from 'react';
5 | import Select, {
6 | components,
7 | GroupHeadingProps,
8 | StylesConfig,
9 | } from 'react-select';
10 | import { Field } from '../components';
11 | import {
12 | ColourOption,
13 | colourOptions,
14 | FlavourOption,
15 | groupedOptions,
16 | } from '../data';
17 |
18 | export default {
19 | title: 'Select/CustomGroupHeading',
20 | component: Select,
21 | argTypes: {},
22 | } as ComponentMeta;
23 |
24 | export function CustomGroupHeading() {
25 | return (
26 |
27 |
28 | inputId="custom-group-heading-id"
29 | defaultValue={colourOptions[1]}
30 | options={groupedOptions}
31 | components={{ GroupHeading }}
32 | styles={styles}
33 | />
34 |
35 | );
36 | }
37 |
38 | // =============================================================================
39 | // Styles
40 | // =============================================================================
41 |
42 | const styles: StylesConfig = {
43 | groupHeading: (base) => ({
44 | ...base,
45 | flex: '1 1',
46 | color: 'white',
47 | margin: 0,
48 | }),
49 | };
50 |
51 | // =============================================================================
52 | // Components
53 | // =============================================================================
54 |
55 | function GroupHeading(props: GroupHeadingProps) {
56 | return (
57 |
66 |
67 |
68 |
69 |
70 |
71 | );
72 | }
73 |
--------------------------------------------------------------------------------
/storybook/stories/CustomIndicatorSeparator.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { IndicatorSeparatorProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomIndicatorSeparator',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomIndicatorSeparator() {
15 | return (
16 |
20 |
27 |
28 | );
29 | }
30 |
31 | // =============================================================================
32 | // Components
33 | // =============================================================================
34 |
35 | function IndicatorSeparator({
36 | innerProps,
37 | }: IndicatorSeparatorProps) {
38 | return (
39 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/storybook/stories/CustomIndicatorsContainer.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { components, IndicatorsContainerProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomIndicatorsContainer',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomIndicatorsContainer() {
15 | return (
16 |
20 |
28 |
29 | );
30 | }
31 |
32 | // =============================================================================
33 | // Components
34 | // =============================================================================
35 |
36 | function IndicatorsContainer(
37 | props: IndicatorsContainerProps
38 | ) {
39 | return (
40 |
41 |
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/storybook/stories/CustomInput.stories.tsx:
--------------------------------------------------------------------------------
1 | import Tooltip from '@atlaskit/tooltip';
2 | import { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, { components, InputProps } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { ColourOption, colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/CustomInput',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | export function CustomInput() {
16 | return (
17 |
18 |
25 |
26 | );
27 | }
28 |
29 | // =============================================================================
30 | // Components
31 | // =============================================================================
32 |
33 | function Input(props: InputProps) {
34 | const component = ;
35 | if (props.isHidden) return component;
36 | return (
37 |
38 |
39 | {component}
40 |
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/storybook/stories/CustomIsOptionDisabled.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { flavourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomIsOptionDisabled',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomIsOptionDisabled() {
15 | return (
16 |
21 | option.rating !== 'safe'}
25 | options={flavourOptions}
26 | />
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/storybook/stories/CustomLoadingIndicator.stories.tsx:
--------------------------------------------------------------------------------
1 | import Spinner from '@atlaskit/spinner';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import type { ComponentMeta } from '@storybook/react';
4 | import * as React from 'react';
5 | import { LoadingIndicatorProps } from 'react-select';
6 | import AsyncSelect from 'react-select/async';
7 | import { Field } from '../components';
8 | import { ColourOption, colourOptions } from '../data';
9 |
10 | export default {
11 | title: 'Select/CustomLoadingIndicator',
12 | component: AsyncSelect,
13 | argTypes: {},
14 | } as ComponentMeta;
15 |
16 | export function CustomLoadingIndicator() {
17 | return (
18 |
22 |
29 |
30 | );
31 | }
32 |
33 | // =============================================================================
34 | // Components
35 | // =============================================================================
36 |
37 | function LoadingIndicator(props: LoadingIndicatorProps) {
38 | return (
39 |
40 |
41 |
42 | );
43 | }
44 |
45 | // =============================================================================
46 | // Utils
47 | // =============================================================================
48 |
49 | function filterColors(inputValue: string) {
50 | return colourOptions.filter((i) =>
51 | i.label.toLowerCase().includes(inputValue.toLowerCase())
52 | );
53 | }
54 |
55 | function promiseOptions(inputValue: string) {
56 | return new Promise((resolve) => {
57 | setTimeout(() => {
58 | resolve(filterColors(inputValue));
59 | }, 1000);
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/storybook/stories/CustomMenu.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { components, MenuProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import {
7 | ColourOption,
8 | colourOptions,
9 | FlavourOption,
10 | GroupedOption,
11 | groupedOptions,
12 | } from '../data';
13 |
14 | export default {
15 | title: 'Select/CustomMenu',
16 | component: Select,
17 | argTypes: {},
18 | } as ComponentMeta;
19 |
20 | export function CustomMenu() {
21 | return (
22 |
23 |
24 | inputId="custom-menu-id"
25 | defaultValue={colourOptions[1]}
26 | options={groupedOptions}
27 | components={{ Menu }}
28 | />
29 |
30 | );
31 | }
32 |
33 | // =============================================================================
34 | // Components
35 | // =============================================================================
36 |
37 | function Menu(
38 | props: MenuProps
39 | ) {
40 | const optionsLength = getLength(props.options);
41 | return (
42 |
43 |
48 | Custom Menu with {optionsLength} options
49 |
50 |
51 | {...props}
52 | >
53 | {props.children}
54 |
55 |
56 | );
57 | }
58 |
59 | // =============================================================================
60 | // Utils
61 | // =============================================================================
62 |
63 | function getLength(
64 | options: readonly (GroupedOption | ColourOption | FlavourOption)[]
65 | ): number {
66 | return options.reduce((acc, curr) => {
67 | if ('options' in curr) return acc + getLength(curr.options);
68 | return acc + 1;
69 | }, 0);
70 | }
71 |
--------------------------------------------------------------------------------
/storybook/stories/CustomMenuList.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { components, MenuListProps } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import {
7 | ColourOption,
8 | colourOptions,
9 | FlavourOption,
10 | GroupedOption,
11 | groupedOptions,
12 | } from '../data';
13 |
14 | export default {
15 | title: 'Select/CustomMenuList',
16 | component: Select,
17 | argTypes: {},
18 | } as ComponentMeta;
19 |
20 | export function CustomMenuList() {
21 | return (
22 |
23 |
24 | inputId="custom-menu-list-id"
25 | defaultValue={colourOptions[1]}
26 | options={groupedOptions}
27 | components={{ MenuList }}
28 | />
29 |
30 | );
31 | }
32 |
33 | // =============================================================================
34 | // Components
35 | // =============================================================================
36 |
37 | function MenuList(
38 | props: MenuListProps
39 | ) {
40 | return (
41 |
42 |
49 | Custom Menu List
50 |
51 | {props.children}
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/storybook/stories/CustomMultiValueContainer.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Tooltip from '@atlaskit/tooltip';
4 | import Select, {
5 | components,
6 | MultiValueGenericProps,
7 | StylesConfig,
8 | } from 'react-select';
9 |
10 | import { Field } from '../components';
11 | import { ColourOption, colourOptions } from '../data';
12 |
13 | export default {
14 | title: 'Select/CustomMultiValueContainer',
15 | component: Select,
16 | argTypes: {},
17 | } as ComponentMeta;
18 |
19 | export function CustomMultiValueContainer() {
20 | return (
21 |
25 |
34 |
35 | );
36 | }
37 |
38 | // =============================================================================
39 | // Styles
40 | // =============================================================================
41 |
42 | const styles: StylesConfig = {
43 | multiValue: (base) => ({
44 | ...base,
45 | border: `2px dotted ${colourOptions[2].color}`,
46 | }),
47 | };
48 |
49 | // =============================================================================
50 | // Components
51 | // =============================================================================
52 |
53 | function MultiValueContainer(props: MultiValueGenericProps) {
54 | return (
55 |
56 |
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/storybook/stories/CustomMultiValueLabel.stories.tsx:
--------------------------------------------------------------------------------
1 | import Tooltip from '@atlaskit/tooltip';
2 | import type { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, {
5 | components,
6 | MultiValueGenericProps,
7 | StylesConfig,
8 | } from 'react-select';
9 |
10 | import { Field } from '../components';
11 | import { ColourOption, colourOptions } from '../data';
12 |
13 | export default {
14 | title: 'Select/CustomMultiValueLabel',
15 | component: Select,
16 | argTypes: {},
17 | } as ComponentMeta;
18 |
19 | export function CustomMultiValueLabel() {
20 | return (
21 |
25 |
33 |
34 | );
35 | }
36 |
37 | // =============================================================================
38 | // Styles
39 | // =============================================================================
40 |
41 | const styles: StylesConfig = {
42 | multiValueLabel: (base) => ({
43 | ...base,
44 | backgroundColor: colourOptions[2].color,
45 | color: 'white',
46 | }),
47 | };
48 |
49 | // =============================================================================
50 | // Components
51 | // =============================================================================
52 |
53 | function MultiValueLabel(props: MultiValueGenericProps) {
54 | return (
55 |
56 |
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/storybook/stories/CustomMultiValueRemove.stories.tsx:
--------------------------------------------------------------------------------
1 | import EmojiIcon from '@atlaskit/icon/glyph/emoji';
2 | import Tooltip from '@atlaskit/tooltip';
3 | import type { ComponentMeta } from '@storybook/react';
4 | import * as React from 'react';
5 | import Select, {
6 | components,
7 | MultiValueRemoveProps,
8 | StylesConfig,
9 | } from 'react-select';
10 | import { ColourOption, colourOptions } from '../data';
11 | import { Field } from '../components';
12 |
13 | export default {
14 | title: 'Select/CustomMultiValueRemove',
15 | component: Select,
16 | argTypes: {},
17 | } as ComponentMeta;
18 |
19 | export function CustomMultiValueRemove() {
20 | return (
21 |
25 |
33 |
34 | );
35 | }
36 |
37 | // =============================================================================
38 | // Styles
39 | // =============================================================================
40 |
41 | const styles: StylesConfig = {
42 | multiValueRemove: (base) => ({
43 | ...base,
44 | border: `1px dotted ${colourOptions[2].color}`,
45 | height: '100%',
46 | }),
47 | };
48 |
49 | // =============================================================================
50 | // Components
51 | // =============================================================================
52 |
53 | function MultiValueRemove(props: MultiValueRemoveProps) {
54 | return (
55 |
56 |
57 |
58 |
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/storybook/stories/CustomNoOptionsMessage.stories.tsx:
--------------------------------------------------------------------------------
1 | import Tooltip from '@atlaskit/tooltip';
2 | import { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, { components, NoticeProps, StylesConfig } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/CustomNoOptionsMessage',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | export function CustomNoOptionsMessage() {
16 | return (
17 |
21 |
27 |
28 | );
29 | }
30 |
31 | // =============================================================================
32 | // Styles
33 | // =============================================================================
34 |
35 | const styles: StylesConfig = {
36 | noOptionsMessage: (base) => ({
37 | ...base,
38 | background: colourOptions[2].color,
39 | color: 'white',
40 | }),
41 | };
42 |
43 | // =============================================================================
44 | // Components
45 | // =============================================================================
46 |
47 | function NoOptionsMessage(props: NoticeProps) {
48 | return (
49 |
50 |
51 |
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/storybook/stories/CustomOption.stories.tsx:
--------------------------------------------------------------------------------
1 | import Tooltip from '@atlaskit/tooltip';
2 | import { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, { components, OptionProps, StylesConfig } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { ColourOption, colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/CustomOption',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | export function CustomOption() {
16 | return (
17 |
18 |
24 |
25 | );
26 | }
27 |
28 | // =============================================================================
29 | // Styles
30 | // =============================================================================
31 |
32 | const styles: StylesConfig = {
33 | option: (base) => ({
34 | ...base,
35 | border: `1px dotted ${colourOptions[2].color}`,
36 | height: '100%',
37 | }),
38 | };
39 |
40 | // =============================================================================
41 | // Components
42 | // =============================================================================
43 |
44 | function Option(props: OptionProps) {
45 | return (
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/storybook/stories/CustomPlaceholder.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, {
4 | components,
5 | PlaceholderProps,
6 | StylesConfig,
7 | } from 'react-select';
8 |
9 | import { Field } from '../components';
10 | import { ColourOption, colourOptions } from '../data';
11 |
12 | export default {
13 | title: 'Select/CustomPlaceholder',
14 | component: Select,
15 | argTypes: {},
16 | } as ComponentMeta;
17 |
18 | export function CustomPlaceholder() {
19 | return (
20 |
21 |
28 |
29 | );
30 | }
31 |
32 | // =============================================================================
33 | // Styles
34 | // =============================================================================
35 |
36 | const styles: StylesConfig = {
37 | placeholder: (base) => ({
38 | ...base,
39 | fontSize: '1em',
40 | color: colourOptions[2].color,
41 | fontWeight: 400,
42 | }),
43 | };
44 |
45 | // =============================================================================
46 | // Components
47 | // =============================================================================
48 |
49 | function Placeholder(props: PlaceholderProps) {
50 | return ;
51 | }
52 |
--------------------------------------------------------------------------------
/storybook/stories/CustomSelectContainer.stories.tsx:
--------------------------------------------------------------------------------
1 | import Tooltip from '@atlaskit/tooltip';
2 | import type { ComponentMeta } from '@storybook/react';
3 | import * as React from 'react';
4 | import Select, { components, ContainerProps, StylesConfig } from 'react-select';
5 | import { Field } from '../components';
6 | import { ColourOption, colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/CustomSelectContainer',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function CustomSelectContainer() {
15 | return (
16 |
17 |
23 |
24 | );
25 | }
26 |
27 | // =============================================================================
28 | // Styles
29 | // =============================================================================
30 |
31 | const styles: StylesConfig = {
32 | container: (base) => ({
33 | ...base,
34 | backgroundColor: colourOptions[2].color,
35 | padding: 5,
36 | }),
37 | };
38 |
39 | // =============================================================================
40 | // Components
41 | // =============================================================================
42 |
43 | function SelectContainer({ children, ...props }: ContainerProps) {
44 | return (
45 |
46 |
47 | {children}
48 |
49 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/storybook/stories/CustomSelectProps.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, {
4 | components,
5 | ControlProps,
6 | Props,
7 | StylesConfig,
8 | } from 'react-select';
9 | import { Field } from '../components';
10 | import { ColourOption, colourOptions, EMOJIS } from '../data';
11 |
12 | export default {
13 | title: 'Select/CustomSelectProps',
14 | component: Select,
15 | argTypes: {},
16 | } as ComponentMeta;
17 |
18 | export function CustomSelectProps(props: Props) {
19 | const [clickCount, setClickCount] = React.useState(0);
20 |
21 | function onClick(event: React.MouseEvent) {
22 | setClickCount(clickCount + 1);
23 | event.preventDefault();
24 | event.stopPropagation();
25 | }
26 |
27 | const emoji = EMOJIS[clickCount % EMOJIS.length];
28 |
29 | return (
30 |
31 |
42 |
43 | );
44 | }
45 |
46 | // =============================================================================
47 | // Styles
48 | // =============================================================================
49 |
50 | const styles: StylesConfig = {
51 | control: (css) => ({ ...css, paddingLeft: '1rem' }),
52 | };
53 |
54 | // =============================================================================
55 | // Components
56 | // =============================================================================
57 |
58 | function Control({ children, ...props }: ControlProps) {
59 | // @ts-ignore
60 | const { emoji, onEmojiClick } = props.selectProps;
61 | const style = { cursor: 'pointer' };
62 |
63 | return (
64 |
65 |
66 | {emoji}
67 |
68 | {children}
69 |
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/storybook/stories/CustomSingleValue.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, {
4 | components,
5 | SingleValueProps,
6 | StylesConfig,
7 | } from 'react-select';
8 | import { Field } from '../components';
9 | import { ColourOption, colourOptions } from '../data';
10 |
11 | export default {
12 | title: 'Select/CustomSingleValue',
13 | component: Select,
14 | argTypes: {},
15 | } as ComponentMeta;
16 |
17 | export function CustomSingleValue() {
18 | return (
19 |
20 |
29 |
30 | );
31 | }
32 |
33 | // =============================================================================
34 | // Styles
35 | // =============================================================================
36 |
37 | const styles: StylesConfig = {
38 | singleValue: (base) => ({
39 | ...base,
40 | padding: 5,
41 | borderRadius: 5,
42 | background: colourOptions[2].color,
43 | color: 'white',
44 | display: 'flex',
45 | }),
46 | };
47 |
48 | // =============================================================================
49 | // Components
50 | // =============================================================================
51 |
52 | function SingleValue({ children, ...props }: SingleValueProps) {
53 | return {children} ;
54 | }
55 |
--------------------------------------------------------------------------------
/storybook/stories/CustomValueContainer.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, {
4 | components,
5 | StylesConfig,
6 | ValueContainerProps,
7 | } from 'react-select';
8 |
9 | import { Field } from '../components';
10 | import { ColourOption, colourOptions } from '../data';
11 |
12 | export default {
13 | title: 'Select/CustomValueContainer',
14 | component: Select,
15 | argTypes: {},
16 | } as ComponentMeta;
17 |
18 | export function CustomValueContainer() {
19 | return (
20 |
21 |
30 |
31 | );
32 | }
33 |
34 | // =============================================================================
35 | // Styles
36 | // =============================================================================
37 |
38 | const styles: StylesConfig = {
39 | singleValue: (base) => ({ ...base, color: 'white' }),
40 | valueContainer: (base) => ({
41 | ...base,
42 | background: colourOptions[2].color,
43 | color: 'white',
44 | width: '100%',
45 | }),
46 | };
47 |
48 | // =============================================================================
49 | // Components
50 | // =============================================================================
51 |
52 | function ValueContainer({
53 | children,
54 | ...props
55 | }: ValueContainerProps) {
56 | return (
57 | {children}
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/storybook/stories/Grouped.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStory } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { defaultArgs, groupedOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/Grouped',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | const Template: ComponentStory = ({
15 | inputId = 'react-select',
16 | ...props
17 | }) => {
18 | return (
19 |
24 |
25 |
26 | );
27 | };
28 |
29 | export const Grouped = Template.bind({});
30 | Grouped.args = {
31 | ...defaultArgs,
32 | options: groupedOptions,
33 | };
34 |
--------------------------------------------------------------------------------
/storybook/stories/MenuBuffer.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { StylesConfig } from 'react-select';
4 | import { Field } from '../components';
5 |
6 | import { colourOptions, StateOption } from '../data';
7 |
8 | export default {
9 | title: 'Select/MenuBuffer',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function MenuBuffer() {
15 | return (
16 |
21 |
26 |
27 | );
28 | }
29 |
30 | const selectStyles: StylesConfig = {
31 | menu: (base) => ({ ...base, marginBottom: 76 }),
32 | };
33 |
--------------------------------------------------------------------------------
/storybook/stories/OnSelectKeepsInput.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select, { InputActionMeta } from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { colourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/OnSelectKeepsInput',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function OnSelectKeepsInput() {
15 | const [menuIsOpen, setMenuIsOpen] = React.useState();
16 |
17 | function handleInputChange(
18 | inputValue: string,
19 | { action, prevInputValue }: InputActionMeta
20 | ) {
21 | if (action === 'input-change') return inputValue;
22 | if (action === 'menu-close') {
23 | if (prevInputValue) {
24 | setMenuIsOpen(true);
25 | } else {
26 | setMenuIsOpen(undefined);
27 | }
28 | }
29 | return prevInputValue;
30 | }
31 |
32 | return (
33 |
38 |
49 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/storybook/stories/StyleCompositionExample.stories.tsx:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from '@emotion/react';
3 | import type { ComponentMeta } from '@storybook/react';
4 | import Select, { OptionProps, StylesConfig } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { ColourOption, colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/StyleCompositionExample',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | export function StyleCompositionExample() {
16 | return (
17 |
18 |
26 |
27 | );
28 | }
29 |
30 | // =============================================================================
31 | // Styles
32 | // =============================================================================
33 |
34 | const styles: StylesConfig = {
35 | option: (base) => ({
36 | ...base,
37 | border: `1px dotted ${colourOptions[2].color}`,
38 | height: '100%',
39 | }),
40 | };
41 |
42 | // =============================================================================
43 | // Components
44 | // =============================================================================
45 |
46 | function Option(props: OptionProps) {
47 | return (
48 |
62 | {props.children}
63 |
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/storybook/stories/StyledSingle.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import chroma from 'chroma-js';
3 | import * as React from 'react';
4 | import Select, { StylesConfig } from 'react-select';
5 |
6 | import { Field } from '../components';
7 | import { ColourOption, colourOptions } from '../data';
8 |
9 | export default {
10 | title: 'Select/StyledSingle',
11 | component: Select,
12 | argTypes: {},
13 | } as ComponentMeta;
14 |
15 | function dot(color = 'transparent') {
16 | return {
17 | alignItems: 'center',
18 | display: 'flex',
19 |
20 | ':before': {
21 | backgroundColor: color,
22 | borderRadius: 10,
23 | content: '" "',
24 | display: 'block',
25 | marginRight: 8,
26 | height: 10,
27 | width: 10,
28 | },
29 | };
30 | }
31 |
32 | const colourStyles: StylesConfig = {
33 | control: (styles) => ({ ...styles, backgroundColor: 'white' }),
34 | option: (styles, { data, isDisabled, isFocused, isSelected }) => {
35 | const color = chroma(data.color);
36 | return {
37 | ...styles,
38 | backgroundColor: isDisabled
39 | ? undefined
40 | : isSelected
41 | ? data.color
42 | : isFocused
43 | ? color.alpha(0.1).css()
44 | : undefined,
45 | color: isDisabled
46 | ? '#ccc'
47 | : isSelected
48 | ? chroma.contrast(color, 'white') > 2
49 | ? 'white'
50 | : 'black'
51 | : data.color,
52 | cursor: isDisabled ? 'not-allowed' : 'default',
53 |
54 | ':active': {
55 | ...styles[':active'],
56 | backgroundColor: !isDisabled
57 | ? isSelected
58 | ? data.color
59 | : color.alpha(0.3).css()
60 | : undefined,
61 | },
62 | };
63 | },
64 | input: (styles) => ({ ...styles, ...dot() }),
65 | placeholder: (styles) => ({ ...styles, ...dot('#ccc') }),
66 | singleValue: (styles, { data }) => ({ ...styles, ...dot(data.color) }),
67 | };
68 |
69 | export function StyledSingle() {
70 | return (
71 |
72 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/storybook/stories/Theme.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { ComponentMeta } from '@storybook/react';
2 | import * as React from 'react';
3 | import Select from 'react-select';
4 |
5 | import { Field } from '../components';
6 | import { flavourOptions } from '../data';
7 |
8 | export default {
9 | title: 'Select/Theme',
10 | component: Select,
11 | argTypes: {},
12 | } as ComponentMeta;
13 |
14 | export function Theme() {
15 | return (
16 |
17 | ({
22 | ...theme,
23 | borderRadius: 0,
24 | colors: {
25 | ...theme.colors,
26 | primary25: 'hotpink',
27 | primary: 'black',
28 | },
29 | })}
30 | />
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/storybook/styles/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/storybook/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './components/**/*.{js,ts,jsx,tsx}',
5 | './stories/**/*.{js,ts,jsx,tsx}',
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | };
12 |
--------------------------------------------------------------------------------
/test-setup.js:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "jsx": "react",
6 | "noEmit": true,
7 | "strict": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "resolveJsonModule": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------