diff --git a/.browserslistrc b/.browserslistrc
new file mode 100644
index 0000000000..93cda006dd
--- /dev/null
+++ b/.browserslistrc
@@ -0,0 +1,3 @@
+> 0.25%
+ie 11
+not op_mini all
diff --git a/.changeset/README.md b/.changeset/README.md
new file mode 100644
index 0000000000..26f218eda3
--- /dev/null
+++ b/.changeset/README.md
@@ -0,0 +1,36 @@
+# Changesets
+
+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)
+
+To help you get started though, here are some things you should know about this folder:
+
+## Changesets are automatically generated
+
+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.
+
+## Each changeset is its own folder
+
+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.
+
+## Changesets are automatically removed
+
+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.
+
+## Changesets come in two parts
+
+You should treat these parts quite differently:
+
+- `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.
+- `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.
+
+## I want to edit the information in a `changes.json` - how do I do it safely?
+
+The best option is to make a new changeset using the changeset command, copy over the `changes.md`, then delete the old changeset.
+
+## Can I rename the folder for my changeset?
+
+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.
+
+## Can I manually delete changesets?
+
+You can, but you should be aware this will remove the intent to release communicated by the changeset, and should be done with caution.
diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 0000000000..71ec72852f
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@0.2.1/schema.json",
+ "changelog": "./getChangelogEntry",
+ "commit": false,
+ "linked": [],
+ "access": "public"
+}
diff --git a/.changeset/getChangelogEntry.js b/.changeset/getChangelogEntry.js
new file mode 100644
index 0000000000..91554cbd2f
--- /dev/null
+++ b/.changeset/getChangelogEntry.js
@@ -0,0 +1,34 @@
+require('dotenv').config();
+const { getInfo } = require('@changesets/get-github-info');
+
+const getReleaseLine = async (changeset, type) => {
+ const [firstLine, ...futureLines] = changeset.summary
+ .split('\n')
+ .map((l) => l.trimRight());
+ let { links } = await getInfo({
+ repo: 'JedWatson/react-select',
+ commit: changeset.commit,
+ });
+ return `- ${links.commit}${links.pull === null ? '' : ` ${links.pull}`}${
+ links.user === null ? '' : ` Thanks ${links.user}!`
+ } - ${firstLine}\n${futureLines.map((l) => ` ${l}`).join('\n')}`;
+};
+
+const getDependencyReleaseLine = async (changesets, dependenciesUpdated) => {
+ if (dependenciesUpdated.length === 0) return '';
+
+ const changesetLinks = changesets.map(
+ (changeset) => `- Updated dependencies [${changeset.commit}]:`
+ );
+
+ const updatedDepenenciesList = dependenciesUpdated.map(
+ (dependency) => ` - ${dependency.name}@${dependency.version}`
+ );
+
+ return [...changesetLinks, ...updatedDepenenciesList].join('\n');
+};
+
+module.exports = {
+ getReleaseLine,
+ getDependencyReleaseLine,
+};
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000000..0664c44068
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,75 @@
+version: 2
+
+docker_defaults: &docker_defaults
+ docker:
+ - image: cypress/browsers:latest
+ environment:
+ TERM: xterm
+ working_directory: ~/project/repo
+
+attach_workspace: &attach_workspace
+ attach_workspace:
+ at: ~/project
+
+install_steps: &install_steps
+ steps:
+ - checkout
+ - restore_cache:
+ name: Restore node_modules cache
+ keys:
+ - dependency-cache-{{ .Branch }}-{{ checksum "yarn.lock" }}
+ - dependency-cache-{{ .Branch }}-
+ - dependency-cache-
+ - cache-{{ checksum "package.json" }}
+ - run:
+ name: Installing Dependencies
+ command: |
+ yarn install --silent
+ - save_cache:
+ name: Save node_modules cache
+ key: dependency-cache-{{ .Branch }}-{{ checksum "package.json" }}
+ paths:
+ - ~/.cache
+ - persist_to_workspace:
+ root: ~/project
+ paths:
+ - repo
+
+workflows:
+ version: 2
+ build_pipeline:
+ jobs:
+ - build
+ - unit_test:
+ requires:
+ - build
+ - end_to_end:
+ requires:
+ - build
+jobs:
+ build:
+ <<: *docker_defaults
+ <<: *install_steps
+ unit_test:
+ <<: *docker_defaults
+ steps:
+ - *attach_workspace
+ - run:
+ name: Running unit tests
+ command: |
+ yarn prettier:check
+ yarn lint
+ yarn type-check
+ yarn test:jest
+ yarn coveralls
+ end_to_end:
+ <<: *docker_defaults
+ steps:
+ - *attach_workspace
+ - run:
+ name: Running E2E tests
+ command: |
+ yarn global add cypress
+ yarn install --silent
+ yarn cypress install
+ yarn e2e
diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
new file mode 100644
index 0000000000..22e243ad13
--- /dev/null
+++ b/.codesandbox/ci.json
@@ -0,0 +1,6 @@
+{
+ "buildCommand": "build",
+ "packages": ["packages/*"],
+ "sandboxes": ["nfmxw"],
+ "node": "20"
+}
diff --git a/.coveralls.yml b/.coveralls.yml
index 6c493c85ba..842b65017b 100644
--- a/.coveralls.yml
+++ b/.coveralls.yml
@@ -1,2 +1,2 @@
service-name: travis-ci
-repo_token: itdMRdBNgDK8Gb5nIA63zVMEryaxTQxkR
+repo_token: itdMRdBNgDK8Gb5nIA63zVMEryaxTQxkR
diff --git a/.editorconfig b/.editorconfig
index 2d16f58976..f83c0c4d6b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,16 +7,11 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-indent_style = tab
-translate_tabs_to_spaces = false
-
-[*.json]
-indent_style = space
-indent_size = 2
-
-[*.yml]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
+
+[.circleci/config.yml]
+indent_size = 4
diff --git a/.eslintignore b/.eslintignore
index fd87c8299d..b7d748ace5 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,5 +1,7 @@
+coverage/*
+cypress/plugins/*
+cypress/support/*
+**/dist/*
lib/*
-dist/*
-examples/dist/*
node_modules/*
-bower_components/*
+**/node_modules/*
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index f4253545b1..0000000000
--- a/.eslintrc
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "parser": "babel-eslint",
- "env": {
- "browser": true,
- "node": true
- },
- "plugins": [
- "react"
- ],
- "rules": {
- "curly": [2, "multi-line"],
- "jsx-quotes": 1,
- "no-shadow": 0,
- "no-trailing-spaces": 0,
- "no-underscore-dangle": 0,
- "no-unused-expressions": 0,
- "object-curly-spacing": [1, "always"],
- "quotes": [2, "single", "avoid-escape"],
- "react/jsx-boolean-value": 1,
- "react/jsx-no-undef": 1,
- "react/jsx-sort-prop-types": 1,
- "react/jsx-uses-react": 1,
- "react/jsx-uses-vars": 1,
- "react/no-did-mount-set-state": 1,
- "react/no-did-update-set-state": 1,
- "react/no-unknown-property": 1,
- "react/prop-types": 1,
- "react/react-in-jsx-scope": 1,
- "react/self-closing-comp": 1,
- "react/sort-comp": 1,
- "react/wrap-multilines": 1,
- "semi": 2,
- "strict": 0
- }
-}
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000000..aec4f80df3
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,50 @@
+module.exports = {
+ extends: ['plugin:react-hooks/recommended', 'plugin:@typescript-eslint/base'],
+ parser: '@typescript-eslint/parser',
+ env: {
+ browser: true,
+ es6: true,
+ node: true,
+ },
+ plugins: ['react', '@typescript-eslint'],
+ rules: {
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ {
+ args: 'after-used',
+ argsIgnorePattern: '^event$',
+ ignoreRestSiblings: true,
+ vars: 'all',
+ varsIgnorePattern: 'jsx|emotionJSX',
+ },
+ ],
+ curly: [2, 'multi-line'],
+ 'jsx-quotes': 1,
+ 'no-shadow': 0,
+ '@typescript-eslint/no-shadow': 2,
+ 'no-trailing-spaces': 1,
+ 'no-underscore-dangle': 1,
+ '@typescript-eslint/no-unused-expressions': 1,
+ 'object-curly-spacing': [1, 'always'],
+ '@typescript-eslint/quotes': [2, 'single', 'avoid-escape'],
+ 'react/jsx-boolean-value': 1,
+ 'react/jsx-no-undef': 1,
+ 'react/jsx-uses-react': 1,
+ 'react/jsx-uses-vars': 1,
+ 'react/jsx-wrap-multilines': 1,
+ 'react/no-did-mount-set-state': 1,
+ 'react/no-did-update-set-state': 1,
+ 'react/no-unknown-property': 1,
+ 'react/react-in-jsx-scope': 1,
+ 'react/self-closing-comp': 1,
+ 'react/sort-prop-types': 1,
+ '@typescript-eslint/semi': 2,
+ '@typescript-eslint/no-inferrable-types': 2,
+ strict: 0,
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ },
+};
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index f3f4a7c2d7..0000000000
--- a/.gitattributes
+++ /dev/null
@@ -1,3 +0,0 @@
-dist/* binary
-examples/dist/* binary
-lib/* binary
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000000..12f58f0116
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+# Contributing
+
+Thanks for your interest in React-Select. All forms of contribution are
+welcome, from issue reports to PRs and documentation / write-ups.
+
+Before you open a PR:
+
+- In development, run `yarn start` to build (+watch) the project source, and run
+ the [development server](http://localhost:8000).
+- Please ensure all the examples work correctly after your change. If you're
+ adding a major new use-case, add a new example demonstrating its use.
+- Be careful to follow the code style of the project. Run `yarn lint` after
+ your changes and ensure you do not introduce any new errors or warnings.
+- This repository uses TypeScript, please run `yarn type-check` after your changes to ensure
+ that you do not introduce any new type errors.
+
+- Ensure that your effort is aligned with the project's roadmap by talking to
+ the maintainers, especially if you are going to spend a lot of time on it.
+- Make sure there's an issue open for any work you take on and intend to submit
+ as a pull request - it helps core members review your concept and direction
+ early and is a good way to discuss what you're planning to do.
+- If you open an issue and are interested in working on a fix, please let us
+ know. We'll help you get started, rather than adding it to the queue.
+- Make sure you do not add regressions by running `yarn test`.
+- Where possible, include tests with your changes, either that demonstrates the
+ bug, or tests the new functionality. If you're not sure how to test your
+ changes, feel free to ping @gwyneplaine or @JedWatson
+- Run `yarn coveralls` to check that the coverage hasn't dropped, and look at the
+ report (under the generated `coverage` directory) to check that your changes are
+ covered
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..0a80e34e6f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,27 @@
+---
+name: Bug report
+about: File a bug report
+title: '
'
+labels: [issue/bug-unconfirmed]
+assignees: ''
+---
+
+**Thanks for using react-select!**
+
+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.
+Questions and feature requests have their own place in our discussions section.
+
+## Are you reporting a bug or runtime error?
+
+Please include a test case that demonstrates the issue you're reporting!
+
+This is very helpful to maintainers in order to help us see the issue you're seeing.
+
+Please note we are currently only directing our efforts towards the current major (v5) version and beyond.
+
+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.
+
+To report bugs against react-select v5 please fork the following code-sandbox:
+https://codesandbox.io/s/react-select-v5-sandbox-y5jtm
+
+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.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..f3cffab5d4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Feature request
+ url: https://github.com/JedWatson/react-select/discussions/categories/ideas
+ about: Got an idea for a feature or want to propose a change? Then this is the place for you.
+ - name: Question on usage
+ url: https://github.com/JedWatson/react-select/discussions/categories/q-a
+ about: If you have a question regarding the usage of the library.
+ - name: StackOverflow
+ url: https://stackoverflow.com/questions/tagged/react-select
+ about: Alternatively you can visit StackOverflow with the `[react-select]` tag
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..902ebdae29
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: 'npm'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
+ ignore:
+ - dependency-name: '*'
+ update-types:
+ ['version-update:semver-minor', 'version-update:semver-patch']
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000000..65b2c9e3ba
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,40 @@
+name: Release
+
+on:
+ push:
+ branches:
+ - master
+
+permissions:
+ contents: read
+
+jobs:
+ release:
+ permissions:
+ # for changesets/action
+ contents: write
+ pull-requests: write
+ name: Release
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Repo
+ uses: actions/checkout@v3
+ with:
+ # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
+ fetch-depth: 0
+
+ - name: Setup Node.js 22.x
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22.x
+
+ - name: Install Dependencies
+ run: yarn
+
+ - name: Create Release Pull Request or Publish to npm
+ uses: changesets/action@v1
+ with:
+ publish: yarn release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.gitignore b/.gitignore
index d2dfea8f34..d44aafc2e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# Build
+lib
+dist
+docs/dist
+.env
+
# Logs
logs
*.log
@@ -10,6 +16,13 @@ pids
# Coverage tools
lib-cov
coverage
+.nyc_output
+
+# Cypress
+cypress/videos
+cypress/screenshots
+cypress/support
+cypress/plugins
# Dependency directory
node_modules
@@ -18,10 +31,15 @@ bower_components
# Publish directory
.publish
-# Editor artifacts
+# Editor artefacts
.idea
# Other
.DS_Store
+.env
+package-lock.json
+
+# Notes
+.NOTES.md
-yarn.lock
+magical-types
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index 56c959651c..0000000000
--- a/.npmignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.editorconfig
-bower.json
-examples/dist
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000000..2bd5a0a98a
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+22
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000000..201bf7f3af
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+coverage/*
+cypress/plugins/*
+cypress/support/*
+**/dist/*
+lib/*
+node_modules/*
+**/node_modules/*
+**/magical-types/*
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000000..0b8804b51d
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,10 @@
+module.exports = {
+ singleQuote: true,
+ trailingComma: 'es5',
+ overrides: [
+ {
+ files: '.changeset/pre.json',
+ options: { parser: 'json-stringify' },
+ },
+ ],
+};
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 8278823bda..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-sudo: false
-language: node_js
-node_js:
- - "v4"
-script:
- - npm run coveralls
diff --git a/CHANGES.md b/CHANGES.md
deleted file mode 100644
index 451b929481..0000000000
--- a/CHANGES.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Changes
-
-## Breaking Changes
-
-Major API changes to Component props, SingleValue and Value have been merged
-
-The component is now "controlled", which means you have to pass value as a prop and always handle the `onChange` event. See https://facebook.github.io/react/docs/forms.html#controlled-components
-
-Using values that aren't in the `options` array is still supported, but they have to be full options (previous versions would expand strings into `{ label: string, value: string }`)
-
-Options & Value components get their label as their Children
-
-new `simpleValue` prop for when you want to deal with values as strings or numbers (legacy behaviour, defaults to false). onChange no longer receives an array of expanded values as the second argument.
-
-`onOptionLabelClick` -> `onValueClick`
-
-Multiple values are now submitted in multiple form fields, which results in an array of values in the form data. To use the old method of submitting a single string of all values joined with the delimiter option, use the `joinValues` prop.
-
-## New Select.Async Component
-
-`loadingPlaceholder` prop
-`cacheAsyncResults` -> `cache` (new external cache support) - defaults to true
-
-## Fixes & Other Changes
-
-new `ignoreAccents` prop (on by default), thanks [Guilherme Guerchmann](https://github.com/Agamennon)
-new `escapeClearsValue` prop (on by default)
-bug where the filter wouldn't be reset after blur
-complex option values are much better supported now, won't throw duplicate key errors and will serialize to the input correctly
-
-## Notes
-
-`undefined` default props are no longer declared
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6afd856a9d..e8a43d8534 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,52 +3,20 @@
Thanks for your interest in React-Select. All forms of contribution are
welcome, from issue reports to PRs and documentation / write-ups.
-* We use node.js v4 for development and testing. Due to incompatibilities with
-JSDOM and older versions of node.js, you'll need to use node 4 to run the
-tests. If you can't install node v4 as your "default" node installation, you
-could try using [nvm](https://github.com/creationix/nvm) to install multiple
-versions concurrently.
-* If you're upgrading your node.js 0.x environment, it's sometimes necessary
-to remove the node_modules directory under react-select, and run npm install
-again, in order to ensure all the correct dependencies for the new version
-of node.js (as a minimum, you'll need to remove the `jsdom` module, and
-reinstall that).
-
Before you open a PR:
-* If you're planning to add or change a major feature in a PR, please ensure
-the change is aligned with the project roadmap by opening an issue first,
-especially if you're going to spend a lot of time on it.
-* In development, run `npm start` to build (+watch) the project source, and run
-the [development server](http://localhost:8000).
-* Please ensure all the examples work correctly after your change. If you're
-adding a major new use-case, add a new example demonstrating its use.
-* Please **do not** commit the build files. Make sure **only** your changes to
-`/src/`, `/less/` and `/examples/src` are included in your PR.
-* Be careful to follow the code style of the project. Run `npm run lint` after
-your changes and ensure you do not introduce any new errors or warnings.
-
-* Ensure that your effort is aligned with the project's roadmap by talking to
-the maintainers, especially if you are going to spend a lot of time on it.
-* Make sure there's an issue open for any work you take on and intend to submit
-as a pull request - it helps core members review your concept and direction
-early and is a good way to discuss what you're planning to do.
-* If you open an issue and are interested in working on a fix, please let us
-know. We'll help you get started, rather than adding it to the queue.
-* Make sure you do not add regressions by running `npm test`.
-* Where possible, include tests with your changes, either that demonstrates the
-bug, or tests the new functionality. If you're not sure how to test your
-changes, feel free to ping @bruderstein
-* Run `npm run cover` to check that the coverage hasn't dropped, and look at the
-report (under the generated `coverage` directory) to check that your changes are
-covered
-* Please [follow our established coding conventions](https://github.com/keystonejs/keystone/wiki/Coding-Standards)
-(with regards to formatting, etc)
-* You can also run `npm run lint` and `npm run style` - our linter is a WIP
-but please ensure there are not more violations than before your changes.
-* All new features and changes need documentation. We have three translations,
-please read our [Documentation Guidelines](https://github.com/keystonejs/keystone/wiki/Documentation-Translation-Guidelines).
-
-* _Make sure you revert your build before submitting a PR_ to reduce the chance
-of conflicts. `gulp build-scripts` is run after PRs are merged and before any
-releases are made.
+- In development, run `yarn start` to build (and watch) the project source, and run
+ the [development server](http://localhost:8000).
+- Please ensure all the examples work correctly after your change. If you're
+ adding a major new use-case, add a new example `/docs/examples` and subsequent documentation demonstrating its use `/docs/pages`.
+- Ensure that your effort is aligned with the project's roadmap by talking to
+ the maintainers, especially if you are going to spend a lot of time on it.
+- Make sure there's an issue open for any work you take on and intend to submit
+ as a pull request - it helps core members review your concept and direction
+ early and is a good way to discuss what you're planning to do.
+- If you open an issue and are interested in working on a fix, please let us
+ know. We'll help you get started, rather than inadvertently doubling up on your hard work.
+- Make sure you do not add regressions by running `yarn test`.
+- Where possible, include tests with your changes, either that demonstrates the
+ bug, or tests the new functionality.
+- All new features and changes need documentation.
diff --git a/HISTORY.md b/HISTORY.md
deleted file mode 100644
index 5862bb2f37..0000000000
--- a/HISTORY.md
+++ /dev/null
@@ -1,539 +0,0 @@
-# React-Select
-
-## v1.0.0-rc.3 / 2017-02-01
-
-* added; `arrowRenderer` prop, thanks [Brian Vaughn](https://github.com/bvaughn)
-* added; child-function support to `Async` and `Creatable` components so that they can compose each other (or future HOCs), thanks [Brian Vaughn](https://github.com/bvaughn)
-* added; `asyncCreatable` HOC that combines `Async` and `Creatable` so they can be used together, thanks [Brian Vaughn](https://github.com/bvaughn)
-* added; undocumented arguments for `menuRenderer`, thanks [Julian Krispel-Samsel](https://github.com/juliankrispel)
-* fixed; Do not focus and open menu when disabled, thanks [nhducit](https://github.com/nhducit)
-* fixed; Scrolling with arrow-keys is not working correctly, thanks [Damian Pieczynski](https://github.com/piecyk)
-* added; "select all text" functionality `Shift+Home|Del`, thanks [Damian Pieczynski](https://github.com/piecyk)
-* added; support for `boolean` values, thanks [Aaron Hardy](https://github.com/Aaronius)
-* fixed; Remove duplicated `promptTextCreator` field from readme, thanks [Jih-Chi Lee](https://github.com/jihchi)
-* fixed; Adding back ref that was removed in rc2, thanks [Martin Jujou](https://github.com/jooj123)
-* fixed; `Creatable` component doesn't allow input key down handling, thanks [Ivan Leonenko](https://github.com/IvanLeonenko)
-* added; Allow react nodes to be passed as loadingPlaceholder, thanks [Daniel Heath](https://github.com/DanielHeath)
-* fixed; IE8 compatibility issues, thanks [Kirill Mesnyankin](https://github.com/strayiker)
-* improved; Allow users to specify noResultsText, thanks [Daniel Heath](https://github.com/DanielHeath)
-* added; Only remove options if a loading placeholder is available, thanks [Daniel Heath](https://github.com/DanielHeath)
-* fixed; firefox display items in two rows due to reflow, thanks [Daniel Heath](https://github.com/DanielHeath)
-* fixed; `Creatable` readme typo, thanks [Ben](https://github.com/rockingskier)
-* fixed; explain way to implement `allowCreate` functionality with `Creatable` to readme, thanks [mayerwin](https://github.com/mayerwin)
-* added; delete key removes an item when there is no input, thanks [forum-is](https://github.com/forum-is)
-* added; `onNewOptionClick` handler for `Creatable`, thanks [Lee Siong Chan](https://github.com/leesiongchan)
-* fixed; `onInputChange` consistent for `Creatable`, thanks [Lee Siong Chan](https://github.com/leesiongchan)
-* fixed; `menuRenderer` is treated consistently between `Creatable` and `Select`, thanks [Brian Vaughn](https://github.com/bvaughn)
-* fixed; `asyncCreatable` options parsing will not parse undefined values into props, thanks [Romain Dardour](https://github.com/unity)
-* added; pass `inputProps` to `inputRenderer`, thanks [Alec Winograd](https://github.com/awinograd)
-* fixed; no exception when clearing an Async field that is not set to multi, thanks [Patrik Stutz](https://github.com/VanCoding)
-* added; allow rendering a custom clear component, thanks [Conor Hastings](https://github.com/conorhastings)
-* fixed; document `ignoreAccents`, thanks [Domenico Matteo](https://github.com/dmatteo)
-* fixed; arrowing up or down in `Select` with 0 options does not throw type error, thanks [Alex Howard](https://github.com/thezanke)
-* fixed; `Creatable` handles null children prop, thanks [Jack Coulter](https://github.com/jscinoz)
-* added; provide `isOpen` to arrowRenderer, thanks [Kuan](https://github.com/khankuan)
-* fixed; re-added the `focus()` method on `Select.Async`, thanks, [Maarten Claes](https://github.com/mcls)
-* fixed; focus the next available option after a selection, not the top option, thanks [Nicolas Raynaud](https://github.com/nraynaud)
-
-Note there has also been a breaking change to the props for the `Async` component: both `minimumInput` and `searchingText` have been removed. See #1226 for more details. Apologies for doing this in an RC release, but we had to trade off between resolving some important bugs and breaking the API, and figured it was better to do this before declaring 1.0.0 stable.
-
-
-## v1.0.0-rc.1 / 2016-09-04
-
-* fixed; reset value to `[]` when `multi=true`, thanks [Michael Williamson](https://github.com/mwilliamson)
-* added; pass index to `renderLabel` method, thanks [nhducit](https://github.com/nhducit)
-* fixed; uncontrolled to controlled component warning in React 15.3
-* fixed; props cleanup, thanks [Forbes Lindesay](https://github.com/ForbesLindesay)
-* fixed; issue where a value of the number `0` would be assumed to be no value, thanks [Hanwen Cheng](https://github.com/hanwencheng)
-* fixed; internal refs converted to callbacks instead of strings, thanks [Johnny Nguyen](https://github.com/gojohnnygo)
-* added; optional `instanceId` prop for server-side rendering, thanks [Jevin Anderson](https://github.com/JevinAnderson)
-* added; `onCloseResetsInput` prop, thanks [Frankie](https://github.com/frankievx)
-* added; `Creatable` component, replaces pre-1.0 `allowCreate` prop, thanks [Brian Vaughn](https://github.com/bvaughn)
-
-## v1.0.0-beta14 / 2016-07-17
-
-* fixed; `react-input-autosize` has been udpated to `1.1.0`, which includes fixes for the new warnings that React 15.2 logs
-* fixed; "Unknown prop `inputClassName` on tag" warning, thanks [Max Stoiber](https://github.com/mxstbr)
-* fixed; Removed unnecessary `onUnfocus`, thanks [Johnny Nguyen](https://github.com/gojohnnygo)
-* added; Support for react components in `searchPromptText`, thanks [Matt](https://github.com/hellaeon)
-* fixed; focus bug on iOS, thanks [Tony deCatanzaro](https://github.com/tonydecat)
-* fixed; Async bugs with Promises, thanks [Vladimir](https://github.com/VladimirPal) and [Ian Firkin](https://github.com/lobsteropteryx)
-* fixed; `searchingText` bug, thanks [Tony deCatanzaro](https://github.com/tonydecat)
-* improved; More antive-like input behaviour, thanks [Johnny Nguyen](https://github.com/gojohnnygo)
-* fixed; Added missing unit (px) to `minWidth` attribute, thanks [Ian Witherow](https://github.com/ianwitherow)
-* added; Support for assistive technologies, thanks [Dave Brotherstone](https://github.com/bruderstein)
-* fixed; React error if `onChange` callback causes a root component to unmount, thanks [Nathan Norton](https://github.com/Xesued)
-* fixed; Open menu is now closed if `disabled` becomes true, thanks [Jason Moon](https://github.com/jsnmoon)
-* fixed; Prevent `getFocusableOptionIndex` from returning a disabled option, thanks [Brian Powers](https://github.com/brianspowers)
-* added; Home, End, Page Up/Down support, thanks [Jason Kadrmas](https://github.com/blackjk3)
-* fixed; Don't render `backspaceToRemoveMessage` if `backspaceRemoves` is set to false, thanks [Ryan Zec](https://github.com/ryanzec)
-* fixed; Issue with an outline appearing on the auto sized input, thanks [Ryan Zec](https://github.com/ryanzec)
-* fixed; Events don't propagate when `esc` is pressed, thanks [Yoshihide Jimbo](https://github.com/jmblog)
-* fixed; Update `required` prop based on nextProps on update, thanks [Matt Shwery](https://github.com/mshwery)
-* fixed; On focus check whether input ref is a real input or an input component, thanks [Peter Brant](https://github.com/pbrant) and [Greg Poole](https://github.com/gpoole)
-
-Also a big thanks to [Brian Vaughn](https://github.com/bvaughn) for his help triaging issues for this release!
-
-## v1.0.0-beta13 / 2016-05-30
-
-* added; `inputRenderer` prop, allows you to override the input component, thanks [Sean Burke](https://github.com/leftmostcat)
-* added; `openOnFocus` prop, causes the menu to always open when the select control is focused, thanks [HuysentruytRuben](https://github.com/HuysentruytRuben)
-* added; `react-virtualised-select` HOC example, thanks [Brian Vaughn](https://github.com/bvaughn)
-* added; `tabSelectsValue` prop can be set to false to prevent selection of focused option when tab is pressed, thanks [Byron Anderson](https://github.com/byronanderson)
-* added; ability to override `resetValue` when clearing the control, thanks [Alexander Luberg](https://github.com/LubergAlexander)
-* added; input can be updated with `onInputChange`, thanks [Brett DeWoody](https://github.com/brettdewoody)
-* added; Styles for .is-selected class, thanks [Danny Herran](https://github.com/dherran)
-* fixed; `noResultsText` prop type is now `stringOrNode` for Async component, thanks [Michael Groeneman](https://github.com/mgroeneman)
-* fixed; `onInputChange` is wrapped by Async component, thanks [Eric O'Connell](https://github.com/drd)
-* fixed; `scrollMenuIntoView` behaviour in IE10, thanks [Ivan Jager](https://github.com/aij)
-* fixed; isEqualNode replaced with strict equality check, thanks [Alexandre Balhier](https://github.com/abalhier)
-* fixed; issue with value object not being passed to `handleRequired`, thanks [Andrew Hite](https://github.com/andyhite)
-* fixed; the menu-outer container is no longer rendered when it does not contain anything, thanks [Kuan](https://github.com/khankuan)
-* improved; better support for IE8 in styles, thanks [Rockallite Wulf](https://github.com/rockallite)
-
-## v1.0.0-beta12 / 2016-04-02
-
-* added; `menuRenderer` method and example for effeciently rendering thousands of options, thanks [Brian Vaughn](https://github.com/bvaughn)
-* added; `optionClassName` prop, thanks [Max Tyler](https://github.com/iam4x)
-
-## v1.0.0-beta11 / 2016-03-09
-
-* updated dependencies to allow use with React 15.x
-* changed; multiple selected values are now submitted using multiple inputs, thanks [Trinh Hoang Nhu](https://github.com/james4388)
-* added; `joinValues` prop to revert the above change and submit multiple values in a single field with the delimiter
-
-## v1.0.0-beta10 / 2016-02-23
-
-* fixed build issues with v1.0.0-beta9
-
-## v1.0.0-beta9 / 2016-02-12
-
-* added; onBlurResetsInput prop, thanks [Sly Bridges](https://github.com/slybridges)
-* changed; Enter selects and retains focus, Tab selects and shifts focus, thanks [RDX](https://github.com/rdsubhas)
-* fixed; Hide noResultsText when value is falsy, thanks [Fernando Alex Helwanger](https://github.com/fhelwanger)
-* added; `required` prop, adds HTML5 required attribute, thanks [Domenico Matteo](https://github.com/dmatteo)
-* fixed; Touch drag behaviour, thanks [Pavel Tarnopolsky](https://github.com/Paveltarno)
-* added; `onOpen` and `onClose` event props, thanks [Jacob Page](https://github.com/DullReferenceException)
-* fixed; Pressing Enter on open Select should stop propagation, thanks [Jeremy Liberman](https://github.com/MrLeebo)
-* fixed; Missing handleMouseDownOnMenu, thanks [Jeremy Liberman](https://github.com/MrLeebo)
-* added; Ensures the selected option is immediately visible when the menu is open, thanks [Martin Jujou](https://github.com/jooj123)
-* added; `autoBlur` prop, blurs the input when a value is selected, thanks [Pavel Tarnopolsky](https://github.com/Paveltarno)
-* fixed; Several isFocused checks weren't working properly
-
-## v1.0.0-beta8 / 2015-12-20
-
-* fixed; input focus bug when toggling `disabled` prop, thanks [Davide Curletti](https://github.com/dcurletti)
-* fixed; `focus()` is now exposed on the `Async` component, thanks [AugustinLF](https://github.com/AugustinLF)
-
-## v1.0.0-beta7 / 2015-12-15
-
-* You can now use React elements for placeholders and the text props, thanks [kromit](https://github.com/kromit) and [Alyssa Biasi](https://github.com/alyssaBiasi)
-* Fixed a problem where the border doesn't show when the element is inside a table, thanks [Rodrigo Boratto](https://github.com/rwrz)
-* New prop `scrollMenuIntoView` scrolls the viewport to display the menu, thanks [Alexander Zaharakis](https://github.com/azaharakis)
-* New LESS / SCSS variable `select-option-bg` lets you control the menu option background color, thanks [Evan Goldenberg](https://github.com/Naveg)
-* Fixed an error in the blur handler on IE when the menu is not visible, thanks [Gaston Sanchez](https://github.com/gaastonsr)
-* Added support for a `clearableValue` option property in `multi` mode, thanks [Sly Bridges](https://github.com/slybridges)
-
-## v1.0.0-beta6 / 2015-11-29
-
-* Test suite complete and passing, with a couple of minor fixes thanks to @bruderstein
-
-## v1.0.0-beta5 / 2015-11-08
-
-* Fixes issues relating to serializing simple values into the hidden field
-
-## v1.0.0-beta4 / 2015-11-08
-
-* New default styles that match [Elemental UI](http://elemental-ui.com) and look right at home in the new [KeystoneJS Admin UI](http://keystonejs.com)
-
-We're potentially going to ship some theme stylesheets in the future, shout out on GitHub if this interests you.
-
-## v1.0.0-beta3 / 2015-11-08
-
-* The selected value populated in the hidden field has been fixed (was `"[object Object]"` before)
-* Added new `autofocus` prop
-* Fixed duplicate key error for options and values with duplicate `value` properties
-* SCSS variables now have `!default` so you can override them
-
-## v1.0.0-beta2 / 2015-11-06
-
-Changed since beta 1:
-
-* Async options cache works again
-* New style props for custom styling the component without modifying css classes: `style` `wrapperStyle` `menuStyle` `menuContainerStyle`
-* The menu opens and closes correctly when `searchable={false}`, there is still some work to do on this use-case
-
-## v1.0.0-beta1 / 2015-11-06
-
-This is a complete rewrite. Major changes include:
-
-* Everything is simpler (I'm nearly done and the source code is only 60% of the size of the last version)
-* No more timeouts or weird handlers, the restructuring has let me make everything more straight-forward
-* The options array is no longer preprocessed into state, just retrieved from props
-* The values array is now initialised in the Options array during render, and not stored in state, which along with the change to options makes the component more reliable and fixes issues with props not updating correctly
-* The component no longer stores its own value in state (ever) - it needs to be passed as a prop and handled with `onChange`.
-* Complex values are now enabled by default (so you're passed the option object, not its value); you can enable the legacy mode with a prop
-* The Value and Option components have been cleaned up as well for consistency
-* The hidden `
` field is now optional and the component is better suited to use in a rich React.js app than it was
-* You can disable options filtering to do the filtering externally with `onInputChange`
-* Accents on characters can now be ignored
-* The `asyncOptions` prop has been replaced by a new wrapper component: `Select.Async`
-
-Note that "Tag mode" (creating options on the fly) isn't reimplemented yet.
-
-A full guide to the breaking changes and new features will be written up soon. In the meantime please see the new examples.
-
-## v0.9.1 / 2015-11-01
-
-* added; new Contributors example w/ async options loading and custom value / label keys
-* fixed; several issues with custom `valueKey` and `labelKey` props
-* fixed; autoload now loads options with no search input
-
-## v0.9.0 / 2015-10-29
-
-* added; SCSS stylesheets!
-* improved; Options rendering should be more performant
-* breaking change; Custom `Option` components now need to pass their `option` prop to event handlers; see [this commit](https://github.com/JedWatson/react-select/commit/89af12a80a972794222b193a767f44234bbe9817) for an example of the required change.
-
-## v0.8.4 / 2015-10-27
-
-* fixed; LESS math operations now work with --strict-math=on, thanks [Vincent Fretin](https://github.com/vincentfretin)
-
-## v0.8.3 / 2015-10-27
-
-* fixed; IE issue where clicking the scrollbar would close the menu, thanks [Pete Nykänen](https://github.com/petetnt)
-
-## v0.8.2 / 2015-10-22
-
-* added; Promise support for `loadAsyncOptions`, thanks [Domenico Matteo](https://github.com/dmatteo)
-
-## v0.8.1 / 2015-10-20
-
-* fixed; `loadAsyncOptions` raises TypeError in setup, see #439 for details, thanks [Pancham Mehrunkar](https://github.com/pancham348)
-
-## v0.8.0 / 2015-10-19
-
-This release contains significant DOM structure and CSS improvements by @jossmac, including:
-
-* no more `position: absolute` for inner controls
-* `display: table` is used for layout, which works in IE8 and above, and [all other modern browsers](http://caniuse.com/#feat=css-table)
-* less "magic numbers" used for layout, should fix various browser-specific alignment issues
-* clear "x" control now animates in
-* clearer `.Select--multi` className replaces `.Select.is-multi`
-* new height & theme variables
-* "dropdown" indicator chevron is no longer displayed for multi-select controls
-
-There are no functional changes, but if you've forked the LESS / CSS to create your own theme you'll want to pay close attention to PR #527 when upgrading to this version.
-
-## v0.7.0 / 2015-10-10
-
-React Select is updated for React 0.14. If you're still using React 0.13, please continue to use `react-select@0.6.x`. There are no functional differences between v0.7.0 and v0.6.12.
-
-Additionally, our tests now require Node.js 4.x. If you are developing `react-select`, please make sure you are running the latest version of node.
-
-Thanks to @bruderstein, @dmatteo and @hull for their help getting these updates shipped!
-
-## v0.6.12 / 2015-10-02
-
-* added; `labelKey` and `valueKey` props, so you can now use different keys in `option` objects for the label and value
-* fixed; additional `isMounted()` checks in timeouts
-* fixed; componentDidUpdate timeout is reset correctly, see #208 and #434, thanks [Petr Gladkikh](https://github.com/PetrGlad)
-* fixed; mousedown event on scrollbar in menu no longer hides it, thanks [Yishai Burt](https://github.com/burtyish)
-
-## v0.6.11 / 2015-09-28
-
-* added; `isLoading` prop, allows indication of async options loading in situations where more control is required, thanks [Jon Gautsch](https://github.com/jgautsch)
-
-## v0.6.10 / 2015-09-24
-
-* fixed; a build issue with the previous release that prevented the stylesheet being generated / included
-* fixed; a LESS syntax issue, thanks [Bob Cardenas](https://github.com/bcardi)
-
-## v0.6.9 / 2015-09-19
-
-* added; `style` key for package.json, thanks [Stephen Wan](https://github.com/stephen)
-* added; `onInputChange` handler that returns the current input value, thanks [Tom Leslie](https://github.com/lomteslie)
-* fixed; simplifying handleKey function & preventDefault behaviour, thanks [davidpene](https://github.com/davidpene)
-* fixed; Display spinner while auto-loading initial data, thanks [Ben Jenkinson](https://github.com/BenJenkinson)
-* fixed; better support for touch events, thanks [Montlouis-Calixte Stéphane](https://github.com/bulby97)
-* fixed; prevent value splitting on non-multi-value select, thanks [Alan R. Soares](https://github.com/alanrsoares)
-
-## v0.6.8 / 2015-09-16
-
-* fixed; broader range of allowed prereleases for React 0.14, including rc1
-* fixed; preventing backspace from navigating back in the browser history, thanks [davidpene](https://github.com/davidpene)
-
-## v0.6.7 / 2015-08-28
-
-* fixed; missing styles for `.Select-search-prompt` and `.Select-searching` issues, thanks [Jaak Erisalu](https://github.com/jaakerisalu) and [davidpene](https://github.com/davidpene)
-
-## v0.6.6 / 2015-08-26
-
-* fixed; issue in Chrome where clicking the scrollbar would close the menu, thanks [Vladimir Matsola](https://github.com/vomchik)
-
-## v0.6.5 / 2015-08-24
-
-* fixed; completely ignores clicks on disabled items, unless the target of the click is a link, thanks [Ben Stahl](https://github.com/bhstahl)
-
-## v0.6.4 / 2015-08-24
-
-This release includes a huge improvement to the examples / website thanks to @jossmac. Also:
-
-* added; support for React 0.14 beta3
-* fixed; disabled options after searching, thanks @bruderstein
-* added; support for "Searching..." text (w/ prop) while loading async results, thanks @bruderstein and @johnomalley
-* added; `className`, `style` and `title` keys are now supported in option properties, thanks @bruderstein
-
-## v0.6.3 / 2015-08-18
-
-Otherwise known as "the real 0.6.2" this includes the updated build for the last version; sorry about that!
-
-## v0.6.2 / 2015-08-13
-
-* changed; if the `searchable` prop is `false`, the menu is opened _or closed_ on click, more like a standard Select input. thanks [MaaikeB](https://github.com/MaaikeB)
-
-## v0.6.1 / 2015-08-09
-
-* added; Support for options with numeric values, thanks [Dave Brotherstone](https://github.com/bruderstein)
-* changed; Disabled options now appear in the search results
, thanks [Dave Brotherstone](https://github.com/bruderstein)
-* fixed; asyncOptions are reloaded on componentWillReceiveProps when the value has changed, thanks [Francis Cote](https://github.com/drfeelgoud)
-* added; `cacheAsyncResults` prop (default `true`) now controls whether the internal cache is used for `asyncOptions`
-
-## v0.6.0 / 2015-08-05
-
-* improved; option, value and single value have been split out into their own components, and can be customised with props. see [#328](https://github.com/JedWatson/react-select/pull/328) for more details.
-* improved; Near-complete test coverage thanks to the awesome work of [Dave Brotherstone](https://github.com/bruderstein)
-* improved; Support all alpha/beta/rc's of React 0.14.0, thanks [Sébastien Lorber](https://github.com/slorber)
-* fixed; Close multi-select menu when tabbing away, thanks [Ben Alpert](https://github.com/spicyj)
-* fixed; Bug where Select shows the value instead of the label (reapplying fix)
-* fixed; `valueRenderer` now works when `multi={false}`, thanks [Chris Portela](https://github.com/0xCMP)
-* added; New property `backspaceRemoves` (default `true`), allows the default behaviour of removing values with backspace when `multi={true}`, thanks [Leo Lehikoinen](https://github.com/lehikol2)
-
-## v0.5.6 / 2015-07-27
-
-* fixed; Allow entering of commas when allowCreate is on but multi is off, thanks [Angelo DiNardi](https://github.com/adinardi)
-* fixed; Times (clear) character is now rendered from string unicode character for consistent output, thanks [Nibbles](https://github.com/Siliconrob)
-* fixed; allowCreate bug, thanks [goodzsq](https://github.com/goodzsq)
-* fixed; changes to props.placeholder weren't being reflected correctly, thanks [alesn](https://github.com/alesn)
-* fixed; error when escape is pressedn where `clearValue` was not passed the event, thanks [Mikhail Kotelnikov](https://github.com/mkotelnikov)
-* added; More tests, thanks [Dave Brotherstone](https://github.com/bruderstein)
-
-## v0.5.5 / 2015-07-12
-
-* fixed; replaced usage of `component.getDOMNode()` with `React.findDOMNode(component)` for compatibility with React 0.14
-
-## v0.5.4 / 2015-07-06
-
-* fixed; regression in 0.5.3 that broke componentWillMount, sorry everyone!
-* added; `addLabelText` prop for customising the "add {label}?" text when in tags mode, thanks [Fenn](https://github.com/Fenntasy)
-
-## v0.5.3 / 2015-07-05
-
-* fixed; autoload issues, thanks [Maxime Tyler](https://github.com/iam4x)
-* fixed; style incompatibilities with Foundation framework, thanks [Timothy Kempf](https://github.com/Fauntleroy)
-
-## v0.5.2 / 2015-06-28
-
-* fixed; bug where Select shows the value instead of the label, thanks [Stephen Demjanenko](https://github.com/sdemjanenko)
-* added; 'is-selected' classname is added to the selected option, thanks [Alexey Volodkin](https://github.com/miraks)
-* fixed; async options are now loaded with the initial value, thanks [Pokai Chang](https://github.com/Neson)
-* fixed; `react-input-autosize` now correctly escapes ampersands (&), not actually a fix in react-select but worth noting here because it would have been causing a problem in `react-select` as well.
-
-## v0.5.1 / 2015-06-21
-
-* added; custom option and value rendering capability, thanks [Brian Reavis](https://github.com/brianreavis)
-* fixed; collapsing issue when single-select or empty multi-select fields are disabled
-* fixed; issue where an empty value would be left after clearing all values in a multi-select field
-
-## v0.5.0 / 2015-06-20
-
-* fixed; `esc` key incorrectly created empty options, thanks [rgrzelak](https://github.com/rgrzelak)
-* adeed; New feature to allow option creation ("tags mode"), enable with `allowCreate` prop, thanks [Florent Vilmart](https://github.com/flovilmart) and [Brian Reavis](https://github.com/brianreavis)
-* fixed; IE8 compatibility fallback for `addEventListener/removeEventListener`, which don't exist in IE8, thanks [Stefan Billiet](https://github.com/StefanBilliet)
-* fixed; Undefined values when using asyncOptions, thanks [bannaN](https://github.com/bannaN)
-* fixed; Prevent add the last focused value when the drop down menu is closed / Pushing enter without dropdown open adds a value, thanks [Giuseppe](https://github.com/giuse88)
-* fixed; Callback context is undefined, thanks [Giuseppe](https://github.com/giuse88)
-* fixed; Issue with event being swallowed on Enter `keydown`, thanks [Kevin Burke](https://github.com/kembuco)
-* added; Support for case-insensitive filtering when `matchPos="start"`, thanks [wesrage](https://github.com/wesrage)
-* added; Support for customizable background color, thanks [John Morales](https://github.com/JohnMorales)
-* fixed; Updated ESLint and cleared up warnings, thanks [Alexander Shemetovsky](https://github.com/AlexKVal)
-* fixed; Close dropdown when clicking on select, thanks [Nik Butenko](https://github.com/nkbt)
-* added; Tests, and mocha test framework, thanks [Craig Dallimore](https://github.com/craigdallimore)
-* fixed; You can now start the example server and watch for changes with `npm start`
-
-
-## v0.4.9 / 2015-05-11
-
-* fixed; focus was being grabbed by the select when `autoload` and `asyncOptions` were set
-* added; `focus` method on the component
-* added; support for disabled options, thanks [Pasha Palangpour](https://github.com/pashap)
-* improved; more closures, less binds, for better performance, thanks [Daniel Cousens](https://github.com/dcousens)
-
-## v0.4.8 / 2015-05-02
-
-* fixed; restored `dist/default.css`
-* fixed; standalone example works again
-* fixed; clarified dependency documentation and added dependencies for Bower
-* fixed; Scoping issues in `_bindCloseMenuIfClickedOutside`, thanks [bannaN](https://github.com/bannaN)
-* fixed; Doesnt try to set focus afterupdate if component is disabled, thanks [bannaN](https://github.com/bannaN)
-
-## v0.4.7 / 2015-04-21
-
-* improved; lodash is no longer a dependency, thanks [Daniel Lo Nigro](https://github.com/Daniel15)
-
-## v0.4.6 / 2015-04-06
-
-* updated; dependencies, build process and input-autosize component
-
-## v0.4.5 / 2015-03-28
-
-* fixed; issue with long options overlapping arrow and clear icons, thanks [Rohit Kalkur](https://github.com/rovolution)
-
-## v0.4.4 / 2015-03-26
-
-* fixed; error handling click events when the menu is closed, thanks [Ilya Petrov](https://github.com/muromec)
-* fixed; issue where options will not be filtered in certain conditions, thanks [G. Kay Lee](https://github.com/gsklee)
-
-## v0.4.3 / 2015-03-25
-
-* added tests and updated dependencies
-
-## v0.4.2 / 2015-03-23
-
-* added; ESLint and contributing guide
-* fixed; incorrect `classnames` variable assignment in window scope
-* fixed; all ESLint errors and warnings (except invalid JSX undefined/unused vars due to ESLint bug)
-* fixed; first option is now focused correctly, thanks [Eivind Siqveland Larsen](https://github.com/esiqveland)
-
-## v0.4.1 / 2015-03-20
-
-* fixed; IE11 issue: clicking on scrollbar within menu no longer closes menu, thanks [Rohit Kalkur](https://github.com/rovolution)
-
-## v0.4.0 / 2015-03-12
-
-* updated; compatible with React 0.13
-
-## v0.3.5 / 2015-03-09
-
-* improved; less/no repaint on scroll for performance wins, thanks [jsmunich](https://github.com/jsmunich)
-* added; `onBlur` and `onFocus` event handlers, thanks [Jonas Budelmann](https://github.com/cloudkite)
-* added; support for `inputProps` prop, passed to the `
` component, thanks [Yann Plantevin](https://github.com/YannPl)
-* changed; now using [react-component-gulp-tasks](https://github.com/JedWatson/react-component-gulp-tasks) for build
-* fixed; issue w/ remote callbacks overriding cached options, thanks [Corey McMahon](https://github.com/coreymcmahon)
-* fixed; if not `this.props.multi`, menu doesn't need handleMouseDown, thanks [wenbing](https://github.com/wenbing)
-
-## v0.3.4 / 2015-02-23
-
-* fixed; issues with the underscore/lodash dependency change, thanks [Aaron Powell](https://github.com/aaronpowell)
-
-## v0.3.3 / 2015-02-22
-
-* added; `disabled` prop, thanks [Danny Shaw](https://github.com/dannyshaw)
-* added; `searchable` prop - set to `false` to disable the search box, thanks [Julen Ruiz Aizpuru](https://github.com/julen)
-* added; `onOptionLabelClick` prop - see [#66](https://github.com/JedWatson/react-select/pull/66) for docs, thanks [Dmitry Smirnov](https://github.com/dmitry-smirnov)
-* fixed; `text-overflow: ellipsis;` typo, thanks [Andru Vallance](https://github.com/andru)
-
-## v0.3.2 / 2015-01-30
-
-* fixed; issue adding undefined values to multiselect, thanks [Tejas Dinkar](https://github.com/gja)
-
-## v0.3.1 / 2015-01-20
-
-* fixed; missing `var` statement
-
-## v0.3.0 / 2015-01-20
-
-* added; node compatible build now available in `/lib`
-
-## v0.2.14 / 2015-01-07
-
-* added; `searchPromptText` property that is displayed when `asyncOptions` is set and there are (a) no options loaded, and (b) no input entered to search on, thanks [Anton Fedchenko](https://github.com/kompot)
-* added; `clearable` property (defaults to `true`) to control whether the "clear" control is available, thanks [Anton Fedchenko](https://github.com/kompot)
-
-## v0.2.13 / 2015-01-05
-
-* fixed; height issues in Safari, thanks [Joss Mackison](https://github.com/jossmac)
-* added; Option to specify "Clear value" label as prop for i18n
-
-## v0.2.12 / 2015-01-04
-
-* fixed; UI now responds to touch events, and works on mobile devices! thanks [Fraser Xu](https://github.com/fraserxu)
-
-## v0.2.11 / 2015-01-04
-
-* fixed; Options in the dropdown now scroll into view when they are focused, thanks [Adam](https://github.com/fmovlex)
-* improved; Example dist is now excluded from the npm package
-
-## v0.2.10 / 2015-01-01
-
-* fixed; More specific mixin name to avoid conflicts (css)
-* fixed; Example CSS now correctly rebuilds on changes in development
-* fixed; Values are now expanded correctly when options change (see #28)
-* added; Option to specify "No results found" label as prop for i18n, thanks [Julen Ruiz Aizpuru](https://github.com/julen)
-
-## v0.2.9 / 2014-12-09
-
-* added; `filterOption` and `filterOptions` props for more control over filtering
-
-## v0.2.8 / 2014-12-08
-
-* added; `matchPos` option to control whether to match the `start` or `any` position in the string when filtering options (default: `any`)
-* added; `matchProp` option to control whether to match the `value`, `label` or `any` property of each option when filtering (default: `any`)
-
-## v0.2.7 / 2014-12-01
-
-* fixed; screen-readers will now read "clear value" instead of "times" for the clear button
-* fixed; non-left-click mousedown events aren't blocked by the control
-
-
-## v0.2.6 / 2014-11-30
-
-* improved; better comparison of changes to [options] in `willReceiveProps`
-* fixed; now focuses the first option correctly when in multiselect mode
-* fixed; fixed focused option behaviour on value change
-* fixed; when filtering, there is always a focused option (#19)
-* changed; using ^ in package.json to compare dependencies
-
-## v0.2.5 / 2014-11-20
-
-* fixed; compatibility with case-sensitive file systems
-
-## v0.2.4 / 2014-11-20
-
-* fixed; package.json pointed at the right file
-
-## v0.2.3 / 2014-11-17
-
-* fixed; Updating state correctly when props change
-* improved; Build tasks and docs
-* added; Working standalone build
-* added; Minified dist version
-* added; Publised to Bower
-
-## v0.2.2 / 2014-11-15
-
-* fixed; backspace event being incorrectly cancelled
-
-## v0.2.1 / 2014-11-15
-
-* fixed; issue where backspace incorrectly clears the value (#14)
-
-## v0.2.0 / 2014-11-15
-
-* changed; Major rewrite to improve focus handling and internal state management
-* added; Support for `multi` prop, enable multiselect mode
-
-## v0.1.1 / 2014-11-03
-
-* added; Support for `onChange` event
-* added; `propTypes` are defined by the `Select` component now
-* added; `className` property, sets the `className` on the outer `div` element
-* fixed; Removed deprecated `React.DOM.x` calls
-
-## v0.1.0 / 2014-11-01
-
-* updated; React to 0.12.0
-
-## v0.0.6 / 2014-10-14
-
-* fixed; Error keeping value when using Async Options
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
deleted file mode 100644
index b7451a6bd3..0000000000
--- a/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,9 +0,0 @@
-### Thanks for using react-select!
-
-If you are reporting an error please include a test case that demonstrates the issue you're reporting!
-This is very helpful to maintainers in order to help us see the issue you're seeing.
-
-Here is a Plunker you can fork that has react-select loaded and supports JSX syntax:
-https://plnkr.co/edit/HTmtER9AMNcPoWhXV707?p=preview
-
-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.
diff --git a/LICENSE b/LICENSE
index e6620b5895..841ac571fa 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016 Jed Watson
+Copyright (c) 2022 Jed Watson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 5a0202284b..99367b05d5 100644
--- a/README.md
+++ b/README.md
@@ -1,424 +1,134 @@
[](https://www.npmjs.com/package/react-select)
-[](https://travis-ci.org/JedWatson/react-select)
+[](https://circleci.com/gh/JedWatson/react-select/tree/master)
[](https://coveralls.io/github/JedWatson/react-select?branch=master)
[](http://thinkmill.com.au/?utm_source=github&utm_medium=badge&utm_campaign=react-select)
-[](https://cdnjs.com/libraries/react-select)
-React-Select
-============
+# React-Select
-A Select control built with and for [React](http://facebook.github.io/react/index.html). Initially built for use in [KeystoneJS](http://www.keystonejs.com).
+The Select control for [React](https://reactjs.org). Initially built for use in [KeystoneJS](https://www.keystonejs.com).
+See [react-select.com](https://www.react-select.com) for live demos and comprehensive docs.
-## New version 1.0.0-rc
+`react-select` is funded by [Thinkmill](https://www.thinkmill.com.au) and [Atlassian](https://atlaskit.atlassian.com).
+We are an open source project that is continuously supported by the community.
-I've nearly completed a major rewrite of this component (see issue [#568](https://github.com/JedWatson/react-select/issues/568) for details and progress). The new code has been merged into `master`, and `react-select@1.0.0-rc` has been published to npm and bower.
+React Select helps you develop powerful select components that _just work_ out of the box, without stopping you from customising the parts that are important to you.
-1.0.0 has some breaking changes. The documentation is still being updated for the new API; notes on the changes can be found in [CHANGES.md](https://github.com/JedWatson/react-select/blob/master/CHANGES.md) and will be finalised into [HISTORY.md](https://github.com/JedWatson/react-select/blob/master/HISTORY.md) soon.
+For the story behind this component, watch Jed's talk at React Conf 2019 - [building React Select](https://youtu.be/yS0jUnmBujE)
-Testing, feedback and PRs for the new version are appreciated.
+Features include:
+- Flexible approach to data, with customisable functions
+- Extensible styling API with [emotion](https://emotion.sh)
+- Component Injection API for complete control over the UI behaviour
+- Controllable state props and modular architecture
+- Long-requested features like option groups, portal support, animation, and more
-## Demo & Examples
+## Using an older version?
-Live demo: [jedwatson.github.io/react-select](http://jedwatson.github.io/react-select/)
+- [v3, v4, and v5 upgrade guide](https://react-select.com/upgrade)
+- [v2 upgrade guide](https://react-select.com/upgrade-to-v2)
+- React Select v1 documentation and examples are available at [v1.react-select.com](https://v1.react-select.com)
-The live demo is still running `v0.9.1`.
+# Installation and usage
-To build the **new 1.0.0** examples locally, clone this repo then run:
+The easiest way to use react-select is to install it from npm and build it into your app with Webpack.
-```javascript
-npm install
-npm start
```
-
-Then open [`localhost:8000`](http://localhost:8000) in a browser.
-
-
-## Installation
-
-The easiest way to use React-Select is to install it from NPM and include it in your own React build process (using [Browserify](http://browserify.org), etc).
-
-```javascript
-npm install react-select --save
+yarn add react-select
```
-At this point you can import react-select and its styles in your application as follows:
+Then use it in your app:
```js
+import React, { useState } from 'react';
import Select from 'react-select';
-// Be sure to include styles at some point, probably during your bootstrapping
-import 'react-select/dist/react-select.css';
-```
-
-You can also use the standalone build by including `react-select.js` and `react-select.css` in your page. (If you do this though you'll also need to include the dependencies.) For example:
-```html
-
-
-
-
-
-
-
-```
-
-
-## Usage
-
-React-Select generates a hidden text field containing the selected value, so you can submit it as part of a standard form. You can also listen for changes with the `onChange` event property.
-
-Options should be provided as an `Array` of `Object`s, each with a `value` and `label` property for rendering and searching. You can use a `disabled` property to indicate whether the option is disabled or not.
-
-The `value` property of each option should be set to either a string or a number.
-
-When the value is changed, `onChange(selectedValueOrValues)` will fire.
-
-```javascript
-var Select = require('react-select');
-
-var options = [
- { value: 'one', label: 'One' },
- { value: 'two', label: 'Two' }
-];
-
-function logChange(val) {
- console.log("Selected: " + val);
-}
-
-
-```
-
-### Custom classNames
-
-You can provide a custom `className` prop to the `
` component, which will be added to the base `.Select` className for the outer container.
-
-The built-in Options renderer also support custom classNames, just add a `className` property to objects in the `options` array.
-
-### Multiselect options
-
-You can enable multi-value selection by setting `multi={true}`. In this mode:
-
-* Selected options will be removed from the dropdown menu
-* The selected values are submitted in multiple ` ` fields, use `joinValues` to submit joined values in a single field instead
-* The values of the selected items are joined using the `delimiter` prop to create the input value when `joinValues` is true
-* A simple value, if provided, will be split using the `delimiter` prop
-* The `onChange` event provides an array of selected options _or_ a comma-separated string of values (eg `"1,2,3"`) if `simpleValue` is true
-* By default, only options in the `options` array can be selected. Use the `Creatable` Component (which wraps `Select`) to allow new options to be created if they do not already exist. Hitting comma (','), ENTER or TAB will add a new option. Versions `0.9.x` and below provided a boolean attribute on the `Select` Component (`allowCreate`) to achieve the same functionality. It is no longer available starting with version `1.0.0`.
-* By default, selected options can be cleared. To disable the possibility of clearing a particular option, add `clearableValue: false` to that option:
-```javascript
-var options = [
- { value: 'one', label: 'One' },
- { value: 'two', label: 'Two', clearableValue: false }
+const options = [
+ { value: 'chocolate', label: 'Chocolate' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'vanilla', label: 'Vanilla' },
];
-```
-Note: the `clearable` prop of the Select component should also be set to `false` to prevent allowing clearing all fields at once
-
-### Async options
-
-If you want to load options asynchronously, instead of providing an `options` Array, provide a `loadOptions` Function.
-
-The function takes two arguments `String input, Function callback`and will be called when the input text is changed.
-
-When your async process finishes getting the options, pass them to `callback(err, data)` in a Object `{ options: [] }`.
-
-The select control will intelligently cache options for input strings that have already been fetched. The cached result set will be filtered as more specific searches are input, so if your async process would only return a smaller set of results for a more specific query, also pass `complete: true` in the callback object. Caching can be disabled by setting `cache` to `false` (Note that `complete: true` will then have no effect).
-
-Unless you specify the property `autoload={false}` the control will automatically load the default set of options (i.e. for `input: ''`) when it is mounted.
-
-```javascript
-var Select = require('react-select');
-
-var getOptions = function(input, callback) {
- setTimeout(function() {
- callback(null, {
- options: [
- { value: 'one', label: 'One' },
- { value: 'two', label: 'Two' }
- ],
- // CAREFUL! Only set this to true when there are no more options,
- // or more specific queries will not be sent to the server.
- complete: true
- });
- }, 500);
-};
-
-
-```
-
-### Async options with Promises
-
-`loadOptions` supports Promises, which can be used in very much the same way as callbacks.
-
-Everything that applies to `loadOptions` with callbacks still applies to the Promises approach (e.g. caching, autoload, ...)
-
-An example using the `fetch` API and ES6 syntax, with an API that returns an object like:
-
-```javascript
-import Select from 'react-select';
-
-/*
- * assuming the API returns something like this:
- * const json = [
- * { value: 'one', label: 'One' },
- * { value: 'two', label: 'Two' }
- * ]
- */
-
-const getOptions = (input) => {
- return fetch(`/users/${input}.json`)
- .then((response) => {
- return response.json();
- }).then((json) => {
- return { options: json };
- });
-}
-
-
-```
-
-### Async options loaded externally
-
-If you want to load options asynchronously externally from the `Select` component, you can have the `Select` component show a loading spinner by passing in the `isLoading` prop set to `true`.
-
-```javascript
-var Select = require('react-select');
-
-var isLoadingExternally = true;
-
-
-```
-
-### User-created tags
-
-The `Creatable` component enables users to create new tags within react-select.
-It decorates a `Select` and so it supports all of the default properties (eg single/multi mode, filtering, etc) in addition to a couple of custom ones (shown below).
-The easiest way to use it is like so:
-```js
-import { Creatable } from 'react-select';
-
-function render (selectProps) {
- return ;
-};
-```
-
-##### Creatable properties
-
-Property | Type | Description
-:---|:---|:---
-`children` | function | Child function responsible for creating the inner Select component. This component can be used to compose HOCs (eg Creatable and Async). Expected signature: `(props: Object): PropTypes.element` |
-`isOptionUnique` | function | Searches for any matching option within the set of options. This function prevents duplicate options from being created. By default this is a basic, case-sensitive comparison of label and value. Expected signature: `({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean` |
-`isValidNewOption` | function | Determines if the current input text represents a valid option. By default any non-empty string will be considered valid. Expected signature: `({ label: string }): boolean` |
-`newOptionCreator` | function | Factory to create new option. Expected signature: `({ label: string, labelKey: string, valueKey: string }): Object` |
-`onNewOptionClick` | function | new option click handler, it calls when new option has been selected. `function(option) {}` |
-`shouldKeyDownEventCreateNewOption` | function | Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. ENTER, TAB and comma keys create new options by default. Expected signature: `({ keyCode: number }): boolean` |
-`promptTextCreator` | function | Factory for overriding default option creator prompt label. By default it will read 'Create option "{label}"'. Expected signature: `(label: String): String` |
+export default function App() {
+ const [selectedOption, setSelectedOption] = useState(null);
-### Combining Async and Creatable
-
-Use the `AsyncCreatable` HOC if you want both _async_ and _creatable_ functionality.
-It ties `Async` and `Creatable` components together and supports a union of their properties (listed above).
-Use it as follows:
-
-```jsx
-import React from 'react';
-import { AsyncCreatable } from 'react-select';
-
-function render (props) {
- // props can be a mix of Async, Creatable, and Select properties
return (
-
+
+
+
);
}
```
-### Filtering options
+## Props
-You can control how options are filtered with the following properties:
+Common props you may want to specify include:
-* `matchPos`: `"start"` or `"any"`: whether to match the text entered at the start or any position in the option value
-* `matchProp`: `"label"`, `"value"` or `"any"`: whether to match the value, label or both values of each option when filtering
-* `ignoreCase`: `Boolean`: whether to ignore case or match the text exactly when filtering
-* `ignoreAccents`: `Boolean`: whether to ignore accents on characters like ø or å
+- `autoFocus` - focus the control when it mounts
+- `className` - apply a className to the control
+- `classNamePrefix` - apply classNames to inner elements with the given prefix
+- `isDisabled` - disable the control
+- `isMulti` - allow the user to select multiple values
+- `isSearchable` - allow the user to search for matching options
+- `name` - generate an HTML input with this name, containing the current value
+- `onChange` - subscribe to change events
+- `options` - specify the options the user can select from
+- `placeholder` - change the text displayed when no option is selected
+- `noOptionsMessage` - ({ inputValue: string }) => string | null - Text to display when there are no options
+- `value` - control the current value
-`matchProp` and `matchPos` both default to `"any"`.
-`ignoreCase` defaults to `true`.
-`ignoreAccents` defaults to `true`.
+See the [props documentation](https://www.react-select.com/props) for complete documentation on the props react-select supports.
-#### Advanced filters
+## Controllable Props
-You can also completely replace the method used to filter either a single option, or the entire options array (allowing custom sort mechanisms, etc.)
+You can control the following props by providing values for them. If you don't, react-select will manage them for you.
-* `filterOption`: `function(Object option, String filter)` returns `Boolean`. Will override `matchPos`, `matchProp`, `ignoreCase` and `ignoreAccents` options.
-* `filterOptions`: `function(Array options, String filter, Array currentValues)` returns `Array filteredOptions`. Will override `filterOption`, `matchPos`, `matchProp`, `ignoreCase` and `ignoreAccents` options.
+- `value` / `onChange` - specify the current value of the control
+- `menuIsOpen` / `onMenuOpen` / `onMenuClose` - control whether the menu is open
+- `inputValue` / `onInputChange` - control the value of the search input (changing this will update the available options)
-For multi-select inputs, when providing a custom `filterOptions` method, remember to exclude current values from the returned array of options.
+If you don't provide these props, you can set the initial value of the state they control:
-#### Filtering large lists
+- `defaultValue` - set the initial value of the control
+- `defaultMenuIsOpen` - set the initial open value of the menu
+- `defaultInputValue` - set the initial value of the search input
-The default `filterOptions` method scans the options array for matches each time the filter text changes.
-This works well but can get slow as the options array grows to several hundred objects.
-For larger options lists a custom filter function like [`react-select-fast-filter-options`](https://github.com/bvaughn/react-select-fast-filter-options) will produce better results.
+## Methods
-### Effeciently rendering large lists with windowing
+React-select exposes two public methods:
-The `menuRenderer` property can be used to override the default drop-down list of options.
-This should be done when the list is large (hundreds or thousands of items) for faster rendering.
-Windowing libraries like [`react-virtualized`](https://github.com/bvaughn/react-virtualized) can then be used to more efficiently render the drop-down menu like so.
-The easiest way to do this is with the [`react-virtualized-select`](https://github.com/bvaughn/react-virtualized-select/) HOC.
-This component decorates a `Select` and uses the react-virtualized `VirtualScroll` component to render options.
-Demo and documentation for this component are available [here](https://bvaughn.github.io/react-virtualized-select/).
+- `focus()` - focus the control programmatically
+- `blur()` - blur the control programmatically
-You can also specify your own custom renderer.
-The custom `menuRenderer` property accepts the following named parameters:
+## Customisation
-| Parameter | Type | Description |
-|:---|:---|:---|
-| focusedOption | `Object` | The currently focused option; should be visible in the menu by default. |
-| focusOption | `Function` | Callback to focus a new option; receives the option as a parameter. |
-| labelKey | `String` | Option labels are accessible with this string key. |
-| optionClassName | `String` | The className that gets used for options |
-| optionComponent | `ReactClass` | The react component that gets used for rendering an option |
-| optionRenderer | `Function` | The function that gets used to render the content of an option |
-| options | `Array` | Ordered array of options to render. |
-| selectValue | `Function` | Callback to select a new option; receives the option as a parameter. |
-| valueArray | `Array` | Array of currently selected options. |
+Check the docs for more information on:
-### Updating input values with onInputChange
+- [Customising the styles](https://www.react-select.com/styles)
+- [Using custom components](https://www.react-select.com/components)
+- [Using the built-in animated components](https://www.react-select.com/home#animated-components)
+- [Creating an async select](https://www.react-select.com/async)
+- [Allowing users to create new options](https://www.react-select.com/creatable)
+- [Advanced use-cases](https://www.react-select.com/advanced)
+- [TypeScript guide](https://www.react-select.com/typescript)
-You can manipulate the input using the onInputChange and returning a new value.
+## TypeScript
-```js
-function cleanInput(inputValue) {
- // Strip all non-number characters from the input
- return inputValue.replace(/[^0-9]/g, "");
-}
-
-
-```
-
-### Overriding default key-down behavior with onInputKeyDown
-
-`Select` listens to `keyDown` events to select items, navigate drop-down list via arrow keys, etc.
-You can extend or override this behavior by providing a `onInputKeyDown` callback.
-
-```js
-function onInputKeyDown(event) {
- switch (event.keyCode) {
- case 9: // TAB
- // Extend default TAB behavior by doing something here
- break;
- case 13: // ENTER
- // Override default ENTER behavior by doing stuff here and then preventing default
- event.preventDefault();
- break;
- }
-}
-
-
-```
-
-### Further options
-
-
- Property | Type | Default | Description
-:-----------------------|:--------------|:--------------|:--------------------------------
- addLabelText | string | 'Add "{label}"?' | text to display when `allowCreate` is true
- arrowRenderer | func | undefined | Renders a custom drop-down arrow to be shown in the right-hand side of the select: `arrowRenderer({ onMouseDown, isOpen })`
- autoBlur | bool | false | Blurs the input element after a selection has been made. Handy for lowering the keyboard on mobile devices
- autofocus | bool | undefined | autofocus the component on mount
- autoload | bool | true | whether to auto-load the default async options set
- autosize | bool | true | If enabled, the input will expand as the length of its value increases
- backspaceRemoves | bool | true | whether pressing backspace removes the last item when there is no input value
- backspaceToRemoveMessage | string | 'Press backspace to remove {last label}' | prompt shown in input when at least one option in a multiselect is shown, set to '' to clear
- cache | bool | true | enables the options cache for `asyncOptions` (default: `true`)
- className | string | undefined | className for the outer element
- clearable | bool | true | should it be possible to reset value
- clearAllText | string | 'Clear all' | title for the "clear" control when `multi` is true
- clearRenderer | func | undefined | Renders a custom clear to be shown in the right-hand side of the select when clearable true: `clearRenderer()`
- clearValueText | string | 'Clear value' | title for the "clear" control
- resetValue | any | null | value to use when you clear the control
- deleteRemoves | bool | true | whether pressing delete key removes the last item when there is no input value
- delimiter | string | ',' | delimiter to use to join multiple values
- disabled | bool | false | whether the Select is disabled or not
- filterOption | func | undefined | method to filter a single option: `function(option, filterString)`
- filterOptions | func | undefined | method to filter the options array: `function([options], filterString, [values])`
- ignoreAccents | bool | true | whether to strip accents when filtering
- ignoreCase | bool | true | whether to perform case-insensitive filtering
- inputProps | object | {} | custom attributes for the Input (in the Select-control) e.g: `{'data-foo': 'bar'}`
- isLoading | bool | false | whether the Select is loading externally or not (such as options being loaded)
- joinValues | bool | false | join multiple values into a single hidden input using the `delimiter`
- labelKey | string | 'label' | the option property to use for the label
- loadOptions | func | undefined | function that returns a promise or calls a callback with the options: `function(input, [callback])`
- matchPos | string | 'any' | (any, start) match the start or entire string when filtering
- matchProp | string | 'any' | (any, label, value) which option property to filter on
- menuBuffer | number | 0 | buffer of px between the base of the dropdown and the viewport to shift if menu doesnt fit in viewport
- menuRenderer | func | undefined | Renders a custom menu with options; accepts the following named parameters: `menuRenderer({ focusedOption, focusOption, options, selectValue, valueArray })`
- multi | bool | undefined | multi-value input
- name | string | undefined | field name, for hidden ` ` tag
- noResultsText | string | 'No results found' | placeholder displayed when there are no matching search results or a falsy value to hide it (can also be a react component)
- onBlur | func | undefined | onBlur handler: `function(event) {}`
- onBlurResetsInput | bool | true | whether to clear input on blur or not
- onChange | func | undefined | onChange handler: `function(newValue) {}`
- onClose | func | undefined | handler for when the menu closes: `function () {}`
- onCloseResetsInput | bool | true | whether to clear input when closing the menu through the arrow
- onFocus | func | undefined | onFocus handler: `function(event) {}`
- onInputChange | func | undefined | onInputChange handler: `function(inputValue) {}`
- onInputKeyDown | func | undefined | input keyDown handler; call `event.preventDefault()` to override default `Select` behavior: `function(event) {}`
- onOpen | func | undefined | handler for when the menu opens: `function () {}`
- onValueClick | func | undefined | onClick handler for value labels: `function (value, event) {}`
- openOnFocus | bool | false | open the options menu when the input gets focus (requires searchable = true)
- optionRenderer | func | undefined | function which returns a custom way to render the options in the menu
- options | array | undefined | array of options
- placeholder | string\|node | 'Select ...' | field placeholder, displayed when there's no value
- scrollMenuIntoView | bool | true | whether the viewport will shift to display the entire menu when engaged
- searchable | bool | true | whether to enable searching feature or not
- searchPromptText | string\|node | 'Type to search' | label to prompt for search input
- loadingPlaceholder | string\|node | 'Loading...' | label to prompt for loading search result
- tabSelectsValue | bool | true | whether to select the currently focused value when the `[tab]` key is pressed
- value | any | undefined | initial field value
- valueKey | string | 'value' | the option property to use for the value
- valueRenderer | func | undefined | function which returns a custom way to render the value selected `function (option) {}`
-
-### Methods
-
-Right now there's simply a `focus()` method that gives the control focus. All other methods on `` elements should be considered private and prone to change.
-
-```javascript
-// focuses the input element
-.focus();
-```
+The v5 release represents a rewrite from JavaScript to TypeScript. The types for v4 and earlier releases are available at [@types](https://www.npmjs.com/package/@types/react-select). See the [TypeScript guide](https://www.react-select.com/typescript) for how to use the types starting with v5.
-# Contributing
+# Thanks
-See our [CONTRIBUTING.md](https://github.com/JedWatson/react-select/blob/master/CONTRIBUTING.md) for information on how to contribute.
+Thank you to everyone who has contributed to this project. It's been a wild ride.
-Thanks to the projects this was inspired by: [Selectize](http://brianreavis.github.io/selectize.js/) (in terms of behaviour and user experience), [React-Autocomplete](https://github.com/rackt/react-autocomplete) (as a quality React Combobox implementation), as well as other select controls including [Chosen](http://harvesthq.github.io/chosen/) and [Select2](http://ivaynberg.github.io/select2/).
+If you like React Select, you should [follow me on Twitter](https://twitter.com/jedwatson)!
+Shout out to [Joss Mackison](https://github.com/jossmac), [Charles Lee](https://github.com/gwyneplaine), [Ben Conolly](https://github.com/Noviny), [Tom Walker](https://github.com/bladey), [Nathan Bierema](https://github.com/Methuselah96), [Eric Bonow](https://github.com/ebonow), [Emma Hamilton](https://github.com/emmatown), [Dave Brotherstone](https://github.com/bruderstein), [Brian Vaughn](https://github.com/bvaughn), and the [Atlassian Design System](https://atlassian.design) team who along with many other contributors have made this possible ❤️
-# License
+## License
-MIT Licensed. Copyright (c) Jed Watson 2016.
+MIT Licensed. Copyright (c) Jed Watson 2022.
diff --git a/TODO.md b/TODO.md
deleted file mode 100644
index ac57413dce..0000000000
--- a/TODO.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# TODO
-
-* options creation (was part of buildMenu and selectFocusedOption)
-* handle comma keypress for tags mode (handleKeyDown keyCode 188)
-* use componentDidUpdate for binding the closeMenuIfClicked... handlers (are these still needed?)
-* the behaviour of searchable=false isn't very good yet, needs docus handling & close on body click
-* pagination support in Async component
-
-## Component Methods
-
-* handle _ closeMenuIfClickedOutside
-* handle _ bindCloseMenuIfClickedOutside
-* handle _ unbindCloseMenuIfClickedOutside
-
-* componentWillUnmount
-* clickedOutsideElement
-* handleMouseDownOnMenu
-
-## Performance concerns
-
-* checking the focused option after every render
-* filtering the options on every render
-
-## Questions
-
-* Why is the reference check in filterOptions for excluded values not matching options?
-
-## Later
-
-* asyncDelay - wait x ms before calling getOptions in Async
-
-## Notes
-
-* You need to provide complex values when using Select.Async or values may not be found in the result set. isLoading can be used to indicate that values are being loaded asynchronously while the component is initialised.
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000000..1a658f42d8
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,13 @@
+module.exports = {
+ plugins: [
+ '@emotion/babel-plugin',
+ ['@babel/plugin-proposal-class-properties', { loose: true }],
+ ['@babel/plugin-proposal-private-methods', { loose: true }],
+ '@babel/plugin-transform-runtime',
+ ],
+ presets: [
+ '@babel/preset-env',
+ '@babel/preset-react',
+ '@babel/preset-typescript',
+ ],
+};
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 19cc369235..0000000000
--- a/bower.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "react-select",
- "main": [
- "dist/react-select.min.js",
- "dist/react-select.min.css"
- ],
- "version": "1.0.0-beta14",
- "homepage": "https://github.com/JedWatson/react-select",
- "authors": [
- "Jed Watson"
- ],
- "description": "A Select control built with and for ReactJS",
- "moduleType": [
- "amd",
- "globals",
- "node"
- ],
- "dependencies": {
- "classnames": "^2.2.0",
- "react-input-autosize": "^1.1.0"
- },
- "keywords": [
- "react",
- "react-component",
- "select",
- "multiselect",
- "combobox",
- "input",
- "form",
- "ui"
- ],
- "license": "MIT",
- "ignore": [
- ".editorconfig",
- ".gitignore",
- "package.json",
- "src",
- "node_modules",
- "example",
- "test"
- ]
-}
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 0000000000..db4974eedf
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1,4 @@
+{
+ "baseUrl": "http://localhost:8000/cypress-tests",
+ "video": false
+}
diff --git a/cypress/fixtures/selectors.json b/cypress/fixtures/selectors.json
new file mode 100644
index 0000000000..da975f7e1c
--- /dev/null
+++ b/cypress/fixtures/selectors.json
@@ -0,0 +1,28 @@
+{
+ "singleBasic": "#cypress-single",
+ "singleBasicSelect": "#basic-select-single",
+ "singleClearable": "#cypress-single-clearable",
+ "singleClearableSelect": "#clearable-select-single",
+ "singleGroupedSelect": "#grouped-options-single",
+ "checkboxDisable": ".disable-checkbox",
+ "checkboxEscapeClearsValue": ".escape-clears-value-checkbox",
+ "groupHeading": ".react-select__group-heading",
+ "indicatorClear": ".react-select__clear-indicator",
+ "indicatorDropdown": ".react-select__dropdown-indicator",
+ "menu": ".react-select__menu",
+ "control": ".react-select__control",
+ "menuOption": ".react-select__option",
+ "noOptionsValue": ".react-select__menu-notice--no-options",
+ "placeholder": ".react-select__placeholder",
+ "singleValue": ".react-select__single-value",
+ "menuSingle": "#basic-select-single .react-select__menu",
+ "singleSelectSingleInput": "#react-select-basic-select-single-input",
+ "toggleMenuSingle": "#basic-select-single .react-select__dropdown-indicator",
+ "firstMultiValueRemove": "#multi-select .react-select__multi-value__remove:first",
+ "menuMulti": "#multi-select .react-select__menu",
+ "multiSelectDefaultValues": "#multi-select .react-select__multi-value",
+ "multiSelectInput": "#react-select-multi-select-input",
+ "placeHolderMulti": "#multi-select .react-select__placeholder",
+ "toggleMenuMulti": "#multi-select .react-select__dropdown-indicator",
+ "focusedOption": ".react-select__option--is-focused"
+}
diff --git a/cypress/integration/multi-select.spec.ts b/cypress/integration/multi-select.spec.ts
new file mode 100644
index 0000000000..eab428c3ce
--- /dev/null
+++ b/cypress/integration/multi-select.spec.ts
@@ -0,0 +1,87 @@
+import selector from '../fixtures/selectors.json';
+import cypressJson from '../../cypress.json';
+
+const setup = [
+ { width: 1440, height: 900, viewport: 'macbook-15', device: 'Laptop' },
+ { width: 375, height: 667, viewport: 'iphone-6', device: 'Mobile' },
+ { width: 768, height: 1024, viewport: 'ipad-2', device: 'Tablet' },
+];
+
+describe('Multi Select', () => {
+ before(() => {
+ cy.visit(cypressJson.baseUrl);
+ cy.title().should('equal', 'React-Select');
+ cy.get('h1').should('contain', 'Test Page for Cypress');
+ });
+ beforeEach(() => {
+ cy.reload();
+ });
+
+ for (let config of setup) {
+ const { viewport } = config;
+ it(`Should display several default values that can be removed in view: ${viewport}`, () => {
+ cy.get(selector.multiSelectDefaultValues).then(function ($defaultValue) {
+ expect($defaultValue).to.have.length(2);
+ expect($defaultValue.eq(0)).to.contain('Purple');
+ expect($defaultValue.eq(1)).to.contain('Red');
+ });
+
+ cy.get(selector.firstMultiValueRemove)
+ .click()
+ .get(selector.multiSelectDefaultValues)
+ .then(function ($defaultValue) {
+ expect($defaultValue).to.have.length(1);
+ expect($defaultValue.eq(0)).to.contain('Red');
+ })
+ .get(selector.menuMulti)
+ .should('not.be.visible');
+ });
+
+ it(`Should be able to remove values on keyboard actions in view: ${viewport}`, () => {
+ cy.get(selector.multiSelectInput)
+ .click()
+ .type('{backspace}', { force: true })
+ .get(selector.multiSelectDefaultValues)
+ .then(function ($defaultValue) {
+ expect($defaultValue).to.have.length(1);
+ expect($defaultValue.eq(0)).to.contain('Purple');
+ })
+ .get(selector.multiSelectInput)
+ .type('{backspace}', { force: true })
+ .get(selector.placeHolderMulti)
+ .should('contain', 'Select...');
+ });
+
+ it(`Should select different options using - click and enter in view: ${viewport}`, () => {
+ cy.get(selector.menuMulti)
+ .should('not.exist')
+ .get(selector.toggleMenuMulti)
+ .click()
+ .get(selector.menuMulti)
+ .should('exist')
+ .get(selector.menuMulti)
+ .should('be.visible')
+ .get(selector.menuOption)
+ .contains('Orange')
+ .click()
+ .get(selector.toggleMenuMulti)
+ .click()
+ .get(selector.menuOption)
+ .contains('Yellow')
+ .click()
+ .get(selector.multiSelectInput)
+ .click({ force: true })
+ .type('Slate', { force: true })
+ .type('{enter}', { force: true })
+ .get(selector.multiSelectDefaultValues)
+ .then(function ($defaultValue) {
+ expect($defaultValue).to.have.length(5);
+ expect($defaultValue.eq(0)).to.contain('Purple');
+ expect($defaultValue.eq(1)).to.contain('Red');
+ expect($defaultValue.eq(2)).to.contain('Orange');
+ expect($defaultValue.eq(3)).to.contain('Yellow');
+ expect($defaultValue.eq(4)).to.contain('Slate');
+ });
+ });
+ }
+});
diff --git a/cypress/integration/single-select.spec.ts b/cypress/integration/single-select.spec.ts
new file mode 100644
index 0000000000..2e7effeca5
--- /dev/null
+++ b/cypress/integration/single-select.spec.ts
@@ -0,0 +1,308 @@
+import selector from '../fixtures/selectors.json';
+import cypressJson from '../../cypress.json';
+
+const setup = [
+ {
+ width: 1440,
+ height: 900,
+ viewport: 'macbook-15' as const,
+ device: 'Laptop',
+ },
+ { width: 375, height: 667, viewport: 'iphone-6' as const, device: 'Mobile' },
+ { width: 768, height: 1024, viewport: 'ipad-2' as const, device: 'Tablet' },
+];
+
+describe('Single Select', () => {
+ before(() => {
+ cy.visit(cypressJson.baseUrl);
+ cy.title().should('equal', 'React-Select');
+ cy.get('h1').should('contain', 'Test Page for Cypress');
+ });
+
+ for (let config of setup) {
+ const { viewport } = config;
+
+ context(`Basic in view: ${viewport}`, () => {
+ before(() => {
+ cy.viewport(viewport);
+ });
+
+ beforeEach(() => {
+ cy.reload();
+ });
+
+ // TODO:
+ // This test seems to fail when cypress tab is focused.
+ // Also, manual testing does not confirm the desired behavior.
+ it.skip(`Should not display the options menu when touched and dragged in view: ${viewport}`, () => {
+ cy.get(selector.toggleMenuSingle)
+ .click()
+ .click()
+ .get(selector.menuSingle)
+ .should('not.be.visible')
+ // to be sure it says focus and the menu is closed
+ .get(selector.singleSelectSingleInput)
+ .trigger('mousedown')
+ .get(selector.menuSingle)
+ .should('not.be.visible');
+ });
+ it(`Should display a default value in view: ${viewport}`, () => {
+ cy.get(selector.singleBasicSelect)
+ .find(selector.singleValue)
+ .should('contain', 'Ocean');
+ });
+
+ it(`Should expand the menu when expand icon is clicked in view: ${viewport}`, () => {
+ cy
+ // Menu is not yet open
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('not.exist')
+ // A dropdown icon is shown
+ .get(selector.singleBasicSelect)
+ .find(selector.indicatorDropdown)
+ .should('be.visible')
+ // Click the icon to open the menu
+ .click()
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('exist')
+ .should('be.visible')
+ .contains('Green');
+ });
+
+ it(`Should close the menu after selecting an option in view: ${viewport}`, () => {
+ cy.get(selector.singleBasicSelect)
+ .find(selector.indicatorDropdown)
+ .click()
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('contain', 'Green')
+ .contains('Green')
+ .click()
+ // Value has updated
+ .get(selector.singleBasicSelect)
+ .find(selector.singleValue)
+ .should('contain', 'Green')
+ // Menu has closed
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('not.exist');
+ });
+
+ it(`Should be disabled once disabled is checked in view: ${viewport}`, () => {
+ cy
+ // Does not start out disabled
+ .get(selector.singleBasicSelect)
+ // .click()
+ .find('input')
+ .should('exist')
+ .should('not.be.disabled')
+ // Disable the select component
+ .get(selector.singleBasic)
+ .find(selector.checkboxDisable)
+ .click()
+ // Now the input should be disabled
+ .get(selector.singleBasicSelect)
+ .click({ force: true })
+ .find('input')
+ .should('exist')
+ .should('be.disabled')
+ // control should have aria-disabled
+ .get(selector.singleBasicSelect)
+ .find(selector.control)
+ .should('have.attr', 'aria-disabled', 'true');
+ });
+
+ it(`Should filter options when searching in view: ${viewport}`, () => {
+ cy.get(selector.singleBasicSelect)
+ .click()
+ .find('input')
+ .type('For', { force: true })
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('contain', 'Forest')
+ .find(selector.menuOption)
+ .should('have.length', 1);
+ });
+
+ it(`Should show "No options" if searched value is not found in view: ${viewport}`, () => {
+ cy.get(selector.singleBasicSelect)
+ .click()
+ .find('input')
+ .type('/', { force: true })
+ .get(selector.noOptionsValue)
+ .should('contain', 'No options');
+ });
+
+ it(`Should not clear the value when backspace is pressed in view: ${viewport}`, () => {
+ cy.get(selector.singleBasicSelect)
+ .click()
+ .find('input')
+ .type('{backspace}', { force: true })
+ .get(selector.singleBasicSelect)
+ .find(selector.placeholder)
+ .should('not.be.visible');
+ });
+ });
+
+ context(`Grouped in view: ${viewport}`, () => {
+ before(() => {
+ cy.viewport(viewport);
+ });
+
+ beforeEach(() => {
+ cy.reload();
+ });
+
+ it(`Should display a default value in view: ${viewport}`, () => {
+ cy.get(selector.singleGroupedSelect)
+ .find(selector.singleValue)
+ .should('contain', 'Blue');
+ });
+
+ it(`Should display group headings in the menu in view: ${viewport}`, () => {
+ cy.get(selector.singleGroupedSelect)
+ .find(selector.indicatorDropdown)
+ .click()
+ .get(selector.singleGroupedSelect)
+ .find(selector.menu)
+ .should('be.visible')
+ .find(selector.groupHeading)
+ .should('have.length', 2);
+ });
+
+ it(`Should focus next option on down arrow key press: ${viewport}`, () => {
+ cy.get(selector.singleGroupedSelect)
+ .click()
+ .find('input')
+ .type('{downarrow}', { force: true })
+ .get(selector.focusedOption)
+ .should('exist');
+ });
+
+ it(`Should focus next option on down arrow key press after filtering: ${viewport}`, () => {
+ cy.get(selector.singleGroupedSelect)
+ .click()
+ .find('input')
+ .type('o', { force: true })
+ .type('{downarrow}', { force: true })
+ .get(selector.focusedOption)
+ .should('exist');
+ });
+ });
+
+ context(`Clearable in view: ${viewport}`, () => {
+ before(() => {
+ cy.viewport(viewport);
+ });
+
+ beforeEach(() => {
+ cy.reload();
+ });
+
+ it(`Should display a default value in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .find(selector.singleValue)
+ .should('contain', 'Blue');
+ });
+
+ it(`Should display a clear indicator in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .find(selector.indicatorClear)
+ .should('be.visible');
+ });
+
+ it(`Should clear the default value when clear is clicked in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .find(selector.indicatorClear)
+ .click()
+ .get(selector.singleClearableSelect)
+ .find(selector.placeholder)
+ .should('be.visible')
+ .should('contain', 'Select...');
+ });
+
+ // 'backspaceRemovesValue' is true by default
+ it(`Should clear the value when backspace is pressed in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .click()
+ .find('input')
+ .type('{backspace}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.placeholder)
+ .should('be.visible')
+ .should('contain', 'Select...');
+ });
+
+ // 'backspaceRemovesValue' is true by default, and delete is included
+ it(`Should clear the value when delete is pressed in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .click()
+ .find('input')
+ .type('{del}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.placeholder)
+ .should('be.visible')
+ .should('contain', 'Select...');
+ });
+
+ it(`Should not open the menu when a value is cleared with backspace in view: ${viewport}`, () => {
+ cy.get(selector.singleClearableSelect)
+ .click()
+ .find('input')
+ // Close the menu, but leave focused
+ .type('{esc}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.menu)
+ .should('not.be.visible')
+ // Clear the value, verify menu doesn't pop
+ .get(selector.singleClearableSelect)
+ .find('input')
+ .type('{backspace}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.menu)
+ .should('not.be.visible');
+ });
+
+ it(`Should clear the value when escape is pressed if escapeClearsValue and menu is closed in view: ${viewport}`, () => {
+ cy
+ // nothing happens if escapeClearsValue is false
+ .get(selector.singleClearableSelect)
+ .click()
+ .find('input')
+ // Escape once to close the menu
+ .type('{esc}', { force: true })
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('not.be.visible')
+ // Escape again to verify value is not cleared
+ .get(selector.singleClearableSelect)
+ .find('input')
+ .type('{esc}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.placeholder)
+ .should('not.be.visible')
+ // Enable escapeClearsValue and try again, it should clear the value
+ .get(selector.singleClearable)
+ .find(selector.checkboxEscapeClearsValue)
+ .click()
+ .get(selector.singleClearableSelect)
+ .click()
+ .find('input')
+ // Escape once to close the menu
+ .type('{esc}', { force: true })
+ .get(selector.singleBasicSelect)
+ .find(selector.menu)
+ .should('not.be.visible')
+ // Escape again to clear value
+ .get(selector.singleClearableSelect)
+ .find('input')
+ .type('{esc}', { force: true })
+ .get(selector.singleClearableSelect)
+ .find(selector.placeholder)
+ .should('be.visible');
+ });
+ });
+ }
+});
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 0000000000..9e0343e3cc
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "commonjs",
+ "noEmit": true,
+ "strict": true,
+ "types": ["cypress"],
+ "esModuleInterop": true,
+ "resolveJsonModule": true
+ }
+}
diff --git a/dist/react-select.css b/dist/react-select.css
deleted file mode 100644
index 658cc59b11..0000000000
--- a/dist/react-select.css
+++ /dev/null
@@ -1,375 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/JedWatson/react-select
-*/
-.Select {
- position: relative;
-}
-.Select,
-.Select div,
-.Select input,
-.Select span {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.Select.is-disabled > .Select-control {
- background-color: #f9f9f9;
-}
-.Select.is-disabled > .Select-control:hover {
- box-shadow: none;
-}
-.Select.is-disabled .Select-arrow-zone {
- cursor: default;
- pointer-events: none;
- opacity: 0.35;
-}
-.Select-control {
- background-color: #fff;
- border-color: #d9d9d9 #ccc #b3b3b3;
- border-radius: 4px;
- border: 1px solid #ccc;
- color: #333;
- cursor: default;
- display: table;
- border-spacing: 0;
- border-collapse: separate;
- height: 36px;
- outline: none;
- overflow: hidden;
- position: relative;
- width: 100%;
-}
-.Select-control:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
-}
-.Select-control .Select-input:focus {
- outline: none;
-}
-.is-searchable.is-open > .Select-control {
- cursor: text;
-}
-.is-open > .Select-control {
- border-bottom-right-radius: 0;
- border-bottom-left-radius: 0;
- background: #fff;
- border-color: #b3b3b3 #ccc #d9d9d9;
-}
-.is-open > .Select-control .Select-arrow {
- top: -2px;
- border-color: transparent transparent #999;
- border-width: 0 5px 5px;
-}
-.is-searchable.is-focused:not(.is-open) > .Select-control {
- cursor: text;
-}
-.is-focused:not(.is-open) > .Select-control {
- border-color: #007eff;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px rgba(0, 126, 255, 0.1);
-}
-.Select-placeholder,
-.Select--single > .Select-control .Select-value {
- bottom: 0;
- color: #aaa;
- left: 0;
- line-height: 34px;
- padding-left: 10px;
- padding-right: 10px;
- position: absolute;
- right: 0;
- top: 0;
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.has-value.Select--single > .Select-control .Select-value .Select-value-label,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value .Select-value-label {
- color: #333;
-}
-.has-value.Select--single > .Select-control .Select-value a.Select-value-label,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value a.Select-value-label {
- cursor: pointer;
- text-decoration: none;
-}
-.has-value.Select--single > .Select-control .Select-value a.Select-value-label:hover,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value a.Select-value-label:hover,
-.has-value.Select--single > .Select-control .Select-value a.Select-value-label:focus,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value a.Select-value-label:focus {
- color: #007eff;
- outline: none;
- text-decoration: underline;
-}
-.Select-input {
- height: 34px;
- padding-left: 10px;
- padding-right: 10px;
- vertical-align: middle;
-}
-.Select-input > input {
- width: 100%;
- background: none transparent;
- border: 0 none;
- box-shadow: none;
- cursor: default;
- display: inline-block;
- font-family: inherit;
- font-size: inherit;
- margin: 0;
- outline: none;
- line-height: 14px;
- /* For IE 8 compatibility */
- padding: 8px 0 12px;
- /* For IE 8 compatibility */
- -webkit-appearance: none;
-}
-.is-focused .Select-input > input {
- cursor: text;
-}
-.has-value.is-pseudo-focused .Select-input {
- opacity: 0;
-}
-.Select-control:not(.is-searchable) > .Select-input {
- outline: none;
-}
-.Select-loading-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: 16px;
-}
-.Select-loading {
- -webkit-animation: Select-animation-spin 400ms infinite linear;
- -o-animation: Select-animation-spin 400ms infinite linear;
- animation: Select-animation-spin 400ms infinite linear;
- width: 16px;
- height: 16px;
- box-sizing: border-box;
- border-radius: 50%;
- border: 2px solid #ccc;
- border-right-color: #333;
- display: inline-block;
- position: relative;
- vertical-align: middle;
-}
-.Select-clear-zone {
- -webkit-animation: Select-animation-fadeIn 200ms;
- -o-animation: Select-animation-fadeIn 200ms;
- animation: Select-animation-fadeIn 200ms;
- color: #999;
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: 17px;
-}
-.Select-clear-zone:hover {
- color: #D0021B;
-}
-.Select-clear {
- display: inline-block;
- font-size: 18px;
- line-height: 1;
-}
-.Select--multi .Select-clear-zone {
- width: 17px;
-}
-.Select-arrow-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: 25px;
- padding-right: 5px;
-}
-.Select-arrow {
- border-color: #999 transparent transparent;
- border-style: solid;
- border-width: 5px 5px 2.5px;
- display: inline-block;
- height: 0;
- width: 0;
- position: relative;
-}
-.is-open .Select-arrow,
-.Select-arrow-zone:hover > .Select-arrow {
- border-top-color: #666;
-}
-.Select--multi .Select-multi-value-wrapper {
- display: inline-block;
-}
-.Select .Select-aria-only {
- display: inline-block;
- height: 1px;
- width: 1px;
- margin: -1px;
- clip: rect(0, 0, 0, 0);
- overflow: hidden;
- float: left;
-}
-@-webkit-keyframes Select-animation-fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-@keyframes Select-animation-fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-.Select-menu-outer {
- border-bottom-right-radius: 4px;
- border-bottom-left-radius: 4px;
- background-color: #fff;
- border: 1px solid #ccc;
- border-top-color: #e6e6e6;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- box-sizing: border-box;
- margin-top: -1px;
- max-height: 200px;
- position: absolute;
- top: 100%;
- width: 100%;
- z-index: 1;
- -webkit-overflow-scrolling: touch;
-}
-.Select-menu {
- max-height: 198px;
- overflow-y: auto;
-}
-.Select-option {
- box-sizing: border-box;
- background-color: #fff;
- color: #666666;
- cursor: pointer;
- display: block;
- padding: 8px 10px;
-}
-.Select-option:last-child {
- border-bottom-right-radius: 4px;
- border-bottom-left-radius: 4px;
-}
-.Select-option.is-selected {
- background-color: #f5faff;
- /* Fallback color for IE 8 */
- background-color: rgba(0, 126, 255, 0.04);
- color: #333;
-}
-.Select-option.is-focused {
- background-color: #ebf5ff;
- /* Fallback color for IE 8 */
- background-color: rgba(0, 126, 255, 0.08);
- color: #333;
-}
-.Select-option.is-disabled {
- color: #cccccc;
- cursor: default;
-}
-.Select-noresults {
- box-sizing: border-box;
- color: #999999;
- cursor: default;
- display: block;
- padding: 8px 10px;
-}
-.Select--multi .Select-input {
- vertical-align: middle;
- margin-left: 10px;
- padding: 0;
-}
-.Select--multi.has-value .Select-input {
- margin-left: 5px;
-}
-.Select--multi .Select-value {
- background-color: #ebf5ff;
- /* Fallback color for IE 8 */
- background-color: rgba(0, 126, 255, 0.08);
- border-radius: 2px;
- border: 1px solid #c2e0ff;
- /* Fallback color for IE 8 */
- border: 1px solid rgba(0, 126, 255, 0.24);
- color: #007eff;
- display: inline-block;
- font-size: 0.9em;
- line-height: 1.4;
- margin-left: 5px;
- margin-top: 5px;
- vertical-align: top;
-}
-.Select--multi .Select-value-icon,
-.Select--multi .Select-value-label {
- display: inline-block;
- vertical-align: middle;
-}
-.Select--multi .Select-value-label {
- border-bottom-right-radius: 2px;
- border-top-right-radius: 2px;
- cursor: default;
- padding: 2px 5px;
-}
-.Select--multi a.Select-value-label {
- color: #007eff;
- cursor: pointer;
- text-decoration: none;
-}
-.Select--multi a.Select-value-label:hover {
- text-decoration: underline;
-}
-.Select--multi .Select-value-icon {
- cursor: pointer;
- border-bottom-left-radius: 2px;
- border-top-left-radius: 2px;
- border-right: 1px solid #c2e0ff;
- /* Fallback color for IE 8 */
- border-right: 1px solid rgba(0, 126, 255, 0.24);
- padding: 1px 5px 3px;
-}
-.Select--multi .Select-value-icon:hover,
-.Select--multi .Select-value-icon:focus {
- background-color: #d8eafd;
- /* Fallback color for IE 8 */
- background-color: rgba(0, 113, 230, 0.08);
- color: #0071e6;
-}
-.Select--multi .Select-value-icon:active {
- background-color: #c2e0ff;
- /* Fallback color for IE 8 */
- background-color: rgba(0, 126, 255, 0.24);
-}
-.Select--multi.is-disabled .Select-value {
- background-color: #fcfcfc;
- border: 1px solid #e3e3e3;
- color: #333;
-}
-.Select--multi.is-disabled .Select-value-icon {
- cursor: not-allowed;
- border-right: 1px solid #e3e3e3;
-}
-.Select--multi.is-disabled .Select-value-icon:hover,
-.Select--multi.is-disabled .Select-value-icon:focus,
-.Select--multi.is-disabled .Select-value-icon:active {
- background-color: #fcfcfc;
-}
-@keyframes Select-animation-spin {
- to {
- transform: rotate(1turn);
- }
-}
-@-webkit-keyframes Select-animation-spin {
- to {
- -webkit-transform: rotate(1turn);
- }
-}
diff --git a/dist/react-select.js b/dist/react-select.js
deleted file mode 100644
index caad9d23f4..0000000000
--- a/dist/react-select.js
+++ /dev/null
@@ -1,2282 +0,0 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Select = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o _this3.props.value.length) {
- _this3.clearOptions();
- }
- _this3.props.onChange(newValues);
- }
- };
-
- return children(_extends({}, this.props, props, {
- isLoading: isLoading,
- onInputChange: this._onInputChange
- }));
- }
- }]);
-
- return Async;
-})(_react.Component);
-
-exports['default'] = Async;
-
-Async.propTypes = propTypes;
-Async.defaultProps = defaultProps;
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5,"./utils/stripDiacritics":11}],2:[function(require,module,exports){
-(function (global){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-function reduce(obj) {
- var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
- return Object.keys(obj).reduce(function (props, key) {
- var value = obj[key];
- if (value !== undefined) props[key] = value;
- return props;
- }, props);
-}
-
-var AsyncCreatable = _react2['default'].createClass({
- displayName: 'AsyncCreatableSelect',
-
- render: function render() {
- var _this = this;
-
- return _react2['default'].createElement(
- _Select2['default'].Async,
- this.props,
- function (asyncProps) {
- return _react2['default'].createElement(
- _Select2['default'].Creatable,
- _this.props,
- function (creatableProps) {
- return _react2['default'].createElement(_Select2['default'], _extends({}, reduce(asyncProps, reduce(creatableProps, {})), {
- onInputChange: function (input) {
- creatableProps.onInputChange(input);
- return asyncProps.onInputChange(input);
- },
- ref: function (ref) {
- creatableProps.ref(ref);
- asyncProps.ref(ref);
- }
- }));
- }
- );
- }
- );
- }
-});
-
-module.exports = AsyncCreatable;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5}],3:[function(require,module,exports){
-(function (global){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var Creatable = _react2['default'].createClass({
- displayName: 'CreatableSelect',
-
- propTypes: {
- // Child function responsible for creating the inner Select component
- // This component can be used to compose HOCs (eg Creatable and Async)
- // (props: Object): PropTypes.element
- children: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.filterOptions
- filterOptions: _react2['default'].PropTypes.any,
-
- // Searches for any matching option within the set of options.
- // This function prevents duplicate options from being created.
- // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean
- isOptionUnique: _react2['default'].PropTypes.func,
-
- // Determines if the current input text represents a valid option.
- // ({ label: string }): boolean
- isValidNewOption: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.menuRenderer
- menuRenderer: _react2['default'].PropTypes.any,
-
- // Factory to create new option.
- // ({ label: string, labelKey: string, valueKey: string }): Object
- newOptionCreator: _react2['default'].PropTypes.func,
-
- // input change handler: function (inputValue) {}
- onInputChange: _react2['default'].PropTypes.func,
-
- // input keyDown handler: function (event) {}
- onInputKeyDown: _react2['default'].PropTypes.func,
-
- // new option click handler: function (option) {}
- onNewOptionClick: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.options
- options: _react2['default'].PropTypes.array,
-
- // Creates prompt/placeholder option text.
- // (filterText: string): string
- promptTextCreator: _react2['default'].PropTypes.func,
-
- // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option.
- shouldKeyDownEventCreateNewOption: _react2['default'].PropTypes.func
- },
-
- // Default prop methods
- statics: {
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- },
-
- getDefaultProps: function getDefaultProps() {
- return {
- filterOptions: _utilsDefaultFilterOptions2['default'],
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- };
- },
-
- createNewOption: function createNewOption() {
- var _props = this.props;
- var isValidNewOption = _props.isValidNewOption;
- var newOptionCreator = _props.newOptionCreator;
- var onNewOptionClick = _props.onNewOptionClick;
- var _props$options = _props.options;
- var options = _props$options === undefined ? [] : _props$options;
- var shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption;
-
- if (isValidNewOption({ label: this.inputValue })) {
- var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey });
- var _isOptionUnique = this.isOptionUnique({ option: option });
-
- // Don't add the same option twice.
- if (_isOptionUnique) {
- if (onNewOptionClick) {
- onNewOptionClick(option);
- } else {
- options.unshift(option);
-
- this.select.selectValue(option);
- }
- }
- }
- },
-
- filterOptions: function filterOptions() {
- var _props2 = this.props;
- var filterOptions = _props2.filterOptions;
- var isValidNewOption = _props2.isValidNewOption;
- var options = _props2.options;
- var promptTextCreator = _props2.promptTextCreator;
-
- // TRICKY Check currently selected options as well.
- // Don't display a create-prompt for a value that's selected.
- // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array.
- var excludeOptions = arguments[2] || [];
-
- var filteredOptions = filterOptions.apply(undefined, arguments) || [];
-
- if (isValidNewOption({ label: this.inputValue })) {
- var _newOptionCreator = this.props.newOptionCreator;
-
- var option = _newOptionCreator({
- label: this.inputValue,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- // TRICKY Compare to all options (not just filtered options) in case option has already been selected).
- // For multi-selects, this would remove it from the filtered list.
- var _isOptionUnique2 = this.isOptionUnique({
- option: option,
- options: excludeOptions.concat(filteredOptions)
- });
-
- if (_isOptionUnique2) {
- var _prompt = promptTextCreator(this.inputValue);
-
- this._createPlaceholderOption = _newOptionCreator({
- label: _prompt,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- filteredOptions.unshift(this._createPlaceholderOption);
- }
- }
-
- return filteredOptions;
- },
-
- isOptionUnique: function isOptionUnique(_ref2) {
- var option = _ref2.option;
- var options = _ref2.options;
- var isOptionUnique = this.props.isOptionUnique;
-
- options = options || this.select.filterOptions();
-
- return isOptionUnique({
- labelKey: this.labelKey,
- option: option,
- options: options,
- valueKey: this.valueKey
- });
- },
-
- menuRenderer: function menuRenderer(params) {
- var menuRenderer = this.props.menuRenderer;
-
- return menuRenderer(_extends({}, params, {
- onSelect: this.onOptionSelect,
- selectValue: this.onOptionSelect
- }));
- },
-
- onInputChange: function onInputChange(input) {
- var onInputChange = this.props.onInputChange;
-
- if (onInputChange) {
- onInputChange(input);
- }
-
- // This value may be needed in between Select mounts (when this.select is null)
- this.inputValue = input;
- },
-
- onInputKeyDown: function onInputKeyDown(event) {
- var _props3 = this.props;
- var shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption;
- var onInputKeyDown = _props3.onInputKeyDown;
-
- var focusedOption = this.select.getFocusedOption();
-
- if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) {
- this.createNewOption();
-
- // Prevent decorated Select from doing anything additional with this keyDown event
- event.preventDefault();
- } else if (onInputKeyDown) {
- onInputKeyDown(event);
- }
- },
-
- onOptionSelect: function onOptionSelect(option, event) {
- if (option === this._createPlaceholderOption) {
- this.createNewOption();
- } else {
- this.select.selectValue(option);
- }
- },
-
- render: function render() {
- var _this = this;
-
- var _props4 = this.props;
- var newOptionCreator = _props4.newOptionCreator;
- var shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption;
-
- var restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']);
-
- var children = this.props.children;
-
- // We can't use destructuring default values to set the children,
- // because it won't apply work if `children` is null. A falsy check is
- // more reliable in real world use-cases.
- if (!children) {
- children = defaultChildren;
- }
-
- var props = _extends({}, restProps, {
- allowCreate: true,
- filterOptions: this.filterOptions,
- menuRenderer: this.menuRenderer,
- onInputChange: this.onInputChange,
- onInputKeyDown: this.onInputKeyDown,
- ref: function ref(_ref) {
- _this.select = _ref;
-
- // These values may be needed in between Select mounts (when this.select is null)
- if (_ref) {
- _this.labelKey = _ref.props.labelKey;
- _this.valueKey = _ref.props.valueKey;
- }
- }
- });
-
- return children(props);
- }
-});
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-
-function isOptionUnique(_ref3) {
- var option = _ref3.option;
- var options = _ref3.options;
- var labelKey = _ref3.labelKey;
- var valueKey = _ref3.valueKey;
-
- return options.filter(function (existingOption) {
- return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey];
- }).length === 0;
-};
-
-function isValidNewOption(_ref4) {
- var label = _ref4.label;
-
- return !!label;
-};
-
-function newOptionCreator(_ref5) {
- var label = _ref5.label;
- var labelKey = _ref5.labelKey;
- var valueKey = _ref5.valueKey;
-
- var option = {};
- option[valueKey] = label;
- option[labelKey] = label;
- option.className = 'Select-create-option-placeholder';
- return option;
-};
-
-function promptTextCreator(label) {
- return 'Create option "' + label + '"';
-}
-
-function shouldKeyDownEventCreateNewOption(_ref6) {
- var keyCode = _ref6.keyCode;
-
- switch (keyCode) {
- case 9: // TAB
- case 13: // ENTER
- case 188:
- // COMMA
- return true;
- }
-
- return false;
-};
-
-module.exports = Creatable;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5,"./utils/defaultFilterOptions":9,"./utils/defaultMenuRenderer":10}],4:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Option = _react2['default'].createClass({
- displayName: 'Option',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- className: _react2['default'].PropTypes.string, // className (based on mouse position)
- instancePrefix: _react2['default'].PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
- isDisabled: _react2['default'].PropTypes.bool, // the option is disabled
- isFocused: _react2['default'].PropTypes.bool, // the option is focused
- isSelected: _react2['default'].PropTypes.bool, // the option is selected
- onFocus: _react2['default'].PropTypes.func, // method to handle mouseEnter on option element
- onSelect: _react2['default'].PropTypes.func, // method to handle click on option element
- onUnfocus: _react2['default'].PropTypes.func, // method to handle mouseLeave on option element
- option: _react2['default'].PropTypes.object.isRequired, // object that is base for that option
- optionIndex: _react2['default'].PropTypes.number },
- // index of the option, used to generate unique ids for aria
- blockEvent: function blockEvent(event) {
- event.preventDefault();
- event.stopPropagation();
- if (event.target.tagName !== 'A' || !('href' in event.target)) {
- return;
- }
- if (event.target.target) {
- window.open(event.target.href, event.target.target);
- } else {
- window.location.href = event.target.href;
- }
- },
-
- handleMouseDown: function handleMouseDown(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
-
- handleMouseEnter: function handleMouseEnter(event) {
- this.onFocus(event);
- },
-
- handleMouseMove: function handleMouseMove(event) {
- this.onFocus(event);
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- this.handleMouseDown(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- onFocus: function onFocus(event) {
- if (!this.props.isFocused) {
- this.props.onFocus(this.props.option, event);
- }
- },
- render: function render() {
- var _props = this.props;
- var option = _props.option;
- var instancePrefix = _props.instancePrefix;
- var optionIndex = _props.optionIndex;
-
- var className = (0, _classnames2['default'])(this.props.className, option.className);
-
- return option.disabled ? _react2['default'].createElement(
- 'div',
- { className: className,
- onMouseDown: this.blockEvent,
- onClick: this.blockEvent },
- this.props.children
- ) : _react2['default'].createElement(
- 'div',
- { className: className,
- style: option.style,
- role: 'option',
- onMouseDown: this.handleMouseDown,
- onMouseEnter: this.handleMouseEnter,
- onMouseMove: this.handleMouseMove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEnd,
- id: instancePrefix + '-option-' + optionIndex,
- title: option.title },
- this.props.children
- );
- }
-});
-
-module.exports = Option;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],5:[function(require,module,exports){
-(function (global){
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/react-select
-*/
-
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = (typeof window !== "undefined" ? window['ReactDOM'] : typeof global !== "undefined" ? global['ReactDOM'] : null);
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _reactInputAutosize = (typeof window !== "undefined" ? window['AutosizeInput'] : typeof global !== "undefined" ? global['AutosizeInput'] : null);
-
-var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _utilsDefaultArrowRenderer = require('./utils/defaultArrowRenderer');
-
-var _utilsDefaultArrowRenderer2 = _interopRequireDefault(_utilsDefaultArrowRenderer);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var _utilsDefaultClearRenderer = require('./utils/defaultClearRenderer');
-
-var _utilsDefaultClearRenderer2 = _interopRequireDefault(_utilsDefaultClearRenderer);
-
-var _Async = require('./Async');
-
-var _Async2 = _interopRequireDefault(_Async);
-
-var _AsyncCreatable = require('./AsyncCreatable');
-
-var _AsyncCreatable2 = _interopRequireDefault(_AsyncCreatable);
-
-var _Creatable = require('./Creatable');
-
-var _Creatable2 = _interopRequireDefault(_Creatable);
-
-var _Option = require('./Option');
-
-var _Option2 = _interopRequireDefault(_Option);
-
-var _Value = require('./Value');
-
-var _Value2 = _interopRequireDefault(_Value);
-
-function stringifyValue(value) {
- var valueType = typeof value;
- if (valueType === 'string') {
- return value;
- } else if (valueType === 'object') {
- return JSON.stringify(value);
- } else if (valueType === 'number' || valueType === 'boolean') {
- return String(value);
- } else {
- return '';
- }
-}
-
-var stringOrNode = _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.string, _react2['default'].PropTypes.node]);
-
-var instanceId = 1;
-
-var Select = _react2['default'].createClass({
-
- displayName: 'Select',
-
- propTypes: {
- addLabelText: _react2['default'].PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input
- 'aria-label': _react2['default'].PropTypes.string, // Aria label (for assistive tech)
- 'aria-labelledby': _react2['default'].PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
- arrowRenderer: _react2['default'].PropTypes.func, // Create drop-down caret element
- autoBlur: _react2['default'].PropTypes.bool, // automatically blur the component when an option is selected
- autofocus: _react2['default'].PropTypes.bool, // autofocus the component on mount
- autosize: _react2['default'].PropTypes.bool, // whether to enable autosizing or not
- backspaceRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- backspaceToRemoveMessage: _react2['default'].PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
- className: _react2['default'].PropTypes.string, // className for the outer element
- clearAllText: stringOrNode, // title for the "clear" control when multi: true
- clearRenderer: _react2['default'].PropTypes.func, // create clearable x element
- clearValueText: stringOrNode, // title for the "clear" control
- clearable: _react2['default'].PropTypes.bool, // should it be possible to reset value
- deleteRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- delimiter: _react2['default'].PropTypes.string, // delimiter to use to join multiple values for the hidden field value
- disabled: _react2['default'].PropTypes.bool, // whether the Select is disabled or not
- escapeClearsValue: _react2['default'].PropTypes.bool, // whether escape clears the value when the menu is closed
- filterOption: _react2['default'].PropTypes.func, // method to filter a single option (option, filterString)
- filterOptions: _react2['default'].PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
- ignoreAccents: _react2['default'].PropTypes.bool, // whether to strip diacritics when filtering
- ignoreCase: _react2['default'].PropTypes.bool, // whether to perform case-insensitive filtering
- inputProps: _react2['default'].PropTypes.object, // custom attributes for the Input
- inputRenderer: _react2['default'].PropTypes.func, // returns a custom input component
- instanceId: _react2['default'].PropTypes.string, // set the components instanceId
- isLoading: _react2['default'].PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded)
- joinValues: _react2['default'].PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
- labelKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- matchPos: _react2['default'].PropTypes.string, // (any|start) match the start or entire string when filtering
- matchProp: _react2['default'].PropTypes.string, // (any|label|value) which option property to filter on
- menuBuffer: _react2['default'].PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
- menuContainerStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu container
- menuRenderer: _react2['default'].PropTypes.func, // renders a custom menu with options
- menuStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu
- multi: _react2['default'].PropTypes.bool, // multi-value input
- name: _react2['default'].PropTypes.string, // generates a hidden tag with this field name for html forms
- noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
- onBlur: _react2['default'].PropTypes.func, // onBlur handler: function (event) {}
- onBlurResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared on blur
- onChange: _react2['default'].PropTypes.func, // onChange handler: function (newValue) {}
- onClose: _react2['default'].PropTypes.func, // fires when the menu is closed
- onCloseResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared when menu is closed through the arrow
- onFocus: _react2['default'].PropTypes.func, // onFocus handler: function (event) {}
- onInputChange: _react2['default'].PropTypes.func, // onInputChange handler: function (inputValue) {}
- onInputKeyDown: _react2['default'].PropTypes.func, // input keyDown handler: function (event) {}
- onMenuScrollToBottom: _react2['default'].PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
- onOpen: _react2['default'].PropTypes.func, // fires when the menu is opened
- onValueClick: _react2['default'].PropTypes.func, // onClick handler for value labels: function (value, event) {}
- openAfterFocus: _react2['default'].PropTypes.bool, // boolean to enable opening dropdown when focused
- openOnFocus: _react2['default'].PropTypes.bool, // always open options menu on focus
- optionClassName: _react2['default'].PropTypes.string, // additional class(es) to apply to the elements
- optionComponent: _react2['default'].PropTypes.func, // option component to render in dropdown
- optionRenderer: _react2['default'].PropTypes.func, // optionRenderer: function (option) {}
- options: _react2['default'].PropTypes.array, // array of options
- pageSize: _react2['default'].PropTypes.number, // number of entries to page when using page up/down keys
- placeholder: stringOrNode, // field placeholder, displayed when there's no value
- required: _react2['default'].PropTypes.bool, // applies HTML5 required attribute when needed
- resetValue: _react2['default'].PropTypes.any, // value to use when you clear the control
- scrollMenuIntoView: _react2['default'].PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
- searchable: _react2['default'].PropTypes.bool, // whether to enable searching feature or not
- simpleValue: _react2['default'].PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
- style: _react2['default'].PropTypes.object, // optional style to apply to the control
- tabIndex: _react2['default'].PropTypes.string, // optional tab index of the control
- tabSelectsValue: _react2['default'].PropTypes.bool, // whether to treat tabbing out while focused to be value selection
- value: _react2['default'].PropTypes.any, // initial field value
- valueComponent: _react2['default'].PropTypes.func, // value component to render
- valueKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- valueRenderer: _react2['default'].PropTypes.func, // valueRenderer: function (option) {}
- wrapperStyle: _react2['default'].PropTypes.object },
-
- // optional style to apply to the component wrapper
- statics: { Async: _Async2['default'], AsyncCreatable: _AsyncCreatable2['default'], Creatable: _Creatable2['default'] },
-
- getDefaultProps: function getDefaultProps() {
- return {
- addLabelText: 'Add "{label}"?',
- arrowRenderer: _utilsDefaultArrowRenderer2['default'],
- autosize: true,
- backspaceRemoves: true,
- backspaceToRemoveMessage: 'Press backspace to remove {label}',
- clearable: true,
- clearAllText: 'Clear all',
- clearRenderer: _utilsDefaultClearRenderer2['default'],
- clearValueText: 'Clear value',
- deleteRemoves: true,
- delimiter: ',',
- disabled: false,
- escapeClearsValue: true,
- filterOptions: _utilsDefaultFilterOptions2['default'],
- ignoreAccents: true,
- ignoreCase: true,
- inputProps: {},
- isLoading: false,
- joinValues: false,
- labelKey: 'label',
- matchPos: 'any',
- matchProp: 'any',
- menuBuffer: 0,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- multi: false,
- noResultsText: 'No results found',
- onBlurResetsInput: true,
- onCloseResetsInput: true,
- openAfterFocus: false,
- optionComponent: _Option2['default'],
- pageSize: 5,
- placeholder: 'Select...',
- required: false,
- scrollMenuIntoView: true,
- searchable: true,
- simpleValue: false,
- tabSelectsValue: true,
- valueComponent: _Value2['default'],
- valueKey: 'value'
- };
- },
-
- getInitialState: function getInitialState() {
- return {
- inputValue: '',
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- required: false
- };
- },
-
- componentWillMount: function componentWillMount() {
- this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
- var valueArray = this.getValueArray(this.props.value);
-
- if (this.props.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], this.props.multi)
- });
- }
- },
-
- componentDidMount: function componentDidMount() {
- if (this.props.autofocus) {
- this.focus();
- }
- },
-
- componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
- var valueArray = this.getValueArray(nextProps.value, nextProps);
-
- if (nextProps.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], nextProps.multi)
- });
- }
- },
-
- componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
- if (nextState.isOpen !== this.state.isOpen) {
- this.toggleTouchOutsideEvent(nextState.isOpen);
- var handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose;
- handler && handler();
- }
- },
-
- componentDidUpdate: function componentDidUpdate(prevProps, prevState) {
- // focus to the selected option
- if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
- var focusedOptionNode = _reactDom2['default'].findDOMNode(this.focused);
- var menuNode = _reactDom2['default'].findDOMNode(this.menu);
- menuNode.scrollTop = focusedOptionNode.offsetTop;
- this.hasScrolledToOption = true;
- } else if (!this.state.isOpen) {
- this.hasScrolledToOption = false;
- }
-
- if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
- this._scrollToFocusedOptionOnUpdate = false;
- var focusedDOM = _reactDom2['default'].findDOMNode(this.focused);
- var menuDOM = _reactDom2['default'].findDOMNode(this.menu);
- var focusedRect = focusedDOM.getBoundingClientRect();
- var menuRect = menuDOM.getBoundingClientRect();
- if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) {
- menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight;
- }
- }
- if (this.props.scrollMenuIntoView && this.menuContainer) {
- var menuContainerRect = this.menuContainer.getBoundingClientRect();
- if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
- window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
- }
- }
- if (prevProps.disabled !== this.props.disabled) {
- this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
- this.closeMenu();
- }
- },
-
- componentWillUnmount: function componentWillUnmount() {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- },
-
- toggleTouchOutsideEvent: function toggleTouchOutsideEvent(enabled) {
- if (enabled) {
- if (!document.addEventListener && document.attachEvent) {
- document.attachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.addEventListener('touchstart', this.handleTouchOutside);
- }
- } else {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- }
- },
-
- handleTouchOutside: function handleTouchOutside(event) {
- // handle touch outside on ios to dismiss menu
- if (this.wrapper && !this.wrapper.contains(event.target)) {
- this.closeMenu();
- }
- },
-
- focus: function focus() {
- if (!this.input) return;
- this.input.focus();
-
- if (this.props.openAfterFocus) {
- this.setState({
- isOpen: true
- });
- }
- },
-
- blurInput: function blurInput() {
- if (!this.input) return;
- this.input.blur();
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.handleMouseDown(event);
- },
-
- handleTouchEndClearValue: function handleTouchEndClearValue(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Clear the value
- this.clearValue(event);
- },
-
- handleMouseDown: function handleMouseDown(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
-
- if (event.target.tagName === 'INPUT') {
- return;
- }
-
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
-
- // for the non-searchable select, toggle the menu
- if (!this.props.searchable) {
- this.focus();
- return this.setState({
- isOpen: !this.state.isOpen
- });
- }
-
- if (this.state.isFocused) {
- // On iOS, we can get into a state where we think the input is focused but it isn't really,
- // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
- // Call focus() again here to be safe.
- this.focus();
-
- var input = this.input;
- if (typeof input.getInput === 'function') {
- // Get the actual DOM input if the ref is an component
- input = input.getInput();
- }
-
- // clears the value so that the cursor will be at the end of input when the component re-renders
- input.value = '';
-
- // if the input is focused, ensure the menu is open
- this.setState({
- isOpen: true,
- isPseudoFocused: false
- });
- } else {
- // otherwise, focus the input and open the menu
- this._openAfterFocus = true;
- this.focus();
- }
- },
-
- handleMouseDownOnArrow: function handleMouseDownOnArrow(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- // If the menu isn't open, let the event bubble to the main handleMouseDown
- if (!this.state.isOpen) {
- return;
- }
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
- // close the menu
- this.closeMenu();
- },
-
- handleMouseDownOnMenu: function handleMouseDownOnMenu(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- this._openAfterFocus = true;
- this.focus();
- },
-
- closeMenu: function closeMenu() {
- if (this.props.onCloseResetsInput) {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: ''
- });
- } else {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: this.state.inputValue
- });
- }
- this.hasScrolledToOption = false;
- },
-
- handleInputFocus: function handleInputFocus(event) {
- if (this.props.disabled) return;
- var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
- if (this.props.onFocus) {
- this.props.onFocus(event);
- }
- this.setState({
- isFocused: true,
- isOpen: isOpen
- });
- this._openAfterFocus = false;
- },
-
- handleInputBlur: function handleInputBlur(event) {
- // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
- if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
- this.focus();
- return;
- }
-
- if (this.props.onBlur) {
- this.props.onBlur(event);
- }
- var onBlurredState = {
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false
- };
- if (this.props.onBlurResetsInput) {
- onBlurredState.inputValue = '';
- }
- this.setState(onBlurredState);
- },
-
- handleInputChange: function handleInputChange(event) {
- var newInputValue = event.target.value;
-
- if (this.state.inputValue !== event.target.value && this.props.onInputChange) {
- var nextState = this.props.onInputChange(newInputValue);
- // Note: != used deliberately here to catch undefined and null
- if (nextState != null && typeof nextState !== 'object') {
- newInputValue = '' + nextState;
- }
- }
-
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- inputValue: newInputValue
- });
- },
-
- handleKeyDown: function handleKeyDown(event) {
- if (this.props.disabled) return;
-
- if (typeof this.props.onInputKeyDown === 'function') {
- this.props.onInputKeyDown(event);
- if (event.defaultPrevented) {
- return;
- }
- }
-
- switch (event.keyCode) {
- case 8:
- // backspace
- if (!this.state.inputValue && this.props.backspaceRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- case 9:
- // tab
- if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
- return;
- }
- this.selectFocusedOption();
- return;
- case 13:
- // enter
- if (!this.state.isOpen) return;
- event.stopPropagation();
- this.selectFocusedOption();
- break;
- case 27:
- // escape
- if (this.state.isOpen) {
- this.closeMenu();
- event.stopPropagation();
- } else if (this.props.clearable && this.props.escapeClearsValue) {
- this.clearValue(event);
- event.stopPropagation();
- }
- break;
- case 38:
- // up
- this.focusPreviousOption();
- break;
- case 40:
- // down
- this.focusNextOption();
- break;
- case 33:
- // page up
- this.focusPageUpOption();
- break;
- case 34:
- // page down
- this.focusPageDownOption();
- break;
- case 35:
- // end key
- if (event.shiftKey) {
- return;
- }
- this.focusEndOption();
- break;
- case 36:
- // home key
- if (event.shiftKey) {
- return;
- }
- this.focusStartOption();
- break;
- case 46:
- // backspace
- if (!this.state.inputValue && this.props.deleteRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- default:
- return;
- }
- event.preventDefault();
- },
-
- handleValueClick: function handleValueClick(option, event) {
- if (!this.props.onValueClick) return;
- this.props.onValueClick(option, event);
- },
-
- handleMenuScroll: function handleMenuScroll(event) {
- if (!this.props.onMenuScrollToBottom) return;
- var target = event.target;
-
- if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) {
- this.props.onMenuScrollToBottom();
- }
- },
-
- handleRequired: function handleRequired(value, multi) {
- if (!value) return true;
- return multi ? value.length === 0 : Object.keys(value).length === 0;
- },
-
- getOptionLabel: function getOptionLabel(op) {
- return op[this.props.labelKey];
- },
-
- /**
- * Turns a value into an array from the given options
- * @param {String|Number|Array} value - the value of the select input
- * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
- * @returns {Array} the value of the select represented in an array
- */
- getValueArray: function getValueArray(value, nextProps) {
- var _this = this;
-
- /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
- var props = typeof nextProps === 'object' ? nextProps : this.props;
- if (props.multi) {
- if (typeof value === 'string') value = value.split(props.delimiter);
- if (!Array.isArray(value)) {
- if (value === null || value === undefined) return [];
- value = [value];
- }
- return value.map(function (value) {
- return _this.expandValue(value, props);
- }).filter(function (i) {
- return i;
- });
- }
- var expandedValue = this.expandValue(value, props);
- return expandedValue ? [expandedValue] : [];
- },
-
- /**
- * Retrieve a value from the given options and valueKey
- * @param {String|Number|Array} value - the selected value(s)
- * @param {Object} props - the Select component's props (or nextProps)
- */
- expandValue: function expandValue(value, props) {
- var valueType = typeof value;
- if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
- var options = props.options;
- var valueKey = props.valueKey;
-
- if (!options) return;
- for (var i = 0; i < options.length; i++) {
- if (options[i][valueKey] === value) return options[i];
- }
- },
-
- setValue: function setValue(value) {
- var _this2 = this;
-
- if (this.props.autoBlur) {
- this.blurInput();
- }
- if (!this.props.onChange) return;
- if (this.props.required) {
- var required = this.handleRequired(value, this.props.multi);
- this.setState({ required: required });
- }
- if (this.props.simpleValue && value) {
- value = this.props.multi ? value.map(function (i) {
- return i[_this2.props.valueKey];
- }).join(this.props.delimiter) : value[this.props.valueKey];
- }
- this.props.onChange(value);
- },
-
- selectValue: function selectValue(value) {
- var _this3 = this;
-
- //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise)
- this.hasScrolledToOption = false;
- if (this.props.multi) {
- this.setState({
- inputValue: '',
- focusedIndex: null
- }, function () {
- _this3.addValue(value);
- });
- } else {
- this.setState({
- isOpen: false,
- inputValue: '',
- isPseudoFocused: this.state.isFocused
- }, function () {
- _this3.setValue(value);
- });
- }
- },
-
- addValue: function addValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- var visibleOptions = this._visibleOptions.filter(function (val) {
- return !val.disabled;
- });
- var lastValueIndex = visibleOptions.indexOf(value);
- this.setValue(valueArray.concat(value));
- if (visibleOptions.length - 1 === lastValueIndex) {
- // the last option was selected; focus the second-last one
- this.focusOption(visibleOptions[lastValueIndex - 1]);
- } else if (visibleOptions.length > lastValueIndex) {
- // focus the option below the selected one
- this.focusOption(visibleOptions[lastValueIndex + 1]);
- }
- },
-
- popValue: function popValue() {
- var valueArray = this.getValueArray(this.props.value);
- if (!valueArray.length) return;
- if (valueArray[valueArray.length - 1].clearableValue === false) return;
- this.setValue(valueArray.slice(0, valueArray.length - 1));
- },
-
- removeValue: function removeValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- this.setValue(valueArray.filter(function (i) {
- return i !== value;
- }));
- this.focus();
- },
-
- clearValue: function clearValue(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, ignore it.
- if (event && event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
- this.setValue(this.getResetValue());
- this.setState({
- isOpen: false,
- inputValue: ''
- }, this.focus);
- },
-
- getResetValue: function getResetValue() {
- if (this.props.resetValue !== undefined) {
- return this.props.resetValue;
- } else if (this.props.multi) {
- return [];
- } else {
- return null;
- }
- },
-
- focusOption: function focusOption(option) {
- this.setState({
- focusedOption: option
- });
- },
-
- focusNextOption: function focusNextOption() {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption: function focusPreviousOption() {
- this.focusAdjacentOption('previous');
- },
-
- focusPageUpOption: function focusPageUpOption() {
- this.focusAdjacentOption('page_up');
- },
-
- focusPageDownOption: function focusPageDownOption() {
- this.focusAdjacentOption('page_down');
- },
-
- focusStartOption: function focusStartOption() {
- this.focusAdjacentOption('start');
- },
-
- focusEndOption: function focusEndOption() {
- this.focusAdjacentOption('end');
- },
-
- focusAdjacentOption: function focusAdjacentOption(dir) {
- var options = this._visibleOptions.map(function (option, index) {
- return { option: option, index: index };
- }).filter(function (option) {
- return !option.option.disabled;
- });
- this._scrollToFocusedOptionOnUpdate = true;
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: '',
- focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
- });
- return;
- }
- if (!options.length) return;
- var focusedIndex = -1;
- for (var i = 0; i < options.length; i++) {
- if (this._focusedOption === options[i].option) {
- focusedIndex = i;
- break;
- }
- }
- if (dir === 'next' && focusedIndex !== -1) {
- focusedIndex = (focusedIndex + 1) % options.length;
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedIndex = focusedIndex - 1;
- } else {
- focusedIndex = options.length - 1;
- }
- } else if (dir === 'start') {
- focusedIndex = 0;
- } else if (dir === 'end') {
- focusedIndex = options.length - 1;
- } else if (dir === 'page_up') {
- var potentialIndex = focusedIndex - this.props.pageSize;
- if (potentialIndex < 0) {
- focusedIndex = 0;
- } else {
- focusedIndex = potentialIndex;
- }
- } else if (dir === 'page_down') {
- var potentialIndex = focusedIndex + this.props.pageSize;
- if (potentialIndex > options.length - 1) {
- focusedIndex = options.length - 1;
- } else {
- focusedIndex = potentialIndex;
- }
- }
-
- if (focusedIndex === -1) {
- focusedIndex = 0;
- }
-
- this.setState({
- focusedIndex: options[focusedIndex].index,
- focusedOption: options[focusedIndex].option
- });
- },
-
- getFocusedOption: function getFocusedOption() {
- return this._focusedOption;
- },
-
- getInputValue: function getInputValue() {
- return this.state.inputValue;
- },
-
- selectFocusedOption: function selectFocusedOption() {
- if (this._focusedOption) {
- return this.selectValue(this._focusedOption);
- }
- },
-
- renderLoading: function renderLoading() {
- if (!this.props.isLoading) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-loading-zone', 'aria-hidden': 'true' },
- _react2['default'].createElement('span', { className: 'Select-loading' })
- );
- },
-
- renderValue: function renderValue(valueArray, isOpen) {
- var _this4 = this;
-
- var renderLabel = this.props.valueRenderer || this.getOptionLabel;
- var ValueComponent = this.props.valueComponent;
- if (!valueArray.length) {
- return !this.state.inputValue ? _react2['default'].createElement(
- 'div',
- { className: 'Select-placeholder' },
- this.props.placeholder
- ) : null;
- }
- var onClick = this.props.onValueClick ? this.handleValueClick : null;
- if (this.props.multi) {
- return valueArray.map(function (value, i) {
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: _this4._instancePrefix + '-value-' + i,
- instancePrefix: _this4._instancePrefix,
- disabled: _this4.props.disabled || value.clearableValue === false,
- key: 'value-' + i + '-' + value[_this4.props.valueKey],
- onClick: onClick,
- onRemove: _this4.removeValue,
- value: value
- },
- renderLabel(value, i),
- _react2['default'].createElement(
- 'span',
- { className: 'Select-aria-only' },
- ' '
- )
- );
- });
- } else if (!this.state.inputValue) {
- if (isOpen) onClick = null;
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: this._instancePrefix + '-value-item',
- disabled: this.props.disabled,
- instancePrefix: this._instancePrefix,
- onClick: onClick,
- value: valueArray[0]
- },
- renderLabel(valueArray[0])
- );
- }
- },
-
- renderInput: function renderInput(valueArray, focusedOptionIndex) {
- var _classNames,
- _this5 = this;
-
- var className = (0, _classnames2['default'])('Select-input', this.props.inputProps.className);
- var isOpen = !!this.state.isOpen;
-
- var ariaOwns = (0, _classnames2['default'])((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames));
-
- // TODO: Check how this project includes Object.assign()
- var inputProps = _extends({}, this.props.inputProps, {
- role: 'combobox',
- 'aria-expanded': '' + isOpen,
- 'aria-owns': ariaOwns,
- 'aria-haspopup': '' + isOpen,
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- 'aria-labelledby': this.props['aria-labelledby'],
- 'aria-label': this.props['aria-label'],
- className: className,
- tabIndex: this.props.tabIndex,
- onBlur: this.handleInputBlur,
- onChange: this.handleInputChange,
- onFocus: this.handleInputFocus,
- ref: function ref(_ref) {
- return _this5.input = _ref;
- },
- required: this.state.required,
- value: this.state.inputValue
- });
-
- if (this.props.inputRenderer) {
- return this.props.inputRenderer(inputProps);
- }
-
- if (this.props.disabled || !this.props.searchable) {
- var _props$inputProps = this.props.inputProps;
- var inputClassName = _props$inputProps.inputClassName;
-
- var divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']);
-
- return _react2['default'].createElement('div', _extends({}, divProps, {
- role: 'combobox',
- 'aria-expanded': isOpen,
- 'aria-owns': isOpen ? this._instancePrefix + '-list' : this._instancePrefix + '-value',
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- className: className,
- tabIndex: this.props.tabIndex || 0,
- onBlur: this.handleInputBlur,
- onFocus: this.handleInputFocus,
- ref: function (ref) {
- return _this5.input = ref;
- },
- 'aria-readonly': '' + !!this.props.disabled,
- style: { border: 0, width: 1, display: 'inline-block' } }));
- }
-
- if (this.props.autosize) {
- return _react2['default'].createElement(_reactInputAutosize2['default'], _extends({}, inputProps, { minWidth: '5' }));
- }
- return _react2['default'].createElement(
- 'div',
- { className: className },
- _react2['default'].createElement('input', inputProps)
- );
- },
-
- renderClear: function renderClear() {
- if (!this.props.clearable || !this.props.value || this.props.value === 0 || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return;
- var clear = this.props.clearRenderer();
-
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- onMouseDown: this.clearValue,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEndClearValue
- },
- clear
- );
- },
-
- renderArrow: function renderArrow() {
- var onMouseDown = this.handleMouseDownOnArrow;
- var isOpen = this.state.isOpen;
- var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen });
-
- return _react2['default'].createElement(
- 'span',
- {
- className: 'Select-arrow-zone',
- onMouseDown: onMouseDown
- },
- arrow
- );
- },
-
- filterOptions: function filterOptions(excludeOptions) {
- var filterValue = this.state.inputValue;
- var options = this.props.options || [];
- if (this.props.filterOptions) {
- // Maintain backwards compatibility with boolean attribute
- var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _utilsDefaultFilterOptions2['default'];
-
- return filterOptions(options, filterValue, excludeOptions, {
- filterOption: this.props.filterOption,
- ignoreAccents: this.props.ignoreAccents,
- ignoreCase: this.props.ignoreCase,
- labelKey: this.props.labelKey,
- matchPos: this.props.matchPos,
- matchProp: this.props.matchProp,
- valueKey: this.props.valueKey
- });
- } else {
- return options;
- }
- },
-
- onOptionRef: function onOptionRef(ref, isFocused) {
- if (isFocused) {
- this.focused = ref;
- }
- },
-
- renderMenu: function renderMenu(options, valueArray, focusedOption) {
- if (options && options.length) {
- return this.props.menuRenderer({
- focusedOption: focusedOption,
- focusOption: this.focusOption,
- instancePrefix: this._instancePrefix,
- labelKey: this.props.labelKey,
- onFocus: this.focusOption,
- onSelect: this.selectValue,
- optionClassName: this.props.optionClassName,
- optionComponent: this.props.optionComponent,
- optionRenderer: this.props.optionRenderer || this.getOptionLabel,
- options: options,
- selectValue: this.selectValue,
- valueArray: valueArray,
- valueKey: this.props.valueKey,
- onOptionRef: this.onOptionRef
- });
- } else if (this.props.noResultsText) {
- return _react2['default'].createElement(
- 'div',
- { className: 'Select-noresults' },
- this.props.noResultsText
- );
- } else {
- return null;
- }
- },
-
- renderHiddenField: function renderHiddenField(valueArray) {
- var _this6 = this;
-
- if (!this.props.name) return;
- if (this.props.joinValues) {
- var value = valueArray.map(function (i) {
- return stringifyValue(i[_this6.props.valueKey]);
- }).join(this.props.delimiter);
- return _react2['default'].createElement('input', {
- type: 'hidden',
- ref: function (ref) {
- return _this6.value = ref;
- },
- name: this.props.name,
- value: value,
- disabled: this.props.disabled });
- }
- return valueArray.map(function (item, index) {
- return _react2['default'].createElement('input', { key: 'hidden.' + index,
- type: 'hidden',
- ref: 'value' + index,
- name: _this6.props.name,
- value: stringifyValue(item[_this6.props.valueKey]),
- disabled: _this6.props.disabled });
- });
- },
-
- getFocusableOptionIndex: function getFocusableOptionIndex(selectedOption) {
- var options = this._visibleOptions;
- if (!options.length) return null;
-
- var focusedOption = this.state.focusedOption || selectedOption;
- if (focusedOption && !focusedOption.disabled) {
- var focusedOptionIndex = options.indexOf(focusedOption);
- if (focusedOptionIndex !== -1) {
- return focusedOptionIndex;
- }
- }
-
- for (var i = 0; i < options.length; i++) {
- if (!options[i].disabled) return i;
- }
- return null;
- },
-
- renderOuter: function renderOuter(options, valueArray, focusedOption) {
- var _this7 = this;
-
- var menu = this.renderMenu(options, valueArray, focusedOption);
- if (!menu) {
- return null;
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menuContainer = ref;
- }, className: 'Select-menu-outer', style: this.props.menuContainerStyle },
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menu = ref;
- }, role: 'listbox', className: 'Select-menu', id: this._instancePrefix + '-list',
- style: this.props.menuStyle,
- onScroll: this.handleMenuScroll,
- onMouseDown: this.handleMouseDownOnMenu },
- menu
- )
- );
- },
-
- render: function render() {
- var _this8 = this;
-
- var valueArray = this.getValueArray(this.props.value);
- var options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null);
- var isOpen = this.state.isOpen;
- if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
- var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
-
- var focusedOption = null;
- if (focusedOptionIndex !== null) {
- focusedOption = this._focusedOption = options[focusedOptionIndex];
- } else {
- focusedOption = this._focusedOption = null;
- }
- var className = (0, _classnames2['default'])('Select', this.props.className, {
- 'Select--multi': this.props.multi,
- 'Select--single': !this.props.multi,
- 'is-disabled': this.props.disabled,
- 'is-focused': this.state.isFocused,
- 'is-loading': this.props.isLoading,
- 'is-open': isOpen,
- 'is-pseudo-focused': this.state.isPseudoFocused,
- 'is-searchable': this.props.searchable,
- 'has-value': valueArray.length
- });
-
- var removeMessage = null;
- if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) {
- removeMessage = _react2['default'].createElement(
- 'span',
- { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' },
- this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])
- );
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.wrapper = ref;
- },
- className: className,
- style: this.props.wrapperStyle },
- this.renderHiddenField(valueArray),
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.control = ref;
- },
- className: 'Select-control',
- style: this.props.style,
- onKeyDown: this.handleKeyDown,
- onMouseDown: this.handleMouseDown,
- onTouchEnd: this.handleTouchEnd,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove
- },
- _react2['default'].createElement(
- 'span',
- { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' },
- this.renderValue(valueArray, isOpen),
- this.renderInput(valueArray, focusedOptionIndex)
- ),
- removeMessage,
- this.renderLoading(),
- this.renderClear(),
- this.renderArrow()
- ),
- isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null
- );
- }
-
-});
-
-exports['default'] = Select;
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Async":1,"./AsyncCreatable":2,"./Creatable":3,"./Option":4,"./Value":6,"./utils/defaultArrowRenderer":7,"./utils/defaultClearRenderer":8,"./utils/defaultFilterOptions":9,"./utils/defaultMenuRenderer":10}],6:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Value = _react2['default'].createClass({
-
- displayName: 'Value',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- disabled: _react2['default'].PropTypes.bool, // disabled prop passed to ReactSelect
- id: _react2['default'].PropTypes.string, // Unique id for the value - used for aria
- onClick: _react2['default'].PropTypes.func, // method to handle click on value label
- onRemove: _react2['default'].PropTypes.func, // method to handle removal of the value
- value: _react2['default'].PropTypes.object.isRequired },
-
- // the option object for this value
- handleMouseDown: function handleMouseDown(event) {
- if (event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- if (this.props.onClick) {
- event.stopPropagation();
- this.props.onClick(this.props.value, event);
- return;
- }
- if (this.props.value.href) {
- event.stopPropagation();
- }
- },
-
- onRemove: function onRemove(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onRemove(this.props.value);
- },
-
- handleTouchEndRemove: function handleTouchEndRemove(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.onRemove(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- renderRemoveIcon: function renderRemoveIcon() {
- if (this.props.disabled || !this.props.onRemove) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-value-icon',
- 'aria-hidden': 'true',
- onMouseDown: this.onRemove,
- onTouchEnd: this.handleTouchEndRemove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove },
- '×'
- );
- },
-
- renderLabel: function renderLabel() {
- var className = 'Select-value-label';
- return this.props.onClick || this.props.value.href ? _react2['default'].createElement(
- 'a',
- { className: className, href: this.props.value.href, target: this.props.value.target, onMouseDown: this.handleMouseDown, onTouchEnd: this.handleMouseDown },
- this.props.children
- ) : _react2['default'].createElement(
- 'span',
- { className: className, role: 'option', 'aria-selected': 'true', id: this.props.id },
- this.props.children
- );
- },
-
- render: function render() {
- return _react2['default'].createElement(
- 'div',
- { className: (0, _classnames2['default'])('Select-value', this.props.value.className),
- style: this.props.value.style,
- title: this.props.value.title
- },
- this.renderRemoveIcon(),
- this.renderLabel()
- );
- }
-
-});
-
-module.exports = Value;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],7:[function(require,module,exports){
-(function (global){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports["default"] = arrowRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function arrowRenderer(_ref) {
- var onMouseDown = _ref.onMouseDown;
-
- return _react2["default"].createElement("span", {
- className: "Select-arrow",
- onMouseDown: onMouseDown
- });
-}
-
-;
-module.exports = exports["default"];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],8:[function(require,module,exports){
-(function (global){
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-exports['default'] = clearRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function clearRenderer() {
- return _react2['default'].createElement('span', {
- className: 'Select-clear',
- dangerouslySetInnerHTML: { __html: '×' }
- });
-}
-
-;
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],9:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _stripDiacritics = require('./stripDiacritics');
-
-var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics);
-
-function filterOptions(options, filterValue, excludeOptions, props) {
- var _this = this;
-
- if (props.ignoreAccents) {
- filterValue = (0, _stripDiacritics2['default'])(filterValue);
- }
-
- if (props.ignoreCase) {
- filterValue = filterValue.toLowerCase();
- }
-
- if (excludeOptions) excludeOptions = excludeOptions.map(function (i) {
- return i[props.valueKey];
- });
-
- return options.filter(function (option) {
- if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false;
- if (props.filterOption) return props.filterOption.call(_this, option, filterValue);
- if (!filterValue) return true;
- var valueTest = String(option[props.valueKey]);
- var labelTest = String(option[props.labelKey]);
- if (props.ignoreAccents) {
- if (props.matchProp !== 'label') valueTest = (0, _stripDiacritics2['default'])(valueTest);
- if (props.matchProp !== 'value') labelTest = (0, _stripDiacritics2['default'])(labelTest);
- }
- if (props.ignoreCase) {
- if (props.matchProp !== 'label') valueTest = valueTest.toLowerCase();
- if (props.matchProp !== 'value') labelTest = labelTest.toLowerCase();
- }
- return props.matchPos === 'start' ? props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue || props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue : props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0 || props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0;
- });
-}
-
-module.exports = filterOptions;
-
-},{"./stripDiacritics":11}],10:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function menuRenderer(_ref) {
- var focusedOption = _ref.focusedOption;
- var instancePrefix = _ref.instancePrefix;
- var labelKey = _ref.labelKey;
- var onFocus = _ref.onFocus;
- var onSelect = _ref.onSelect;
- var optionClassName = _ref.optionClassName;
- var optionComponent = _ref.optionComponent;
- var optionRenderer = _ref.optionRenderer;
- var options = _ref.options;
- var valueArray = _ref.valueArray;
- var valueKey = _ref.valueKey;
- var onOptionRef = _ref.onOptionRef;
-
- var Option = optionComponent;
-
- return options.map(function (option, i) {
- var isSelected = valueArray && valueArray.indexOf(option) > -1;
- var isFocused = option === focusedOption;
- var optionClass = (0, _classnames2['default'])(optionClassName, {
- 'Select-option': true,
- 'is-selected': isSelected,
- 'is-focused': isFocused,
- 'is-disabled': option.disabled
- });
-
- return _react2['default'].createElement(
- Option,
- {
- className: optionClass,
- instancePrefix: instancePrefix,
- isDisabled: option.disabled,
- isFocused: isFocused,
- isSelected: isSelected,
- key: 'option-' + i + '-' + option[valueKey],
- onFocus: onFocus,
- onSelect: onSelect,
- option: option,
- optionIndex: i,
- ref: function (ref) {
- onOptionRef(ref, isFocused);
- }
- },
- optionRenderer(option, i)
- );
- });
-}
-
-module.exports = menuRenderer;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],11:[function(require,module,exports){
-'use strict';
-
-var map = [{ 'base': 'A', 'letters': /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g }, { 'base': 'AA', 'letters': /[\uA732]/g }, { 'base': 'AE', 'letters': /[\u00C6\u01FC\u01E2]/g }, { 'base': 'AO', 'letters': /[\uA734]/g }, { 'base': 'AU', 'letters': /[\uA736]/g }, { 'base': 'AV', 'letters': /[\uA738\uA73A]/g }, { 'base': 'AY', 'letters': /[\uA73C]/g }, { 'base': 'B', 'letters': /[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g }, { 'base': 'C', 'letters': /[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g }, { 'base': 'D', 'letters': /[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g }, { 'base': 'DZ', 'letters': /[\u01F1\u01C4]/g }, { 'base': 'Dz', 'letters': /[\u01F2\u01C5]/g }, { 'base': 'E', 'letters': /[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g }, { 'base': 'F', 'letters': /[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g }, { 'base': 'G', 'letters': /[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g }, { 'base': 'H', 'letters': /[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g }, { 'base': 'I', 'letters': /[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g }, { 'base': 'J', 'letters': /[\u004A\u24BF\uFF2A\u0134\u0248]/g }, { 'base': 'K', 'letters': /[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g }, { 'base': 'L', 'letters': /[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g }, { 'base': 'LJ', 'letters': /[\u01C7]/g }, { 'base': 'Lj', 'letters': /[\u01C8]/g }, { 'base': 'M', 'letters': /[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g }, { 'base': 'N', 'letters': /[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g }, { 'base': 'NJ', 'letters': /[\u01CA]/g }, { 'base': 'Nj', 'letters': /[\u01CB]/g }, { 'base': 'O', 'letters': /[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g }, { 'base': 'OI', 'letters': /[\u01A2]/g }, { 'base': 'OO', 'letters': /[\uA74E]/g }, { 'base': 'OU', 'letters': /[\u0222]/g }, { 'base': 'P', 'letters': /[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g }, { 'base': 'Q', 'letters': /[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g }, { 'base': 'R', 'letters': /[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g }, { 'base': 'S', 'letters': /[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g }, { 'base': 'T', 'letters': /[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g }, { 'base': 'TZ', 'letters': /[\uA728]/g }, { 'base': 'U', 'letters': /[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g }, { 'base': 'V', 'letters': /[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g }, { 'base': 'VY', 'letters': /[\uA760]/g }, { 'base': 'W', 'letters': /[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g }, { 'base': 'X', 'letters': /[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g }, { 'base': 'Y', 'letters': /[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g }, { 'base': 'Z', 'letters': /[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g }, { 'base': 'a', 'letters': /[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g }, { 'base': 'aa', 'letters': /[\uA733]/g }, { 'base': 'ae', 'letters': /[\u00E6\u01FD\u01E3]/g }, { 'base': 'ao', 'letters': /[\uA735]/g }, { 'base': 'au', 'letters': /[\uA737]/g }, { 'base': 'av', 'letters': /[\uA739\uA73B]/g }, { 'base': 'ay', 'letters': /[\uA73D]/g }, { 'base': 'b', 'letters': /[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g }, { 'base': 'c', 'letters': /[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g }, { 'base': 'd', 'letters': /[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g }, { 'base': 'dz', 'letters': /[\u01F3\u01C6]/g }, { 'base': 'e', 'letters': /[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g }, { 'base': 'f', 'letters': /[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g }, { 'base': 'g', 'letters': /[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g }, { 'base': 'h', 'letters': /[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g }, { 'base': 'hv', 'letters': /[\u0195]/g }, { 'base': 'i', 'letters': /[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g }, { 'base': 'j', 'letters': /[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g }, { 'base': 'k', 'letters': /[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g }, { 'base': 'l', 'letters': /[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g }, { 'base': 'lj', 'letters': /[\u01C9]/g }, { 'base': 'm', 'letters': /[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g }, { 'base': 'n', 'letters': /[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g }, { 'base': 'nj', 'letters': /[\u01CC]/g }, { 'base': 'o', 'letters': /[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g }, { 'base': 'oi', 'letters': /[\u01A3]/g }, { 'base': 'ou', 'letters': /[\u0223]/g }, { 'base': 'oo', 'letters': /[\uA74F]/g }, { 'base': 'p', 'letters': /[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g }, { 'base': 'q', 'letters': /[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g }, { 'base': 'r', 'letters': /[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g }, { 'base': 's', 'letters': /[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g }, { 'base': 't', 'letters': /[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g }, { 'base': 'tz', 'letters': /[\uA729]/g }, { 'base': 'u', 'letters': /[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g }, { 'base': 'v', 'letters': /[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g }, { 'base': 'vy', 'letters': /[\uA761]/g }, { 'base': 'w', 'letters': /[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g }, { 'base': 'x', 'letters': /[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g }, { 'base': 'y', 'letters': /[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g }, { 'base': 'z', 'letters': /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g }];
-
-module.exports = function stripDiacritics(str) {
- for (var i = 0; i < map.length; i++) {
- str = str.replace(map[i].letters, map[i].base);
- }
- return str;
-};
-
-},{}]},{},[5])(5)
-});
\ No newline at end of file
diff --git a/dist/react-select.min.css b/dist/react-select.min.css
deleted file mode 100644
index cfb7baee9a..0000000000
--- a/dist/react-select.min.css
+++ /dev/null
@@ -1 +0,0 @@
-.Select,.Select-control{position:relative}.Select-control,.Select-input>input{width:100%;cursor:default;outline:0}.Select-arrow-zone,.Select-clear-zone,.Select-loading-zone{text-align:center;cursor:pointer}.Select,.Select div,.Select input,.Select span{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.Select.is-disabled>.Select-control{background-color:#f9f9f9}.Select.is-disabled>.Select-control:hover{box-shadow:none}.Select.is-disabled .Select-arrow-zone{cursor:default;pointer-events:none;opacity:.35}.Select-control{background-color:#fff;border-radius:4px;border:1px solid #ccc;color:#333;display:table;border-spacing:0;border-collapse:separate;height:36px;overflow:hidden}.is-searchable.is-focused:not(.is-open)>.Select-control,.is-searchable.is-open>.Select-control{cursor:text}.Select-control:hover{box-shadow:0 1px 0 rgba(0,0,0,.06)}.Select-control .Select-input:focus{outline:0}.is-open>.Select-control{border-bottom-right-radius:0;border-bottom-left-radius:0;background:#fff;border-color:#b3b3b3 #ccc #d9d9d9}.is-open>.Select-control .Select-arrow{top:-2px;border-color:transparent transparent #999;border-width:0 5px 5px}.is-focused:not(.is-open)>.Select-control{border-color:#007eff;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 0 3px rgba(0,126,255,.1)}.Select--single>.Select-control .Select-value,.Select-placeholder{bottom:0;color:#aaa;left:0;line-height:34px;padding-left:10px;padding-right:10px;position:absolute;right:0;top:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.has-value.Select--single>.Select-control .Select-value .Select-value-label,.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value .Select-value-label{color:#333}.has-value.Select--single>.Select-control .Select-value a.Select-value-label,.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label{cursor:pointer;text-decoration:none}.has-value.Select--single>.Select-control .Select-value a.Select-value-label:focus,.has-value.Select--single>.Select-control .Select-value a.Select-value-label:hover,.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label:focus,.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label:hover{color:#007eff;outline:0;text-decoration:underline}.Select-input{height:34px;padding-left:10px;padding-right:10px;vertical-align:middle}.Select-input>input{background:none;border:0;box-shadow:none;display:inline-block;font-family:inherit;font-size:inherit;margin:0;line-height:14px;padding:8px 0 12px;-webkit-appearance:none}.Select-loading,.Select-loading-zone{width:16px;position:relative;vertical-align:middle}.is-focused .Select-input>input{cursor:text}.has-value.is-pseudo-focused .Select-input{opacity:0}.Select-control:not(.is-searchable)>.Select-input{outline:0}.Select-loading-zone{display:table-cell}.Select-loading{-webkit-animation:Select-animation-spin .4s infinite linear;-o-animation:Select-animation-spin .4s infinite linear;animation:Select-animation-spin .4s infinite linear;height:16px;box-sizing:border-box;border-radius:50%;border:2px solid #ccc;border-right-color:#333;display:inline-block}.Select-clear-zone{-webkit-animation:Select-animation-fadeIn .2s;-o-animation:Select-animation-fadeIn .2s;animation:Select-animation-fadeIn .2s;color:#999;display:table-cell;position:relative;vertical-align:middle;width:17px}.Select-clear-zone:hover{color:#D0021B}.Select-clear{display:inline-block;font-size:18px;line-height:1}.Select--multi .Select-clear-zone{width:17px}.Select-arrow-zone{display:table-cell;position:relative;vertical-align:middle;width:25px;padding-right:5px}.Select--multi .Select-multi-value-wrapper,.Select-arrow{display:inline-block}.Select-arrow{border-color:#999 transparent transparent;border-style:solid;border-width:5px 5px 2.5px;height:0;width:0;position:relative}.Select-arrow-zone:hover>.Select-arrow,.is-open .Select-arrow{border-top-color:#666}.Select .Select-aria-only{display:inline-block;height:1px;width:1px;margin:-1px;clip:rect(0,0,0,0);overflow:hidden;float:left}.Select-noresults,.Select-option{box-sizing:border-box;display:block;padding:8px 10px}@-webkit-keyframes Select-animation-fadeIn{from{opacity:0}to{opacity:1}}@keyframes Select-animation-fadeIn{from{opacity:0}to{opacity:1}}.Select-menu-outer{border-bottom-right-radius:4px;border-bottom-left-radius:4px;background-color:#fff;border:1px solid #ccc;border-top-color:#e6e6e6;box-shadow:0 1px 0 rgba(0,0,0,.06);box-sizing:border-box;margin-top:-1px;max-height:200px;position:absolute;top:100%;width:100%;z-index:1;-webkit-overflow-scrolling:touch}.Select-menu{max-height:198px;overflow-y:auto}.Select-option{background-color:#fff;color:#666;cursor:pointer}.Select-option:last-child{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.Select-option.is-selected{background-color:#f5faff;background-color:rgba(0,126,255,.04);color:#333}.Select-option.is-focused{background-color:#ebf5ff;background-color:rgba(0,126,255,.08);color:#333}.Select-option.is-disabled{color:#ccc;cursor:default}.Select-noresults{color:#999;cursor:default}.Select--multi .Select-input{vertical-align:middle;margin-left:10px;padding:0}.Select--multi.has-value .Select-input{margin-left:5px}.Select--multi .Select-value{background-color:#ebf5ff;background-color:rgba(0,126,255,.08);border-radius:2px;border:1px solid #c2e0ff;border:1px solid rgba(0,126,255,.24);color:#007eff;display:inline-block;font-size:.9em;line-height:1.4;margin-left:5px;margin-top:5px;vertical-align:top}.Select--multi .Select-value-icon,.Select--multi .Select-value-label{display:inline-block;vertical-align:middle}.Select--multi .Select-value-label{border-bottom-right-radius:2px;border-top-right-radius:2px;cursor:default;padding:2px 5px}.Select--multi a.Select-value-label{color:#007eff;cursor:pointer;text-decoration:none}.Select--multi a.Select-value-label:hover{text-decoration:underline}.Select--multi .Select-value-icon{cursor:pointer;border-bottom-left-radius:2px;border-top-left-radius:2px;border-right:1px solid #c2e0ff;border-right:1px solid rgba(0,126,255,.24);padding:1px 5px 3px}.Select--multi .Select-value-icon:focus,.Select--multi .Select-value-icon:hover{background-color:#d8eafd;background-color:rgba(0,113,230,.08);color:#0071e6}.Select--multi .Select-value-icon:active{background-color:#c2e0ff;background-color:rgba(0,126,255,.24)}.Select--multi.is-disabled .Select-value{background-color:#fcfcfc;border:1px solid #e3e3e3;color:#333}.Select--multi.is-disabled .Select-value-icon{cursor:not-allowed;border-right:1px solid #e3e3e3}.Select--multi.is-disabled .Select-value-icon:active,.Select--multi.is-disabled .Select-value-icon:focus,.Select--multi.is-disabled .Select-value-icon:hover{background-color:#fcfcfc}@keyframes Select-animation-spin{to{transform:rotate(1turn)}}@-webkit-keyframes Select-animation-spin{to{-webkit-transform:rotate(1turn)}}
\ No newline at end of file
diff --git a/dist/react-select.min.js b/dist/react-select.min.js
deleted file mode 100644
index 7d2a0b0309..0000000000
--- a/dist/react-select.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Select=e()}}(function(){return function e(t,u,n){function s(i,a){if(!u[i]){if(!t[i]){var r="function"==typeof require&&require;if(!a&&r)return r(i,!0);if(o)return o(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var p=u[i]={exports:{}};t[i][0].call(p.exports,function(e){var u=t[i][1][e];return s(u?u:e)},p,p.exports,e,t,u,n)}return u[i].exports}for(var o="function"==typeof require&&require,i=0;ie.props.value.length&&e.clearOptions(),e.props.onChange(t)}};return u(l({},this.props,r,{isLoading:i,onInputChange:this._onInputChange}))}}]),t}(c.Component);u["default"]=C,C.propTypes=b,C.defaultProps=m,t.exports=u["default"]}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./Select":5,"./utils/stripDiacritics":11}],2:[function(e,t,u){(function(u){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function s(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return Object.keys(e).reduce(function(t,u){var n=e[u];return void 0!==n&&(t[u]=n),t},t)}var o=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,n)&&(u[n]=e[n]);return u}function o(e){return f["default"].createElement(E["default"],e)}function i(e){var t=e.option,u=e.options,n=e.labelKey,s=e.valueKey;return 0===u.filter(function(e){return e[n]===t[n]||e[s]===t[s]}).length}function a(e){var t=e.label;return!!t}function r(e){var t=e.label,u=e.labelKey,n=e.valueKey,s={};return s[n]=t,s[u]=t,s.className="Select-create-option-placeholder",s}function l(e){return'Create option "'+e+'"'}function p(e){var t=e.keyCode;switch(t){case 9:case 13:case 188:return!0}return!1}var d=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,n)&&(u[n]=e[n]);return u}function i(e,t,u){return t in e?Object.defineProperty(e,t,{value:u,enumerable:!0,configurable:!0,writable:!0}):e[t]=u,e}function a(e){var t=typeof e;return"string"===t?e:"object"===t?JSON.stringify(e):"number"===t||"boolean"===t?String(e):""}Object.defineProperty(u,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;ta.bottom||i.topt.offsetHeight&&!(t.scrollHeight-t.offsetHeight-t.scrollTop)&&this.props.onMenuScrollToBottom()}},handleRequired:function(e,t){return!e||(t?0===e.length:0===Object.keys(e).length)},getOptionLabel:function(e){return e[this.props.labelKey]},getValueArray:function(e,t){var u=this,n="object"==typeof t?t:this.props;if(n.multi){if("string"==typeof e&&(e=e.split(n.delimiter)),!Array.isArray(e)){if(null===e||void 0===e)return[];e=[e]}return e.map(function(e){return u.expandValue(e,n)}).filter(function(e){return e})}var s=this.expandValue(e,n);return s?[s]:[]},expandValue:function(e,t){var u=typeof e;if("string"!==u&&"number"!==u&&"boolean"!==u)return e;var n=t.options,s=t.valueKey;if(n)for(var o=0;on&&this.focusOption(u[n+1])},popValue:function(){var e=this.getValueArray(this.props.value);e.length&&e[e.length-1].clearableValue!==!1&&this.setValue(e.slice(0,e.length-1))},removeValue:function(e){var t=this.getValueArray(this.props.value);this.setValue(t.filter(function(t){return t!==e})),this.focus()},clearValue:function(e){e&&"mousedown"===e.type&&0!==e.button||(e.stopPropagation(),e.preventDefault(),this.setValue(this.getResetValue()),this.setState({isOpen:!1,inputValue:""},this.focus))},getResetValue:function(){return void 0!==this.props.resetValue?this.props.resetValue:this.props.multi?[]:null},focusOption:function(e){this.setState({focusedOption:e})},focusNextOption:function(){this.focusAdjacentOption("next")},focusPreviousOption:function(){this.focusAdjacentOption("previous")},focusPageUpOption:function(){this.focusAdjacentOption("page_up")},focusPageDownOption:function(){this.focusAdjacentOption("page_down")},focusStartOption:function(){this.focusAdjacentOption("start")},focusEndOption:function(){this.focusAdjacentOption("end")},focusAdjacentOption:function(e){var t=this._visibleOptions.map(function(e,t){return{option:e,index:t}}).filter(function(e){return!e.option.disabled});if(this._scrollToFocusedOptionOnUpdate=!0,!this.state.isOpen)return void this.setState({isOpen:!0,inputValue:"",focusedOption:this._focusedOption||(t.length?t["next"===e?0:t.length-1].option:null)});if(t.length){for(var u=-1,n=0;n0?u-=1:u=t.length-1;else if("start"===e)u=0;else if("end"===e)u=t.length-1;else if("page_up"===e){var s=u-this.props.pageSize;u=s<0?0:s}else if("page_down"===e){var s=u+this.props.pageSize;u=s>t.length-1?t.length-1:s}u===-1&&(u=0),this.setState({focusedIndex:t[u].index,focusedOption:t[u].option})}},getFocusedOption:function(){return this._focusedOption},getInputValue:function(){return this.state.inputValue},selectFocusedOption:function(){if(this._focusedOption)return this.selectValue(this._focusedOption)},renderLoading:function(){if(this.props.isLoading)return p["default"].createElement("span",{className:"Select-loading-zone","aria-hidden":"true"},p["default"].createElement("span",{className:"Select-loading"}))},renderValue:function(e,t){var u=this,n=this.props.valueRenderer||this.getOptionLabel,s=this.props.valueComponent;if(!e.length)return this.state.inputValue?null:p["default"].createElement("div",{className:"Select-placeholder"},this.props.placeholder);var o=this.props.onValueClick?this.handleValueClick:null;return this.props.multi?e.map(function(e,t){return p["default"].createElement(s,{id:u._instancePrefix+"-value-"+t,instancePrefix:u._instancePrefix,disabled:u.props.disabled||e.clearableValue===!1,key:"value-"+t+"-"+e[u.props.valueKey],onClick:o,onRemove:u.removeValue,value:e},n(e,t),p["default"].createElement("span",{className:"Select-aria-only"}," "))}):this.state.inputValue?void 0:(t&&(o=null),p["default"].createElement(s,{id:this._instancePrefix+"-value-item",disabled:this.props.disabled,instancePrefix:this._instancePrefix,onClick:o,value:e[0]},n(e[0])))},renderInput:function(e,t){var u,n=this,s=(0,y["default"])("Select-input",this.props.inputProps.className),a=!!this.state.isOpen,l=(0,y["default"])((u={},i(u,this._instancePrefix+"-list",a),i(u,this._instancePrefix+"-backspace-remove-message",this.props.multi&&!this.props.disabled&&this.state.isFocused&&!this.state.inputValue),u)),d=r({},this.props.inputProps,{role:"combobox","aria-expanded":""+a,"aria-owns":l,"aria-haspopup":""+a,"aria-activedescendant":a?this._instancePrefix+"-option-"+t:this._instancePrefix+"-value","aria-labelledby":this.props["aria-labelledby"],"aria-label":this.props["aria-label"],className:s,tabIndex:this.props.tabIndex,onBlur:this.handleInputBlur,onChange:this.handleInputChange,onFocus:this.handleInputFocus,ref:function(e){return n.input=e},required:this.state.required,value:this.state.inputValue});if(this.props.inputRenderer)return this.props.inputRenderer(d);if(this.props.disabled||!this.props.searchable){var c=this.props.inputProps,f=(c.inputClassName,o(c,["inputClassName"]));return p["default"].createElement("div",r({},f,{role:"combobox","aria-expanded":a,"aria-owns":a?this._instancePrefix+"-list":this._instancePrefix+"-value","aria-activedescendant":a?this._instancePrefix+"-option-"+t:this._instancePrefix+"-value",className:s,tabIndex:this.props.tabIndex||0,onBlur:this.handleInputBlur,onFocus:this.handleInputFocus,ref:function(e){return n.input=e},"aria-readonly":""+!!this.props.disabled,style:{border:0,width:1,display:"inline-block"}}))}return this.props.autosize?p["default"].createElement(h["default"],r({},d,{minWidth:"5"})):p["default"].createElement("div",{className:s},p["default"].createElement("input",d))},renderClear:function(){if(this.props.clearable&&this.props.value&&0!==this.props.value&&(!this.props.multi||this.props.value.length)&&!this.props.disabled&&!this.props.isLoading){var e=this.props.clearRenderer();return p["default"].createElement("span",{className:"Select-clear-zone",title:this.props.multi?this.props.clearAllText:this.props.clearValueText,"aria-label":this.props.multi?this.props.clearAllText:this.props.clearValueText,onMouseDown:this.clearValue,onTouchStart:this.handleTouchStart,onTouchMove:this.handleTouchMove,onTouchEnd:this.handleTouchEndClearValue},e)}},renderArrow:function(){var e=this.handleMouseDownOnArrow,t=this.state.isOpen,u=this.props.arrowRenderer({onMouseDown:e,isOpen:t});return p["default"].createElement("span",{className:"Select-arrow-zone",onMouseDown:e},u)},filterOptions:function K(e){var t=this.state.inputValue,u=this.props.options||[];if(this.props.filterOptions){var K="function"==typeof this.props.filterOptions?this.props.filterOptions:m["default"];return K(u,t,e,{filterOption:this.props.filterOption,ignoreAccents:this.props.ignoreAccents,ignoreCase:this.props.ignoreCase,labelKey:this.props.labelKey,matchPos:this.props.matchPos,matchProp:this.props.matchProp,valueKey:this.props.valueKey})}return u},onOptionRef:function(e,t){t&&(this.focused=e)},renderMenu:function(e,t,u){return e&&e.length?this.props.menuRenderer({focusedOption:u,focusOption:this.focusOption,
-instancePrefix:this._instancePrefix,labelKey:this.props.labelKey,onFocus:this.focusOption,onSelect:this.selectValue,optionClassName:this.props.optionClassName,optionComponent:this.props.optionComponent,optionRenderer:this.props.optionRenderer||this.getOptionLabel,options:e,selectValue:this.selectValue,valueArray:t,valueKey:this.props.valueKey,onOptionRef:this.onOptionRef}):this.props.noResultsText?p["default"].createElement("div",{className:"Select-noresults"},this.props.noResultsText):null},renderHiddenField:function(e){var t=this;if(this.props.name){if(this.props.joinValues){var u=e.map(function(e){return a(e[t.props.valueKey])}).join(this.props.delimiter);return p["default"].createElement("input",{type:"hidden",ref:function(e){return t.value=e},name:this.props.name,value:u,disabled:this.props.disabled})}return e.map(function(e,u){return p["default"].createElement("input",{key:"hidden."+u,type:"hidden",ref:"value"+u,name:t.props.name,value:a(e[t.props.valueKey]),disabled:t.props.disabled})})}},getFocusableOptionIndex:function(e){var t=this._visibleOptions;if(!t.length)return null;var u=this.state.focusedOption||e;if(u&&!u.disabled){var n=t.indexOf(u);if(n!==-1)return n}for(var s=0;s-1)return!1;if(n.filterOption)return n.filterOption.call(s,e,t);if(!t)return!0;var o=String(e[n.valueKey]),a=String(e[n.labelKey]);return n.ignoreAccents&&("label"!==n.matchProp&&(o=(0,i["default"])(o)),"value"!==n.matchProp&&(a=(0,i["default"])(a))),n.ignoreCase&&("label"!==n.matchProp&&(o=o.toLowerCase()),"value"!==n.matchProp&&(a=a.toLowerCase())),"start"===n.matchPos?"label"!==n.matchProp&&o.substr(0,t.length)===t||"value"!==n.matchProp&&a.substr(0,t.length)===t:"label"!==n.matchProp&&o.indexOf(t)>=0||"value"!==n.matchProp&&a.indexOf(t)>=0})}var o=e("./stripDiacritics"),i=n(o);t.exports=s},{"./stripDiacritics":11}],10:[function(e,t,u){(function(e){"use strict";function u(e){return e&&e.__esModule?e:{"default":e}}function n(e){var t=e.focusedOption,u=e.instancePrefix,n=(e.labelKey,e.onFocus),s=e.onSelect,i=e.optionClassName,r=e.optionComponent,l=e.optionRenderer,p=e.options,d=e.valueArray,c=e.valueKey,f=e.onOptionRef,h=r;return p.map(function(e,r){var p=d&&d.indexOf(e)>-1,E=e===t,y=(0,o["default"])(i,{"Select-option":!0,"is-selected":p,"is-focused":E,"is-disabled":e.disabled});return a["default"].createElement(h,{className:y,instancePrefix:u,isDisabled:e.disabled,isFocused:E,isSelected:p,key:"option-"+r+"-"+e[c],onFocus:n,onSelect:s,option:e,optionIndex:r,ref:function(e){f(e,E)}},l(e,r))})}var s="undefined"!=typeof window?window.classNames:"undefined"!=typeof e?e.classNames:null,o=u(s),i="undefined"!=typeof window?window.React:"undefined"!=typeof e?e.React:null,a=u(i);t.exports=n}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],11:[function(e,t,u){"use strict";var n=[{base:"A",letters:/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},{base:"AA",letters:/[\uA732]/g},{base:"AE",letters:/[\u00C6\u01FC\u01E2]/g},{base:"AO",letters:/[\uA734]/g},{base:"AU",letters:/[\uA736]/g},{base:"AV",letters:/[\uA738\uA73A]/g},{base:"AY",letters:/[\uA73C]/g},{base:"B",letters:/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},{base:"C",letters:/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},{base:"D",letters:/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},{base:"DZ",letters:/[\u01F1\u01C4]/g},{base:"Dz",letters:/[\u01F2\u01C5]/g},{base:"E",letters:/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},{base:"F",letters:/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},{base:"G",letters:/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},{base:"H",letters:/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},{base:"I",letters:/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},{base:"J",letters:/[\u004A\u24BF\uFF2A\u0134\u0248]/g},{base:"K",letters:/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},{base:"L",letters:/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},{base:"LJ",letters:/[\u01C7]/g},{base:"Lj",letters:/[\u01C8]/g},{base:"M",letters:/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},{base:"N",letters:/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},{base:"NJ",letters:/[\u01CA]/g},{base:"Nj",letters:/[\u01CB]/g},{base:"O",letters:/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},{base:"OI",letters:/[\u01A2]/g},{base:"OO",letters:/[\uA74E]/g},{base:"OU",letters:/[\u0222]/g},{base:"P",letters:/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},{base:"Q",letters:/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},{base:"R",letters:/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},{base:"S",letters:/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},{base:"T",letters:/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},{base:"TZ",letters:/[\uA728]/g},{base:"U",letters:/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},{base:"V",letters:/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},{base:"VY",letters:/[\uA760]/g},{base:"W",letters:/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},{base:"X",letters:/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},{base:"Y",letters:/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},{base:"Z",letters:/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},{base:"a",letters:/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},{base:"aa",letters:/[\uA733]/g},{base:"ae",letters:/[\u00E6\u01FD\u01E3]/g},{base:"ao",letters:/[\uA735]/g},{base:"au",letters:/[\uA737]/g},{base:"av",letters:/[\uA739\uA73B]/g},{base:"ay",letters:/[\uA73D]/g},{base:"b",letters:/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},{base:"c",letters:/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},{base:"d",letters:/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},{base:"dz",letters:/[\u01F3\u01C6]/g},{base:"e",letters:/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},{base:"f",letters:/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},{base:"g",letters:/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},{base:"h",letters:/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},{base:"hv",letters:/[\u0195]/g},{base:"i",letters:/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},{base:"j",letters:/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},{base:"k",letters:/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},{base:"l",letters:/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},{base:"lj",letters:/[\u01C9]/g},{base:"m",letters:/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},{base:"n",letters:/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},{base:"nj",letters:/[\u01CC]/g},{base:"o",letters:/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},{base:"oi",letters:/[\u01A3]/g},{base:"ou",letters:/[\u0223]/g},{base:"oo",letters:/[\uA74F]/g},{base:"p",letters:/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},{base:"q",letters:/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},{base:"r",letters:/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},{base:"s",letters:/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},{base:"t",letters:/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},{base:"tz",letters:/[\uA729]/g},{base:"u",letters:/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},{base:"v",letters:/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},{base:"vy",letters:/[\uA761]/g},{base:"w",letters:/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},{base:"x",letters:/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},{base:"y",letters:/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},{base:"z",letters:/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}];t.exports=function(e){for(var t=0;t (
+
+);
+const Container = (props: JSX.IntrinsicElements['div']) => (
+
+);
+const A = (props: JSX.IntrinsicElements['a']) => (
+
+);
+
+export default function Footer() {
+ return (
+
+
+
+ Copyright © Jed Watson ,
+ 2022. MIT Licensed.
+
+
+ Thanks to Thinkmill and{' '}
+ Atlassian for supporting this
+ project.
+
+
+
+ );
+}
diff --git a/docs/App/GitHubButton.tsx b/docs/App/GitHubButton.tsx
new file mode 100644
index 0000000000..383649b038
--- /dev/null
+++ b/docs/App/GitHubButton.tsx
@@ -0,0 +1,96 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react';
+
+interface Props {
+ readonly count: number;
+ readonly repo: string;
+}
+
+const StarButton = ({ count, repo }: Props) => (
+
+
+
+
+
+ Star
+
+
0 ? 1 : 0,
+ padding: '6px 7px',
+ position: 'relative',
+ textDecoration: 'none',
+ transition: 'opacity 200ms',
+
+ '&:before': {
+ border: '4px solid transparent',
+ borderRightColor: 'white',
+ content: '" "',
+ height: 0,
+ left: -8,
+ top: '50%',
+ marginTop: -4,
+ position: 'absolute',
+ width: 0,
+ },
+ }}
+ href={`${repo}/stargazers`}
+ target="_blank"
+ >
+ {count && count.toLocaleString()}
+
+
+);
+
+export default StarButton;
diff --git a/docs/App/Header.tsx b/docs/App/Header.tsx
new file mode 100644
index 0000000000..1eff8b463f
--- /dev/null
+++ b/docs/App/Header.tsx
@@ -0,0 +1,285 @@
+/** @jsx jsx */
+import fetch from 'unfetch';
+import { Component, Ref, RefCallback } from 'react';
+import { jsx } from '@emotion/react';
+import { RouteComponentProps, withRouter } from 'react-router-dom';
+
+import Select, { StylesConfig } from 'react-select';
+import GitHubButton from './GitHubButton';
+import TwitterButton from './TwitterButton';
+import isArray from '../isArray';
+
+const smallDevice = '@media (max-width: 769px)';
+const largeDevice = '@media (min-width: 770px)';
+
+interface Change {
+ value: string;
+ icon: string;
+ label: string;
+}
+
+const changes = [
+ {
+ value: '/typescript',
+ icon: '🛠️',
+ label: 'Written in TypeScript',
+ },
+ {
+ value: '/props',
+ icon: '❤️',
+ label: 'Simpler and more extensible',
+ },
+ {
+ value: '/styles',
+ icon: '🎨',
+ label: 'CSS-in-JS styling API',
+ },
+ {
+ value: '/components',
+ icon: '📦',
+ label: 'Replaceable component architecture',
+ },
+ {
+ value: '/advanced',
+ icon: '🔥',
+ label: 'Lots of advanced functionality',
+ },
+ {
+ value: '/upgrade',
+ icon: '🗺',
+ label: 'Check out the Upgrade Guide',
+ },
+];
+
+function getLabel({ icon, label }: Change) {
+ return (
+
+ {icon}
+ {label}
+
+ );
+}
+
+const headerSelectStyles: StylesConfig = {
+ control: (base, { isFocused }) => ({
+ ...base,
+ backgroundClip: 'padding-box',
+ borderColor: 'rgba(0,0,0,0.1)',
+ boxShadow: isFocused ? '0 0 0 1px #4C9AFF' : undefined,
+
+ ':hover': {
+ borderColor: 'rgba(0,0,0,0.2)',
+ },
+ }),
+ option: (base) => ({
+ ...base,
+ padding: '4px 12px',
+ }),
+ placeholder: (base) => ({
+ ...base,
+ color: 'black',
+ }),
+};
+
+const Gradient = (props: JSX.IntrinsicElements['div']) => (
+
+);
+const Container = (props: JSX.IntrinsicElements['div']) => (
+
+);
+
+interface HeaderState {
+ readonly stars: number;
+}
+
+const apiUrl = 'https://api.github.com/repos/jedwatson/react-select';
+
+class Header extends Component {
+ nav: HTMLElement | undefined;
+ content!: HTMLElement;
+ state: HeaderState = { stars: 0 };
+ componentDidMount() {
+ this.getStarCount();
+ }
+ getStarCount = () => {
+ fetch(apiUrl)
+ .then((res) => res.json())
+ .then((data) => {
+ const stars = data.stargazers_count;
+ this.setState({ stars });
+ })
+ .catch((err) => {
+ console.error('Error retrieving data', err);
+ });
+ };
+ isHome = (props = this.props) => {
+ const valid = ['/', '/home'];
+ return valid.includes(props.location.pathname);
+ };
+ setContentRef: RefCallback = (ref) => {
+ if (!ref) return;
+ this.content = ref;
+ };
+ getContentHeight = () => {
+ if (!this.content) {
+ return 'auto';
+ }
+
+ return this.content.scrollHeight;
+ };
+ render() {
+ const { children, history } = this.props;
+ const { stars } = this.state;
+
+ return (
+
+ {children}
+
+
+
+ React Select
+
+ {
+ history.push(opt.value);
+ }}
+ />
+
+
+
+ );
+ }
+}
+
+interface CollapseProps {
+ readonly height: 'auto' | number;
+ readonly isCollapsed: boolean;
+ readonly innerRef: Ref;
+}
+
+const Collapse = ({
+ height,
+ isCollapsed,
+ innerRef,
+ ...props
+}: CollapseProps & JSX.IntrinsicElements['div']) => {
+ return (
+
+ );
+};
+
+interface ContentProps {
+ readonly onChange: (option: Change) => void;
+ readonly stars: number;
+}
+
+const Content = ({ onChange, stars }: ContentProps) => (
+
+
+
+ A flexible and beautiful Select Input control for ReactJS with
+ multiselect, autocomplete, async and creatable support.
+
+
+
+
+
+
+
+
+ {
+ if (option && !isArray(option)) {
+ onChange(option);
+ }
+ }}
+ value={null}
+ placeholder="🎉 Feature Highlights"
+ styles={headerSelectStyles}
+ />
+
+
+
+);
+
+export default withRouter(Header);
diff --git a/docs/App/PageNav.tsx b/docs/App/PageNav.tsx
new file mode 100644
index 0000000000..b00dd52485
--- /dev/null
+++ b/docs/App/PageNav.tsx
@@ -0,0 +1,185 @@
+/** @jsx jsx */
+import { Component, FunctionComponent, MouseEvent, RefCallback } from 'react';
+import { jsx } from '@emotion/react';
+import { Route, RouteComponentProps, Switch } from 'react-router-dom';
+
+import { animatedScrollTo } from 'react-select/src/utils';
+import routes from './routes';
+import ScrollSpy from './ScrollSpy';
+import Sticky from './Sticky';
+import store, { Data } from '../markdown/store';
+
+const navWidth = 180;
+const appGutter = 20;
+const contentGutter = 30;
+
+const smallDevice = '@media (max-width: 769px)';
+const largeDevice = '@media (min-width: 770px)';
+
+const NavSection: FunctionComponent = () => {
+ const routeKeys = Object.keys(routes);
+ return (
+
+ {routeKeys.map((r) => (
+ } />
+ ))}
+
+ );
+};
+
+interface NavState {
+ readonly links: readonly Data[];
+ readonly activeId: string | null;
+}
+
+class PageNav extends Component {
+ scrollSpy!: ScrollSpy;
+ state: NavState = { activeId: null, links: [] };
+ componentDidMount() {
+ const { match } = this.props;
+
+ // eslint-disable-next-line
+ this.setState({ links: store.getPageHeadings(match.path) });
+ }
+ componentDidUpdate({ history, location }: RouteComponentProps) {
+ const { hash } = this.props.location; // old hash
+ const shouldRefresh = location.hash !== hash && history.action !== 'POP';
+
+ // this makes everything work, need those fresh nodes
+ if (shouldRefresh && this.scrollSpy.buildNodeList) {
+ this.scrollSpy.buildNodeList();
+ }
+ }
+ getSelected = (ids: readonly (string | null)[]) => {
+ const activeId = ids[0];
+ if (activeId !== this.state.activeId) {
+ this.setState({ activeId });
+ }
+ };
+ getScrollSpy: RefCallback = (ref) => {
+ if (!ref) return;
+ this.scrollSpy = ref;
+ };
+ handleItemClick = ({
+ event,
+ hash,
+ }: {
+ readonly event: MouseEvent;
+ readonly hash: string;
+ }) => {
+ event.preventDefault();
+ const path = `#${hash}`;
+ const el = document.querySelector(path);
+ const { history } = this.props;
+
+ if (el && el.offsetTop) {
+ history.replace(path);
+ animatedScrollTo(window, el.offsetTop);
+ }
+ };
+ render() {
+ const { activeId, links } = this.state;
+ const isSmallDevice = window.innerWidth <= 769;
+
+ return links && links.length ? (
+
+
+
+ {links.map((l) => {
+ const hash = l.path.slice(1);
+ const selected = hash === activeId;
+
+ return l.level > 0 ? (
+ {
+ this.handleItemClick({ event, hash });
+ }}
+ >
+ {l.label}
+
+ ) : null;
+ })}
+
+
+
+ ) : null;
+ }
+}
+
+export default NavSection;
+
+const Nav = (props: JSX.IntrinsicElements['div']) => (
+
+);
+
+interface NavItemProps {
+ readonly level: number;
+ readonly selected: boolean;
+}
+
+const NavItem = ({
+ level,
+ selected,
+ ...props
+}: NavItemProps & JSX.IntrinsicElements['div']) => (
+
+);
diff --git a/docs/App/ScrollSpy.tsx b/docs/App/ScrollSpy.tsx
new file mode 100644
index 0000000000..6bb0bec6a7
--- /dev/null
+++ b/docs/App/ScrollSpy.tsx
@@ -0,0 +1,76 @@
+import React, { Component, ReactElement, RefCallback } from 'react';
+import rafSchedule from 'raf-schd';
+import NodeResolver from 'react-node-resolver';
+
+interface Props {
+ readonly children: ReactElement;
+ readonly onChange: (elements: readonly (string | null)[]) => void;
+}
+interface State {
+ readonly elements: readonly HTMLElement[];
+}
+
+function getStyle(el: HTMLElement, prop: string) {
+ const val = window.getComputedStyle(el, null).getPropertyValue(prop);
+ return parseFloat(val);
+}
+function isInView(el: HTMLElement) {
+ let rect = el.getBoundingClientRect();
+
+ const topOffset =
+ (getStyle(el, 'padding-top') + getStyle(el, 'margin-top')) * -1;
+
+ if (rect.top >= topOffset && rect.bottom <= window.innerHeight) {
+ return true;
+ }
+
+ return false;
+}
+
+export default class ScrollSpy extends Component {
+ nav: HTMLElement | undefined;
+ allIds = [];
+ state: State = { elements: [] };
+ static defaultProps = { preserveHeight: false };
+ componentDidMount() {
+ window.addEventListener('scroll', this.handleScroll, false);
+ this.buildNodeList();
+ }
+ componentWillUnmount() {
+ window.removeEventListener('scroll', this.handleScroll);
+ }
+ handleScroll = rafSchedule((event: Event) => {
+ event.preventDefault();
+ const { onChange } = this.props;
+ const { elements } = this.state;
+ if (!elements.length) return;
+
+ const idsInView = elements
+ .filter(isInView)
+ .map((i) => i.getAttribute('id'));
+ if (idsInView.length) {
+ onChange(idsInView);
+ }
+ });
+ getElements: RefCallback = (ref) => {
+ if (!ref) return;
+ this.nav = ref;
+ };
+ buildNodeList = () => {
+ if (!this.nav) return;
+
+ const anchorList = this.nav.querySelectorAll('[data-hash]');
+ const elements = Array.from(anchorList).map(
+ (i) => document.querySelector(`#${i.dataset.hash}`)!
+ );
+
+ this.setState({ elements });
+ };
+ render() {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+}
diff --git a/docs/App/Section.tsx b/docs/App/Section.tsx
new file mode 100644
index 0000000000..f21605af7d
--- /dev/null
+++ b/docs/App/Section.tsx
@@ -0,0 +1,33 @@
+import React, { FunctionComponent } from 'react';
+import { Redirect, Route, RouteComponentProps, Switch } from 'react-router-dom';
+
+import routes from './routes';
+
+const Section: FunctionComponent = () => {
+ const routeKeys = Object.keys(routes);
+ return (
+
+ {routeKeys.map((r) => (
+ } />
+ ))}
+
+
+ );
+};
+
+const Content = ({ location, match }: RouteComponentProps) => {
+ const page = routes[match.path];
+
+ return (
+ (
+
+
+
+ )}
+ />
+ );
+};
+
+export default Section;
diff --git a/docs/App/Sticky.tsx b/docs/App/Sticky.tsx
new file mode 100644
index 0000000000..b9ac213532
--- /dev/null
+++ b/docs/App/Sticky.tsx
@@ -0,0 +1,108 @@
+import React, { Component, CSSProperties, RefCallback } from 'react';
+import rafSchedule from 'raf-schd';
+
+interface Props {
+ readonly preserveHeight: boolean;
+}
+interface State {
+ readonly height: number | 'auto';
+ readonly isFixed: boolean;
+ readonly overScroll: number;
+ readonly scrollHeight: number | null | undefined;
+ readonly width: number | 'auto';
+}
+
+export default class Sticky extends Component {
+ innerEl: HTMLDivElement | undefined;
+ outerEl: HTMLDivElement | undefined;
+ state: State = {
+ height: 'auto',
+ isFixed: false,
+ overScroll: 0,
+ scrollHeight: null,
+ width: 'auto',
+ };
+ static defaultProps = { preserveHeight: false };
+ componentDidMount() {
+ window.addEventListener('scroll', this.handleScroll, false);
+ // this.handleScroll();
+ }
+ componentWillUnmount() {
+ window.removeEventListener('scroll', this.handleScroll);
+ }
+ handleScroll = rafSchedule((event: Event) => {
+ if (!this.innerEl || !this.outerEl) return;
+
+ const offsetBottom = 88; // footer height
+ const { top: outerTop } = this.outerEl.getBoundingClientRect();
+ const innerTop = (this.innerEl.offsetTop && this.innerEl.offsetTop) || 0;
+ const scrollY = window.pageYOffset;
+ const maxScroll =
+ document.body &&
+ document.body.scrollHeight - window.innerHeight - offsetBottom;
+ const { isFixed, overScroll } = this.state;
+
+ // check for `isFixed` before setting state to prevent thrashing
+ if (isFixed && outerTop > 0) {
+ this.setState({ isFixed: false });
+ } else if (!isFixed && scrollY >= innerTop) {
+ this.setState({ isFixed: true });
+ }
+
+ // handle over scroll
+ if (maxScroll && scrollY >= maxScroll) {
+ this.setState({ overScroll: scrollY - maxScroll });
+ } else if (overScroll > 0 && scrollY < maxScroll) {
+ this.setState({ overScroll: 0 });
+ }
+ });
+ getOuterEl: RefCallback = (ref) => {
+ if (!ref) return;
+
+ this.outerEl = ref;
+ };
+ getInnerEl: RefCallback = (ref) => {
+ if (!ref) return;
+
+ this.innerEl = ref;
+
+ // get dimensions once, we're not interested in resize events
+ const firstChild = ref.firstElementChild!;
+ const availableHeight = window.innerHeight;
+ let { height, width } = firstChild.getBoundingClientRect();
+ let scrollHeight;
+
+ if (typeof this.state.height !== 'number') {
+ if (height > availableHeight) scrollHeight = availableHeight;
+ this.setState({ height, scrollHeight, width });
+ }
+ };
+ render() {
+ const { preserveHeight } = this.props;
+ const { height, isFixed, overScroll, scrollHeight, width } = this.state;
+ const outerStyle = isFixed && preserveHeight ? { height } : undefined;
+ const fixedStyles: CSSProperties = {
+ position: 'fixed',
+ top: 0,
+ width,
+ zIndex: 1,
+ };
+ const scrollStyles = scrollHeight
+ ? {
+ height: overScroll ? scrollHeight - overScroll : scrollHeight,
+ overflow: 'scroll',
+ }
+ : null;
+ const innerStyle = isFixed
+ ? { ...fixedStyles, ...scrollStyles }
+ : undefined;
+
+ return (
+
+
+ {this.props.children}
+
+
+ );
+ }
+}
diff --git a/docs/App/TwitterButton.tsx b/docs/App/TwitterButton.tsx
new file mode 100644
index 0000000000..350e1654d9
--- /dev/null
+++ b/docs/App/TwitterButton.tsx
@@ -0,0 +1,46 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react';
+
+const TwitterButton = () => (
+
+);
+
+export default TwitterButton;
diff --git a/docs/App/components.tsx b/docs/App/components.tsx
new file mode 100644
index 0000000000..519e79fb70
--- /dev/null
+++ b/docs/App/components.tsx
@@ -0,0 +1,137 @@
+/** @jsx jsx */
+import { Component } from 'react';
+import {
+ Link,
+ LinkProps,
+ RouteComponentProps,
+ withRouter,
+} from 'react-router-dom';
+import { jsx } from '@emotion/react';
+
+const navWidth = 180;
+const appWidth = 800;
+const appGutter = 20;
+const contentGutter = 30;
+const smallDevice = '@media (max-width: 769px)';
+const largeDevice = '@media (min-width: 770px)';
+
+export const AppContainer = (props: JSX.IntrinsicElements['div']) => (
+
+);
+export const PageContent = (props: JSX.IntrinsicElements['div']) => (
+
+);
+export const AppContent = (props: JSX.IntrinsicElements['div']) => (
+
+);
+
+// ==============================
+// Navigation
+// ==============================
+
+export const PrimaryNav = (props: JSX.IntrinsicElements['div']) => (
+
+);
+export const PrimaryNavItem = ({
+ selected,
+ ...props
+}: LinkProps & { readonly selected: boolean }) => (
+
+);
+
+// ==============================
+// Scroll Restoration
+// ==============================
+
+// Return scroll to top on route change
+class ScrollToTop extends Component {
+ componentDidUpdate(prevProps: RouteComponentProps) {
+ const { history, location } = this.props;
+
+ // do not influence scroll on browser back/forward
+ if (history.action === 'POP') return;
+
+ // no scroll when extending the current path
+ const pathArr = location.pathname.split('/');
+ if (!prevProps.location.pathname.includes(pathArr[1])) {
+ window.scrollTo(0, 0);
+ }
+ }
+
+ render() {
+ return this.props.children;
+ }
+}
+
+export const ScrollRestoration = withRouter(ScrollToTop);
diff --git a/docs/App/index.tsx b/docs/App/index.tsx
new file mode 100644
index 0000000000..7e0ac0642b
--- /dev/null
+++ b/docs/App/index.tsx
@@ -0,0 +1,93 @@
+import React, { Component, Fragment } from 'react';
+import { BrowserRouter, Route, Switch } from 'react-router-dom';
+import { Helmet } from 'react-helmet';
+
+import Header from './Header';
+import Footer from './Footer';
+// import NoMatch from '../NoMatch';
+
+import {
+ AppContainer,
+ AppContent,
+ PageContent,
+ PrimaryNav,
+ PrimaryNavItem,
+ ScrollRestoration,
+} from './components';
+import Section from './Section';
+import PageNav from './PageNav';
+import Tests from '../Tests';
+
+const sections = [
+ { label: 'Home', path: '/home' },
+ { label: 'Props', path: '/props' },
+ { label: 'Styles', path: '/styles' },
+ { label: 'Components', path: '/components' },
+ { label: 'Async', path: '/async' },
+ { label: 'Creatable', path: '/creatable' },
+ { label: 'Advanced', path: '/advanced' },
+ { label: 'TypeScript', path: '/typescript' },
+ { label: 'Upgrading', path: '/upgrade' },
+];
+
+export default class App extends Component {
+ render() {
+ return (
+
+
+
+
+
+
+ (
+
+ {sections.map((l) => {
+ const selected = location.pathname.includes(l.path);
+
+ return (
+
+ {l.label}
+
+ );
+ })}
+
+ )}
+ />
+
+
+
+
+
+ React Select
+
+
+ (
+
+
+
+
+
+
+
+
+ )}
+ />
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/docs/App/routes.ts b/docs/App/routes.ts
new file mode 100644
index 0000000000..0b0cc00e75
--- /dev/null
+++ b/docs/App/routes.ts
@@ -0,0 +1,26 @@
+import { ComponentType } from 'react';
+import Home from '../pages/home';
+import Props from '../pages/props';
+import Styles from '../pages/styles';
+import Components from '../pages/components';
+import Async from '../pages/async';
+import Creatable from '../pages/creatable';
+import Advanced from '../pages/advanced';
+import TypeScript from '../pages/typescript';
+import Upgrade from '../pages/upgrade';
+import UpgradeToV2 from '../pages/upgrade-to-v2';
+
+const routes: { readonly [key: string]: ComponentType } = {
+ '/home': Home,
+ '/props': Props,
+ '/styles': Styles,
+ '/components': Components,
+ '/async': Async,
+ '/creatable': Creatable,
+ '/advanced': Advanced,
+ '/typescript': TypeScript,
+ '/upgrade': Upgrade,
+ '/upgrade-to-v2': UpgradeToV2,
+};
+
+export default routes;
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
new file mode 100644
index 0000000000..39b7f8a950
--- /dev/null
+++ b/docs/CHANGELOG.md
@@ -0,0 +1,127 @@
+# @react-select/docs
+
+## 3.1.3
+
+### Patch Changes
+
+- [`0773095f`](https://github.com/JedWatson/react-select/commit/0773095f4990b636f64ae7d0ab593353a1e03b22) [#5457](https://github.com/JedWatson/react-select/pull/5457) Thanks [@nderkim](https://github.com/nderkim)! - Add classNames API and unstyled prop
+
+- Updated dependencies [0773095f]:
+ - react-select@undefined
+
+## 3.1.2
+
+### Patch Changes
+
+- [`0ca2d5ba`](https://github.com/JedWatson/react-select/commit/0ca2d5ba4aa42fb2a1bf033bcee660a293e39e50) [#5431](https://github.com/JedWatson/react-select/pull/5431) Thanks [@nderkim](https://github.com/nderkim)! - Change `class` components to `functional` components
+
+- Updated dependencies [0ca2d5ba]:
+ - react-select@undefined
+
+## 3.1.1
+
+### Patch Changes
+
+- [638f5455](https://github.com/JedWatson/react-select/commit/638f545517d320fe70ca954511a71e96956abae3) [#4702](https://github.com/JedWatson/react-select/pull/4702) Thanks [@Methuselah96](https://github.com/Methuselah96)! - The Option generic is no longer required to extend the OptionBase type
+
+- Updated dependencies [10225290]:
+- Updated dependencies [53f1972b]:
+- Updated dependencies [b41f4ceb]:
+- Updated dependencies [4b028829]:
+- Updated dependencies [7fcec537]:
+- Updated dependencies [ca2c0e5b]:
+- Updated dependencies [9e82aadc]:
+- Updated dependencies [638f5455]:
+- Updated dependencies [23cea0b5]:
+- Updated dependencies [ef87c3ac]:
+ - react-select@undefined
+
+## 3.1.1-beta.1
+
+### Patch Changes
+
+- [638f5455](https://github.com/JedWatson/react-select/commit/638f545517d320fe70ca954511a71e96956abae3) [#4702](https://github.com/JedWatson/react-select/pull/4702) Thanks [@Methuselah96](https://github.com/Methuselah96)! - The Option generic is no longer required to extend the OptionBase type
+
+- Updated dependencies [10225290]:
+- Updated dependencies [53f1972b]:
+- Updated dependencies [b41f4ceb]:
+- Updated dependencies [7fcec537]:
+- Updated dependencies [9e82aadc]:
+- Updated dependencies [638f5455]:
+ - react-select@undefined
+
+## 3.1.1-beta.0
+
+### Patch Changes
+
+- Updated dependencies [4b028829]:
+- Updated dependencies [ef87c3ac]:
+ - react-select@undefined
+
+## 3.1.0
+
+### Minor Changes
+
+- [2baf5a9d](https://github.com/JedWatson/react-select/commit/2baf5a9df2f4f56f9c9374fcb879cb5259a6d8d0) [#4414](https://github.com/JedWatson/react-select/pull/4414) Thanks [@ebonow](https://github.com/ebonow)! - Add ariaLiveMessages prop for internationalization and other customisations
+
+### Patch Changes
+
+- Updated dependencies [2ffed9c6]:
+- Updated dependencies [c955415c]:
+- Updated dependencies [3ca22b2f]:
+- Updated dependencies [dce3863f]:
+- Updated dependencies [2baf5a9d]:
+- Updated dependencies [7cdb8a6b]:
+- Updated dependencies [ec7c0728]:
+ - react-select@undefined
+
+## 3.0.1
+
+### Patch Changes
+
+- [a016c878](https://github.com/JedWatson/react-select/commit/a016c87821d9289ef9c317c0c397d64a0824ce16) [#4420](https://github.com/JedWatson/react-select/pull/4420) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Bump dependency on @babel/runtime in order to fix compatibility issues with Webpack 5
+
+- [0dbf0438](https://github.com/JedWatson/react-select/commit/0dbf043864ce7a7fa7d822182b4f1770aad5b036) [#4387](https://github.com/JedWatson/react-select/pull/4387) Thanks [@ebonow](https://github.com/ebonow)! - Update example for MultiSelectSort to prevent dragging on multiValueRemove component #4387
+
+- Updated dependencies [f600d13f]:
+- Updated dependencies [b5f9b0c5]:
+- Updated dependencies [a016c878]:
+- Updated dependencies [19b76342]:
+- Updated dependencies [10b5f5a5]:
+ - react-select@undefined
+
+## 3.0.0
+
+### Major Changes
+
+- [26b6325c](https://github.com/JedWatson/react-select/commit/26b6325c95113591e568451bc2296f98318a8dd9) [#4283](https://github.com/JedWatson/react-select/pull/4283) Thanks [@majgaard](https://github.com/majgaard)! - Upgrades Emotion dependency to v11.0.0
+
+ BREAKING CHANGE: The NonceProvider component now requires a `cacheKey` prop that corresponds to the `key` for the Emotion cache.
+
+### Patch Changes
+
+- Updated dependencies [2d5496d5]:
+- Updated dependencies [02050675]:
+- Updated dependencies [26b6325c]:
+- Updated dependencies [b2488bb5]:
+ - react-select@undefined
+
+## 2.4.6
+
+### Patch Changes
+
+- [7af1aafb](https://github.com/JedWatson/react-select/commit/7af1aafb2314db02544b7970784b868e97ec4824) [#4295](https://github.com/JedWatson/react-select/pull/4295) Thanks [@JedWatson](https://github.com/JedWatson)! - Fix menuplacement context
+
+- Updated dependencies [c8d74bd5]:
+- Updated dependencies [c8447f48]:
+- Updated dependencies [7af1aafb]:
+- Updated dependencies [32ad5c04]:
+- Updated dependencies [6af14fbb]:
+- Updated dependencies [0eb1ef96]:
+- Updated dependencies [ad608c8f]:
+ - react-select@undefined
+
+## 2.4.5
+
+- Updated dependencies [[9ad152b](https://github.com/JedWatson/react-select/commit/9ad152b)]:
+ - react-select@3.0.0
diff --git a/docs/ExampleWrapper.tsx b/docs/ExampleWrapper.tsx
new file mode 100644
index 0000000000..eb01b177b3
--- /dev/null
+++ b/docs/ExampleWrapper.tsx
@@ -0,0 +1,254 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react'; // eslint-disable-line no-unused-vars
+import { CSSObject } from '@emotion/serialize';
+import { ReactNode, useState } from 'react';
+import CodeSandboxer, { GitInfo } from 'react-codesandboxer';
+import { CodeBlock } from './markdown/renderer';
+import pkg from '../packages/react-select/package.json';
+import { defaultTheme } from 'react-select';
+import Svg, { SvgProps } from './Svg';
+
+const { colors } = defaultTheme;
+
+const gitInfo: GitInfo = {
+ account: 'JedWatson',
+ repository: 'react-select',
+ branch: 'master',
+ host: 'github',
+};
+
+const sourceUrl = `https://github.com/${gitInfo.account}/react-select/tree/${gitInfo.branch}`;
+
+interface Props {
+ children?: ReactNode;
+ readonly label: string;
+ readonly raw: { readonly default: string };
+ readonly urlPath: string;
+ readonly isEditable?: boolean;
+}
+
+export default ({
+ children,
+ label,
+ raw,
+ urlPath,
+ isEditable = true,
+}: Props) => {
+ const [showCode, setShowCode] = useState(false);
+
+ return (
+
+
+ {label}
+
+ {raw ? (
+ setShowCode((prev) => !prev)}
+ title="View Source"
+ >
+
+
+ ) : (
+
+
+
+ )}
+ {isEditable ? (
+
+ {({ isLoading }) => (
+
+ {isLoading ? : }
+
+ )}
+
+ ) : null}
+
+
+ {showCode && raw ? (
+
+ ) : null}
+ {children}
+
+ );
+};
+
+const ExampleHeading = (props: any) => (
+ h4': {
+ margin: 0,
+ },
+ }}
+ {...props}
+ />
+);
+
+// ==============================
+// Source & Sandbox Actions
+// ==============================
+
+const SourceIcon = (props: Omit
) => (
+
+ Source Code Icon
+
+
+);
+const NewWindowIcon = (props: Omit) => (
+
+ New Window Icon
+
+
+);
+
+const actionCSS: CSSObject = {
+ alignItems: 'center',
+ background: 0,
+ border: 0,
+ borderRadius: 3,
+ boxSizing: 'border-box',
+ color: colors.neutral40,
+ cursor: 'pointer',
+ display: 'flex',
+ fontSize: 'inherit',
+ height: 24,
+ marginLeft: 2,
+ justifyContent: 'center',
+ position: 'relative',
+ transition: 'background-color 150ms, box-shadow 150ms, color 150ms',
+ width: 30,
+
+ ':hover': {
+ backgroundColor: colors.neutral5,
+ outline: 0,
+ },
+ ':active': {
+ backgroundColor: colors.neutral10,
+ bottom: -1,
+ },
+};
+
+interface ActionProps {
+ readonly css?: CSSObject;
+}
+const ButtonAction = ({
+ css,
+ ...props
+}: ActionProps & Omit) => {
+ return (
+
+ );
+};
+const AAction = ({
+ css,
+ ...props
+}: ActionProps & Omit) => {
+ return (
+
+ );
+};
+
+const Actions = (props: JSX.IntrinsicElements['div']) => (
+
+);
+
+// ==============================
+// Spinner
+// ==============================
+
+const Spinner = () => {
+ const offset = 187;
+ const duration = '1.4s';
+ const size = 16;
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/docs/NoMatch.tsx b/docs/NoMatch.tsx
new file mode 100644
index 0000000000..f33a9f6af4
--- /dev/null
+++ b/docs/NoMatch.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { H1 } from './styled-components';
+
+export default function NoMatch() {
+ return (
+
+
Oops!
+
Couldn't find this page.
+
Back home
+
+ );
+}
diff --git a/docs/PropTypes/Async.ts b/docs/PropTypes/Async.ts
new file mode 100644
index 0000000000..c59b00f00f
--- /dev/null
+++ b/docs/PropTypes/Async.ts
@@ -0,0 +1 @@
+export { AsyncAdditionalProps } from 'react-select/src/useAsync';
diff --git a/docs/PropTypes/Creatable.ts b/docs/PropTypes/Creatable.ts
new file mode 100644
index 0000000000..b57319889f
--- /dev/null
+++ b/docs/PropTypes/Creatable.ts
@@ -0,0 +1 @@
+export { CreatableAdditionalProps } from 'react-select/src/useCreatable';
diff --git a/docs/PropTypes/Select.ts b/docs/PropTypes/Select.ts
new file mode 100644
index 0000000000..0c8fd9fa64
--- /dev/null
+++ b/docs/PropTypes/Select.ts
@@ -0,0 +1,10 @@
+import { Component } from 'react';
+
+import { Props, defaultProps } from 'react-select/src/Select';
+import { GroupBase } from 'react-select';
+
+export default class Select extends Component<
+ Props>
+> {
+ defaultProps = defaultProps;
+}
diff --git a/docs/PropTypes/components/ClearIndicator.ts b/docs/PropTypes/components/ClearIndicator.ts
new file mode 100644
index 0000000000..d3c9fb1520
--- /dev/null
+++ b/docs/PropTypes/components/ClearIndicator.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, ClearIndicatorProps } from 'react-select';
+
+export default class ClearIndicator<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Control.ts b/docs/PropTypes/components/Control.ts
new file mode 100644
index 0000000000..d7331715c9
--- /dev/null
+++ b/docs/PropTypes/components/Control.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { ControlProps, GroupBase } from 'react-select';
+
+export default class Control<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/DropdownIndicator.ts b/docs/PropTypes/components/DropdownIndicator.ts
new file mode 100644
index 0000000000..b1a7812854
--- /dev/null
+++ b/docs/PropTypes/components/DropdownIndicator.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, DropdownIndicatorProps } from 'react-select';
+
+export default class DropdownIndicator<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Group.ts b/docs/PropTypes/components/Group.ts
new file mode 100644
index 0000000000..def9bedb9c
--- /dev/null
+++ b/docs/PropTypes/components/Group.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, GroupProps } from 'react-select';
+
+export default class Group<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/IndicatorsContainer.ts b/docs/PropTypes/components/IndicatorsContainer.ts
new file mode 100644
index 0000000000..9a2db0badd
--- /dev/null
+++ b/docs/PropTypes/components/IndicatorsContainer.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, IndicatorsContainerProps } from 'react-select';
+
+export default class IndicatorsContainer<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/IndicatorsSeparator.ts b/docs/PropTypes/components/IndicatorsSeparator.ts
new file mode 100644
index 0000000000..7d9897affb
--- /dev/null
+++ b/docs/PropTypes/components/IndicatorsSeparator.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { DropdownIndicatorProps, GroupBase } from 'react-select';
+
+export default class DropdownIndicator<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Input.ts b/docs/PropTypes/components/Input.ts
new file mode 100644
index 0000000000..0022ab711f
--- /dev/null
+++ b/docs/PropTypes/components/Input.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, InputProps } from 'react-select';
+
+export default class Input<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/LoadingIndicator.ts b/docs/PropTypes/components/LoadingIndicator.ts
new file mode 100644
index 0000000000..1c09686f60
--- /dev/null
+++ b/docs/PropTypes/components/LoadingIndicator.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, LoadingIndicatorProps } from 'react-select';
+
+export default class LoadingIndicator<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/LoadingMessage.ts b/docs/PropTypes/components/LoadingMessage.ts
new file mode 100644
index 0000000000..8dac6d7fd0
--- /dev/null
+++ b/docs/PropTypes/components/LoadingMessage.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, NoticeProps } from 'react-select';
+
+export default class LoadingMessage<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Menu.ts b/docs/PropTypes/components/Menu.ts
new file mode 100644
index 0000000000..b884e22870
--- /dev/null
+++ b/docs/PropTypes/components/Menu.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MenuProps } from 'react-select';
+
+export default class Menu<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/MenuList.ts b/docs/PropTypes/components/MenuList.ts
new file mode 100644
index 0000000000..3dd4f0923c
--- /dev/null
+++ b/docs/PropTypes/components/MenuList.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MenuListProps } from 'react-select';
+
+export default class MenuList<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/MultiValue.ts b/docs/PropTypes/components/MultiValue.ts
new file mode 100644
index 0000000000..8dc9ac59e3
--- /dev/null
+++ b/docs/PropTypes/components/MultiValue.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MultiValueProps } from 'react-select';
+
+export default class MultiValue<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/MultiValueContainer.ts b/docs/PropTypes/components/MultiValueContainer.ts
new file mode 100644
index 0000000000..8b42e54deb
--- /dev/null
+++ b/docs/PropTypes/components/MultiValueContainer.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MultiValueGenericProps } from 'react-select';
+
+export default class MultiValueContainer<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/MultiValueLabel.ts b/docs/PropTypes/components/MultiValueLabel.ts
new file mode 100644
index 0000000000..979bc31c5e
--- /dev/null
+++ b/docs/PropTypes/components/MultiValueLabel.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MultiValueGenericProps } from 'react-select';
+
+export default class MultiValueLabel<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/MultiValueRemove.ts b/docs/PropTypes/components/MultiValueRemove.ts
new file mode 100644
index 0000000000..d51c97ce24
--- /dev/null
+++ b/docs/PropTypes/components/MultiValueRemove.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, MultiValueGenericProps } from 'react-select';
+
+export default class MultiValueRemove<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/NoOptionsMessage.ts b/docs/PropTypes/components/NoOptionsMessage.ts
new file mode 100644
index 0000000000..64c66dffc0
--- /dev/null
+++ b/docs/PropTypes/components/NoOptionsMessage.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, NoticeProps } from 'react-select';
+
+export default class NoOptionsMessage<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Option.ts b/docs/PropTypes/components/Option.ts
new file mode 100644
index 0000000000..4b2b638f53
--- /dev/null
+++ b/docs/PropTypes/components/Option.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, OptionProps } from 'react-select';
+
+export default class Option<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/Placeholder.ts b/docs/PropTypes/components/Placeholder.ts
new file mode 100644
index 0000000000..b4344609a1
--- /dev/null
+++ b/docs/PropTypes/components/Placeholder.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, PlaceholderProps } from 'react-select';
+
+export default class Placeholder<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/SelectContainer.ts b/docs/PropTypes/components/SelectContainer.ts
new file mode 100644
index 0000000000..a33f17f266
--- /dev/null
+++ b/docs/PropTypes/components/SelectContainer.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { ContainerProps, GroupBase } from 'react-select';
+
+export default class SelectContainer<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/SingleValue.ts b/docs/PropTypes/components/SingleValue.ts
new file mode 100644
index 0000000000..39c6a34531
--- /dev/null
+++ b/docs/PropTypes/components/SingleValue.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, SingleValueProps } from 'react-select';
+
+export default class SingleValue<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/components/ValueContainer.ts b/docs/PropTypes/components/ValueContainer.ts
new file mode 100644
index 0000000000..9aa6bd27c3
--- /dev/null
+++ b/docs/PropTypes/components/ValueContainer.ts
@@ -0,0 +1,8 @@
+import { Component } from 'react';
+import { GroupBase, ValueContainerProps } from 'react-select';
+
+export default class ValueContainer<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends Component> {}
diff --git a/docs/PropTypes/stateManager.ts b/docs/PropTypes/stateManager.ts
new file mode 100644
index 0000000000..bbb152e3d7
--- /dev/null
+++ b/docs/PropTypes/stateManager.ts
@@ -0,0 +1 @@
+export { StateManagerAdditionalProps } from 'react-select/src/useStateManager';
diff --git a/docs/Svg.tsx b/docs/Svg.tsx
new file mode 100644
index 0000000000..6af51ede43
--- /dev/null
+++ b/docs/Svg.tsx
@@ -0,0 +1,25 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react';
+
+export type SvgProps = { readonly size: number } & JSX.IntrinsicElements['svg'];
+
+const Svg = ({ size, ...props }: SvgProps) => (
+
+);
+
+export default Svg;
diff --git a/docs/Table.tsx b/docs/Table.tsx
new file mode 100644
index 0000000000..33ae3b2675
--- /dev/null
+++ b/docs/Table.tsx
@@ -0,0 +1,40 @@
+/** @jsx jsx */
+import { FunctionComponent } from 'react';
+import { jsx } from '@emotion/react';
+
+export const Table: FunctionComponent = ({ children }) => (
+
+);
+
+export const Header: FunctionComponent = ({ children }) => (
+
+ {children}
+
+);
+
+export const Cell: FunctionComponent = ({ children }) => (
+
+ {children}
+
+);
diff --git a/docs/Tests.tsx b/docs/Tests.tsx
new file mode 100644
index 0000000000..58daf08939
--- /dev/null
+++ b/docs/Tests.tsx
@@ -0,0 +1,240 @@
+import React, {
+ ChangeEventHandler,
+ ComponentProps,
+ ComponentType,
+ useState,
+} from 'react';
+
+import Select, { MenuPlacement } from 'react-select';
+import { H1, Note } from './styled-components';
+import { colourOptions, groupedOptions, optionLength } from './data';
+
+import * as animatedComponents from 'react-select/animated';
+
+interface SuiteProps {
+ readonly selectComponent: ComponentType>;
+ readonly idSuffix: string;
+}
+
+const AnimatedSelect = (props: ComponentProps) => (
+
+);
+
+const TestSuite = ({ selectComponent: SelectComp, idSuffix }: SuiteProps) => {
+ const [isDisabled, setIsDisabled] = useState(false);
+ const [isFixed, setIsFixed] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [escapeClearsValue, setEscapeClearsValue] = useState(false);
+ const [portalPlacement, setPortalPlacement] = useState('top');
+ const [blockScroll, setBlockScroll] = useState(true);
+ const toggleDisabled = () => {
+ setIsDisabled((state) => !state);
+ };
+ const toggleLoading = () => {
+ setIsLoading((state) => !state);
+ };
+ const toggleScroll = () => {
+ setBlockScroll((state) => !state);
+ };
+ const toggleMode = () => {
+ setIsFixed((state) => !state);
+ };
+ const toggleEscapeClearsValue = () => {
+ setEscapeClearsValue((state) => !state);
+ };
+
+ const setPlacement: ChangeEventHandler = ({
+ currentTarget,
+ }) => {
+ const newPortalPlacement =
+ currentTarget && (currentTarget.value as MenuPlacement);
+ setPortalPlacement(newPortalPlacement);
+ };
+
+ const menuPortalTarget = !isFixed ? document.body : null;
+
+ return (
+
+
+ ({ ...base, zIndex: 999 }),
+ }}
+ isDisabled={isDisabled}
+ isLoading={isLoading}
+ options={colourOptions}
+ />
+
+
+ Disabled
+
+
+
+ Loading
+
+
+
+
Grouped
+
+
+
+
+
Clearable
+
+
+
+
+ escapeClearsValue
+
+
+
+
Portalled
+
+
+
{'overflow: hidden; position: absolute;'}
+
+
+
+ auto
+ bottom
+ top
+
+
+
+
+ Fixed
+
+
+
+ Portal
+
+
+
+ Block Scroll
+
+
+
+
+ );
+};
+
+export default function Tests() {
+ return (
+
+
Test Page for Cypress
+
Single Select
+
+
Animated components
+
+
Multi Select
+
+
+
+
+
Long Values
+
+
+
+
+ );
+}
diff --git a/docs/_redirects b/docs/_redirects
new file mode 100644
index 0000000000..ad37e2c2c9
--- /dev/null
+++ b/docs/_redirects
@@ -0,0 +1 @@
+/* /index.html 200
diff --git a/docs/data.ts b/docs/data.ts
new file mode 100644
index 0000000000..27b21fc6fe
--- /dev/null
+++ b/docs/data.ts
@@ -0,0 +1,142 @@
+export interface ColourOption {
+ readonly value: string;
+ readonly label: string;
+ readonly color: string;
+ readonly isFixed?: boolean;
+ readonly isDisabled?: boolean;
+}
+
+export const colourOptions: readonly ColourOption[] = [
+ { value: 'ocean', label: 'Ocean', color: '#00B8D9', isFixed: true },
+ { value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true },
+ { value: 'purple', label: 'Purple', color: '#5243AA' },
+ { value: 'red', label: 'Red', color: '#FF5630', isFixed: true },
+ { value: 'orange', label: 'Orange', color: '#FF8B00' },
+ { value: 'yellow', label: 'Yellow', color: '#FFC400' },
+ { value: 'green', label: 'Green', color: '#36B37E' },
+ { value: 'forest', label: 'Forest', color: '#00875A' },
+ { value: 'slate', label: 'Slate', color: '#253858' },
+ { value: 'silver', label: 'Silver', color: '#666666' },
+];
+
+export interface FlavourOption {
+ readonly value: string;
+ readonly label: string;
+ readonly rating: string;
+}
+
+export const flavourOptions: readonly FlavourOption[] = [
+ { value: 'vanilla', label: 'Vanilla', rating: 'safe' },
+ { value: 'chocolate', label: 'Chocolate', rating: 'good' },
+ { value: 'strawberry', label: 'Strawberry', rating: 'wild' },
+ { value: 'salted-caramel', label: 'Salted Caramel', rating: 'crazy' },
+];
+
+export interface StateOption {
+ readonly value: string;
+ readonly label: string;
+}
+
+export const stateOptions: readonly StateOption[] = [
+ { value: 'AL', label: 'Alabama' },
+ { value: 'AK', label: 'Alaska' },
+ { value: 'AS', label: 'American Samoa' },
+ { value: 'AZ', label: 'Arizona' },
+ { value: 'AR', label: 'Arkansas' },
+ { value: 'CA', label: 'California' },
+ { value: 'CO', label: 'Colorado' },
+ { value: 'CT', label: 'Connecticut' },
+ { value: 'DE', label: 'Delaware' },
+ { value: 'DC', label: 'District Of Columbia' },
+ { value: 'FM', label: 'Federated States Of Micronesia' },
+ { value: 'FL', label: 'Florida' },
+ { value: 'GA', label: 'Georgia' },
+ { value: 'GU', label: 'Guam' },
+ { value: 'HI', label: 'Hawaii' },
+ { value: 'ID', label: 'Idaho' },
+ { value: 'IL', label: 'Illinois' },
+ { value: 'IN', label: 'Indiana' },
+ { value: 'IA', label: 'Iowa' },
+ { value: 'KS', label: 'Kansas' },
+ { value: 'KY', label: 'Kentucky' },
+ { value: 'LA', label: 'Louisiana' },
+ { value: 'ME', label: 'Maine' },
+ { value: 'MH', label: 'Marshall Islands' },
+ { value: 'MD', label: 'Maryland' },
+ { value: 'MA', label: 'Massachusetts' },
+ { value: 'MI', label: 'Michigan' },
+ { value: 'MN', label: 'Minnesota' },
+ { value: 'MS', label: 'Mississippi' },
+ { value: 'MO', label: 'Missouri' },
+ { value: 'MT', label: 'Montana' },
+ { value: 'NE', label: 'Nebraska' },
+ { value: 'NV', label: 'Nevada' },
+ { value: 'NH', label: 'New Hampshire' },
+ { value: 'NJ', label: 'New Jersey' },
+ { value: 'NM', label: 'New Mexico' },
+ { value: 'NY', label: 'New York' },
+ { value: 'NC', label: 'North Carolina' },
+ { value: 'ND', label: 'North Dakota' },
+ { value: 'MP', label: 'Northern Mariana Islands' },
+ { value: 'OH', label: 'Ohio' },
+ { value: 'OK', label: 'Oklahoma' },
+ { value: 'OR', label: 'Oregon' },
+ { value: 'PW', label: 'Palau' },
+ { value: 'PA', label: 'Pennsylvania' },
+ { value: 'PR', label: 'Puerto Rico' },
+ { value: 'RI', label: 'Rhode Island' },
+ { value: 'SC', label: 'South Carolina' },
+ { value: 'SD', label: 'South Dakota' },
+ { value: 'TN', label: 'Tennessee' },
+ { value: 'TX', label: 'Texas' },
+ { value: 'UT', label: 'Utah' },
+ { value: 'VT', label: 'Vermont' },
+ { value: 'VI', label: 'Virgin Islands' },
+ { value: 'VA', label: 'Virginia' },
+ { value: 'WA', label: 'Washington' },
+ { value: 'WV', label: 'West Virginia' },
+ { value: 'WI', label: 'Wisconsin' },
+ { value: 'WY', label: 'Wyoming' },
+];
+
+export const optionLength = [
+ { value: 1, label: 'general' },
+ {
+ value: 2,
+ label:
+ 'Evil is the moment when I lack the strength to be true to the Good that compels me.',
+ },
+ {
+ value: 3,
+ label:
+ "It is now an easy matter to spell out the ethic of a truth: 'Do all that you can to persevere in that which exceeds your perseverance. Persevere in the interruption. Seize in your being that which has seized and broken you.",
+ },
+];
+
+export const dogOptions = [
+ { id: 1, label: 'Chihuahua' },
+ { id: 2, label: 'Bulldog' },
+ { id: 3, label: 'Dachshund' },
+ { id: 4, label: 'Akita' },
+];
+
+// let bigOptions = [];
+// for (let i = 0; i < 10000; i++) {
+// bigOptions = bigOptions.concat(colourOptions);
+// }
+
+export interface GroupedOption {
+ readonly label: string;
+ readonly options: readonly ColourOption[] | readonly FlavourOption[];
+}
+
+export const groupedOptions: readonly GroupedOption[] = [
+ {
+ label: 'Colours',
+ options: colourOptions,
+ },
+ {
+ label: 'Flavours',
+ options: flavourOptions,
+ },
+];
diff --git a/docs/examples/AccessingInternals.tsx b/docs/examples/AccessingInternals.tsx
new file mode 100644
index 0000000000..ef314c85a4
--- /dev/null
+++ b/docs/examples/AccessingInternals.tsx
@@ -0,0 +1,106 @@
+import React, { Fragment, useRef } from 'react';
+
+import Select, { SelectInstance } from 'react-select';
+import AsyncSelect from 'react-select/async';
+import CreatableSelect from 'react-select/creatable';
+
+import { Note } from '../styled-components';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+export default function AccessingInternals() {
+ const selectRef = useRef | null>(null);
+ const asyncRef = useRef | null>(null);
+ const creatableRef = useRef | null>(null);
+
+ // Focus handlers
+ const focus = () => {
+ console.log(selectRef);
+ selectRef.current?.focus();
+ };
+ const focusAsync = () => {
+ console.log(asyncRef);
+ asyncRef.current?.focus();
+ };
+ const focusCreatable = () => {
+ console.log(creatableRef);
+ creatableRef.current?.focus();
+ };
+
+ // Blur handlers
+ const blur = () => {
+ selectRef.current?.blur();
+ };
+ const blurAsync = () => {
+ asyncRef.current?.blur();
+ };
+ const blurCreatable = () => {
+ creatableRef.current?.blur();
+ };
+
+ return (
+
+ Creatable Select
+
+
+
+ Focus
+
+
+
+
+ Blur
+
+
+ Async Select
+
+
+
+ Focus
+
+
+
+
+ Blur
+
+
+ Select
+
+
+
+ Focus
+
+
+
+
+ Blur
+
+
+
+ );
+}
diff --git a/docs/examples/AnimatedMulti.tsx b/docs/examples/AnimatedMulti.tsx
new file mode 100644
index 0000000000..4444f26df7
--- /dev/null
+++ b/docs/examples/AnimatedMulti.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import Select from 'react-select';
+import makeAnimated from 'react-select/animated';
+import { colourOptions } from '../data';
+
+const animatedComponents = makeAnimated();
+
+export default function AnimatedMulti() {
+ return (
+
+ );
+}
diff --git a/docs/examples/AsyncCallbacks.tsx b/docs/examples/AsyncCallbacks.tsx
new file mode 100644
index 0000000000..69f40cbd99
--- /dev/null
+++ b/docs/examples/AsyncCallbacks.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+
+import AsyncSelect from 'react-select/async';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const loadOptions = (
+ inputValue: string,
+ callback: (options: ColourOption[]) => void
+) => {
+ setTimeout(() => {
+ callback(filterColors(inputValue));
+ }, 1000);
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/AsyncCreatable.tsx b/docs/examples/AsyncCreatable.tsx
new file mode 100644
index 0000000000..50d440c15f
--- /dev/null
+++ b/docs/examples/AsyncCreatable.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+
+import AsyncCreatableSelect from 'react-select/async-creatable';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+export default () => (
+
+);
diff --git a/docs/examples/AsyncMulti.tsx b/docs/examples/AsyncMulti.tsx
new file mode 100644
index 0000000000..e58d197861
--- /dev/null
+++ b/docs/examples/AsyncMulti.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+
+import AsyncSelect from 'react-select/async';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+export default () => (
+
+);
diff --git a/docs/examples/AsyncPromises.tsx b/docs/examples/AsyncPromises.tsx
new file mode 100644
index 0000000000..afca61dcf3
--- /dev/null
+++ b/docs/examples/AsyncPromises.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+
+import AsyncSelect from 'react-select/async';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+export default () => (
+
+);
diff --git a/docs/examples/BasicGrouped.tsx b/docs/examples/BasicGrouped.tsx
new file mode 100644
index 0000000000..8fd7194ef4
--- /dev/null
+++ b/docs/examples/BasicGrouped.tsx
@@ -0,0 +1,43 @@
+import React, { CSSProperties } from 'react';
+
+import Select from 'react-select';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ GroupedOption,
+ groupedOptions,
+} from '../data';
+
+const groupStyles = {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+};
+const groupBadgeStyles: CSSProperties = {
+ backgroundColor: '#EBECF0',
+ borderRadius: '2em',
+ color: '#172B4D',
+ display: 'inline-block',
+ fontSize: 12,
+ fontWeight: 'normal',
+ lineHeight: '1',
+ minWidth: 1,
+ padding: '0.16666666666667em 0.5em',
+ textAlign: 'center',
+};
+
+const formatGroupLabel = (data: GroupedOption) => (
+
+ {data.label}
+ {data.options.length}
+
+);
+
+export default () => (
+
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ formatGroupLabel={formatGroupLabel}
+ />
+);
diff --git a/docs/examples/BasicMulti.tsx b/docs/examples/BasicMulti.tsx
new file mode 100644
index 0000000000..9cc30d6d43
--- /dev/null
+++ b/docs/examples/BasicMulti.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import Select from 'react-select';
+import { colourOptions } from '../data';
+
+export default () => (
+
+);
diff --git a/docs/examples/BasicSingle.tsx b/docs/examples/BasicSingle.tsx
new file mode 100644
index 0000000000..872b56c330
--- /dev/null
+++ b/docs/examples/BasicSingle.tsx
@@ -0,0 +1,74 @@
+import React, { useState } from 'react';
+
+import Select from 'react-select';
+import { colourOptions } from '../data';
+
+const Checkbox = ({ children, ...props }: JSX.IntrinsicElements['input']) => (
+
+
+ {children}
+
+);
+
+export default () => {
+ const [isClearable, setIsClearable] = useState(true);
+ const [isSearchable, setIsSearchable] = useState(true);
+ const [isDisabled, setIsDisabled] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isRtl, setIsRtl] = useState(false);
+
+ return (
+ <>
+
+
+
+ setIsClearable((state) => !state)}
+ >
+ Clearable
+
+ setIsSearchable((state) => !state)}
+ >
+ Searchable
+
+ setIsDisabled((state) => !state)}
+ >
+ Disabled
+
+ setIsLoading((state) => !state)}
+ >
+ Loading
+
+ setIsRtl((state) => !state)}>
+ RTL
+
+
+ >
+ );
+};
diff --git a/docs/examples/ControlledMenu.tsx b/docs/examples/ControlledMenu.tsx
new file mode 100644
index 0000000000..a17f8095c6
--- /dev/null
+++ b/docs/examples/ControlledMenu.tsx
@@ -0,0 +1,44 @@
+import React, { useRef, useState } from 'react';
+
+import Select, { SelectInstance } from 'react-select';
+import { colourOptions } from '../data';
+import { Note } from '../styled-components';
+
+const Checkbox = (props: JSX.IntrinsicElements['input']) => (
+
+);
+
+export default () => {
+ const ref = useRef(null);
+ const [menuIsOpen, setMenuIsOpen] = useState(false);
+
+ const toggleMenuIsOpen = () => {
+ setMenuIsOpen((value) => !value);
+ const selectEl = ref.current;
+ if (!selectEl) return;
+ if (menuIsOpen) selectEl.blur();
+ else selectEl.focus();
+ };
+
+ return (
+ <>
+ ({ ...base, position: 'relative' }) }}
+ name="color"
+ options={colourOptions}
+ />
+
+
+ menuIsOpen
+
+ >
+ );
+};
diff --git a/docs/examples/CreatableAdvanced.tsx b/docs/examples/CreatableAdvanced.tsx
new file mode 100644
index 0000000000..1deb68aa27
--- /dev/null
+++ b/docs/examples/CreatableAdvanced.tsx
@@ -0,0 +1,47 @@
+import React, { useState } from 'react';
+
+import CreatableSelect from 'react-select/creatable';
+
+interface Option {
+ readonly label: string;
+ readonly value: string;
+}
+
+const createOption = (label: string) => ({
+ label,
+ value: label.toLowerCase().replace(/\W/g, ''),
+});
+
+const defaultOptions = [
+ createOption('One'),
+ createOption('Two'),
+ createOption('Three'),
+];
+
+export default () => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [options, setOptions] = useState(defaultOptions);
+ const [value, setValue] = useState();
+
+ const handleCreate = (inputValue: string) => {
+ setIsLoading(true);
+ setTimeout(() => {
+ const newOption = createOption(inputValue);
+ setIsLoading(false);
+ setOptions((prev) => [...prev, newOption]);
+ setValue(newOption);
+ }, 1000);
+ };
+
+ return (
+ setValue(newValue)}
+ onCreateOption={handleCreate}
+ options={options}
+ value={value}
+ />
+ );
+};
diff --git a/docs/examples/CreatableInputOnly.tsx b/docs/examples/CreatableInputOnly.tsx
new file mode 100644
index 0000000000..6c7a28269b
--- /dev/null
+++ b/docs/examples/CreatableInputOnly.tsx
@@ -0,0 +1,48 @@
+import React, { KeyboardEventHandler } from 'react';
+
+import CreatableSelect from 'react-select/creatable';
+
+const components = {
+ DropdownIndicator: null,
+};
+
+interface Option {
+ readonly label: string;
+ readonly value: string;
+}
+
+const createOption = (label: string) => ({
+ label,
+ value: label,
+});
+
+export default () => {
+ const [inputValue, setInputValue] = React.useState('');
+ const [value, setValue] = React.useState([]);
+
+ const handleKeyDown: KeyboardEventHandler = (event) => {
+ if (!inputValue) return;
+ switch (event.key) {
+ case 'Enter':
+ case 'Tab':
+ setValue((prev) => [...prev, createOption(inputValue)]);
+ setInputValue('');
+ event.preventDefault();
+ }
+ };
+
+ return (
+ setValue(newValue)}
+ onInputChange={(newValue) => setInputValue(newValue)}
+ onKeyDown={handleKeyDown}
+ placeholder="Type something and press enter..."
+ value={value}
+ />
+ );
+};
diff --git a/docs/examples/CreatableMulti.tsx b/docs/examples/CreatableMulti.tsx
new file mode 100644
index 0000000000..4b75dc26f0
--- /dev/null
+++ b/docs/examples/CreatableMulti.tsx
@@ -0,0 +1,6 @@
+import React from 'react';
+
+import CreatableSelect from 'react-select/creatable';
+import { colourOptions } from '../data';
+
+export default () => ;
diff --git a/docs/examples/CreatableSingle.tsx b/docs/examples/CreatableSingle.tsx
new file mode 100644
index 0000000000..f03bab8059
--- /dev/null
+++ b/docs/examples/CreatableSingle.tsx
@@ -0,0 +1,6 @@
+import React from 'react';
+
+import CreatableSelect from 'react-select/creatable';
+import { colourOptions } from '../data';
+
+export default () => ;
diff --git a/docs/examples/CreateFilter.tsx b/docs/examples/CreateFilter.tsx
new file mode 100644
index 0000000000..4d6513a4de
--- /dev/null
+++ b/docs/examples/CreateFilter.tsx
@@ -0,0 +1,67 @@
+import React, { useState } from 'react';
+import Select, { createFilter } from 'react-select';
+import { colourOptions } from '../data';
+import { Note } from '../styled-components';
+
+const Checkbox = (props: JSX.IntrinsicElements['input']) => (
+
+);
+
+export default () => {
+ const [ignoreCase, setIgnoreCase] = useState(false);
+ const [ignoreAccents, setIgnoreAccents] = useState(false);
+ const [trim, setTrim] = useState(false);
+ const [matchFromStart, setMatchFromStart] = useState(false);
+
+ const filterConfig = {
+ ignoreCase,
+ ignoreAccents,
+ trim,
+ matchFrom: matchFromStart ? ('start' as const) : ('any' as const),
+ };
+
+ return (
+ <>
+
+
+ setIgnoreCase((prev) => !prev)}
+ id="cypress-single__clearable-checkbox"
+ />
+ Ignore Case
+
+
+ setIgnoreAccents((prev) => !prev)}
+ id="cypress-single__clearable-checkbox"
+ />
+ Ignore Accents
+
+
+ setTrim((prev) => !prev)}
+ id="cypress-single__clearable-checkbox"
+ />
+ Trim
+
+
+ setMatchFromStart((prev) => !prev)}
+ id="cypress-single__clearable-checkbox"
+ />
+ Match from the start
+
+ >
+ );
+};
diff --git a/docs/examples/CustomAriaLive.tsx b/docs/examples/CustomAriaLive.tsx
new file mode 100644
index 0000000000..582b6a94e1
--- /dev/null
+++ b/docs/examples/CustomAriaLive.tsx
@@ -0,0 +1,57 @@
+import React, { CSSProperties, useState } from 'react';
+
+import Select, { AriaOnFocus } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+export default function CustomAriaLive() {
+ const [ariaFocusMessage, setAriaFocusMessage] = useState('');
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+ const style: { [key: string]: CSSProperties } = {
+ blockquote: {
+ fontStyle: 'italic',
+ fontSize: '.75rem',
+ margin: '1rem 0',
+ },
+ label: {
+ fontSize: '.75rem',
+ fontWeight: 'bold',
+ lineHeight: 2,
+ },
+ };
+
+ const onFocus: AriaOnFocus = ({ focused, isDisabled }) => {
+ const msg = `You are currently focused on option ${focused.label}${
+ isDisabled ? ', disabled' : ''
+ }`;
+ setAriaFocusMessage(msg);
+ return msg;
+ };
+
+ const onMenuOpen = () => setIsMenuOpen(true);
+ const onMenuClose = () => setIsMenuOpen(false);
+
+ return (
+
+ );
+}
diff --git a/docs/examples/CustomClearIndicator.tsx b/docs/examples/CustomClearIndicator.tsx
new file mode 100644
index 0000000000..f1b66c35ad
--- /dev/null
+++ b/docs/examples/CustomClearIndicator.tsx
@@ -0,0 +1,45 @@
+import React, { CSSProperties, FunctionComponent } from 'react';
+
+import Select, { ClearIndicatorProps } from 'react-select';
+import { CSSObject } from '@emotion/serialize';
+import { ColourOption, colourOptions } from '../data';
+
+const CustomClearText: FunctionComponent = () => <>clear all>;
+const ClearIndicator = (props: ClearIndicatorProps) => {
+ const {
+ children = ,
+ getStyles,
+ innerProps: { ref, ...restInnerProps },
+ } = props;
+ return (
+
+ );
+};
+
+const ClearIndicatorStyles = (
+ base: CSSObject,
+ state: ClearIndicatorProps
+): CSSObject => ({
+ ...base,
+ cursor: 'pointer',
+ color: state.isFocused ? 'blue' : 'black',
+});
+
+export default function CustomClearIndicator() {
+ return (
+
+ );
+}
diff --git a/docs/examples/CustomControl.tsx b/docs/examples/CustomControl.tsx
new file mode 100644
index 0000000000..1f1783983f
--- /dev/null
+++ b/docs/examples/CustomControl.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+
+import Select, { components, ControlProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+const controlStyles = {
+ border: '1px solid black',
+ padding: '5px',
+ background: colourOptions[2].color,
+ color: 'white',
+};
+
+const ControlComponent = (props: ControlProps) => (
+
+);
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomDropdownIndicator.tsx b/docs/examples/CustomDropdownIndicator.tsx
new file mode 100644
index 0000000000..cb1d3f9ecc
--- /dev/null
+++ b/docs/examples/CustomDropdownIndicator.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import EmojiIcon from '@atlaskit/icon/glyph/emoji';
+import Select, { components, DropdownIndicatorProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const DropdownIndicator = (
+ props: DropdownIndicatorProps
+) => {
+ return (
+
+
+
+ );
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomFilterOptions.tsx b/docs/examples/CustomFilterOptions.tsx
new file mode 100644
index 0000000000..14225da741
--- /dev/null
+++ b/docs/examples/CustomFilterOptions.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import Select from 'react-select';
+import { colourOptions } from '../data';
+
+const filterOptions = (
+ candidate: { label: string; value: string; data: any },
+ input: string
+) => {
+ if (input) {
+ return candidate.value === customOptions[0].value;
+ }
+ return true;
+};
+
+const customOptions = [
+ {
+ value: 'custom',
+ label: 'Using a custom filter to always display this option on search',
+ },
+ ...colourOptions,
+];
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomGetOptionLabel.tsx b/docs/examples/CustomGetOptionLabel.tsx
new file mode 100644
index 0000000000..2ddf3783b5
--- /dev/null
+++ b/docs/examples/CustomGetOptionLabel.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import Select from 'react-select';
+import { flavourOptions } from '../data';
+
+export default () => (
+ <>
+
+ Composing a display label from the label property and rating property in
+ the options object
+
+ `${option.label}: ${option.rating}`}
+ />
+ >
+);
diff --git a/docs/examples/CustomGetOptionValue.tsx b/docs/examples/CustomGetOptionValue.tsx
new file mode 100644
index 0000000000..023e6bd9b2
--- /dev/null
+++ b/docs/examples/CustomGetOptionValue.tsx
@@ -0,0 +1,19 @@
+import React, { Fragment } from 'react';
+import Select from 'react-select';
+import { dogOptions } from '../data';
+
+export default function CustomGetOptionValue() {
+ return (
+
+ Using id property, instead of value property.
+ `${option['id']}`}
+ />
+
+ );
+}
diff --git a/docs/examples/CustomGroup.tsx b/docs/examples/CustomGroup.tsx
new file mode 100644
index 0000000000..ea34c21053
--- /dev/null
+++ b/docs/examples/CustomGroup.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+
+import Select, { components, GroupProps } from 'react-select';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ groupedOptions,
+} from '../data';
+
+const groupStyles = {
+ border: `2px dotted ${colourOptions[2].color}`,
+ borderRadius: '5px',
+ background: '#f2fcff',
+};
+
+const Group = (props: GroupProps) => (
+
+
+
+);
+
+export default () => (
+
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ components={{ Group }}
+ />
+);
diff --git a/docs/examples/CustomGroupHeading.tsx b/docs/examples/CustomGroupHeading.tsx
new file mode 100644
index 0000000000..6233b78886
--- /dev/null
+++ b/docs/examples/CustomGroupHeading.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+
+import Select, { components, GroupHeadingProps } from 'react-select';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ groupedOptions,
+} from '../data';
+import EditorPanelIcon from '@atlaskit/icon/glyph/editor/panel';
+import Tooltip from '@atlaskit/tooltip';
+
+const groupStyles = {
+ border: `2px dotted ${colourOptions[2].color}`,
+ color: 'white',
+ background: colourOptions[2].color,
+ padding: '5px 0px',
+ display: 'flex',
+};
+
+const GroupHeading = (
+ props: GroupHeadingProps
+) => (
+
+
+
+
+
+
+);
+
+export default () => (
+
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ components={{ GroupHeading }}
+ styles={{
+ groupHeading: (base) => ({
+ ...base,
+ flex: '1 1',
+ color: 'white',
+ margin: 0,
+ }),
+ }}
+ />
+);
diff --git a/docs/examples/CustomIndicatorSeparator.tsx b/docs/examples/CustomIndicatorSeparator.tsx
new file mode 100644
index 0000000000..f736d3aa3d
--- /dev/null
+++ b/docs/examples/CustomIndicatorSeparator.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import Select, { IndicatorSeparatorProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const indicatorSeparatorStyle = {
+ alignSelf: 'stretch',
+ backgroundColor: colourOptions[2].color,
+ marginBottom: 8,
+ marginTop: 8,
+ width: 1,
+};
+
+const IndicatorSeparator = ({
+ innerProps,
+}: IndicatorSeparatorProps) => {
+ return ;
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomIndicatorsContainer.tsx b/docs/examples/CustomIndicatorsContainer.tsx
new file mode 100644
index 0000000000..11e7877b40
--- /dev/null
+++ b/docs/examples/CustomIndicatorsContainer.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import Select, { components, IndicatorsContainerProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const IndicatorsContainer = (
+ props: IndicatorsContainerProps
+) => {
+ return (
+
+
+
+ );
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomInput.tsx b/docs/examples/CustomInput.tsx
new file mode 100644
index 0000000000..9096dd9d45
--- /dev/null
+++ b/docs/examples/CustomInput.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, InputProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const Input = (props: InputProps) => {
+ if (props.isHidden) {
+ return ;
+ }
+ return (
+
+
+
+
+
+ );
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/CustomIsOptionDisabled.tsx b/docs/examples/CustomIsOptionDisabled.tsx
new file mode 100644
index 0000000000..81834db042
--- /dev/null
+++ b/docs/examples/CustomIsOptionDisabled.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import Select from 'react-select';
+import { flavourOptions } from '../data';
+
+export default () => (
+ <>
+
+ Disable all options that do not have a 'safe' rating, via the
+ isOptionsDisabled fn prop
+
+ option.rating !== 'safe'}
+ />
+ >
+);
diff --git a/docs/examples/CustomLoadingIndicator.tsx b/docs/examples/CustomLoadingIndicator.tsx
new file mode 100644
index 0000000000..868ea7a0fb
--- /dev/null
+++ b/docs/examples/CustomLoadingIndicator.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Spinner from '@atlaskit/spinner';
+import Tooltip from '@atlaskit/tooltip';
+import AsyncSelect from 'react-select/async';
+import { LoadingIndicatorProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const LoadingIndicator = (props: LoadingIndicatorProps) => {
+ return (
+
+
+
+ );
+};
+
+const filterColors = (inputValue: string) =>
+ colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+const CustomLoadingIndicator = () => {
+ return (
+
+ );
+};
+
+export default CustomLoadingIndicator;
diff --git a/docs/examples/CustomLoadingMessage.tsx b/docs/examples/CustomLoadingMessage.tsx
new file mode 100644
index 0000000000..830235c518
--- /dev/null
+++ b/docs/examples/CustomLoadingMessage.tsx
@@ -0,0 +1,50 @@
+import React, { CSSProperties } from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import AsyncSelect from 'react-select/async';
+import { NoticeProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const LoadingMessage = (props: NoticeProps) => {
+ return (
+
+
+ {props.children}
+
+
+ );
+};
+
+const filterColors = (inputValue: string) =>
+ colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+const CustomLoadingMessage = () => {
+ return (
+ ({
+ ...base,
+ backgroundColor: colourOptions[2].color,
+ color: 'white',
+ }),
+ }}
+ components={{ LoadingMessage }}
+ />
+ );
+};
+
+export default CustomLoadingMessage;
diff --git a/docs/examples/CustomMenu.tsx b/docs/examples/CustomMenu.tsx
new file mode 100644
index 0000000000..8147cea939
--- /dev/null
+++ b/docs/examples/CustomMenu.tsx
@@ -0,0 +1,49 @@
+import React, { Fragment } from 'react';
+
+import Select, { components, MenuProps } from 'react-select';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ GroupedOption,
+ groupedOptions,
+} from '../data';
+
+function getLength(
+ options: readonly (GroupedOption | ColourOption | FlavourOption)[]
+): number {
+ return options.reduce((acc, curr) => {
+ if ('options' in curr) return acc + getLength(curr.options);
+ return acc + 1;
+ }, 0);
+}
+
+const menuHeaderStyle = {
+ padding: '8px 12px',
+};
+
+const Menu = (
+ props: MenuProps
+) => {
+ const optionsLength = getLength(props.options);
+ return (
+
+
+ Custom Menu with {optionsLength} options
+
+
+ {...props}
+ >
+ {props.children}
+
+
+ );
+};
+
+export default () => (
+
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ components={{ Menu }}
+ />
+);
diff --git a/docs/examples/CustomMenuList.tsx b/docs/examples/CustomMenuList.tsx
new file mode 100644
index 0000000000..4c43e14a2f
--- /dev/null
+++ b/docs/examples/CustomMenuList.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+
+import Select, { components, MenuListProps } from 'react-select';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ GroupedOption,
+ groupedOptions,
+} from '../data';
+
+const menuHeaderStyle = {
+ padding: '8px 12px',
+ background: colourOptions[2].color,
+ color: 'white',
+};
+
+const MenuList = (
+ props: MenuListProps
+) => {
+ return (
+
+ Custom Menu List
+ {props.children}
+
+ );
+};
+
+export default () => (
+
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ components={{ MenuList }}
+ />
+);
diff --git a/docs/examples/CustomMultiValueContainer.tsx b/docs/examples/CustomMultiValueContainer.tsx
new file mode 100644
index 0000000000..3679ffd644
--- /dev/null
+++ b/docs/examples/CustomMultiValueContainer.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, MultiValueGenericProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const MultiValueContainer = (props: MultiValueGenericProps) => {
+ return (
+
+
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ border: `2px dotted ${colourOptions[2].color}`,
+ }),
+ }}
+ defaultValue={[colourOptions[4], colourOptions[5]]}
+ isMulti
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomMultiValueLabel.tsx b/docs/examples/CustomMultiValueLabel.tsx
new file mode 100644
index 0000000000..061f9d1d60
--- /dev/null
+++ b/docs/examples/CustomMultiValueLabel.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, MultiValueGenericProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const MultiValueLabel = (props: MultiValueGenericProps) => {
+ return (
+
+
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ backgroundColor: colourOptions[2].color,
+ color: 'white',
+ }),
+ }}
+ defaultValue={[colourOptions[4], colourOptions[5]]}
+ isMulti
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomMultiValueRemove.tsx b/docs/examples/CustomMultiValueRemove.tsx
new file mode 100644
index 0000000000..7a3ccd05af
--- /dev/null
+++ b/docs/examples/CustomMultiValueRemove.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import EmojiIcon from '@atlaskit/icon/glyph/emoji';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, MultiValueRemoveProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const MultiValueRemove = (props: MultiValueRemoveProps) => {
+ return (
+
+
+
+
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ border: `1px dotted ${colourOptions[2].color}`,
+ height: '100%',
+ }),
+ }}
+ defaultValue={[colourOptions[4], colourOptions[5]]}
+ isMulti
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomNoOptionsMessage.tsx b/docs/examples/CustomNoOptionsMessage.tsx
new file mode 100644
index 0000000000..d4d18fa4dc
--- /dev/null
+++ b/docs/examples/CustomNoOptionsMessage.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, NoticeProps } from 'react-select';
+import { colourOptions } from '../data';
+
+const msgStyles = {
+ background: colourOptions[2].color,
+ color: 'white',
+};
+
+const NoOptionsMessage = (props: NoticeProps) => {
+ return (
+
+
+
+ );
+};
+
+const CustomNoOptionsMessage = () => {
+ return (
+ ({ ...base, ...msgStyles }) }}
+ isSearchable
+ name="color"
+ options={[]}
+ />
+ );
+};
+
+export default CustomNoOptionsMessage;
diff --git a/docs/examples/CustomOption.tsx b/docs/examples/CustomOption.tsx
new file mode 100644
index 0000000000..6da04c93c6
--- /dev/null
+++ b/docs/examples/CustomOption.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import Tooltip from '@atlaskit/tooltip';
+import Select, { components, OptionProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const Option = (props: OptionProps) => {
+ return (
+
+
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ border: `1px dotted ${colourOptions[2].color}`,
+ height: '100%',
+ }),
+ }}
+ defaultValue={colourOptions[4]}
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomPlaceholder.tsx b/docs/examples/CustomPlaceholder.tsx
new file mode 100644
index 0000000000..5ea556c836
--- /dev/null
+++ b/docs/examples/CustomPlaceholder.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import Select, { components, PlaceholderProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const Placeholder = (props: PlaceholderProps) => {
+ return ;
+};
+
+export default () => (
+ ({
+ ...base,
+ fontSize: '1em',
+ color: colourOptions[2].color,
+ fontWeight: 400,
+ }),
+ }}
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomSelectContainer.tsx b/docs/examples/CustomSelectContainer.tsx
new file mode 100644
index 0000000000..ccb7047e96
--- /dev/null
+++ b/docs/examples/CustomSelectContainer.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import Select, { components, ContainerProps } from 'react-select';
+import Tooltip from '@atlaskit/tooltip';
+import { ColourOption, colourOptions } from '../data';
+
+const SelectContainer = ({
+ children,
+ ...props
+}: ContainerProps) => {
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ backgroundColor: colourOptions[2].color,
+ padding: 5,
+ }),
+ }}
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomSelectProps.tsx b/docs/examples/CustomSelectProps.tsx
new file mode 100644
index 0000000000..98c8ac24f0
--- /dev/null
+++ b/docs/examples/CustomSelectProps.tsx
@@ -0,0 +1,57 @@
+import React, { MouseEventHandler, useState } from 'react';
+import Select, {
+ components,
+ ControlProps,
+ Props,
+ StylesConfig,
+} from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const EMOJIS = ['👍', '🤙', '👏', '👌', '🙌', '✌️', '🖖', '👐'];
+
+const Control = ({ children, ...props }: ControlProps) => {
+ // @ts-ignore
+ const { emoji, onEmojiClick } = props.selectProps;
+ const style = { cursor: 'pointer' };
+
+ return (
+
+
+ {emoji}
+
+ {children}
+
+ );
+};
+
+const CustomSelectProps = (props: Props) => {
+ const [clickCount, setClickCount] = useState(0);
+
+ const onClick: MouseEventHandler = (e) => {
+ setClickCount(clickCount + 1);
+ e.preventDefault();
+ e.stopPropagation();
+ };
+
+ const styles: StylesConfig = {
+ control: (css) => ({ ...css, paddingLeft: '1rem' }),
+ };
+
+ const emoji = EMOJIS[clickCount % EMOJIS.length];
+
+ return (
+
+ );
+};
+
+export default CustomSelectProps;
diff --git a/docs/examples/CustomSingleValue.tsx b/docs/examples/CustomSingleValue.tsx
new file mode 100644
index 0000000000..74bf30bb8b
--- /dev/null
+++ b/docs/examples/CustomSingleValue.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import Select, { components, SingleValueProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const SingleValue = ({
+ children,
+ ...props
+}: SingleValueProps) => (
+ {children}
+);
+
+export default () => (
+ ({
+ ...base,
+ padding: 5,
+ borderRadius: 5,
+ background: colourOptions[2].color,
+ color: 'white',
+ display: 'flex',
+ }),
+ }}
+ components={{ SingleValue }}
+ isSearchable
+ name="color"
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/CustomValueContainer.tsx b/docs/examples/CustomValueContainer.tsx
new file mode 100644
index 0000000000..f8f908bdd3
--- /dev/null
+++ b/docs/examples/CustomValueContainer.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import Select, { components, ValueContainerProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const ValueContainer = ({
+ children,
+ ...props
+}: ValueContainerProps) => (
+ {children}
+);
+
+export default () => (
+ ({ ...base, color: 'white' }),
+ valueContainer: (base) => ({
+ ...base,
+ background: colourOptions[2].color,
+ color: 'white',
+ width: '100%',
+ }),
+ }}
+ components={{ ValueContainer }}
+ isSearchable
+ name="color"
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/DefaultOptions.tsx b/docs/examples/DefaultOptions.tsx
new file mode 100644
index 0000000000..8c0fe86f63
--- /dev/null
+++ b/docs/examples/DefaultOptions.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+
+import AsyncSelect from 'react-select/async';
+import { ColourOption, colourOptions } from '../data';
+
+const filterColors = (inputValue: string) => {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+};
+
+const promiseOptions = (inputValue: string) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+
+export default () => (
+
+);
diff --git a/docs/examples/Experimental.tsx b/docs/examples/Experimental.tsx
new file mode 100644
index 0000000000..7bc4a0e90f
--- /dev/null
+++ b/docs/examples/Experimental.tsx
@@ -0,0 +1,231 @@
+/** @jsx jsx */
+import { useState } from 'react';
+import { jsx } from '@emotion/react';
+import { CSSObject } from '@emotion/serialize';
+import moment, { Moment } from 'moment';
+import * as chrono from 'chrono-node';
+
+import Select, {
+ GroupProps,
+ OptionProps,
+ components as SelectComponents,
+} from 'react-select';
+
+interface DateOption {
+ date: Moment;
+ value: Date;
+ label: string;
+ display?: string;
+}
+
+const createOptionForDate = (d: Moment | Date) => {
+ const date = moment.isMoment(d) ? d : moment(d);
+ return {
+ date,
+ value: date.toDate(),
+ label: date.calendar(null, {
+ sameDay: '[Today] (Do MMM YYYY)',
+ nextDay: '[Tomorrow] (Do MMM YYYY)',
+ nextWeek: '[Next] dddd (Do MMM YYYY)',
+ lastDay: '[Yesterday] (Do MMM YYYY)',
+ lastWeek: '[Last] dddd (Do MMM YYYY)',
+ sameElse: 'Do MMMM YYYY',
+ }),
+ };
+};
+
+interface CalendarGroup {
+ label: string;
+ options: readonly DateOption[];
+}
+
+const defaultOptions: (DateOption | CalendarGroup)[] = [
+ 'today',
+ 'tomorrow',
+ 'yesterday',
+].map((i) => createOptionForDate(chrono.parseDate(i)));
+
+const createCalendarOptions = (date = new Date()) => {
+ const daysInMonth = Array.apply(null, Array(moment(date).daysInMonth())).map(
+ (x, i) => {
+ const d = moment(date).date(i + 1);
+ return { ...createOptionForDate(d), display: 'calendar' };
+ }
+ );
+ return {
+ label: moment(date).format('MMMM YYYY'),
+ options: daysInMonth,
+ };
+};
+
+defaultOptions.push(createCalendarOptions());
+
+const suggestions = [
+ 'sunday',
+ 'saturday',
+ 'friday',
+ 'thursday',
+ 'wednesday',
+ 'tuesday',
+ 'monday',
+ 'december',
+ 'november',
+ 'october',
+ 'september',
+ 'august',
+ 'july',
+ 'june',
+ 'may',
+ 'april',
+ 'march',
+ 'february',
+ 'january',
+ 'yesterday',
+ 'tomorrow',
+ 'today',
+].reduce<{ [key: string]: string }>((acc, str) => {
+ for (let i = 1; i < str.length; i++) {
+ acc[str.substr(0, i)] = str;
+ }
+ return acc;
+}, {});
+
+const suggest = (str: string) =>
+ str
+ .split(/\b/)
+ .map((i) => suggestions[i] || i)
+ .join('');
+
+const days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
+
+const daysHeaderStyles: CSSObject = {
+ marginTop: '5px',
+ paddingTop: '5px',
+ paddingLeft: '2%',
+ borderTop: '1px solid #eee',
+};
+const daysHeaderItemStyles: CSSObject = {
+ color: '#999',
+ cursor: 'default',
+ fontSize: '75%',
+ fontWeight: 500,
+ display: 'inline-block',
+ width: '12%',
+ margin: '0 1%',
+ textAlign: 'center',
+};
+const daysContainerStyles: CSSObject = {
+ paddingTop: '5px',
+ paddingLeft: '2%',
+};
+
+const Group = (props: GroupProps) => {
+ const {
+ Heading,
+ getStyles,
+ getClassNames,
+ children,
+ label,
+ headingProps,
+ cx,
+ theme,
+ selectProps,
+ } = props;
+ return (
+
+
+ {label}
+
+
+ {days.map((day, i) => (
+
+ {day}
+
+ ))}
+
+
{children}
+
+ );
+};
+
+const getOptionStyles = (defaultStyles: CSSObject): CSSObject => ({
+ ...defaultStyles,
+ display: 'inline-block',
+ width: '12%',
+ margin: '0 1%',
+ textAlign: 'center',
+ borderRadius: '4px',
+});
+
+const Option = (props: OptionProps) => {
+ const { data, getStyles, innerRef, innerProps } = props;
+ if (data.display === 'calendar') {
+ const defaultStyles = getStyles('option', props);
+ const styles = getOptionStyles(defaultStyles);
+ if (data.date.date() === 1) {
+ const indentBy = data.date.day();
+ if (indentBy) {
+ styles.marginLeft = `${indentBy * 14 + 1}%`;
+ }
+ }
+ return (
+
+ {data.date.format('D')}
+
+ );
+ } else return ;
+};
+
+interface DatePickerProps {
+ readonly value: DateOption | null;
+ readonly onChange: (newValue: DateOption | null) => void;
+}
+
+const DatePicker = (props: DatePickerProps) => {
+ const [options, setOptions] = useState(defaultOptions);
+
+ const handleInputChange = (value: string) => {
+ if (!value) {
+ setOptions(defaultOptions);
+ return;
+ }
+ const date = chrono.parseDate(suggest(value.toLowerCase()));
+ if (!date) {
+ setOptions([]);
+ return;
+ }
+ setOptions([createOptionForDate(date), createCalendarOptions(date)]);
+ };
+
+ return (
+
+ {...props}
+ components={{ Group, Option }}
+ filterOption={null}
+ isMulti={false}
+ isOptionSelected={(o, v) => v.some((i) => i.date.isSame(o.date, 'day'))}
+ maxMenuHeight={380}
+ onChange={props.onChange}
+ onInputChange={handleInputChange}
+ options={options}
+ value={props.value}
+ />
+ );
+};
+
+export default () => {
+ const [value, setValue] = useState(
+ defaultOptions[0] as DateOption
+ );
+
+ return (
+ setValue(newValue)} />
+ );
+};
diff --git a/docs/examples/FixedOptions.tsx b/docs/examples/FixedOptions.tsx
new file mode 100644
index 0000000000..e45af75611
--- /dev/null
+++ b/docs/examples/FixedOptions.tsx
@@ -0,0 +1,63 @@
+import React, { useState } from 'react';
+
+import Select, { ActionMeta, OnChangeValue, StylesConfig } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const styles: StylesConfig = {
+ multiValue: (base, state) => {
+ return state.data.isFixed ? { ...base, backgroundColor: 'gray' } : base;
+ },
+ multiValueLabel: (base, state) => {
+ return state.data.isFixed
+ ? { ...base, fontWeight: 'bold', color: 'white', paddingRight: 6 }
+ : base;
+ },
+ multiValueRemove: (base, state) => {
+ return state.data.isFixed ? { ...base, display: 'none' } : base;
+ },
+};
+
+const orderOptions = (values: readonly ColourOption[]) => {
+ return values
+ .filter((v) => v.isFixed)
+ .concat(values.filter((v) => !v.isFixed));
+};
+
+export default () => {
+ const [value, setValue] = useState(
+ orderOptions([colourOptions[0], colourOptions[1], colourOptions[3]])
+ );
+
+ const onChange = (
+ newValue: OnChangeValue,
+ actionMeta: ActionMeta
+ ) => {
+ switch (actionMeta.action) {
+ case 'remove-value':
+ case 'pop-value':
+ if (actionMeta.removedValue.isFixed) {
+ return;
+ }
+ break;
+ case 'clear':
+ newValue = colourOptions.filter((v) => v.isFixed);
+ break;
+ }
+
+ setValue(orderOptions(newValue));
+ };
+
+ return (
+ !v.isFixed)}
+ name="colors"
+ className="basic-multi-select"
+ classNamePrefix="select"
+ onChange={onChange}
+ options={colourOptions}
+ />
+ );
+};
diff --git a/docs/examples/MenuBuffer.tsx b/docs/examples/MenuBuffer.tsx
new file mode 100644
index 0000000000..f46ad682f1
--- /dev/null
+++ b/docs/examples/MenuBuffer.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import Select from 'react-select';
+
+import { colourOptions } from '../data';
+
+export default () => (
+ ({ ...base, marginBottom: 76 }) }}
+ />
+);
diff --git a/docs/examples/MenuPortal.tsx b/docs/examples/MenuPortal.tsx
new file mode 100644
index 0000000000..feabc6453c
--- /dev/null
+++ b/docs/examples/MenuPortal.tsx
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import Modal from '@atlaskit/modal-dialog';
+import Button from '@atlaskit/button';
+import Select, { MenuPlacement } from 'react-select';
+import { H1, Note } from '../styled-components';
+
+import { colourOptions } from '../data';
+
+export default () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [isFixed, setIsFixed] = useState(false);
+ const [menuPlacement, setMenuPlacement] = useState('bottom');
+
+ return (
+ <>
+ setIsOpen(true)}>Open Modal
+ {isOpen ? (
+ setIsOpen(false)}>
+ Portaled Menu Element
+ ({ ...base, zIndex: 9999 }) }}
+ menuPortalTarget={document.body}
+ isSearchable
+ name="color"
+ menuPosition={isFixed ? 'fixed' : 'absolute'}
+ menuPlacement={menuPlacement}
+ options={colourOptions}
+ menuShouldScrollIntoView={false}
+ />
+
+
+ setMenuPlacement(e.currentTarget.value as MenuPlacement)
+ }
+ value={menuPlacement}
+ id="cypress-portalled__radio-bottom"
+ >
+ auto
+ bottom
+ top
+
+
+
+ setIsFixed((prev) => !prev)}
+ value="fixed"
+ checked={isFixed}
+ id="cypress-portalled__fixed"
+ />
+ Fixed
+
+
+ setIsFixed((prev) => !prev)}
+ value="portal"
+ checked={!isFixed}
+ id="cypress-portalled__portal"
+ />
+ Portal
+
+
+ ) : null}
+ >
+ );
+};
diff --git a/docs/examples/MultiSelectSort.tsx b/docs/examples/MultiSelectSort.tsx
new file mode 100644
index 0000000000..846df42cb4
--- /dev/null
+++ b/docs/examples/MultiSelectSort.tsx
@@ -0,0 +1,92 @@
+import React, { MouseEventHandler } from 'react';
+
+import Select, {
+ components,
+ MultiValueGenericProps,
+ MultiValueProps,
+ OnChangeValue,
+ Props,
+} from 'react-select';
+import {
+ SortableContainer,
+ SortableContainerProps,
+ SortableElement,
+ SortEndHandler,
+ SortableHandle,
+} from 'react-sortable-hoc';
+import { ColourOption, colourOptions } from '../data';
+
+function arrayMove(array: readonly T[], from: number, to: number) {
+ const slicedArray = array.slice();
+ slicedArray.splice(
+ to < 0 ? array.length + to : to,
+ 0,
+ slicedArray.splice(from, 1)[0]
+ );
+ return slicedArray;
+}
+
+const SortableMultiValue = SortableElement(
+ (props: MultiValueProps) => {
+ // this prevents the menu from being opened/closed when the user clicks
+ // on a value to begin dragging it. ideally, detecting a click (instead of
+ // a drag) would still focus the control and toggle the menu, but that
+ // requires some magic with refs that are out of scope for this example
+ const onMouseDown: MouseEventHandler = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ };
+ const innerProps = { ...props.innerProps, onMouseDown };
+ return ;
+ }
+);
+
+const SortableMultiValueLabel = SortableHandle(
+ (props: MultiValueGenericProps) =>
+);
+
+const SortableSelect = SortableContainer(Select) as React.ComponentClass<
+ Props & SortableContainerProps
+>;
+
+export default function MultiSelectSort() {
+ const [selected, setSelected] = React.useState([
+ colourOptions[4],
+ colourOptions[5],
+ ]);
+
+ const onChange = (selectedOptions: OnChangeValue) =>
+ setSelected(selectedOptions);
+
+ const onSortEnd: SortEndHandler = ({ oldIndex, newIndex }) => {
+ const newValue = arrayMove(selected, oldIndex, newIndex);
+ setSelected(newValue);
+ console.log(
+ 'Values sorted:',
+ newValue.map((i) => i.value)
+ );
+ };
+
+ return (
+ node.getBoundingClientRect()}
+ // react-select props:
+ isMulti
+ options={colourOptions}
+ value={selected}
+ onChange={onChange}
+ components={{
+ // @ts-ignore We're failing to provide a required index prop to SortableElement
+ MultiValue: SortableMultiValue,
+ MultiValueLabel: SortableMultiValueLabel,
+ }}
+ closeMenuOnSelect={false}
+ />
+ );
+}
diff --git a/docs/examples/OnSelectResetsInput.tsx b/docs/examples/OnSelectResetsInput.tsx
new file mode 100644
index 0000000000..8f8838b02a
--- /dev/null
+++ b/docs/examples/OnSelectResetsInput.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import Select, { InputActionMeta } from 'react-select';
+import { colourOptions } from '../data';
+
+export default () => {
+ const [menuIsOpen, setMenuIsOpen] = React.useState();
+
+ const onInputChange = (
+ inputValue: string,
+ { action, prevInputValue }: InputActionMeta
+ ) => {
+ if (action === 'input-change') return inputValue;
+ if (action === 'menu-close') {
+ if (prevInputValue) setMenuIsOpen(true);
+ else setMenuIsOpen(undefined);
+ }
+ return prevInputValue;
+ };
+
+ return (
+
+ );
+};
diff --git a/docs/examples/Popout.tsx b/docs/examples/Popout.tsx
new file mode 100644
index 0000000000..2823fdf51d
--- /dev/null
+++ b/docs/examples/Popout.tsx
@@ -0,0 +1,138 @@
+/** @jsx jsx */
+import { ReactNode, useState } from 'react';
+import { jsx } from '@emotion/react';
+import Button from '@atlaskit/button';
+
+import Select, { StylesConfig } from 'react-select';
+import { defaultTheme } from 'react-select';
+import { StateOption, stateOptions } from '../data';
+
+const { colors } = defaultTheme;
+
+const selectStyles: StylesConfig = {
+ control: (provided) => ({
+ ...provided,
+ minWidth: 240,
+ margin: 8,
+ }),
+ menu: () => ({ boxShadow: 'inset 0 1px 0 rgba(0, 0, 0, 0.1)' }),
+};
+
+export default () => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [value, setValue] = useState();
+
+ return (
+ setIsOpen(false)}
+ target={
+ }
+ onClick={() => setIsOpen((prev) => !prev)}
+ isSelected={isOpen}
+ >
+ {value ? `State: ${value.label}` : 'Select a State'}
+
+ }
+ >
+ {
+ setValue(newValue);
+ setIsOpen(false);
+ }}
+ options={stateOptions}
+ placeholder="Search..."
+ styles={selectStyles}
+ tabSelectsValue={false}
+ value={value}
+ />
+
+ );
+};
+
+// styled components
+
+const Menu = (props: JSX.IntrinsicElements['div']) => {
+ const shadow = 'hsla(218, 50%, 10%, 0.1)';
+ return (
+
+ );
+};
+const Blanket = (props: JSX.IntrinsicElements['div']) => (
+
+);
+const Dropdown = ({
+ children,
+ isOpen,
+ target,
+ onClose,
+}: {
+ children?: ReactNode;
+ readonly isOpen: boolean;
+ readonly target: ReactNode;
+ readonly onClose: () => void;
+}) => (
+
+ {target}
+ {isOpen ?
{children} : null}
+ {isOpen ? : null}
+
+);
+const Svg = (p: JSX.IntrinsicElements['svg']) => (
+
+);
+const DropdownIndicator = () => (
+
+);
+const ChevronDown = () => (
+
+
+
+);
diff --git a/docs/examples/StyleCompositionExample.tsx b/docs/examples/StyleCompositionExample.tsx
new file mode 100644
index 0000000000..789700cb45
--- /dev/null
+++ b/docs/examples/StyleCompositionExample.tsx
@@ -0,0 +1,52 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react';
+import Select, { OptionProps } from 'react-select';
+import { ColourOption, colourOptions } from '../data';
+
+const Option = (props: OptionProps) => {
+ const {
+ children,
+ className,
+ cx,
+ getStyles,
+ isDisabled,
+ isFocused,
+ isSelected,
+ innerRef,
+ innerProps,
+ } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default () => (
+ ({
+ ...base,
+ border: `1px dotted ${colourOptions[2].color}`,
+ height: '100%',
+ }),
+ }}
+ defaultValue={colourOptions[4]}
+ options={colourOptions}
+ />
+);
diff --git a/docs/examples/StyledMulti.tsx b/docs/examples/StyledMulti.tsx
new file mode 100644
index 0000000000..7864a30f61
--- /dev/null
+++ b/docs/examples/StyledMulti.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import chroma from 'chroma-js';
+
+import { ColourOption, colourOptions } from '../data';
+import Select, { StylesConfig } from 'react-select';
+
+const colourStyles: StylesConfig = {
+ control: (styles) => ({ ...styles, backgroundColor: 'white' }),
+ option: (styles, { data, isDisabled, isFocused, isSelected }) => {
+ const color = chroma(data.color);
+ return {
+ ...styles,
+ backgroundColor: isDisabled
+ ? undefined
+ : isSelected
+ ? data.color
+ : isFocused
+ ? color.alpha(0.1).css()
+ : undefined,
+ color: isDisabled
+ ? '#ccc'
+ : isSelected
+ ? chroma.contrast(color, 'white') > 2
+ ? 'white'
+ : 'black'
+ : data.color,
+ cursor: isDisabled ? 'not-allowed' : 'default',
+
+ ':active': {
+ ...styles[':active'],
+ backgroundColor: !isDisabled
+ ? isSelected
+ ? data.color
+ : color.alpha(0.3).css()
+ : undefined,
+ },
+ };
+ },
+ multiValue: (styles, { data }) => {
+ const color = chroma(data.color);
+ return {
+ ...styles,
+ backgroundColor: color.alpha(0.1).css(),
+ };
+ },
+ multiValueLabel: (styles, { data }) => ({
+ ...styles,
+ color: data.color,
+ }),
+ multiValueRemove: (styles, { data }) => ({
+ ...styles,
+ color: data.color,
+ ':hover': {
+ backgroundColor: data.color,
+ color: 'white',
+ },
+ }),
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/StyledSingle.tsx b/docs/examples/StyledSingle.tsx
new file mode 100644
index 0000000000..d5a49d9ab9
--- /dev/null
+++ b/docs/examples/StyledSingle.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import chroma from 'chroma-js';
+
+import { ColourOption, colourOptions } from '../data';
+import Select, { StylesConfig } from 'react-select';
+
+const dot = (color = 'transparent') => ({
+ alignItems: 'center',
+ display: 'flex',
+
+ ':before': {
+ backgroundColor: color,
+ borderRadius: 10,
+ content: '" "',
+ display: 'block',
+ marginRight: 8,
+ height: 10,
+ width: 10,
+ },
+});
+
+const colourStyles: StylesConfig = {
+ control: (styles) => ({ ...styles, backgroundColor: 'white' }),
+ option: (styles, { data, isDisabled, isFocused, isSelected }) => {
+ const color = chroma(data.color);
+ return {
+ ...styles,
+ backgroundColor: isDisabled
+ ? undefined
+ : isSelected
+ ? data.color
+ : isFocused
+ ? color.alpha(0.1).css()
+ : undefined,
+ color: isDisabled
+ ? '#ccc'
+ : isSelected
+ ? chroma.contrast(color, 'white') > 2
+ ? 'white'
+ : 'black'
+ : data.color,
+ cursor: isDisabled ? 'not-allowed' : 'default',
+
+ ':active': {
+ ...styles[':active'],
+ backgroundColor: !isDisabled
+ ? isSelected
+ ? data.color
+ : color.alpha(0.3).css()
+ : undefined,
+ },
+ };
+ },
+ input: (styles) => ({ ...styles, ...dot() }),
+ placeholder: (styles) => ({ ...styles, ...dot('#ccc') }),
+ singleValue: (styles, { data }) => ({ ...styles, ...dot(data.color) }),
+};
+
+export default () => (
+
+);
diff --git a/docs/examples/Theme.tsx b/docs/examples/Theme.tsx
new file mode 100644
index 0000000000..8106ab4600
--- /dev/null
+++ b/docs/examples/Theme.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import { flavourOptions } from '../data';
+import Select from 'react-select';
+
+export default () => (
+ ({
+ ...theme,
+ borderRadius: 0,
+ colors: {
+ ...theme.colors,
+ primary25: 'hotpink',
+ primary: 'black',
+ },
+ })}
+ />
+);
diff --git a/docs/examples/index.tsx b/docs/examples/index.tsx
new file mode 100644
index 0000000000..e8bff14f43
--- /dev/null
+++ b/docs/examples/index.tsx
@@ -0,0 +1,54 @@
+export { default as AccessingInternals } from './AccessingInternals';
+export { default as ControlledMenu } from './ControlledMenu';
+export { default as AnimatedMulti } from './AnimatedMulti';
+export { default as AsyncCallbacks } from './AsyncCallbacks';
+export { default as AsyncCreatable } from './AsyncCreatable';
+export { default as AsyncPromises } from './AsyncPromises';
+export { default as BasicGrouped } from './BasicGrouped';
+export { default as BasicMulti } from './BasicMulti';
+export { default as BasicSingle } from './BasicSingle';
+export { default as CustomAriaLive } from './CustomAriaLive';
+export { default as CustomControl } from './CustomControl';
+export { default as CreatableAdvanced } from './CreatableAdvanced';
+export { default as CreatableInputOnly } from './CreatableInputOnly';
+export { default as CreateFilter } from './CreateFilter';
+export { default as CreatableMulti } from './CreatableMulti';
+export { default as CreatableSingle } from './CreatableSingle';
+export { default as CustomSelectProps } from './CustomSelectProps';
+export { default as CustomClearIndicator } from './CustomClearIndicator';
+export { default as CustomDropdownIndicator } from './CustomDropdownIndicator';
+export { default as CustomLoadingIndicator } from './CustomLoadingIndicator';
+export { default as CustomLoadingMessage } from './CustomLoadingMessage';
+export { default as CustomGroup } from './CustomGroup';
+export { default as CustomMenu } from './CustomMenu';
+export { default as CustomMenuList } from './CustomMenuList';
+export { default as CustomIndicatorsContainer } from './CustomIndicatorsContainer';
+export { default as CustomIndicatorSeparator } from './CustomIndicatorSeparator';
+export { default as CustomNoOptionsMessage } from './CustomNoOptionsMessage';
+export { default as CustomMultiValueContainer } from './CustomMultiValueContainer';
+export { default as CustomOption } from './CustomOption';
+export { default as CustomMultiValueLabel } from './CustomMultiValueLabel';
+export { default as CustomMultiValueRemove } from './CustomMultiValueRemove';
+export { default as CustomInput } from './CustomInput';
+export { default as CustomGroupHeading } from './CustomGroupHeading';
+export { default as CustomPlaceholder } from './CustomPlaceholder';
+export { default as CustomSelectContainer } from './CustomSelectContainer';
+export { default as CustomSingleValue } from './CustomSingleValue';
+export { default as CustomValueContainer } from './CustomValueContainer';
+export { default as CustomGetOptionLabel } from './CustomGetOptionLabel';
+export { default as CustomGetOptionValue } from './CustomGetOptionValue';
+export { default as CustomFilterOptions } from './CustomFilterOptions';
+export { default as CustomIsOptionDisabled } from './CustomIsOptionDisabled';
+export { default as DefaultOptions } from './DefaultOptions';
+export { default as Experimental } from './Experimental';
+export { default as FixedOptions } from './FixedOptions';
+export { default as MultiSelectSort } from './MultiSelectSort';
+export { default as Popout } from './Popout';
+export { default as StyledMulti } from './StyledMulti';
+export { default as StyledSingle } from './StyledSingle';
+export { default as OnSelectResetsInput } from './OnSelectResetsInput';
+export { default as AsyncMulti } from './AsyncMulti';
+export { default as MenuBuffer } from './MenuBuffer';
+export { default as MenuPortal } from './MenuPortal';
+export { default as Theme } from './Theme';
+export { default as StyleCompositionExample } from './StyleCompositionExample';
diff --git a/examples/src/favicon.ico b/docs/favicon.ico
similarity index 100%
rename from examples/src/favicon.ico
rename to docs/favicon.ico
diff --git a/docs/generate-magical-types/generate/package.json b/docs/generate-magical-types/generate/package.json
new file mode 100644
index 0000000000..3ea23b80e4
--- /dev/null
+++ b/docs/generate-magical-types/generate/package.json
@@ -0,0 +1,4 @@
+{
+ "main": "dist/react-select-generate-magical-types-generate.cjs.js",
+ "module": "dist/react-select-generate-magical-types-generate.esm.js"
+}
diff --git a/docs/generate-magical-types/package.json b/docs/generate-magical-types/package.json
new file mode 100644
index 0000000000..0879e4ece4
--- /dev/null
+++ b/docs/generate-magical-types/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@react-select/generate-magical-types",
+ "main": "dist/generate-magical-types.cjs.js",
+ "exports": {
+ "./generate": {
+ "module": "./generate/dist/react-select-generate-magical-types-generate.esm.js",
+ "import": "./generate/dist/react-select-generate-magical-types-generate.cjs.mjs",
+ "default": "./generate/dist/react-select-generate-magical-types-generate.cjs.js"
+ },
+ "./serialize": {
+ "module": "./serialize/dist/react-select-generate-magical-types-serialize.esm.js",
+ "import": "./serialize/dist/react-select-generate-magical-types-serialize.cjs.mjs",
+ "default": "./serialize/dist/react-select-generate-magical-types-serialize.cjs.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "//": "these deps aren't real, they're just to appease preconstruct",
+ "dependencies": {
+ "@babel/runtime": "*",
+ "@magical-types/convert-type": "*",
+ "@magical-types/serialization": "*",
+ "ts-morph": "*",
+ "fs-extra": "*",
+ "flatted": "*"
+ },
+ "preconstruct": {
+ "entrypoints": [
+ "generate.ts",
+ "serialize.ts"
+ ]
+ }
+}
diff --git a/docs/generate-magical-types/serialize/package.json b/docs/generate-magical-types/serialize/package.json
new file mode 100644
index 0000000000..c2c2c78370
--- /dev/null
+++ b/docs/generate-magical-types/serialize/package.json
@@ -0,0 +1,4 @@
+{
+ "main": "dist/react-select-generate-magical-types-serialize.cjs.js",
+ "module": "dist/react-select-generate-magical-types-serialize.esm.js"
+}
diff --git a/docs/generate-magical-types/src/generate.ts b/docs/generate-magical-types/src/generate.ts
new file mode 100644
index 0000000000..732c80028c
--- /dev/null
+++ b/docs/generate-magical-types/src/generate.ts
@@ -0,0 +1,117 @@
+import path from 'path';
+
+// @ts-ignore
+import fs from 'fs-extra';
+import * as flatted from 'flatted';
+import { Project } from 'ts-morph';
+import { MagicalNode } from '@magical-types/types';
+import { convertType, getPropTypesType } from '@magical-types/convert-type';
+
+type MagicalNodesForPackage = Record<
+ string,
+ { type: 'component' | 'other'; node: MagicalNode }
+>;
+
+export type MagicalNodes = Record;
+
+if (process.env.NODE_ENV === 'test') {
+ fs.outputFileSync(
+ path.join(__dirname, '..', 'dist', 'magical-types.json'),
+ flatted.stringify({})
+ );
+} else {
+ const OTHERFILES: string[] = ['stateManager', 'Async', 'Creatable'];
+ const getOtherProps = (obj: MagicalNodes) => {
+ OTHERFILES.forEach((name: string) => {
+ let pkgExports: MagicalNodesForPackage = {};
+ obj[`${name}`] = pkgExports;
+ let sourceFile = project.getSourceFile(
+ path.join(__dirname, '../../PropTypes', `${name}.ts`)
+ );
+ if (!sourceFile) {
+ sourceFile = project.getSourceFile(
+ path.join(__dirname, '../../PropTypes', `${name}.tsx`)
+ );
+ }
+ if (!sourceFile) {
+ throw new Error(`source file not found for ${name}`);
+ }
+ resolveTypes({ sourceFile, item: name, pkgExports });
+ });
+ };
+
+ const resolveTypes = ({
+ sourceFile,
+ item,
+ pkgExports,
+ }: {
+ sourceFile: any;
+ item: string;
+ pkgExports: MagicalNodesForPackage;
+ }) => {
+ let exportedDeclarations = sourceFile.getExportedDeclarations();
+ for (const [exportName, declaration] of exportedDeclarations) {
+ if (declaration.length) {
+ let type = declaration[0].getType().compilerType;
+ let typeKind: 'component' | 'other' = 'other';
+ console.log(`about to convert ${exportName} from ${item}`);
+ if (exportName[0].toUpperCase() === exportName[0]) {
+ try {
+ type = getPropTypesType(type);
+ typeKind = 'component';
+ } catch (err) {}
+ }
+ pkgExports[exportName] = {
+ node: convertType(type, []),
+ type: typeKind,
+ };
+ console.log('converted');
+ }
+ }
+ };
+
+ let project = new Project({
+ addFilesFromTsConfig: true,
+ tsConfigFilePath: path.resolve(__dirname, '../../../tsconfig.json'),
+ });
+ console.log('done');
+ let pkgDir = path.resolve(__dirname, '../../../packages');
+ let pkgs = fs
+ .readdirSync(pkgDir, {
+ withFileTypes: true,
+ })
+ .filter(
+ // @ts-ignore
+ (x) =>
+ x.isDirectory() &&
+ fs.existsSync(path.join(pkgDir, path.join(x.name), 'package.json'))
+ )
+ // @ts-ignore
+ .map((x) => x.name);
+
+ let obj: MagicalNodes = {};
+
+ for (const item of pkgs) {
+ let pkgExports: MagicalNodesForPackage = {};
+ obj[`${item}`] = pkgExports;
+ let sourceFile = project.getSourceFile(
+ path.join(pkgDir, item, 'src', 'index.tsx')
+ );
+ if (!sourceFile) {
+ sourceFile = project.getSourceFile(
+ path.join(pkgDir, item, 'src', 'index.ts')
+ );
+ }
+ if (!sourceFile) {
+ throw new Error(`source file not found for ${item}`);
+ }
+ resolveTypes({ sourceFile, item, pkgExports });
+ }
+
+ getOtherProps(obj);
+
+ fs.outputFileSync(
+ path.join(__dirname, '..', 'dist', 'magical-types.json'),
+ flatted.stringify(obj)
+ );
+}
diff --git a/docs/generate-magical-types/src/serialize.ts b/docs/generate-magical-types/src/serialize.ts
new file mode 100644
index 0000000000..ecfa7b4393
--- /dev/null
+++ b/docs/generate-magical-types/src/serialize.ts
@@ -0,0 +1,93 @@
+import path from 'path';
+
+// @ts-ignore
+import fs from 'fs-extra';
+import * as flatted from 'flatted';
+import { MagicalNode } from '@magical-types/types';
+import {
+ chunkNodes,
+ serializeNodes,
+} from '@magical-types/serialization/serialize';
+
+import { MagicalNodeMetadata, MagicalNodes } from './types';
+
+const allTypes: MagicalNodes = flatted.parse(
+ fs.readFileSync(
+ path.join(__dirname, '..', 'dist', 'magical-types.json'),
+ 'utf8'
+ )
+);
+
+const magicalTypesDir = path.resolve(__dirname, '..', '..', 'magical-types');
+
+fs.removeSync(magicalTypesDir);
+
+fs.ensureDirSync(magicalTypesDir);
+
+let rootNodes: MagicalNode[] = [];
+
+for (const pkgName in allTypes) {
+ for (const exportName in allTypes[pkgName]) {
+ rootNodes.push(allTypes[pkgName][exportName].node);
+ }
+}
+
+console.log('serializing nodes');
+const serializationResult = serializeNodes(rootNodes);
+console.log('done');
+
+console.log('chunking nodes');
+const chunkedNodes = chunkNodes(serializationResult);
+console.log('done');
+
+let outputPaths = chunkedNodes.map((x, index) =>
+ path.join(
+ magicalTypesDir,
+ `magical-types-${index}-${Math.random().toString(36)}.json`
+ )
+);
+
+let outputUrlSegments = outputPaths.map(
+ (filepath) => `/magical-types/${path.basename(filepath)}`
+);
+let manifestOutputPath = path.resolve(
+ magicalTypesDir,
+ 'magical-types-manifest.json'
+);
+
+const metadataWithIndexes: MagicalNodeMetadata = {};
+
+for (const pkgName in allTypes) {
+ metadataWithIndexes[pkgName] = {};
+ for (const exportName in allTypes[pkgName]) {
+ if (serializationResult.nodesMeta.has(allTypes[pkgName][exportName].node)) {
+ metadataWithIndexes[pkgName][exportName] = {
+ type: allTypes[pkgName][exportName].type,
+ index: serializationResult.nodesMeta.get(
+ allTypes[pkgName][exportName].node
+ )!.index,
+ };
+ }
+ }
+}
+
+(async () => {
+ console.log('writing output');
+ await Promise.all([
+ fs.writeFile(
+ manifestOutputPath,
+ JSON.stringify({
+ paths: outputUrlSegments,
+ types: metadataWithIndexes,
+ })
+ ),
+ ...outputPaths.map((filepath, index) =>
+ fs.writeFile(filepath, JSON.stringify(chunkedNodes[index]))
+ ),
+ ]);
+
+ console.log('done');
+})().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});
diff --git a/docs/generate-magical-types/src/types.ts b/docs/generate-magical-types/src/types.ts
new file mode 100644
index 0000000000..e2102a66f9
--- /dev/null
+++ b/docs/generate-magical-types/src/types.ts
@@ -0,0 +1,18 @@
+import { MagicalNode, MagicalNodeIndex } from '@magical-types/types';
+
+export type MagicalNodeMetadata = Record<
+ string,
+ Record
+>;
+
+export type MagicalNodeRecord = {
+ type: 'component' | 'other';
+ index: MagicalNodeIndex;
+};
+
+export type MagicalNodesForPackage = Record<
+ string,
+ { type: 'component' | 'other'; node: MagicalNode }
+>;
+
+export type MagicalNodes = Record;
diff --git a/docs/index.css b/docs/index.css
new file mode 100644
index 0000000000..27281e215c
--- /dev/null
+++ b/docs/index.css
@@ -0,0 +1,78 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto:400,500,700');
+
+body {
+ -moz-font-feature-settings: 'liga' on;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ color: #253858;
+ font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
+ Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: 400;
+ margin: 0;
+ padding: 0;
+ text-rendering: optimizeLegibility;
+}
+p > a,
+p > a:hover,
+p > a:visited,
+li > a,
+li > a:hover,
+li > a:visited {
+ color: #2684ff;
+}
+code {
+ font-family: Roboto Mono, Monaco, monospace;
+}
+p > code {
+ white-space: nowrap;
+}
+p,
+ul,
+ol {
+ line-height: 1.5;
+}
+td p {
+ margin: 0;
+}
+h1,
+h2,
+h3,
+h4,
+h5 {
+ color: #091e42;
+}
+h6 {
+ color: #777;
+ margin-bottom: 0.25em;
+ text-transform: uppercase;
+}
+@keyframes dropIn {
+ from,
+ 60%,
+ 75%,
+ 90%,
+ to {
+ animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+ }
+ 0% {
+ opacity: 0;
+ transform: translate3d(0, -1666px, 0);
+ }
+ 60% {
+ opacity: 1;
+ transform: translate3d(0, 26px, 0);
+ }
+ 75% {
+ transform: translate3d(0, -10px, 0);
+ }
+ 90% {
+ transform: translate3d(0, 6px, 0);
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ }
+}
+.animate-dropin {
+ animation: dropIn 0.66s;
+}
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000000..f204a513a7
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,50 @@
+
+
+
+ React-Select
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/index.tsx b/docs/index.tsx
new file mode 100644
index 0000000000..a7afb60f2c
--- /dev/null
+++ b/docs/index.tsx
@@ -0,0 +1,6 @@
+import '@babel/polyfill';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+ReactDOM.render( , document.getElementById('root'));
diff --git a/docs/isArray.ts b/docs/isArray.ts
new file mode 100644
index 0000000000..8d587b0522
--- /dev/null
+++ b/docs/isArray.ts
@@ -0,0 +1,6 @@
+/**
+ * Alternative to Array.isArray that correctly narrows the type for readonly arrays.
+ */
+export default function isArray(arg: unknown): arg is readonly T[] {
+ return Array.isArray(arg);
+}
diff --git a/docs/markdown/renderer.tsx b/docs/markdown/renderer.tsx
new file mode 100644
index 0000000000..f2c4202570
--- /dev/null
+++ b/docs/markdown/renderer.tsx
@@ -0,0 +1,207 @@
+/** @jsx emotionJSX */
+import md, {
+ CodeProps,
+ CommonProps,
+ HeadingProps,
+ LinkProps,
+} from 'react-markings';
+import { jsx as emotionJSX } from '@emotion/react'; // eslint-disable-line no-unused-vars
+import { Link as RRLink } from 'react-router-dom';
+
+import Svg, { SvgProps } from '../Svg';
+import store from './store';
+
+// ==============================
+// Syntax Highlighter
+// ==============================
+
+import SyntaxHighlighter, {
+ registerLanguage,
+} from 'react-syntax-highlighter/prism-light';
+import jsx from 'react-syntax-highlighter/languages/prism/jsx';
+import { coy } from 'react-syntax-highlighter/styles/prism';
+import { ReactElement } from 'react';
+
+const customCoy = {
+ ...coy,
+ 'code[class*="language-"]': {
+ ...coy['code[class*="language-"]'],
+ fontFamily: null, // inherit from css
+ },
+ 'pre[class*="language-"]': {
+ ...coy['pre[class*="language-"]'],
+ fontFamily: null, // inherit from css
+ },
+};
+
+registerLanguage('jsx', jsx);
+
+// ==============================
+// Helpers
+// ==============================
+
+function slugify(str: string): string {
+ return str.replace(/\W/g, '-').toLowerCase();
+}
+
+// ==============================
+// Renderers
+// ==============================
+
+function isReactElement(child: ReactElement | string): child is ReactElement {
+ return (child as ReactElement).props;
+}
+
+function getLabel(children: (ReactElement | string)[] | ReactElement | string) {
+ let str = '';
+
+ if (Array.isArray(children)) {
+ children.forEach((c) => {
+ if (Array.isArray(c)) {
+ getLabel(c);
+ } else if (isReactElement(c)) {
+ str = c.props.children;
+ } else {
+ str = c;
+ }
+ });
+ } else if (isReactElement(children)) {
+ getLabel(children.props.children);
+ } else {
+ str = children;
+ }
+
+ return str;
+}
+
+const Chain = (props: Omit) => (
+
+ Link to
+
+
+);
+
+const Heading = (props: HeadingProps) => {
+ const { children, level, nodeKey } = props;
+
+ const Tag = `h${level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+ const label = getLabel(children);
+ const slug = slugify(label);
+ const linkify = [1, 2].includes(level);
+
+ if (linkify) {
+ store.add(nodeKey, { key: nodeKey, label, level, path: `#${slug}` });
+ }
+ const css = {
+ '&:first-child': { marginTop: 0 },
+ };
+
+ return linkify ? (
+
+ svg': { opacity: 1, transitionDelay: '300ms' },
+ }}
+ >
+
+ {children}
+
+
+ ) : (
+ {children}
+ );
+};
+
+export const Code = ({ literal }: CodeProps) => (
+
+ {literal}
+
+);
+
+interface CodeBlockProps {
+ codeinfo?: string[];
+ literal: string | null;
+ nodeKey?: string;
+}
+
+export const CodeBlock = ({
+ codeinfo,
+ literal,
+ nodeKey,
+ ...props
+}: CodeBlockProps) => {
+ const language = codeinfo![0];
+
+ return (
+
+ {literal}
+
+ );
+};
+CodeBlock.defaultProps = { codeinfo: [], language: 'jsx' };
+
+const Blockquote = ({ nodeKey, ...props }: CommonProps) => (
+
+);
+
+const Link = ({ nodeKey, href, ...props }: LinkProps) =>
+ href[0] === '/' ? (
+
+ ) : (
+
+ );
+
+// ==============================
+// Exports
+// ==============================
+
+export default md.customize({
+ renderers: { Blockquote, Code, Heading, CodeBlock, Link },
+});
diff --git a/docs/markdown/store.ts b/docs/markdown/store.ts
new file mode 100644
index 0000000000..b44298d15d
--- /dev/null
+++ b/docs/markdown/store.ts
@@ -0,0 +1,40 @@
+export interface Data {
+ key: string;
+ label: string;
+ level: number;
+ path: string;
+}
+
+class HeadingStore {
+ store: { [key: string]: Data } = {};
+ headings: { [key: string]: Data[] } = {};
+
+ add(key: string, data: Data) {
+ console.log('add being called with', data.label);
+ if (!this.headings[location.pathname]) {
+ this.headings[location.pathname] = [];
+ }
+
+ if (!this.store[key]) {
+ this.store[key] = data;
+ this.headings[location.pathname].push(data);
+ }
+ }
+ getStore() {
+ return this.store;
+ }
+ getPageHeadings(page: string) {
+ return this.headings[page];
+ }
+ getAllHeadings() {
+ return this.headings;
+ }
+ getHeadingByKey(key: string) {
+ return this.store[key];
+ }
+}
+
+// global heading store
+const store = new HeadingStore();
+
+export default store;
diff --git a/docs/package.json b/docs/package.json
new file mode 100644
index 0000000000..0d37ceb7f1
--- /dev/null
+++ b/docs/package.json
@@ -0,0 +1,64 @@
+{
+ "name": "@react-select/docs",
+ "private": true,
+ "version": "3.1.3",
+ "main": "dist/docs.cjs.js",
+ "author": "Jed Watson",
+ "license": "MIT",
+ "dependencies": {
+ "@atlaskit/button": "^15.1.4",
+ "@atlaskit/icon": "^11.0.1",
+ "@atlaskit/modal-dialog": "^11.2.5",
+ "@atlaskit/spinner": "^15.0.6",
+ "@atlaskit/tooltip": "^17.1.2",
+ "@babel/runtime": "^7.12.0",
+ "@emotion/react": "^11.8.1",
+ "@magical-types/convert-type": "^0.1.4",
+ "@magical-types/pretty": "^0.3.5",
+ "@magical-types/serialization": "^0.2.1",
+ "@magical-types/types": "^0.1.2",
+ "@types/chroma-js": "^1.4.3",
+ "@types/node-fetch": "^2.5.8",
+ "@types/raf-schd": "^4.0.0",
+ "@types/react-codesandboxer": "^3.1.0",
+ "@types/react-helmet": "^5.0.16",
+ "@types/react-markings": "^1.3.0",
+ "@types/react-node-resolver": "^2.0.0",
+ "@types/react-router-dom": "^4.3.5",
+ "@types/react-syntax-highlighter": "^0.0.8",
+ "@types/webpack": "^4.41.26",
+ "@types/webpack-dev-server": "^3.11.1",
+ "babel-plugin-macros": "^3.0.1",
+ "chroma-js": "^2.4.2",
+ "chrono-node": "^2.1.11",
+ "clean-webpack-plugin": "^3.0.0",
+ "codesandboxer": "^0.1.1",
+ "fork-ts-checker-webpack-plugin": "^6.1.0",
+ "html-webpack-plugin": "^3.2.0",
+ "moment": "^2.29.4",
+ "raf-schd": "^4.0.3",
+ "raw-loader": "^2.0.0",
+ "react": "^16.13.0",
+ "react-codesandboxer": "^3.1.5",
+ "react-dom": "^16.13.0",
+ "react-helmet": "^5.2.0",
+ "react-markings": "^1.3.0",
+ "react-router-dom": "^4.2.2",
+ "react-select": "^5.7.0",
+ "react-sortable-hoc": "^1.9.1",
+ "react-syntax-highlighter": "^7.0.1",
+ "style-loader": "^0.23.1",
+ "styled-components": "^4.4.1",
+ "ts-node": "^9.1.1",
+ "unfetch": "^4.2.0",
+ "webpack": "^4.30.0",
+ "webpack-cli": "^4.10.0",
+ "webpack-dev-server": "^3.3.1"
+ },
+ "scripts": {
+ "site-prebuild": "node ./generate-magical-types/generate && node ./generate-magical-types/serialize",
+ "start": "yarn site-prebuild && webpack serve --progress",
+ "start:test": "NODE_ENV=test yarn site-prebuild && webpack serve --progress",
+ "build:docs": "rimraf docs/dist && yarn site-prebuild && webpack --progress --mode production"
+ }
+}
diff --git a/docs/pages/advanced/index.tsx b/docs/pages/advanced/index.tsx
new file mode 100644
index 0000000000..2d7f8fc74a
--- /dev/null
+++ b/docs/pages/advanced/index.tsx
@@ -0,0 +1,297 @@
+import React, { Fragment } from 'react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+import ExampleWrapper from '../../ExampleWrapper';
+import {
+ AccessingInternals,
+ BasicGrouped,
+ CreateFilter,
+ ControlledMenu,
+ CustomAriaLive,
+ CustomFilterOptions,
+ CustomGetOptionLabel,
+ CustomGetOptionValue,
+ CustomIsOptionDisabled,
+ Experimental,
+ MenuBuffer,
+ MenuPortal,
+ MultiSelectSort,
+ Popout,
+ OnSelectResetsInput,
+} from '../../examples';
+
+export default function Advanced() {
+ return (
+
+
+ Advanced - React Select
+
+
+ {md`
+ # Advanced
+
+ ## Accessibility
+ Accessibility is important. React-select is committed to providing a custom experience to all users and relies heavily on the aria-live spec to provide
+ a custom experience for all users. As such, we also provide an api to address internationalization or further customisation.
+
+ ${(
+
+
+
+ )}
+
+ ## Sortable MultiSelect
+ Using the [react-sortable-hoc](https://www.npmjs.com/package/react-sortable-hoc) package we can easily allow sorting of MultiSelect values by drag and drop.
+
+ ${(
+
+
+
+ )}
+
+ ## Custom Filter logic
+ While React-Select assumes a standard way of filtering the menu on search, our api allows you to customise that filtering logic in various ways.
+
+ ### createFilter function
+ React-Select exports a createFilter function that returns a filterOption method. By using this, users can pick and choose bits of the filtration logic to customise,
+ without having to rewrite the logic wholesale.
+
+ ~~~jsx
+ // default filter configuration
+ ignoreCase: true,
+ ignoreAccents: true,
+ matchFrom: 'any',
+ stringify: option => \`\${option.label} \${option.value}\`,
+ trim: true,
+ ~~~
+
+ Below is an example of how you could use the createFilter function to customise filtration logic in react-select.
+
+ ${(
+
+
+
+ )}
+
+ ### filterOption
+ If you really would like to rewrite the filtration logic from the ground up, simply declare a new filterOption function to be passed in as a prop to react-select.
+ For details on the shape of the filterOption prop, please see the proptypes in the api docs [here](/props).
+
+ ${(
+
+
+
+ )}
+ ~~~jsx
+ ~~~
+ > Please note that if you are using a Select that is creatable, you would also likey want to include the "Create" option.
+ ~~~jsx
+ const filterOption = (candidate, input) => {
+ return candidate.data.__isNew__ || candidate.label.includes(input);
+ };
+ ~~~
+
+
+ ## Replacing builtins
+ For a list of builtins that we expose, please see the API docs [here](/props#prop-types).
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ## Methods
+
+ These two methods sit as callable methods on the component. They are designed
+ to be accessible to wrapping components.
+
+ ### \`focus()\`
+
+ Focused the internal control input.
+
+ ### \`blur()\`
+
+ Blur the internal control input.
+
+ ## Action Meta
+ React Select exposes a variety of eventListeners to you via props.
+ The onchange function prop now has the following signature.
+ (value: ValueType, action: ActionType) => undefined;
+
+ The action argument is a string with the following possible values
+
+ * 'select-option': Selecting an option from the list
+ * 'deselect-option': (Multiple) Deselecting an option from the list
+ * 'remove-value': (Multiple) Removing a selected option with the remove button
+ * 'pop-value': Removing options using backspace
+ * 'set-value': Calling setValue from a component without an action
+ * 'clear': Removing all selected options with the clear button
+ * 'create-option': (Creatable) Creating a new option
+
+ By explicitly passing you what type of change event has been fired, we allow you to have more granular control
+ over how the select behaves after an onChange even is fired.
+
+ Below is an example of replicating the behaviour of the deprecated props from react-select v1, onSelectResetsInput and closeOnSelect
+
+ ${(
+
+
+
+ )}
+
+ ## Portaling
+ React-select exposes a menuPortalTarget prop, that lets you portal the select menu to a dom node of your choosing.
+ Additionally we expose the menuPortal styles for layering purposes.
+
+ ${(
+
+
+
+ )}
+
+ ## Controlled Props
+
+ ${(
+
+
+
+ )}
+
+ ## Accessing Internals
+ ${(
+
+
+
+ )}
+
+ ## SSR / Universal Rendering
+
+ React-Select uses Emotion for CSS which has zero-config server rendering. This means that all you need to do to server-render React-Select is call React's \`renderToString\` or use a framework like Next.js or Gatsby and it will work.
+
+ ~~~jsx
+ import { renderToString } from 'react-dom/server'
+ import App from './App'
+
+ const html = renderToString( )
+ ~~~
+
+ ## Experimental
+
+ Experimental recipes of prop combinations with react-select.
+
+ ${(
+
+
+
+ )}
+
+ A popular recipe for using select when there's limited real estate.
+
+ > When \`controlShouldRenderValue\` is disabled, it's recommended to also disable \`isClearable\` and \`backspaceRemovesValue\`.
+
+ ${(
+
+
+
+ )}
+
+ This example uses a combination of custom components and functions to make react-select behave like a date picker.
+
+ > Type a date like "25/8/18", "tomorrow", "next monday", or "6 weeks from now" into the field to get date suggestions.
+
+ `}
+
+ );
+}
diff --git a/docs/pages/async/index.tsx b/docs/pages/async/index.tsx
new file mode 100644
index 0000000000..25ee5d5083
--- /dev/null
+++ b/docs/pages/async/index.tsx
@@ -0,0 +1,89 @@
+import React, { Fragment } from 'react';
+import Helmet from 'react-helmet';
+import ExampleWrapper from '../../ExampleWrapper';
+import md from '../../markdown/renderer';
+import {
+ AsyncCallbacks,
+ AsyncMulti,
+ AsyncPromises,
+ DefaultOptions,
+} from '../../examples';
+
+export default function Async() {
+ return (
+
+
+ Async - React Select
+
+
+ {md`
+ # Async
+ Use the Async component to load options from a remote source as the user types.
+
+ ~~~jsx
+ import Async, { useAsync } from 'react-select/async';
+ ~~~
+
+ ## Loading Asynchronously
+
+ The loadOptions prop allows users to either resolve from a callback...
+
+ ${(
+
+
+
+ )}
+
+ or resolve from a returned promise....
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ## defaultOptions
+
+ The defaultOptions prop determines "when" your remote request is initially fired. There are two valid values for this property. Providing an option array to this prop will populate the initial set of options used when opening the select, at which point the remote load only occurs when filtering the options (typing in the control). Providing the prop by itself (or with 'true') tells the control to immediately fire the remote request, described by your loadOptions, to get those initial values for the Select.
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+ `}
+
+ );
+}
diff --git a/docs/pages/components/index.tsx b/docs/pages/components/index.tsx
new file mode 100644
index 0000000000..5ce78c347e
--- /dev/null
+++ b/docs/pages/components/index.tsx
@@ -0,0 +1,566 @@
+import React, { Fragment } from 'react';
+import { Helmet } from 'react-helmet';
+
+import md from '../../markdown/renderer';
+import ExampleWrapper from '../../ExampleWrapper';
+import {
+ CustomSelectProps,
+ CustomClearIndicator,
+ CustomDropdownIndicator,
+ CustomLoadingIndicator,
+ CustomLoadingMessage,
+ CustomIndicatorsContainer,
+ CustomIndicatorSeparator,
+ CustomNoOptionsMessage,
+ CustomMultiValueContainer,
+ CustomMultiValueRemove,
+ CustomMultiValueLabel,
+ CustomControl,
+ CustomGroup,
+ CustomInput,
+ CustomOption,
+ CustomMenu,
+ CustomMenuList,
+ CustomPlaceholder,
+ CustomSelectContainer,
+ CustomSingleValue,
+ CustomGroupHeading,
+ CustomValueContainer,
+} from '../../examples';
+
+export default function Components() {
+ return (
+
+
+ Components - React Select
+
+
+ {md`
+ # Components
+
+ The main feature of this library is providing consumers with the
+ building blocks necessary to create _their_ component.
+
+ The following components are customisable and switchable:
+ * ClearIndicator
+ * Control
+ * DropdownIndicator
+ * DownChevron
+ * CrossIcon
+ * Group
+ * GroupHeading
+ * IndicatorsContainer
+ * IndicatorSeparator
+ * Input
+ * LoadingIndicator
+ * Menu
+ * MenuList
+ * MenuPortal
+ * LoadingMessage
+ * NoOptionsMessage
+ * MultiValue
+ * MultiValueContainer
+ * MultiValueLabel
+ * MultiValueRemove
+ * Option
+ * Placeholder
+ * SelectContainer
+ * SingleValue
+ * ValueContainer
+
+ ## Replacing Components
+
+ React-Select allows you to augment layout and functionality by replacing
+ the default components with your own, using the \`components\`
+ property. These components are given all the current props and state
+ letting you achieve anything you dream up.
+
+ ## Inner Ref
+ Some components also take an innerRef prop that react-select needs in
+ order to manage internal behaviour. Please assign this to the ref
+ property of the relevant react-element. For example:
+
+ ~~~~
+ const CustomOption = ({ innerRef, innerProps }) => (
+
)
+ ~~~~
+
+ ### Inner Props
+
+ All functional properties that the component needs are provided in
+ \`innerProps\` which you must spread.
+
+ ### Common Props
+
+ Every component receives \`commonProps\` which are spread onto
+ the component. These include:
+
+ * \`clearValue\`
+ * \`getStyles\`
+ * \`getValue\`
+ * \`hasValue\`
+ * \`isMulti\`
+ * \`isRtl\`
+ * \`options\`
+ * \`selectOption\`
+ * \`setValue\`
+ * \`selectProps\`
+
+ ~~~jsx
+ import React from 'react';
+ import Select from 'react-select';
+
+ const CustomOption = ({ innerProps, isDisabled }) =>
+ !isDisabled ? (
+ {/* your component internals */}
+ ) : null;
+
+ class Component extends React.Component {
+ render() {
+ return ;
+ }
+ }
+
+ ~~~
+
+ ## Defining components
+
+ When defining replacement components, it is important to do so __outside__ the scope of
+ rendering the Select. Defining a replacement component directly in the components prop can
+ cause issues.
+
+ On this topic, React
+ [documentation](https://reactjs.org/docs/higher-order-components.html#dont-use-hocs-inside-the-render-method)
+ has the following to say:
+
+ > The problem here isn’t just about performance — remounting a component causes the state
+ of that component and all of its children to be lost.
+
+ This statement applies as well when replacing components in react-select with inline definitions.
+
+ ~~~jsx
+ // Bad: Inline declaration will cause remounting issues
+ const BadSelect = props => (
+ (
+
+ 👎 {children}
+
+ )}}
+ />
+ )
+
+ // Good: Custom component declared outside of the Select scope
+ const Control = ({ children, ...props }) => (
+
+ 👍 {children}
+
+ );
+
+ const GoodSelect = props =>
+
+ ~~~
+
+ There will likely be times that data or methods may need to be shared,
+ but this can be achieved with the \`selectProps\` prop passed to each component.
+
+ ${(
+
+
+
+ )}
+
+ ~~~
+ ~~~
+
+ ## Adjusting the Styling
+
+ The \`styles\` prop allows you to pass styles to a particular component, without
+ replacing the entire component. If you only want to change styling, you should
+ start by using the \`styles\` prop.
+
+ ## Replaceable components
+
+ ### ClearIndicator
+
+ The indicator presented to clear the values from the component. The default
+ component is a cross. The conditions under which the indicator will not be
+ rendered when:
+
+ * When \`isClearable\` is false, or when \`isMulti\` is false, and \`isClearable\` is undefined
+ * When the select is disabled
+ * When the select has no value
+ * When the select is loading
+
+ See [props docs](/props#clearindicator) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Control
+
+ The second highest level wrapper around the components. It is responsible for the
+ positioning of the \`ValueContainer\` and \`IndicatorsContainer\`. It is followed
+ by the Menu.
+
+ See [props docs](/props#control) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Dropdown Indicator
+
+ The indicator for opening the select, designed to indicate to users that
+ this is a select. By default it is a chevron pointed down.
+
+ See [props docs](/props#dropdownindicator) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Group
+
+ The wrapper around each group if the Select has groups in its data. The default
+ component is responsible both for mapping its options, as well as rendering
+ its data into the GroupHeading.
+
+ See [props docs](/props#group) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### GroupHeading
+
+ Component that renders the data of a group.
+
+ See [props docs](/props#groupheading) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### IndicatorsContainer
+
+ Wraps the indicators. This is one of the two components directly under the
+ control. The indicators that \`react-select\` will check to render by are:
+
+ * Clear Indicator
+ * Loading Indicator
+ * Dropdown Indicator
+
+ See [props docs](/props#indicatorscontainer) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Indicator Separator
+
+ Component directly to the the inner side of the Dropdown Indicator. By default
+ it is a line to act as a visual separator.
+
+ See [props docs](/props#customindicatorseparator) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Input
+
+ Input to render when an input is required. If the select is not searchable,
+ a dummy input is rendered instead. If the select is disabled, a div of the
+ correct size and shape is rendered.
+
+ All provided inputs are given aria attributes to ensure the input is accessible
+ by default.
+
+ See [props docs](/props#input) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### LoadingIndicator
+
+ Loading indicator to be displayed in the Indicators Container when \`isLoading\`
+ is true. By default it is three dots.
+
+ See [props docs](/props#loadingindicator) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Menu
+
+ The wrapper for the dropdown menu in the select. It is responsible for wrapping
+ the menu items. If you want to modify the options themselves, you should use
+ the \`Option\` component.
+
+ See [props docs](/props#menu) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### MenuList
+
+ Inner wrapper for the menu. It directly wraps around the returned options.
+
+ See [props docs](/props#menulist) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### LoadingMessage
+
+ Message to display in the menu when there are no options and \`isLoading\` is
+ true. By default it is 'Loading...'
+
+ See [props docs](/props#loadingmessage) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### NoOptionsMessage
+
+ Message to be displayed in the menu if there are no options passed in.
+
+ See [props docs](/props#nooptionsmessage) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### MultiValue
+
+ Component used to display a selected option in the input when \`isMulti\` is
+ true. Takes responsibility for rendering the \`MultiValueContainer\`,
+ \`MultiValueLabel\`, and \`MultiValueRemove\`.
+
+ ### MultiValueContainer
+
+ Wraps the Label and Remove in a Multi Value
+
+ See [props docs](/props#multivaluecontainer) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### MultiValueLabel
+
+ Receives the value of the option and is responsible for rendering it to the
+ input.
+
+ See [props docs](/props#multivaluelabel) for more details
+
+ ${(
+
+
+
+ )}
+
+
+ ### MultiValueRemove
+
+ Receives an onClick to remove the selected item. By default it is a cross.
+
+ See [props docs](/props#multivalueremove) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### Option
+
+ Component responsible for displaying an option in the menu.
+
+ See [props docs](/props#option) for more details
+
+ ${(
+
+
+
+ )}
+
+
+ ### Placeholder
+
+ Component to be displayed in the input when nothing is selected. By default
+ it is the text 'Select...'
+
+ See [props docs](/props#placeholder) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### SelectContainer
+
+ The wrapper around the entire select component.
+
+ See [props docs](/props#selectcontainer) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### SingleValue
+
+ The component that displays the selected value in the input for a single select.
+
+ See [props docs](/props#singlevalue) for more details
+
+ ${(
+
+
+
+ )}
+
+ ### ValueContainer
+
+ Container responsible for loading the placeholder value and the input.
+
+ See [props docs](/props#valuecontainer) for more details
+
+ ${(
+
+
+
+ )}
+ `}
+
+ );
+}
diff --git a/docs/pages/creatable/index.tsx b/docs/pages/creatable/index.tsx
new file mode 100644
index 0000000000..87d8b6d763
--- /dev/null
+++ b/docs/pages/creatable/index.tsx
@@ -0,0 +1,91 @@
+import React, { Fragment } from 'react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+import ExampleWrapper from '../../ExampleWrapper';
+
+import {
+ AsyncCreatable,
+ CreatableAdvanced,
+ CreatableInputOnly,
+ CreatableMulti,
+ CreatableSingle,
+} from '../../examples';
+
+export default function Creatable() {
+ return (
+
+
+ Creatable - React Select
+
+
+ {md`
+ # Creatable
+
+ ~~~jsx
+ import Creatable, { useCreatable } from 'react-select/creatable';
+ ~~~
+
+ For the prop definition, please see the API docs [here](/props)
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ > This example uses the \`onCreateOption\` prop to handle new options.
+
+ > To simulate waiting for a back-end service to create a new option, the input is disabled for a second before the new option is added to the list and the value is updated.
+
+ ${(
+
+
+
+ )}
+
+ > This example uses the combined async + creatable variant, imported from \`react-select/async-creatable\`
+
+ ${(
+
+
+
+ )}
+ `}
+
+ );
+}
diff --git a/docs/pages/home/index.tsx b/docs/pages/home/index.tsx
new file mode 100644
index 0000000000..733cafc809
--- /dev/null
+++ b/docs/pages/home/index.tsx
@@ -0,0 +1,199 @@
+import React from 'react';
+import ExampleWrapper from '../../ExampleWrapper';
+import md from '../../markdown/renderer';
+import {
+ AsyncCallbacks,
+ AsyncPromises,
+ AnimatedMulti,
+ BasicSingle,
+ BasicGrouped,
+ BasicMulti,
+ CreatableSingle,
+ FixedOptions,
+ StyledMulti,
+ StyledSingle,
+} from '../../examples';
+
+export default function Home() {
+ return md`
+ # Welcome
+
+ Each of the examples below is an interactive example of react-select.
+
+ See the source or open the examples on codesandbox using the buttons that appear when you hover over each select below.
+
+ For complete docs, see the [Props API](/props) and [Advanced Usage](/advanced).
+
+ To contribute, or open an issue, check out the [source code on GitHub](https://github.com/JedWatson/react-select).
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ ${( )}
+
+ ## Getting Started
+
+ Start by installing \`react-select\`
+
+ ~~~bash
+ yarn add react-select
+ ~~~
+
+ or
+
+ ~~~bash
+ npm i --save react-select
+ ~~~
+
+ Import the default export and render in your component:
+
+ ~~~jsx
+ import React from 'react'
+ import Select from 'react-select'
+
+ const options = [
+ { value: 'chocolate', label: 'Chocolate' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'vanilla', label: 'Vanilla' }
+ ]
+
+ const MyComponent = () => (
+
+ )
+ ~~~
+
+ ${(
+
+
+
+ )}
+
+ ## Animated Components
+
+ React-Select comes with a makeAnimated function that create animated wrappers around components passed in as arguments.
+ If no arguments are passed, built-in components are wrapped instead.
+
+ ~~~jsx
+ import makeAnimated from 'react-select/animated';
+ ~~~
+
+ Remove the values below to see them in action.
+
+ ${(
+
+
+
+ )}
+
+ ## Custom Styles
+
+ Style individual components with custom css using the \`styles\` prop.
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ You can see a full explanation of how to do this on the [styles](/styles) page.
+
+ # Async
+ Use the Async component to load options from a remote source as the user types.
+
+ ~~~jsx
+ import AsyncSelect from 'react-select/async';
+ ~~~
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ You can see a full explanation of how to do this on the [async](/async) page.
+
+ # Creatable
+ The Creatable component enables users to create new options along with choosing existing options.
+
+ ~~~jsx
+ import Creatable from 'react-select/creatable';
+ ~~~
+
+ ${(
+
+
+
+ )}
+
+ You can see a full explanation of how to do this on the [creatable](/creatable) page.
+
+ # Fixed Options
+
+ ${(
+
+
+
+ )}
+`;
+}
diff --git a/docs/pages/props/index.tsx b/docs/pages/props/index.tsx
new file mode 100644
index 0000000000..4b8ee95b18
--- /dev/null
+++ b/docs/pages/props/index.tsx
@@ -0,0 +1,259 @@
+import React, { Fragment } from 'react';
+
+import { Helmet } from 'react-helmet';
+import type { MagicalNodeRecord } from '../../generate-magical-types/src/types';
+import md from '../../markdown/renderer';
+
+import { metadata, useMagicalNodes, getNodeType } from '../../utils';
+import { PropTypes } from '@magical-types/pretty';
+
+type ShowTypesProps = {
+ getNode?: getNodeType;
+ type?: MagicalNodeRecord;
+};
+
+const ShowTypes = ({ getNode, type }: ShowTypesProps) => {
+ if (!type || !type.index) return null;
+ if (!getNode) return loading ;
+
+ return ;
+};
+
+export default function Api() {
+ const getNode = useMagicalNodes();
+ const stateManagerTypes = metadata['stateManager'];
+ const selectTypes = metadata['react-select'];
+ const asyncTypes = metadata['Async'];
+ const creatableTypes = metadata['Creatable'];
+ console.log(stateManagerTypes);
+ return (
+
+
+ API - React Select
+
+
+ {md`
+ # API
+
+ ## Prop Types
+
+ ### Internal Types
+
+ You'll see these in the public props below:
+
+ ~~~js
+ type OptionType = { [string]: any }
+ type OptionsType = Array
+
+ type GroupType = {
+ [string]: any, // group label
+ options: OptionsType,
+ }
+
+ type ValueType = OptionType | OptionsType | null | void
+
+ type CommonProps = {
+ clearValue: () => void,
+ getStyles: (string, any) => {},
+ getValue: () => ValueType,
+ hasValue: boolean,
+ isMulti: boolean,
+ options: OptionsType,
+ selectOption: OptionType => void,
+ selectProps: any,
+ setValue: (ValueType, ActionTypes) => void,
+ emotion: any,
+ }
+
+ // passed as the second argument to \`onChange\`
+ type ActionTypes = | 'clear' | 'create-option' | 'deselect-option' | 'pop-value' | 'remove-value' | 'select-option' | 'set-value'
+ ~~~
+
+ Even when commonProps are not listed in the prop types below, a custom component
+ will still have access to them.
+
+ ## StateManager Props
+
+ The statemanager is a utility class that wraps around the base Select and each Select variant to
+ expose inputValue and value as controllable props. For more detailed information on these props and their usage
+ please see the [controlled props](/advanced#controlled-props) section of the advanced page.
+
+ ${(
+
+ )}
+
+ ## Select Props
+
+ These base props are those available to be passed to all select variants.
+
+ ${( )}
+
+ ## Async props
+
+ These props are included with in both the Async and AsyncCreatable select. For
+ more on using async selects, see the [async select documentation](/async)
+
+ ${( )}
+
+ ## Creatable props
+
+ ${(
+
+ )}
+
+ These props are included with in both the Creatable and AsyncCreatable select. For
+ more on using creatable selects, see the [creatable select documentation](/creatable)
+
+
+ ## Replacing Components
+
+ React-Select allows you to augment layout and functionality by replacing
+ the default components with your own, using the \`components\`
+ property. These components are given all the current props and state
+ letting you achieve anything you dream up. For more information in replacing
+ components see [the components documentation](/components)
+
+ ### Inner Ref
+ Some components are passed an innerRef property to facilitate for internally
+ managed behaviour within the base select. This should be assigned to the
+ ref property of the relevant dom element.
+ i.e.
+
+ ~~~
+ const CustomOptionComponent = ({ innerProps, innerRef }) =>
+ (
)
+ ~~~
+
+ ### Inner Props
+
+ All functional properties that the component needs are provided in
+ \`innerProps\` which you must spread.
+
+ ## Components
+
+ **IMPORTANT NOTE** The below props are provided automatically by \`react-select\`
+ when these components are passed into the \`components\` object above. Knowing
+ their API is most necessary if you intend to provide your own components, to
+ understand what information they will be handed.
+
+ ### ClearIndicator
+
+ ${( )}
+
+ ### Control
+
+ ${( )}
+ ### DropdownIndicator
+
+ ${(
+
+ )}
+
+ ### Group
+
+ ${( )}
+
+ ### GroupHeading
+
+ Group Heading can be any component.
+
+ ### IndicatorsContainer
+
+ ${(
+
+ )}
+
+ ### IndicatorSeparator
+
+ ${(
+
+ )}
+
+ ### Input
+
+ ${( )}
+
+ ### LoadingIndicator
+
+ ${(
+
+ )}
+
+ ### Menu
+
+ ${( )}
+
+ ### MenuList
+
+ ${( )}
+
+ ### LoadingMessage
+
+ ${( )}
+
+ ### NoOptionsMessage
+
+ ${( )}
+
+ ### MultiValue
+
+ ${( )}
+
+ ### MultiValueContainer
+
+ ${(
+
+ )}
+
+ ### MultiValueLabel
+
+ ${(
+
+ )}
+
+ ### MultiValueRemove
+
+ ${(
+
+ )}
+
+ ### Option
+
+ ${( )}
+
+ ### Placeholder
+
+ ${( )}
+
+ ### SelectContainer
+
+ ${( )}
+
+ ### SingleValue
+
+ ${( )}
+
+ ### ValueContainer
+
+ ${( )}
+
+
+ `}
+
+ );
+}
diff --git a/docs/pages/styles/index.tsx b/docs/pages/styles/index.tsx
new file mode 100644
index 0000000000..e113c6e997
--- /dev/null
+++ b/docs/pages/styles/index.tsx
@@ -0,0 +1,274 @@
+/** @jsx jsx */
+import React, { Fragment } from 'react';
+import { jsx } from '@emotion/react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+import ExampleWrapper from '../../ExampleWrapper';
+import {
+ StyledSingle,
+ StyledMulti,
+ Theme,
+ StyleCompositionExample,
+} from '../../examples';
+import { ColorSample } from '../../styled-components';
+import { defaultTheme } from 'react-select';
+
+export default function Styles() {
+ return (
+
+
+ Styles - React Select
+
+
+ {md`
+ # Styles
+
+ React Select offers 3 main APIs for styling:
+
+ - [The styles prop](#the-styles-prop)
+ - [The classNames prop](#the-classnames-prop)
+ - [The classNamePrefix prop](#the-classnameprefix-prop)
+
+ ## The styles prop
+
+ The recommended way to provide custom styles to \`react-select\` is to use the \`styles\` prop.
+ \`styles\` takes an object with keys to represent the various [inner components](#inner-components) that \`react-select\` is made up of.
+ Each inner component takes a callback function with the following signature:
+
+ ~~~jsx
+ ({
+ ...baseStyles,
+ borderColor: state.isFocused ? 'grey' : 'red',
+ }),
+ }}
+ />
+ ~~~
+
+ The first argument is an object with the base styles. Spreading the base styles into your returned object lets you extend it however you like while maintaining existing styles. Alternatively, you can omit the provided styles and completely take control of the component's styles.
+
+ The second argument is the current state (features like \`isFocused\`, \`isSelected\` etc). This allows you to implement dynamic styles for each of the components.
+
+ ## The classNames prop
+
+ As of version \`5.7.0\` of \`react-select\` you can now use the \`classNames\` prop for styling. Note: this is not to be confused with the \`className\` prop, which will add a class to the component.
+
+ \`classNames\` takes an object with keys to represent the various [inner components](#inner-components) that \`react-select\` is made up of.
+ Each inner component takes a callback function with the following signature:
+
+ ~~~jsx
+
+ state.isFocused ? 'border-red-600' : 'border-grey-300',
+ }}
+ />
+ ~~~
+
+ ### Note on CSS specificity
+
+ If you are using the \`classNames\` API and you are trying to override some base styles with the same level of specificity, you must ensure that your provided styles are declared later than the styles from React Select (e.g. the \`link\` or \`style\` tag in the head of your HTML document) in order for them to take precedence.
+
+ For an example on how you might want to do this, see the [Storybook example here](https://github.com/JedWatson/react-select/blob/master/storybook/stories/ClassNamesWithTailwind.stories.tsx).
+
+ ## The unstyled prop
+
+ If you are trying to style everything from scratch you can use the \`unstyled\` prop. This removes all the presentational styles from React Select (leaving some important functional styles, like those for menu positioning and input width in multi select).
+
+ This will make it easier to completely specify your own \`styles\` _or_ \`classNames\` to control the look of React Select, without having to specifically override the default theme we apply.
+
+ ## Inner components
+
+
+ See list of keys for all of React Select's inner components
+
+ clearIndicator
+ container
+ control
+ dropdownIndicator
+ group
+ groupHeading
+ indicatorsContainer
+ indicatorSeparator
+ input
+ loadingIndicator
+ loadingMessage
+ menu
+ menuList
+ menuPortal
+ multiValue
+ multiValueLabel
+ multiValueRemove
+ noOptionsMessage
+ option
+ placeholder
+ singleValue
+ valueContainer
+
+
+
+ ## The classNamePrefix prop
+
+ If you provide the \`classNamePrefix\` prop to React Select, all inner elements will be given a className with the provided prefix.
+
+ Given the following JSX:
+
+ ~~~jsx
+
+ ~~~
+
+ ...the DOM structure is similar to this:
+
+ ~~~html
+
+ ~~~
+
+ ## Select props
+
+ In the \`state\` argument for both the \`styles\` and \`classNames\` API, you have access to \`selectProps\` which will allow you to gain access to your own arguments passed into the Select body.
+
+
+
+
+
+ ## cx and custom Components
+
+ In the event that you need to rewrite a particular component, you'll also have to compose together the styling functionality.
+ Thankfully all the requisite parts are supplied to you via props as below:
+
+ ### cx
+ cx is an internal utility function that manages the composition of emotion style declarations, className/classNamePrefixes and
+ additional BEM style modifiers into a selector value for each component.
+ It has the following signature:
+
+ ~~~
+ (prefix ?: string,
+ cssKey?: string,
+ state?: {},
+ className?: string) => string
+ ~~~
+
+ * prefix: is the value of the optional classNamePrefix,
+ * cssKey: is the uid generated by the invocation of the css method imported from emotion
+ * state: an object declaring state based modifiers to be applied to our selector
+ * className: any className prop specified for custom components will also be composed into the selector string produced by the cx functions
+
+ ### getStyles
+ Each component gets passed a getStyles method which has the following signature:
+
+ ~~~
+ (key: string, props: Object) => stylesObject;
+ ~~~
+
+ The key is a lowercased string value corresponding to the component that the styles apply to,
+ i.e. option for the Option component, menuplacer for the MenuPlacer component.
+
+ The props argument is an object of relevant properties/ state values that are relevant to computing styles,
+ i.e. isFocused or isSelected. Additional props can be added here for computation using the styles api.
+
+ In the end configuring your custom component with the correct styling functionality should look like this
+ ~~~
+ import { css } from 'emotion';
+
+ const CustomOption = ({ cx, children, getStyles, innerRef, ...props }) => (
+
+ {children}
+
+ )
+ ~~~
+
+ ${(
+
+
+
+ )}
+
+ ## Overriding the theme
+
+ The default styles are derived from a theme object, which you can mutate like \`styles\`.
+
+ The \`theme\` object is available for the \`styles\` functions as well.
+
+ ${(
+
+
+
+ )}
+
+ ###### Theme colors
+
+ ${(
+
+ {Object.keys(defaultTheme.colors).map((key) => (
+
+ ))}
+
+ )}
+
+ ## Examples
+
+ ${(
+
+
+
+ )}
+
+ ${(
+
+
+
+ )}
+
+ `}
+
+ );
+}
diff --git a/docs/pages/typescript/index.tsx b/docs/pages/typescript/index.tsx
new file mode 100644
index 0000000000..f296b03e20
--- /dev/null
+++ b/docs/pages/typescript/index.tsx
@@ -0,0 +1,114 @@
+import React from 'react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+
+export default function TypeScript() {
+ return (
+ <>
+
+ TypeScript - React Select
+
+
+ {md`
+# TypeScript usage
+
+## Select generics
+
+There are three generics used by the \`Select\` component: \`Option\`, \`IsMulti\`, and \`Group\`. All of them are optional and TypeScript attempts to detect them automatically, but sometimes it might need some help. Many of the \`react-select\` types include the three generics like this:
+
+~~~jsx
+interface SelectProps<
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+> {
+ ...
+}
+~~~
+
+### \`Option = unknown\`
+
+This is the type of the option passed into the \`options\` prop (or the \`options\` property on groups). If TypeScript can't detect what type this should be, it defaults to \`unknown\`. This generic comes in handy for correctly typing callbacks like \`filterOption\`, \`formatOptionLabel\`, \`getOptionLabel\`, \`getOptionValue\`, \`isOptionDisabled\`, \`isOptionSelected\`, \`onChange\`, etc.
+
+### \`IsMulti extends boolean = false\`
+
+This type is \`false\` for single-selects and is \`true\` for multi-selects. It defaults to \`false\` for the exported components because TypeScript isn't smart enough to figure out that it should be \`false\` if the \`isMulti\` prop is not specified, but on other exported interfaces it defaults to \`boolean\` so that it handles both single-select and multi-select values. This generic is primarily used to determine the type of the first argument passed to \`onChange\` which will be \`Option | null\` if \`IsMulti\` is \`false\` and will be \`readonly Option[]\` if \`IsMulti\` is \`true\`.
+
+### \`Group extends GroupBase = GroupBase \`
+
+This generic is the type for the groups that are passed into the \`options\` when using groups. The \`GroupBase\` type is:
+
+~~~jsx
+interface GroupBase {
+ readonly options: readonly Option[];
+ readonly label?: string;
+}
+~~~
+
+This generic comes in handy when trying to type the \`formatGroupLabel\` prop.
+
+### Wrapping the \`Select\` component
+
+Oftentimes the \`Select\` component is wrapped in another component that is used throughout an app and the wrapper should be just as flexible as the original \`Select\` component (i.e., allow for different \`Option\` types, groups, single-select, or multi-select). In order to provide this flexibility, the wrapping component should re-declare the generics and forward them to the underlying \`Select\`. Here is an example of how to do that:
+
+~~~jsx
+function CustomSelect<
+ Option,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+>(props: Props ) {
+ return (
+ ({ ...theme, borderRadius: 0 })} />
+ );
+}
+~~~
+
+## onChange
+
+If you have a single-select you can type \`onChange\` like this:
+
+~~~jsx
+const onChange = (option: Option | null, actionMeta: ActionMeta) => {
+ ...
+}
+~~~
+
+If you have a multi-select you can type \`onChange\` like this:
+
+~~~jsx
+const onChange = (option: readonly Option[], actionMeta: ActionMeta ) => {
+ ...
+}
+~~~
+
+The \`actionMeta\` parameter is optional. \`ActionMeta\` is a union that is discriminated on the \`action\` type. Take a look at [types.ts](https://github.com/JedWatson/react-select/blob/master/packages/react-select/src/types.ts) in the source code to see its full definition.
+
+## Custom Select props
+
+You can use module augmentation to add custom props to the \`Select\` prop types:
+
+~~~jsx
+import type {} from 'react-select/base';
+// This import is necessary for module augmentation.
+// It allows us to extend the 'Props' interface in the 'react-select/base' module
+// and add our custom property 'myCustomProp' to it.
+
+declare module 'react-select/base' {
+ export interface Props<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+ > {
+ myCustomProp: string;
+ }
+}
+~~~
+
+This will make the custom prop available both when using the \`Select\` component as well as when accessing \`selectProps\` when [customising components](./components).
+ `}
+ >
+ );
+}
diff --git a/docs/pages/upgrade-to-v2/index.tsx b/docs/pages/upgrade-to-v2/index.tsx
new file mode 100644
index 0000000000..57b374001f
--- /dev/null
+++ b/docs/pages/upgrade-to-v2/index.tsx
@@ -0,0 +1,297 @@
+import React, { Fragment } from 'react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+
+import PropChanges from './props';
+
+export default function UpgradeGuide() {
+ return (
+
+
+ {'React Select v1.x -> 2.x Upgrade Guide'}
+
+
+ {md`
+# Upgrade guide for v2
+
+> This guide is a work in progress. Please [open an issue](https://github.com/jedwatson/react-select/issues)
+> if you need something clarified, or [submit a PR](https://github.com/jedwatson/react-select/pulls)
+> if you have an improvement!
+
+React-select v2 is a complete rewrite, and includes some major changes:
+
+- The architecture has been cleaned up
+- Many redundant props have been removed
+- Several major features have been added (including option groups!)
+- The custom component API has been reinvented and is much more consistent
+- Styles are now implemented with css-in-js rather than less / scss stylesheets
+- Support for option groups has been added 🎉
+- You can use any shape of data in your options array, and control how they are
+ handled by providing custom functions
+
+With that in mind, we've tried to make the upgrade as easy as possible. How
+complex the upgrade is will depend on how much you have customised react-select.
+
+We've also done our best to keep feature parity with v1, either through
+continuing to support props or by providing another way to achieve the same
+result.
+
+## Concepts
+
+### Controllable Props and defaults
+
+In v2, there are three optional props you can use to control the state of the
+component:
+
+- \`value\` controls the select value
+- \`inputValue\` controls the search input value
+- \`menuIsOpen\` controls whether the menu is open
+
+You can use none, any, or all of these depending on your requirements.
+
+The props have associated events that are called when the value should change.
+Here's an example implementation of all three:
+
+~~~js
+ this.setState({ value })}
+ inputValue={this.state.inputValue}
+ onInputChange={(inputValue) => this.setState({ inputValue })}
+ menuIsOpen={this.state.menuIsOpen}
+ onMenuOpen={() => this.setState({ menuIsOpen: true })}
+ onMenuClose={() => this.setState({ menuIsOpen: false })}
+/>
+~~~
+
+If you don't use the controlled props, react-select has props that let you
+default their value when it mounts:
+
+~~~js
+
+~~~
+
+For more information, see
+[controlled components](https://reactjs.org/docs/forms.html#controlled-components)
+and [uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html)
+in the React docs.
+
+### Action Meta
+
+The \`onChange\` prop is now passed a second argument, which contains meta about
+why the event was called. For example:
+
+~~~js
+onChange = (newValue, actionMeta) => console.log(actionMeta);
+// possible values:
+{
+ action: 'select-option' |
+ 'deselect-option' |
+ 'remove-value' |
+ 'pop-value' |
+ 'set-value' |
+ 'clear' |
+ 'create-option';
+}
+~~~
+
+The new \`onInputChange\` prop also passes actionMeta:
+
+~~~js
+onInputChange = (newValue, actionMeta) => console.log(actionMeta);
+// possible values:
+{
+ action: 'set-value' | 'input-change' | 'input-blur' | 'menu-close';
+}
+~~~
+
+### Options Data
+
+You can now provide option data in any shape you like, without conforming to the
+expected \`{ label, value }\` keys.
+
+This means the \`labelKey\` and \`valueKey\` props are no longer supported.
+
+Instead, you can use the following props to customise how react-select deals
+with your options:
+
+~~~
+ boolean}
+ formatOptionLabel={(option: {}, context: {} ) => Node}
+ getOptionLabel={(option: {}) => string}
+ getOptionValue={(option: {}) => string}
+ isOptionDisabled={(option: {}, value: [{}]) => boolean}
+ isOptionSelected?={(option: {}, value: [{}]) => boolean}
+/>
+~~~
+
+## New Styles API
+
+Where v1 included LESS / SCSS stylesheets and applied styles using classNames,
+v2 uses css-in-js to apply styles. This gives you complete control over how
+the control looks, but is a significant change.
+
+Each component that react-select renders has a corresponding key that you can
+specify in the \`styles\` prop. Each value you provide should be a function that
+takes the default styles, and returns your customised style object.
+
+For example, to give the control a white background:
+
+~~~js
+styles={{
+ control: (base) => ({ ...base, color: 'white' })
+}}
+~~~
+
+See the [Styles Documentation](/styles) for more details and examples.
+
+This means the following props have been removed, and their use-cases should now
+be handled with the new styles API:
+
+- \`menuContainerStyle\`
+- \`menuStyle\`
+- \`optionClassName\`
+- \`wrapperStyle\`
+
+### Using classNames
+
+If you provide the \`classNamePrefix\` prop to react-select, all inner elements will
+be given a className based on the one you have provided.
+
+For example, given \`classNamePrefix="react-select"\`, the DOM would roughly look
+like this:
+
+~~~html
+
+~~~
+
+## New Components API
+
+React-select v1 had several props that would allow you to render specific parts
+of the UI, or specify your own custom components.
+
+In v2, we've doubled down on this approach and introduced a new \`components\`
+prop that lets you replace any part of react-select.
+
+For example, to render a custom \`Option\` component:
+
+~~~js
+components={{
+ Option: ({ children, innerProps }) => (
+
+ {children}
+
+ )
+}}
+~~~
+
+All components are passed a set of common props. The most important to
+understand are:
+
+- \`children\` - if the component should contain other components (for example,
+ a menu contains options) they will be passed as children. This way you don't
+ need to re-implement more than you absolutely need to.
+- \`innerProps\` - a set of props that should be spread onto the DOM element
+ your component returns. It wires up accessibility attributes and events.
+- \`getStyles\` - a function that will return an object containing the styles
+ for the component. If you have specified custom style modifiers, they will be
+ executed by this function.
+- \`innerRef\` - additional some components need to expose a ref to
+ the base Select component, to facilitate internally managed behaviour.
+ We specify this as innerRef to avoid collision with React's reserved \`ref\`
+ keyword when we spread props.
+
+Aside from innerRef (where applicable), you don't _have_ to use these props, and are free to implement whatever - but
+they are intended to help make custom implementations easier to manage.
+
+See the [Components Documentation](/components) for more details and
+examples.
+
+This means the following props have been removed, and their use-cases should now
+be handled with the new components API:
+
+- \`inputProps\`
+- \`inputRenderer\`
+- \`menuRenderer\`
+- \`optionComponent\`
+- \`optionRenderer\`
+- \`valueComponent\`
+- \`valueRenderer\`
+- \`arrowRenderer\`
+- \`clearRenderer\`
+
+## Filtering
+
+Where react-select v1 had several props for controlling how options are
+filtered, v2 simply expects you to provide a function that tests each option
+against the input value.
+
+The new export \`createFilter\` allows you to easily create a filter function
+that implements the same options previously available as props to react-select.
+
+For example:
+
+~~~js
+import Select, { createFilter } from 'react-select';
+
+const customFilter = createFilter({
+ ignoreCase?: boolean,
+ ignoreAccents?: boolean,
+ stringify?: Object => string,
+ trim?: boolean,
+ matchFrom?: 'any' | 'start',
+});
+
+
+~~~
+
+See the [Advanced Guide](/advanced) for more details and examples.
+
+## Simple Value
+
+React-select v1 allowed you to use strings for the \`value\` prop, but with v2 we've deprecated this behaviour
+in favor of a value prop that is always either an array of Options objects or an Options object.
+If you still want to manage your selected values as a simple string you
+can easily do so by applying a simple filter on your dataset as below.
+
+~~~js
+const options = [
+ { name: 'John', id: 1 },
+ { name: 'Doe', id: 2 },
+];
+return (
+ id === this.state.id)}
+ getOptionLabel={({ name }) => name}
+ getOptionValue={({ id }) => id}
+ onChange={({ value }) => this.setState({ id: value })}
+ />
+);
+~~~
+
+Note that if you use the default react-select options schema (an array with
+objects having \`label\` and \`value\` keys) you don't need to define
+\`getOptionValue\` nor \`getOptionLabel\`.
+
+## Prop Update Guide
+ `}
+
+
+ );
+}
diff --git a/docs/pages/upgrade-to-v2/props.tsx b/docs/pages/upgrade-to-v2/props.tsx
new file mode 100644
index 0000000000..7c44a4139a
--- /dev/null
+++ b/docs/pages/upgrade-to-v2/props.tsx
@@ -0,0 +1,363 @@
+import React, {
+ Component,
+ Fragment,
+ FunctionComponent,
+ ReactElement,
+} from 'react';
+
+import Select, { components, OptionProps } from 'react-select';
+import md from '../../markdown/renderer';
+import { Table, Header, Cell } from '../../Table';
+
+const Code: FunctionComponent = ({ children }) => {children};
+
+const propChangeData: (
+ | [string, string]
+ | [string, string, string | ReactElement]
+)[] = [
+ ['aria-describedby', 'unchanged'],
+ ['aria-label', 'unchanged'],
+ ['aria-labelledby', 'unchanged'],
+ ['arrowRenderer', 'components'],
+ ['autoBlur', 'renamed', 'blurInputOnSelect'],
+ ['autoFocus', 'unchanged'],
+ ['autoLoad', 'removed', 'see the Async component (defaultOptions)'],
+ ['autosize', 'components'],
+ ['backspaceRemoves', 'renamed', 'backspaceRemovesValue'],
+ [
+ 'backspaceToRemoveMessage',
+ 'removed',
+ 'may be implemented in a later version',
+ ],
+ ['className', 'unchanged'],
+ ['clearable', 'renamed', 'isClearable'],
+ ['clearAllText', 'removed'],
+ ['clearRenderer', 'components'],
+ ['clearValueText', 'removed'],
+ ['closeOnSelect', 'renamed', 'closeMenuOnSelect'],
+ ['deleteRemoves', 'removed'],
+ ['delimiter', 'unchanged'],
+ ['disabled', 'renamed', 'isDisabled'],
+ ['escapeClearsValue', 'unchanged'],
+ [
+ 'filterOptions',
+ 'removed',
+ md`
+use \`filterOption\` instead
+ `,
+ ],
+ ['id', 'unchanged'],
+ [
+ 'ignoreAccents',
+ 'removed',
+ md`
+see \`createFilter()\`
+ `,
+ ],
+ [
+ 'ignoreCase',
+ 'removed',
+ md`
+see \`createFilter()\`
+ `,
+ ],
+ ['inputProps', 'components'],
+ ['inputRenderer', 'components'],
+ ['instanceId', 'unchanged'],
+ ['isLoading', 'unchanged'],
+ [
+ 'joinValues',
+ 'removed',
+ md`
+now inferred from \`delimiter\`
+ `,
+ ],
+ ['labelKey', 'removed'],
+ ['loadOptions', 'unchanged'],
+ [
+ 'matchPos',
+ 'removed',
+ md`
+see \`createFilter()\`
+ `,
+ ],
+ [
+ 'matchProp',
+ 'removed',
+ md`
+see \`createFilter()\`
+ `,
+ ],
+ ['menuBuffer', 'styles'],
+ ['menuContainerStyle', 'styles'],
+ ['menuRenderer', 'components'],
+ ['menuStyle', 'styles'],
+ ['multi', 'renamed', 'isMulti'],
+ ['name', 'unchanged'],
+ ['noResultsText', 'renamed', 'noOptionsMessage'],
+ ['onBlur', 'unchanged'],
+ ['onBlurResetsInput', 'removed'],
+ ['onClose', 'renamed', 'onMenuClose'],
+ ['onCloseResetsInput', 'removed'],
+ ['onFocus', 'unchanged'],
+ ['onInputChange', 'unchanged'],
+ ['onInputKeyDown', 'renamed', 'onKeyDown'],
+ ['onMenuScrollToBottom', 'unchanged'],
+ ['onOpen', 'renamed', 'onMenuOpen'],
+ ['onSelectResetsInput', 'removed'],
+ ['onValueClick', 'removed'],
+ ['openOnClick', 'renamed', 'openMenuOnClick'],
+ ['openOnFocus', 'renamed', 'openMenuOnFocus'],
+ ['optionClassName', 'components'],
+ ['optionComponent', 'components'],
+ ['optionRenderer', 'components'],
+ ['options', 'unchanged'],
+ ['pageSize', 'unchanged'],
+ ['placeholder', 'changed', 'now only accepts a string'],
+ ['removeSelected', 'renamed', 'hideSelectedOptions'],
+ ['required', 'removed', 'may be implemented in a later version'],
+ [
+ 'resetValue',
+ 'removed',
+ md`
+control the \`value\` prop
+ `,
+ ],
+ ['rtl', 'renamed', 'isRtl'],
+ ['scrollMenuIntoView', 'renamed', 'menuShouldScrollIntoView'],
+ ['searchable', 'renamed', 'isSearchable'],
+ ['searchPromptText', 'removed'],
+ ['simpleValue', 'removed'],
+ ['style', 'styles'],
+ ['tabIndex', 'unchanged'],
+ ['tabSelectsValue', 'unchanged'],
+ [
+ 'trimFilter',
+ 'removed',
+ md`
+see \`createFilter()\`
+ `,
+ ],
+ ['value', 'unchanged'],
+ ['valueComponent', 'components'],
+ ['valueKey', 'removed'],
+ ['valueRenderer', 'components'],
+ ['wrapperStyle', 'styles'],
+];
+
+interface Props {
+ prop: string;
+ status: string;
+ note: string | ReactElement | undefined;
+}
+
+class PropStatus extends Component {
+ renderStatus() {
+ const { status, note } = this.props;
+ switch (status) {
+ case 'components':
+ return (
+
+ | removed |
+ use the new Components API |
+
+ );
+ case 'styles':
+ return (
+
+ | removed |
+ use the new Styles API |
+
+ );
+ case 'renamed':
+ return (
+
+ | renamed |
+
+ use {note}
+ |
+
+ );
+ default:
+ return (
+
+ | {status} |
+ {note} |
+
+ );
+ }
+ }
+ render() {
+ const { prop } = this.props;
+ return (
+
+
+ {prop}
+ |
+ {this.renderStatus()}
+
+ );
+ }
+}
+
+interface InputOptionState {
+ readonly isActive: boolean;
+}
+
+class InputOption extends Component {
+ state: InputOptionState = { isActive: false };
+ onMouseDown = () => this.setState({ isActive: true });
+ onMouseUp = () => this.setState({ isActive: false });
+ onMouseLeave = () => this.setState({ isActive: false });
+
+ render() {
+ const {
+ getStyles,
+ isDisabled,
+ isFocused,
+ isSelected,
+ children,
+ innerProps,
+ ...rest
+ } = this.props;
+ const { isActive } = this.state;
+
+ // styles
+ let bg = 'transparent';
+ if (isFocused) bg = '#eee';
+ if (isActive) bg = '#B2D4FF';
+
+ const style = {
+ alignItems: 'center',
+ backgroundColor: bg,
+ color: 'inherit',
+ display: 'flex ',
+ };
+
+ // prop assignment
+ const props = {
+ ...innerProps,
+ onMouseDown: this.onMouseDown,
+ onMouseUp: this.onMouseUp,
+ onMouseLeave: this.onMouseLeave,
+ style,
+ };
+
+ return (
+
+
+ {children}
+
+ );
+ }
+}
+
+const allOptions = [
+ { value: 'removed', label: 'removed' },
+ { value: 'unchanged', label: 'unchanged' },
+ { value: 'renamed', label: 'renamed' },
+];
+
+const filterOptions = [
+ { value: 'propName', label: 'propName' },
+ { value: 'status', label: 'status' },
+];
+
+const getDisplayedStatus = (status: string) => {
+ if (status === 'components' || status === 'styles') return 'removed';
+ else return status;
+};
+
+interface PropChangesProps {}
+
+interface PropChangesState {
+ readonly selectedOptions: readonly string[];
+ readonly filterValue: string;
+}
+
+class PropChanges extends Component {
+ state: PropChangesState = {
+ selectedOptions: allOptions.map((opt) => opt.value),
+ filterValue: filterOptions[0].value,
+ };
+
+ render() {
+ let { selectedOptions, filterValue } = this.state;
+
+ return (
+
+ {/* filter */}
+ Filter Props
+ {
+ if (Array.isArray(options)) {
+ this.setState({
+ selectedOptions: options.map((opt) => opt.value),
+ });
+ }
+ }}
+ options={allOptions}
+ components={{
+ Option: InputOption,
+ }}
+ />
+ {/* sort */}
+ Sort Props
+ {
+ if (!Array.isArray(option)) {
+ this.setState({ filterValue: option ? option.value : '' });
+ }
+ }}
+ options={filterOptions}
+ />
+
+
+
+
+
+
+
+
+
+ {propChangeData
+ .sort((a, b) => {
+ if (filterValue === 'propName') {
+ return a[0].localeCompare(b[0]);
+ } else {
+ return getDisplayedStatus(a[1]).localeCompare(
+ getDisplayedStatus(b[1])
+ );
+ }
+ })
+ .map((data) => {
+ const [prop, status, note] = data;
+ return selectedOptions.includes(getDisplayedStatus(status)) ? (
+
+ ) : null;
+ })}
+
+
+
+ );
+ }
+}
+
+export default PropChanges;
diff --git a/docs/pages/upgrade/index.tsx b/docs/pages/upgrade/index.tsx
new file mode 100644
index 0000000000..d3cf505974
--- /dev/null
+++ b/docs/pages/upgrade/index.tsx
@@ -0,0 +1,475 @@
+import React from 'react';
+import Helmet from 'react-helmet';
+import md from '../../markdown/renderer';
+import { Cell, Header, Table } from '../../Table';
+
+export default function Upgrade() {
+ return (
+ <>
+
+ {'React Select Upgrade Guide'}
+
+
+ <>
+ {md`
+# Upgrade guide
+
+## From v4 to v5
+
+### Summary
+
+- Convert to TypeScript - TypeScript types now come packaged with \`react-select\` so you no longer need to have \`@types/react-select\` installed; we no longer include Flow types
+- Drop IE11 support - this allows us to make changes to our CSS that we've wanted to make for a long time as well as remove unnecessary JS solutions (those changes are noted below)
+- Use \`forwardRef\` for all wrapped components - this means that if you were accessing anything on the \`Select\` instance using a \`ref\`, the \`ref\` will now reference the internal \`Select\` directly (see below for how to upgrade)
+- Replace HOCs with hooks - if you were using our HOCs to create custom \`Select\`s (i.e., \`makeCreatableSelect\`, \`manageState\`, \`makeAsyncSelect\`) these have now been replaced by hooks (i.e., \`useCreatable\`, \`useStateManager\`, \`useAsync\`)
+- Remove dependency on [AutosizeInput](https://github.com/JedWatson/react-input-autosize) - our new solution uses CSS grid which IE11 does not fully support; also \`.prefix__input\` now targets the input and NOT the container
+- Improve screen reader experience - this isn't a breaking change in the API but it does change the screen reader announcements
+- Use CSS grid for single value layout - this also isn't a breaking change in the API but is it a change in the styles since it switches to using CSS grid (not fully supported by IE11) for single-value \`Select\`s
+- Remove \`readonly\` attribute on our \`DummyInput\` - this results in better accessibility but uses \`caret-color\` which is not available on IE11
+
+### Details
+
+#### Convert to TypeScript
+
+We've rewritten \`react-select\` in TypeScript which means you can remove any dependencies on \`@types/react-select\`. If you were using the Flow types than look into contributing types for v5 to \`flow-typed\`.
+
+Here are the most notable changes when replacing \`@types/react-select\` with our packaged types:
+ `}
+
+
+ {md`
+If you were previously importing a type from the \`src\` directory when using \`@types/react-select\`:
+
+~~~jsx
+import { ... } from 'react-select/src/...';
+~~~
+
+These should now be imported from the \`dist/declarations/src\` directory:
+
+~~~jsx
+import { ... } from 'react-select/dist/declarations/src/...';
+~~~
+
+We export any types from the main entry point that we think might be useful to the user. If you are using a type that is not exported from the main entry point please open a PR or issue so that we can add it.
+
+If you are using custom props for the \`Select\` component you can use module augmentation to add them to the \`Select\` prop types:
+
+~~~jsx
+declare module 'react-select/dist/declarations/src/Select' {
+ export interface Props<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+ > {
+ myCustomProp: string;
+ }
+}
+~~~
+
+#### Drop IE11 support
+
+This allows us to use modern CSS in order to improve the quality of \`react-select\` and remove excessive JavaScript code to work around not having the ability to use modern CSS. If you need IE11 support either:
+
+1. Stay on v4.
+2. Attempt to use our [Styles API](./styles) and/or [Components API](./components) to override styles and/or components that don't support IE11. The only change that might be hard to override is "Remove \`readonly\` attribute on our \`DummyInput\`" since you can't override the \`DummyInput\` component with the Styles or Components API.
+3. If there are simple changes that make \`react-select\` compatible with IE11, open a PR. We are unlikely to provide official support for IE11 since supporting IE11 makes maintaining \`react-select\` a lot more difficult and holds us back from changes we want to make, but we also are glad to accept simple changes if they make your life easier.
+
+#### Use \`forwardRef\` for all wrapped components
+
+NOTE: Accessing any of the internals of the \`Select\` component using \`ref\`s is not part of our public API. The internals of the \`Select\` component can change at any time (including in minor and patch releases). The only methods on the \`Select\` component that are part of the public API are the \`focus()\` and \`blur()\` methods.
+
+\`react-select\` exports five components: \`BaseSelect\`, \`CreatableSelect\`, \`Select\` (the default export), \`AsyncSelect\`, \`AsyncCreatableSelect\`. The last four components are wrappers around the \`BaseSelect\`. Previously the \`ref\` for each of these components was pointing to itself, but now we use \`forwardRef\` which means that the \`ref\`s for all five components now point to \`BaseSelect\`.
+
+The \`focus()\` and \`blur()\` methods are untouched by this change. However if you were accessing the internals of the \`BaseSelect\` component, you will need to update how you were accessing the \`BaseSelect\`. Here is how to update access to the \`BaseSelect\` component:
+ `}
+
+
+ {md`
+#### Replace HOCs with hooks
+
+The primary reason for this change is that hooks combined with generic components are easier to type in TypeScript than HOCs combined with generic components. These HOCs/hooks are considered advanced usage.
+
+If you were using the HOCs, it shouldn't be too hard to replace them with its corresponding hook (i.e., \`useStateManager\`, \`useCreatable\`, or \`useAsync\`). As an example, here is how the state managed Select (the default export) used to be constructed with the \`manageState\` HOC:
+
+~~~jsx
+const Select = manageState(SelectBase);
+~~~
+
+With hooks it is now constructed like this:
+
+~~~jsx
+const Select = (props) => {
+ const baseSelectProps = useStateManager(props);
+ return ;
+};
+~~~
+
+Consult the source code for how the other components are constructed.
+
+#### Remove dependency on AutosizeInput
+
+This is an exciting change because we get to drop a dependency on \`react-input-autosize\`. We now use a pure CSS solution to auto-size the input, however this means that we have to drop support for IE11 since IE11 does not fully support CSS grid. As part of this refactor the \`.prefix__input\` CSS class now targets the input itself and NOT the container. See [#4625](https://github.com/JedWatson/react-select/pull/4625) for more details.
+
+#### Improve screen reader experience
+
+The following improvements have been made for screen reader users:
+
+- NVDA now announces the context text when initially focused
+- Selected option(s) (single and multi) are now announced when initially focused
+- VoiceOver now announces the context text when re-focusing
+- The clear action is now announced
+- Placeholder text is now announced
+- Mobile VoiceOver is now able to remove selected multi options
+
+Also we've added the role of combobox and the required ARIA attributes to the \`Input\` and \`DummyInput\` components to allow JAWS support and a better screen reader experience overall. See [#4695](https://github.com/JedWatson/react-select/issues/4695) for more details.
+
+#### Use CSS grid for single value layout
+
+Previously the absolution positioning of both the value and the placeholder pulled them out of the flow, and thus the component itself collapsed down when used as a flex child. To solve this we are now using CSS grid for the single value layout.
+
+
+
+### Remove \`readonly\` attribute on our \`DummyInput\`
+
+Previously we added the \`readonly\` attribute to the \`DummyInput\` (when \`isSearchable\` is set to \`false\`) in order to hide the flashing cursor and prevent devices from showing a virtual keyboard. However the \`readonly\` attribute causes the \`DummyInput\` to be removed from the tab order in iOS Safari. In order to solve this we're replacing the \`readonly\` attribute with setting the \`caret-color\` CSS prop (which IE11 does not support) to \`transparent\` and setting the \`inputMode\` attribute on the \` \` to \`none\`.
+
+## From v3 to v4
+
+### Summary
+
+- Standardize value passed to \`onChange\` - the \`onChange\` handler is now always passed an array of options if \`isMulti\` is set to \`true\`
+- Emotion 11 - should only affect you if you're using the \`NonceProvider\` component
+- Remove usage of UNSAFE React methods - shouldn't affect you except now you won't see those warning messages in the console anymore
+
+### Details
+
+#### Standardize value passed to \`onChange\`
+
+This change makes it so that the first parameter passed to the \`onChange\` callback will now always be an array of options if \`isMulti\` is set to \`true\` and will always be a single option or \`null\` if \`isMulti\` is set to \`false\`. Previously the first parameter of \`onChange\` could be an array _or_ \`null\` when \`isMulti\` was set to \`true\`.
+
+That means if you were previously using nullish coalescing in order to handle \`null\` for \`isMulti\` like this:
+
+~~~jsx
+ setValues(newValues ?? [])} />
+~~~
+
+You can now remove the nullish coalescing because \`onChange\` will always be an array when \`isMulti\` is set to \`true\`:
+
+~~~jsx
+ setValues(newValues)} />
+~~~
+
+#### Emotion 11
+
+The \`NonceProvider\` component now requires a \`cacheKey\` prop that corresponds to the [newly required \`key\` prop](https://emotion.sh/docs/emotion-11#emotions-caches) for the Emotion cache. This won't affect you if you aren't using \`NonceProvider\`. See [#4283](https://github.com/JedWatson/react-select/pull/4283) for more details.
+
+#### Remove usage of UNSAFE React methods
+
+This isn't necessarily a breaking change, but it required a large refactor in order to accomplish so we released this in a major upgrade in case it has some unintended consequences.
+
+## From v2 to v3
+
+The core motivation behind 3.0.0 is to set us up to leverage new tools to make react-select better. As such we've made the following changes:
+
+### Breaking Changes
+
+- Upgrade from Emotion 9 to Emotion 10
+- Multiple Entrypoints
+- UMD builds deprecated
+- React 16.8 required as peer dependencies
+- Normalized Values [#3416](https://github.com/JedWatson/react-select/pull/3416)
+
+### What this means for you
+
+#### Emotion 10
+
+Moving to the latest major version of emotion affords us zero-config SSR and enabling easier CSP support. Unfortunately this will be a breaking change for consumers who are currently leveraging emotion to build custom components for react-select. For example, you'd previously create an custom Option component with emotion like so:
+
+~~~jsx
+import { css } from 'emotion'
+
+const customOption = ({ cx, className, getStyles, _ }) =>
+
+~~~
+
+With react-select 3.0.0, and emotion 10 it would be the following:
+
+~~~jsx
+/** @jsx jsx */
+import { jsx } from '@emotion/core';
+
+const customOption = ({ cx, className, getStyles, _ }) =>
+
+~~~
+
+#### Multiple Entrypoints:
+
+v3.0.0 separates removes the following components from the main entry point, and instead exports them as separate entrypoints:
+
+- Async (now exported from react-select/async)
+- Creatable (now exported from react-select/creatable)
+- Async Creatable (now exported from react-select/async-creatable)
+- makeAnimated and default animated components (now exported from react-select/animated)
+
+Where you’d previously import them as such
+
+~~~jsx
+\timport { Async } from 'react-select'
+~~~
+
+Or as:
+
+~~~jsx
+\timport Async from 'react-select/lib/Async'
+~~~
+
+Now imports look like this:
+
+~~~jsx
+\timport AsyncSelect from 'react-select/async'
+~~~
+
+This should have no bundle-size impact on react-select consumers currently leveraging tree-shaking. However for consumers who aren’t leveraging tree-shaking, this should help alleviate some of the bundle-weight.
+
+#### UMD Builds
+
+UMD builds have been removed as of react-select v3.
+
+#### Peer dependency on React 16.8
+
+We've decided on requiring 16.8 as a peer dependency for react-select 3.0.0. This is motivated by our commitment to leveraging the improvements in recent versions of React such as hooks to make react-select even better.
+
+#### Normalized Values
+
+At the moment, if no value is specified by the consumer, it's instantiated as a null value, regardless of whether the select isMulti or not.
+
+When isMulti is false this is fine. On selection of an option, the value becomes an object, and on clearing of said value, it returns to being null. \`(null --> {} --> null)\`
+
+However when isMulti is true, this becomes more inconsistent. On selection of options, the value becomes an array of options, removing values extricates them from this array, removing the last selected value results in an empty array, instead of the initial base state of null.
+\`(null --> [{}] --> [])\`
+
+We rectify this in 3.0.0, on removal of _all_ selected values in an isMulti Select, the value passed to onChange is \`null\` and not \`[]\`.
+
+
+## From v1 to v2
+
+You can find the v2 upgrade guide [here](./upgrade-to-v2).
+ `}
+ >
+ >
+ );
+}
+
+const TypesReplacementTable = () => (
+
+
+
+
+
+
+
+
+
+
+ | {md`
+\`OptionTypeBase\`
+ `} |
+ no replacement |
+ {md`
+Options can be any type (if using \`getOptionValue\` and \`getOptionLabel\`) so there's no longer a base type for options
+ `} |
+
+
+ | {md`
+\`OptionsType\`
+ `} |
+ {md`
+\`Options\`
+ `} |
+ |
+
+
+ | {md`
+\`GroupTypeBase\`
+ `} |
+ {md`
+\`GroupBase\`
+ `} |
+ |
+
+
+ | {md`
+\`GroupedOptionsType\`
+ `} |
+ no replacement |
+ {md`
+This is equivalent to \`ReadonlyArray\`
+ `} |
+
+
+ | {md`
+\`ValueType\`
+ `} |
+ {md`
+\`OnChangeValue\`
+ `} |
+ |
+
+
+ | {md`
+\`InputActionTypes\`
+ `} |
+ {md`
+\`InputAction\`
+ `} |
+ |
+
+
+ | {md`
+\`NamedProps\`
+ `} |
+ {md`
+\`Props\`
+ `} |
+ |
+
+
+ | {md`
+\`Select\` (the \`ref\` type)
+ `} |
+ {md`
+\`SelectInstance\`
+ `} |
+ {md`
+See "Use \`forwardRef\` for all wrapped components" for more details
+ `} |
+
+
+ | {md`
+\`AsyncSelect\` (the \`ref\` type)
+ `} |
+ {md`
+\`SelectInstance\`
+ `} |
+ {md`
+See "Use \`forwardRef\` for all wrapped components" for more details
+ `} |
+
+
+ | {md`
+\`CreatableSelect\` (the \`ref\` type)
+ `} |
+ {md`
+\`SelectInstance\`
+ `} |
+ {md`
+See "Use \`forwardRef\` for all wrapped components" for more details
+ `} |
+
+
+ | {md`
+\`AsyncCreatableSelect\` (the \`ref\` type)
+ `} |
+ {md`
+\`SelectInstance\`
+ `} |
+ {md`
+See "Use \`forwardRef\` for all wrapped components" for more details
+ `} |
+
+
+
+);
+
+const RefReplacementTable = () => (
+
+
+
+
+
+
+
+
+
+
+ | {md`
+\`BaseSelect\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+
+
+ | {md`
+\`CreatableSelect\`
+ `} |
+ {md`
+\`ref.select.select\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+
+
+ | {md`
+\`Select\`
+ `} |
+ {md`
+\`ref.select\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+
+
+ | {md`
+\`AsyncSelect\`
+ `} |
+ {md`
+\`ref.select.select\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+
+
+ | {md`
+\`AsyncCreatableSelect\`
+ `} |
+ {md`
+\`ref.select.select.select\`
+ `} |
+ {md`
+\`ref\`
+ `} |
+
+
+
+);
diff --git a/docs/styled-components.tsx b/docs/styled-components.tsx
new file mode 100644
index 0000000000..16ce5ceb61
--- /dev/null
+++ b/docs/styled-components.tsx
@@ -0,0 +1,128 @@
+/** @jsx emotionJSX */
+import { jsx as emotionJSX } from '@emotion/react';
+
+import SyntaxHighlighter, {
+ registerLanguage,
+} from 'react-syntax-highlighter/prism-light';
+import jsx from 'react-syntax-highlighter/languages/prism/jsx';
+import { tomorrow } from 'react-syntax-highlighter/styles/prism';
+import { HTMLAttributes } from 'react';
+
+const customTomorrow = {
+ ...tomorrow,
+ 'code[class*="language-"]': {
+ ...tomorrow['code[class*="language-"]'],
+ fontFamily: null, // inherit from css
+ },
+ 'pre[class*="language-"]': {
+ ...tomorrow['pre[class*="language-"]'],
+ fontFamily: null, // inherit from css
+ },
+};
+
+registerLanguage('jsx', jsx);
+
+export const Hr = () => (
+
+);
+
+export const Note = ({
+ Tag = 'div',
+ ...props
+}: { readonly Tag?: string } & HTMLAttributes
) => (
+
+);
+
+export const H1 = (props: JSX.IntrinsicElements['h1']) => (
+
+);
+export const H2 = (props: any) => ;
+
+export const ColorSample = ({
+ name,
+ color,
+}: {
+ color: string;
+ name: string;
+}) => (
+
+
+ {name}
+
+);
+
+// ==============================
+// Code
+// ==============================
+
+export const Code = (props: JSX.IntrinsicElements['code']) => (
+
+);
+
+interface PreProps {
+ readonly children: string;
+ readonly language: string;
+}
+
+export const CodeBlock = ({ children, language, ...props }: PreProps) => {
+ return (
+
+ {children}
+
+ );
+};
+CodeBlock.defaultProps = { language: 'jsx' };
diff --git a/docs/tsconfig.json b/docs/tsconfig.json
new file mode 100644
index 0000000000..9183baf05d
--- /dev/null
+++ b/docs/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "commonjs",
+ "jsx": "react",
+ "noEmit": true,
+ "strict": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true
+ }
+}
diff --git a/docs/utils.ts b/docs/utils.ts
new file mode 100644
index 0000000000..5b9d6ee4a0
--- /dev/null
+++ b/docs/utils.ts
@@ -0,0 +1,36 @@
+import { useEffect, useState } from 'react';
+import { MagicalNode, MagicalNodeIndex } from '@magical-types/types';
+import { deserialize } from '@magical-types/serialization/deserialize';
+
+import type { MagicalNodeMetadata } from './generate-magical-types/src/types';
+// @ts-ignore
+import manifest from './magical-types/magical-types-manifest.json';
+
+export type getNodeType =
+ | ((index: MagicalNodeIndex) => MagicalNode)
+ | undefined;
+
+let getNode: getNodeType;
+
+export const metadata: MagicalNodeMetadata = (manifest as any).types;
+
+export function useMagicalNodes() {
+ let [, forceUpdate] = useState(0);
+
+ useEffect(() => {
+ if (!getNode) {
+ fetch(manifest.paths[0])
+ .then((x) => x.json())
+ .then((firstNodeGroup) => {
+ getNode = deserialize([
+ firstNodeGroup,
+ ...(manifest.paths as string[])
+ .slice(1)
+ .map((path) => () => fetch(path).then((x) => x.json())),
+ ]);
+ forceUpdate(1);
+ });
+ }
+ }, []);
+ return getNode;
+}
diff --git a/docs/webpack.config.ts b/docs/webpack.config.ts
new file mode 100644
index 0000000000..ee3e1c4de5
--- /dev/null
+++ b/docs/webpack.config.ts
@@ -0,0 +1,76 @@
+import * as path from 'path';
+import * as webpack from 'webpack';
+import CopyWebpackPlugin from 'copy-webpack-plugin';
+import HtmlWebpackPlugin from 'html-webpack-plugin';
+import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
+import { config } from 'dotenv';
+import { CleanWebpackPlugin } from 'clean-webpack-plugin';
+
+config();
+
+const webpackConfig: webpack.Configuration = {
+ context: __dirname,
+ entry: {
+ index: './index',
+ },
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: '[name].js',
+ publicPath: '/',
+ },
+ devServer: {
+ port: 8000,
+ historyApiFallback: true,
+ },
+ // devtool: 'source-map',
+ devtool: 'cheap-module-eval-source-map',
+ resolve: {
+ extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(ts|js)x?$/,
+ exclude: [/node_modules/],
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ root: path.join(__dirname, '..'),
+ },
+ },
+ ],
+ },
+ {
+ test: /\.css$/,
+ use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
+ },
+ ],
+ },
+ plugins: [
+ // new webpack.DefinePlugin({
+ // 'process.env.CLIENT_ID': `'${process.env.CLIENT_ID}'`,
+ // 'process.env.CLIENT_SECRET': `'${process.env.CLIENT_SECRET}'`,
+ // }),
+ new CleanWebpackPlugin(),
+ new HtmlWebpackPlugin({
+ filename: 'index.html',
+ inject: false,
+ template: path.resolve(__dirname, 'index.html'),
+ }),
+ new CopyWebpackPlugin([
+ '_redirects',
+ 'favicon.ico',
+ 'index.css',
+ 'magical-types/*',
+ ]),
+ new ForkTsCheckerWebpackPlugin({
+ async: false,
+ typescript: {
+ configFile: './tsconfig.json',
+ },
+ }),
+ ],
+};
+
+export default webpackConfig;
diff --git a/examples/dist/.gitignore b/examples/dist/.gitignore
deleted file mode 100644
index c33fa28330..0000000000
--- a/examples/dist/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-## This file is here to ensure it is included in the gh-pages branch,
-## when `gulp deploy` is used to push updates to the demo site.
-
-# Dependency directory
-node_modules
diff --git a/examples/dist/app.js b/examples/dist/app.js
deleted file mode 100644
index b6dd9a0823..0000000000
--- a/examples/dist/app.js
+++ /dev/null
@@ -1,9902 +0,0 @@
-require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o>> (32 - b));
- },
-
- // Bit-wise rotation right
- rotr: function(n, b) {
- return (n << (32 - b)) | (n >>> b);
- },
-
- // Swap big-endian to little-endian and vice versa
- endian: function(n) {
- // If number given, swap endian
- if (n.constructor == Number) {
- return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00;
- }
-
- // Else, assume array and swap all items
- for (var i = 0; i < n.length; i++)
- n[i] = crypt.endian(n[i]);
- return n;
- },
-
- // Generate an array of any length of random bytes
- randomBytes: function(n) {
- for (var bytes = []; n > 0; n--)
- bytes.push(Math.floor(Math.random() * 256));
- return bytes;
- },
-
- // Convert a byte array to big-endian 32-bit words
- bytesToWords: function(bytes) {
- for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
- words[b >>> 5] |= bytes[i] << (24 - b % 32);
- return words;
- },
-
- // Convert big-endian 32-bit words to a byte array
- wordsToBytes: function(words) {
- for (var bytes = [], b = 0; b < words.length * 32; b += 8)
- bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
- return bytes;
- },
-
- // Convert a byte array to a hex string
- bytesToHex: function(bytes) {
- for (var hex = [], i = 0; i < bytes.length; i++) {
- hex.push((bytes[i] >>> 4).toString(16));
- hex.push((bytes[i] & 0xF).toString(16));
- }
- return hex.join('');
- },
-
- // Convert a hex string to a byte array
- hexToBytes: function(hex) {
- for (var bytes = [], c = 0; c < hex.length; c += 2)
- bytes.push(parseInt(hex.substr(c, 2), 16));
- return bytes;
- },
-
- // Convert a byte array to a base-64 string
- bytesToBase64: function(bytes) {
- for (var base64 = [], i = 0; i < bytes.length; i += 3) {
- var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
- for (var j = 0; j < 4; j++)
- if (i * 8 + j * 6 <= bytes.length * 8)
- base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
- else
- base64.push('=');
- }
- return base64.join('');
- },
-
- // Convert a base-64 string to a byte array
- base64ToBytes: function(base64) {
- // Remove non-base-64 characters
- base64 = base64.replace(/[^A-Z0-9+\/]/ig, '');
-
- for (var bytes = [], i = 0, imod4 = 0; i < base64.length;
- imod4 = ++i % 4) {
- if (imod4 == 0) continue;
- bytes.push(((base64map.indexOf(base64.charAt(i - 1))
- & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2))
- | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
- }
- return bytes;
- }
- };
-
- module.exports = crypt;
-})();
-
-},{}],18:[function(require,module,exports){
-'use strict';
-module.exports = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
-},{}],19:[function(require,module,exports){
-'use strict';
-
-var canUseDOM = require('./inDOM');
-
-var size;
-
-module.exports = function (recalc) {
- if (!size || recalc) {
- if (canUseDOM) {
- var scrollDiv = document.createElement('div');
-
- scrollDiv.style.position = 'absolute';
- scrollDiv.style.top = '-9999px';
- scrollDiv.style.width = '50px';
- scrollDiv.style.height = '50px';
- scrollDiv.style.overflow = 'scroll';
-
- document.body.appendChild(scrollDiv);
- size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
- document.body.removeChild(scrollDiv);
- }
- }
-
- return size;
-};
-},{"./inDOM":18}],20:[function(require,module,exports){
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- *
- */
-
-/*eslint-disable no-self-compare */
-
-'use strict';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-/**
- * inlined Object.is polyfill to avoid requiring consumers ship their own
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
- */
-function is(x, y) {
- // SameValue algorithm
- if (x === y) {
- // Steps 1-5, 7-10
- // Steps 6.b-6.e: +0 != -0
- // Added the nonzero y check to make Flow happy, but it is redundant
- return x !== 0 || y !== 0 || 1 / x === 1 / y;
- } else {
- // Step 6.a: NaN == NaN
- return x !== x && y !== y;
- }
-}
-
-/**
- * Performs equality by iterating through keys on an object and returning false
- * when any key has values which are not strictly equal between the arguments.
- * Returns true when the values of all keys are strictly equal.
- */
-function shallowEqual(objA, objB) {
- if (is(objA, objB)) {
- return true;
- }
-
- if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
- return false;
- }
-
- var keysA = Object.keys(objA);
- var keysB = Object.keys(objB);
-
- if (keysA.length !== keysB.length) {
- return false;
- }
-
- // Test for A's keys different from B.
- for (var i = 0; i < keysA.length; i++) {
- if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
- return false;
- }
- }
-
- return true;
-}
-
-module.exports = shallowEqual;
-},{}],21:[function(require,module,exports){
-/*!
- * Determine if an object is a Buffer
- *
- * @author Feross Aboukhadijeh
- * @license MIT
- */
-
-// The _isBuffer check is for Safari 5-7 support, because it's missing
-// Object.prototype.constructor. Remove this eventually
-module.exports = function (obj) {
- return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
-}
-
-function isBuffer (obj) {
- return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
-}
-
-// For Node v0.10 support. Remove this eventually.
-function isSlowBuffer (obj) {
- return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
-}
-
-},{}],22:[function(require,module,exports){
-module.exports = function() {
- var mediaQuery;
- if (typeof window !== "undefined" && window !== null) {
- mediaQuery = "(-webkit-min-device-pixel-ratio: 1.25), (min--moz-device-pixel-ratio: 1.25), (-o-min-device-pixel-ratio: 5/4), (min-resolution: 1.25dppx)";
- if (window.devicePixelRatio > 1.25) {
- return true;
- }
- if (window.matchMedia && window.matchMedia(mediaQuery).matches) {
- return true;
- }
- }
- return false;
-};
-
-},{}],23:[function(require,module,exports){
-// the whatwg-fetch polyfill installs the fetch() function
-// on the global object (window or self)
-//
-// Return that as the export for use in Webpack, Browserify etc.
-require('whatwg-fetch');
-module.exports = self.fetch.bind(self);
-
-},{"whatwg-fetch":83}],24:[function(require,module,exports){
-(function(){
- var crypt = require('crypt'),
- utf8 = require('charenc').utf8,
- isBuffer = require('is-buffer'),
- bin = require('charenc').bin,
-
- // The core
- md5 = function (message, options) {
- // Convert to byte array
- if (message.constructor == String)
- if (options && options.encoding === 'binary')
- message = bin.stringToBytes(message);
- else
- message = utf8.stringToBytes(message);
- else if (isBuffer(message))
- message = Array.prototype.slice.call(message, 0);
- else if (!Array.isArray(message))
- message = message.toString();
- // else, assume byte array already
-
- var m = crypt.bytesToWords(message),
- l = message.length * 8,
- a = 1732584193,
- b = -271733879,
- c = -1732584194,
- d = 271733878;
-
- // Swap endian
- for (var i = 0; i < m.length; i++) {
- m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF |
- ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00;
- }
-
- // Padding
- m[l >>> 5] |= 0x80 << (l % 32);
- m[(((l + 64) >>> 9) << 4) + 14] = l;
-
- // Method shortcuts
- var FF = md5._ff,
- GG = md5._gg,
- HH = md5._hh,
- II = md5._ii;
-
- for (var i = 0; i < m.length; i += 16) {
-
- var aa = a,
- bb = b,
- cc = c,
- dd = d;
-
- a = FF(a, b, c, d, m[i+ 0], 7, -680876936);
- d = FF(d, a, b, c, m[i+ 1], 12, -389564586);
- c = FF(c, d, a, b, m[i+ 2], 17, 606105819);
- b = FF(b, c, d, a, m[i+ 3], 22, -1044525330);
- a = FF(a, b, c, d, m[i+ 4], 7, -176418897);
- d = FF(d, a, b, c, m[i+ 5], 12, 1200080426);
- c = FF(c, d, a, b, m[i+ 6], 17, -1473231341);
- b = FF(b, c, d, a, m[i+ 7], 22, -45705983);
- a = FF(a, b, c, d, m[i+ 8], 7, 1770035416);
- d = FF(d, a, b, c, m[i+ 9], 12, -1958414417);
- c = FF(c, d, a, b, m[i+10], 17, -42063);
- b = FF(b, c, d, a, m[i+11], 22, -1990404162);
- a = FF(a, b, c, d, m[i+12], 7, 1804603682);
- d = FF(d, a, b, c, m[i+13], 12, -40341101);
- c = FF(c, d, a, b, m[i+14], 17, -1502002290);
- b = FF(b, c, d, a, m[i+15], 22, 1236535329);
-
- a = GG(a, b, c, d, m[i+ 1], 5, -165796510);
- d = GG(d, a, b, c, m[i+ 6], 9, -1069501632);
- c = GG(c, d, a, b, m[i+11], 14, 643717713);
- b = GG(b, c, d, a, m[i+ 0], 20, -373897302);
- a = GG(a, b, c, d, m[i+ 5], 5, -701558691);
- d = GG(d, a, b, c, m[i+10], 9, 38016083);
- c = GG(c, d, a, b, m[i+15], 14, -660478335);
- b = GG(b, c, d, a, m[i+ 4], 20, -405537848);
- a = GG(a, b, c, d, m[i+ 9], 5, 568446438);
- d = GG(d, a, b, c, m[i+14], 9, -1019803690);
- c = GG(c, d, a, b, m[i+ 3], 14, -187363961);
- b = GG(b, c, d, a, m[i+ 8], 20, 1163531501);
- a = GG(a, b, c, d, m[i+13], 5, -1444681467);
- d = GG(d, a, b, c, m[i+ 2], 9, -51403784);
- c = GG(c, d, a, b, m[i+ 7], 14, 1735328473);
- b = GG(b, c, d, a, m[i+12], 20, -1926607734);
-
- a = HH(a, b, c, d, m[i+ 5], 4, -378558);
- d = HH(d, a, b, c, m[i+ 8], 11, -2022574463);
- c = HH(c, d, a, b, m[i+11], 16, 1839030562);
- b = HH(b, c, d, a, m[i+14], 23, -35309556);
- a = HH(a, b, c, d, m[i+ 1], 4, -1530992060);
- d = HH(d, a, b, c, m[i+ 4], 11, 1272893353);
- c = HH(c, d, a, b, m[i+ 7], 16, -155497632);
- b = HH(b, c, d, a, m[i+10], 23, -1094730640);
- a = HH(a, b, c, d, m[i+13], 4, 681279174);
- d = HH(d, a, b, c, m[i+ 0], 11, -358537222);
- c = HH(c, d, a, b, m[i+ 3], 16, -722521979);
- b = HH(b, c, d, a, m[i+ 6], 23, 76029189);
- a = HH(a, b, c, d, m[i+ 9], 4, -640364487);
- d = HH(d, a, b, c, m[i+12], 11, -421815835);
- c = HH(c, d, a, b, m[i+15], 16, 530742520);
- b = HH(b, c, d, a, m[i+ 2], 23, -995338651);
-
- a = II(a, b, c, d, m[i+ 0], 6, -198630844);
- d = II(d, a, b, c, m[i+ 7], 10, 1126891415);
- c = II(c, d, a, b, m[i+14], 15, -1416354905);
- b = II(b, c, d, a, m[i+ 5], 21, -57434055);
- a = II(a, b, c, d, m[i+12], 6, 1700485571);
- d = II(d, a, b, c, m[i+ 3], 10, -1894986606);
- c = II(c, d, a, b, m[i+10], 15, -1051523);
- b = II(b, c, d, a, m[i+ 1], 21, -2054922799);
- a = II(a, b, c, d, m[i+ 8], 6, 1873313359);
- d = II(d, a, b, c, m[i+15], 10, -30611744);
- c = II(c, d, a, b, m[i+ 6], 15, -1560198380);
- b = II(b, c, d, a, m[i+13], 21, 1309151649);
- a = II(a, b, c, d, m[i+ 4], 6, -145523070);
- d = II(d, a, b, c, m[i+11], 10, -1120210379);
- c = II(c, d, a, b, m[i+ 2], 15, 718787259);
- b = II(b, c, d, a, m[i+ 9], 21, -343485551);
-
- a = (a + aa) >>> 0;
- b = (b + bb) >>> 0;
- c = (c + cc) >>> 0;
- d = (d + dd) >>> 0;
- }
-
- return crypt.endian([a, b, c, d]);
- };
-
- // Auxiliary functions
- md5._ff = function (a, b, c, d, x, s, t) {
- var n = a + (b & c | ~b & d) + (x >>> 0) + t;
- return ((n << s) | (n >>> (32 - s))) + b;
- };
- md5._gg = function (a, b, c, d, x, s, t) {
- var n = a + (b & d | c & ~d) + (x >>> 0) + t;
- return ((n << s) | (n >>> (32 - s))) + b;
- };
- md5._hh = function (a, b, c, d, x, s, t) {
- var n = a + (b ^ c ^ d) + (x >>> 0) + t;
- return ((n << s) | (n >>> (32 - s))) + b;
- };
- md5._ii = function (a, b, c, d, x, s, t) {
- var n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
- return ((n << s) | (n >>> (32 - s))) + b;
- };
-
- // Package private blocksize
- md5._blocksize = 16;
- md5._digestsize = 16;
-
- module.exports = function (message, options) {
- if (message === undefined || message === null)
- throw new Error('Illegal argument ' + message);
-
- var digestbytes = crypt.wordsToBytes(md5(message, options));
- return options && options.asBytes ? digestbytes :
- options && options.asString ? bin.bytesToString(digestbytes) :
- crypt.bytesToHex(digestbytes);
- };
-
-})();
-
-},{"charenc":16,"crypt":17,"is-buffer":21}],25:[function(require,module,exports){
-/*
-object-assign
-(c) Sindre Sorhus
-@license MIT
-*/
-
-'use strict';
-/* eslint-disable no-unused-vars */
-var getOwnPropertySymbols = Object.getOwnPropertySymbols;
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-var propIsEnumerable = Object.prototype.propertyIsEnumerable;
-
-function toObject(val) {
- if (val === null || val === undefined) {
- throw new TypeError('Object.assign cannot be called with null or undefined');
- }
-
- return Object(val);
-}
-
-function shouldUseNative() {
- try {
- if (!Object.assign) {
- return false;
- }
-
- // Detect buggy property enumeration order in older V8 versions.
-
- // https://bugs.chromium.org/p/v8/issues/detail?id=4118
- var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
- test1[5] = 'de';
- if (Object.getOwnPropertyNames(test1)[0] === '5') {
- return false;
- }
-
- // https://bugs.chromium.org/p/v8/issues/detail?id=3056
- var test2 = {};
- for (var i = 0; i < 10; i++) {
- test2['_' + String.fromCharCode(i)] = i;
- }
- var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
- return test2[n];
- });
- if (order2.join('') !== '0123456789') {
- return false;
- }
-
- // https://bugs.chromium.org/p/v8/issues/detail?id=3056
- var test3 = {};
- 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
- test3[letter] = letter;
- });
- if (Object.keys(Object.assign({}, test3)).join('') !==
- 'abcdefghijklmnopqrst') {
- return false;
- }
-
- return true;
- } catch (err) {
- // We don't expect any of the above to throw, but better to be safe.
- return false;
- }
-}
-
-module.exports = shouldUseNative() ? Object.assign : function (target, source) {
- var from;
- var to = toObject(target);
- var symbols;
-
- for (var s = 1; s < arguments.length; s++) {
- from = Object(arguments[s]);
-
- for (var key in from) {
- if (hasOwnProperty.call(from, key)) {
- to[key] = from[key];
- }
- }
-
- if (getOwnPropertySymbols) {
- symbols = getOwnPropertySymbols(from);
- for (var i = 0; i < symbols.length; i++) {
- if (propIsEnumerable.call(from, symbols[i])) {
- to[symbols[i]] = from[symbols[i]];
- }
- }
- }
- }
-
- return to;
-};
-
-},{}],26:[function(require,module,exports){
-(function (process){
-// Generated by CoffeeScript 1.7.1
-(function() {
- var getNanoSeconds, hrtime, loadTime;
-
- if ((typeof performance !== "undefined" && performance !== null) && performance.now) {
- module.exports = function() {
- return performance.now();
- };
- } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) {
- module.exports = function() {
- return (getNanoSeconds() - loadTime) / 1e6;
- };
- hrtime = process.hrtime;
- getNanoSeconds = function() {
- var hr;
- hr = hrtime();
- return hr[0] * 1e9 + hr[1];
- };
- loadTime = getNanoSeconds();
- } else if (Date.now) {
- module.exports = function() {
- return Date.now() - loadTime;
- };
- loadTime = Date.now();
- } else {
- module.exports = function() {
- return new Date().getTime() - loadTime;
- };
- loadTime = new Date().getTime();
- }
-
-}).call(this);
-
-}).call(this,require('_process'))
-},{"_process":27}],27:[function(require,module,exports){
-// shim for using process in browser
-var process = module.exports = {};
-
-// cached from whatever global is present so that test runners that stub it
-// don't break things. But we need to wrap it in a try catch in case it is
-// wrapped in strict mode code which doesn't define any globals. It's inside a
-// function because try/catches deoptimize in certain engines.
-
-var cachedSetTimeout;
-var cachedClearTimeout;
-
-function defaultSetTimout() {
- throw new Error('setTimeout has not been defined');
-}
-function defaultClearTimeout () {
- throw new Error('clearTimeout has not been defined');
-}
-(function () {
- try {
- if (typeof setTimeout === 'function') {
- cachedSetTimeout = setTimeout;
- } else {
- cachedSetTimeout = defaultSetTimout;
- }
- } catch (e) {
- cachedSetTimeout = defaultSetTimout;
- }
- try {
- if (typeof clearTimeout === 'function') {
- cachedClearTimeout = clearTimeout;
- } else {
- cachedClearTimeout = defaultClearTimeout;
- }
- } catch (e) {
- cachedClearTimeout = defaultClearTimeout;
- }
-} ())
-function runTimeout(fun) {
- if (cachedSetTimeout === setTimeout) {
- //normal enviroments in sane situations
- return setTimeout(fun, 0);
- }
- // if setTimeout wasn't available but was latter defined
- if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
- cachedSetTimeout = setTimeout;
- return setTimeout(fun, 0);
- }
- try {
- // when when somebody has screwed with setTimeout but no I.E. maddness
- return cachedSetTimeout(fun, 0);
- } catch(e){
- try {
- // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
- return cachedSetTimeout.call(null, fun, 0);
- } catch(e){
- // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
- return cachedSetTimeout.call(this, fun, 0);
- }
- }
-
-
-}
-function runClearTimeout(marker) {
- if (cachedClearTimeout === clearTimeout) {
- //normal enviroments in sane situations
- return clearTimeout(marker);
- }
- // if clearTimeout wasn't available but was latter defined
- if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
- cachedClearTimeout = clearTimeout;
- return clearTimeout(marker);
- }
- try {
- // when when somebody has screwed with setTimeout but no I.E. maddness
- return cachedClearTimeout(marker);
- } catch (e){
- try {
- // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
- return cachedClearTimeout.call(null, marker);
- } catch (e){
- // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
- // Some versions of I.E. have different rules for clearTimeout vs setTimeout
- return cachedClearTimeout.call(this, marker);
- }
- }
-
-
-
-}
-var queue = [];
-var draining = false;
-var currentQueue;
-var queueIndex = -1;
-
-function cleanUpNextTick() {
- if (!draining || !currentQueue) {
- return;
- }
- draining = false;
- if (currentQueue.length) {
- queue = currentQueue.concat(queue);
- } else {
- queueIndex = -1;
- }
- if (queue.length) {
- drainQueue();
- }
-}
-
-function drainQueue() {
- if (draining) {
- return;
- }
- var timeout = runTimeout(cleanUpNextTick);
- draining = true;
-
- var len = queue.length;
- while(len) {
- currentQueue = queue;
- queue = [];
- while (++queueIndex < len) {
- if (currentQueue) {
- currentQueue[queueIndex].run();
- }
- }
- queueIndex = -1;
- len = queue.length;
- }
- currentQueue = null;
- draining = false;
- runClearTimeout(timeout);
-}
-
-process.nextTick = function (fun) {
- var args = new Array(arguments.length - 1);
- if (arguments.length > 1) {
- for (var i = 1; i < arguments.length; i++) {
- args[i - 1] = arguments[i];
- }
- }
- queue.push(new Item(fun, args));
- if (queue.length === 1 && !draining) {
- runTimeout(drainQueue);
- }
-};
-
-// v8 likes predictible objects
-function Item(fun, array) {
- this.fun = fun;
- this.array = array;
-}
-Item.prototype.run = function () {
- this.fun.apply(null, this.array);
-};
-process.title = 'browser';
-process.browser = true;
-process.env = {};
-process.argv = [];
-process.version = ''; // empty string to avoid regexp issues
-process.versions = {};
-
-function noop() {}
-
-process.on = noop;
-process.addListener = noop;
-process.once = noop;
-process.off = noop;
-process.removeListener = noop;
-process.removeAllListeners = noop;
-process.emit = noop;
-
-process.binding = function (name) {
- throw new Error('process.binding is not supported');
-};
-
-process.cwd = function () { return '/' };
-process.chdir = function (dir) {
- throw new Error('process.chdir is not supported');
-};
-process.umask = function() { return 0; };
-
-},{}],28:[function(require,module,exports){
-'use strict';
-var strictUriEncode = require('strict-uri-encode');
-var objectAssign = require('object-assign');
-
-function encoderForArrayFormat(opts) {
- switch (opts.arrayFormat) {
- case 'index':
- return function (key, value, index) {
- return value === null ? [
- encode(key, opts),
- '[',
- index,
- ']'
- ].join('') : [
- encode(key, opts),
- '[',
- encode(index, opts),
- ']=',
- encode(value, opts)
- ].join('');
- };
-
- case 'bracket':
- return function (key, value) {
- return value === null ? encode(key, opts) : [
- encode(key, opts),
- '[]=',
- encode(value, opts)
- ].join('');
- };
-
- default:
- return function (key, value) {
- return value === null ? encode(key, opts) : [
- encode(key, opts),
- '=',
- encode(value, opts)
- ].join('');
- };
- }
-}
-
-function parserForArrayFormat(opts) {
- var result;
-
- switch (opts.arrayFormat) {
- case 'index':
- return function (key, value, accumulator) {
- result = /\[(\d*)]$/.exec(key);
-
- key = key.replace(/\[\d*]$/, '');
-
- if (!result) {
- accumulator[key] = value;
- return;
- }
-
- if (accumulator[key] === undefined) {
- accumulator[key] = {};
- }
-
- accumulator[key][result[1]] = value;
- };
-
- case 'bracket':
- return function (key, value, accumulator) {
- result = /(\[])$/.exec(key);
-
- key = key.replace(/\[]$/, '');
-
- if (!result || accumulator[key] === undefined) {
- accumulator[key] = value;
- return;
- }
-
- accumulator[key] = [].concat(accumulator[key], value);
- };
-
- default:
- return function (key, value, accumulator) {
- if (accumulator[key] === undefined) {
- accumulator[key] = value;
- return;
- }
-
- accumulator[key] = [].concat(accumulator[key], value);
- };
- }
-}
-
-function encode(value, opts) {
- if (opts.encode) {
- return opts.strict ? strictUriEncode(value) : encodeURIComponent(value);
- }
-
- return value;
-}
-
-function keysSorter(input) {
- if (Array.isArray(input)) {
- return input.sort();
- } else if (typeof input === 'object') {
- return keysSorter(Object.keys(input)).sort(function (a, b) {
- return Number(a) - Number(b);
- }).map(function (key) {
- return input[key];
- });
- }
-
- return input;
-}
-
-exports.extract = function (str) {
- return str.split('?')[1] || '';
-};
-
-exports.parse = function (str, opts) {
- opts = objectAssign({arrayFormat: 'none'}, opts);
-
- var formatter = parserForArrayFormat(opts);
-
- // Create an object with no prototype
- // https://github.com/sindresorhus/query-string/issues/47
- var ret = Object.create(null);
-
- if (typeof str !== 'string') {
- return ret;
- }
-
- str = str.trim().replace(/^(\?|#|&)/, '');
-
- if (!str) {
- return ret;
- }
-
- str.split('&').forEach(function (param) {
- var parts = param.replace(/\+/g, ' ').split('=');
- // Firefox (pre 40) decodes `%3D` to `=`
- // https://github.com/sindresorhus/query-string/pull/37
- var key = parts.shift();
- var val = parts.length > 0 ? parts.join('=') : undefined;
-
- // missing `=` should be `null`:
- // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
- val = val === undefined ? null : decodeURIComponent(val);
-
- formatter(decodeURIComponent(key), val, ret);
- });
-
- return Object.keys(ret).sort().reduce(function (result, key) {
- var val = ret[key];
- if (Boolean(val) && typeof val === 'object' && !Array.isArray(val)) {
- // Sort object keys, not values
- result[key] = keysSorter(val);
- } else {
- result[key] = val;
- }
-
- return result;
- }, Object.create(null));
-};
-
-exports.stringify = function (obj, opts) {
- var defaults = {
- encode: true,
- strict: true,
- arrayFormat: 'none'
- };
-
- opts = objectAssign(defaults, opts);
-
- var formatter = encoderForArrayFormat(opts);
-
- return obj ? Object.keys(obj).sort().map(function (key) {
- var val = obj[key];
-
- if (val === undefined) {
- return '';
- }
-
- if (val === null) {
- return encode(key, opts);
- }
-
- if (Array.isArray(val)) {
- var result = [];
-
- val.slice().forEach(function (val2) {
- if (val2 === undefined) {
- return;
- }
-
- result.push(formatter(key, val2, result.length));
- });
-
- return result.join('&');
- }
-
- return encode(key, opts) + '=' + encode(val, opts);
- }).filter(function (x) {
- return x.length > 0;
- }).join('&') : '';
-};
-
-},{"object-assign":25,"strict-uri-encode":82}],29:[function(require,module,exports){
-(function (global){
-var now = require('performance-now')
- , root = typeof window === 'undefined' ? global : window
- , vendors = ['moz', 'webkit']
- , suffix = 'AnimationFrame'
- , raf = root['request' + suffix]
- , caf = root['cancel' + suffix] || root['cancelRequest' + suffix]
-
-for(var i = 0; !raf && i < vendors.length; i++) {
- raf = root[vendors[i] + 'Request' + suffix]
- caf = root[vendors[i] + 'Cancel' + suffix]
- || root[vendors[i] + 'CancelRequest' + suffix]
-}
-
-// Some versions of FF have rAF but not cAF
-if(!raf || !caf) {
- var last = 0
- , id = 0
- , queue = []
- , frameDuration = 1000 / 60
-
- raf = function(callback) {
- if(queue.length === 0) {
- var _now = now()
- , next = Math.max(0, frameDuration - (_now - last))
- last = next + _now
- setTimeout(function() {
- var cp = queue.slice(0)
- // Clear queue here to prevent
- // callbacks from appending listeners
- // to the current frame's queue
- queue.length = 0
- for(var i = 0; i < cp.length; i++) {
- if(!cp[i].cancelled) {
- try{
- cp[i].callback(last)
- } catch(e) {
- setTimeout(function() { throw e }, 0)
- }
- }
- }
- }, Math.round(next))
- }
- queue.push({
- handle: ++id,
- callback: callback,
- cancelled: false
- })
- return id
- }
-
- caf = function(handle) {
- for(var i = 0; i < queue.length; i++) {
- if(queue[i].handle === handle) {
- queue[i].cancelled = true
- }
- }
- }
-}
-
-module.exports = function(fn) {
- // Wrap in a new function to prevent
- // `cancel` potentially being assigned
- // to the native rAF function
- return raf.call(root, fn)
-}
-module.exports.cancel = function() {
- caf.apply(root, arguments)
-}
-module.exports.polyfill = function() {
- root.requestAnimationFrame = raf
- root.cancelAnimationFrame = caf
-}
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"performance-now":26}],30:[function(require,module,exports){
-module.exports = require('react/lib/shallowCompare');
-},{"react/lib/shallowCompare":81}],31:[function(require,module,exports){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _md = require('md5');
-
-var _md2 = _interopRequireDefault(_md);
-
-var _queryString = require('query-string');
-
-var _queryString2 = _interopRequireDefault(_queryString);
-
-var _isRetina = require('is-retina');
-
-var _isRetina2 = _interopRequireDefault(_isRetina);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var Gravatar = function (_React$Component) {
- _inherits(Gravatar, _React$Component);
-
- function Gravatar() {
- _classCallCheck(this, Gravatar);
-
- return _possibleConstructorReturn(this, Object.getPrototypeOf(Gravatar).apply(this, arguments));
- }
-
- _createClass(Gravatar, [{
- key: 'render',
- value: function render() {
- var base = this.props.protocol + 'www.gravatar.com/avatar/';
-
- var query = _queryString2.default.stringify({
- s: this.props.size,
- r: this.props.rating,
- d: this.props.default
- });
-
- var retinaQuery = _queryString2.default.stringify({
- s: this.props.size * 2,
- r: this.props.rating,
- d: this.props.default
- });
-
- // Gravatar service currently trims and lowercases all registered emails
- var formattedEmail = ('' + this.props.email).trim().toLowerCase();
-
- var hash = void 0;
- if (this.props.md5) {
- hash = this.props.md5;
- } else if (typeof this.props.email === 'string') {
- hash = (0, _md2.default)(formattedEmail);
- } else {
- console.warn('Gravatar image can not be fetched. Either the "email" or "md5" prop must be specified.');
- return _react2.default.createElement('script', null);
- }
-
- var src = '' + base + hash + '?' + query;
- var retinaSrc = '' + base + hash + '?' + retinaQuery;
-
- var modernBrowser = true; // server-side, we render for modern browsers
-
- if (typeof window !== 'undefined') {
- // this is not NodeJS
- modernBrowser = 'srcset' in document.createElement('img');
- }
-
- var className = 'react-gravatar';
- if (this.props.className) {
- className = className + ' ' + this.props.className;
- }
-
- // Clone this.props and then delete Component specific props so we can
- // spread the rest into the img.
-
- var rest = _objectWithoutProperties(this.props, []);
-
- delete rest.md5;
- delete rest.email;
- delete rest.protocol;
- delete rest.rating;
- delete rest.size;
- delete rest.style;
- delete rest.className;
- delete rest.default;
- if (!modernBrowser && (0, _isRetina2.default)()) {
- return _react2.default.createElement('img', _extends({
- alt: 'Gravatar for ' + formattedEmail,
- style: this.props.style,
- src: retinaSrc,
- height: this.props.size,
- width: this.props.size
- }, rest, {
- className: className
- }));
- }
- return _react2.default.createElement('img', _extends({
- alt: 'Gravatar for ' + formattedEmail,
- style: this.props.style,
- src: src,
- srcSet: retinaSrc + ' 2x',
- height: this.props.size,
- width: this.props.size
- }, rest, {
- className: className
- }));
- }
- }]);
-
- return Gravatar;
-}(_react2.default.Component);
-
-Gravatar.displayName = 'Gravatar';
-Gravatar.propTypes = {
- email: _react2.default.PropTypes.string,
- md5: _react2.default.PropTypes.string,
- size: _react2.default.PropTypes.number,
- rating: _react2.default.PropTypes.string,
- default: _react2.default.PropTypes.string,
- className: _react2.default.PropTypes.string,
- protocol: _react2.default.PropTypes.string,
- style: _react2.default.PropTypes.object
-};
-Gravatar.defaultProps = {
- size: 50,
- rating: 'g',
- default: 'retro',
- protocol: '//'
-};
-
-
-module.exports = Gravatar;
-},{"is-retina":22,"md5":24,"query-string":28,"react":undefined}],32:[function(require,module,exports){
-module.exports =
-/******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var installedModules = {};
-/******/
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-/******/
-/******/ // Check if module is in cache
-/******/ if(installedModules[moduleId])
-/******/ return installedModules[moduleId].exports;
-/******/
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = installedModules[moduleId] = {
-/******/ exports: {},
-/******/ id: moduleId,
-/******/ loaded: false
-/******/ };
-/******/
-/******/ // Execute the module function
-/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
-/******/ // Flag the module as loaded
-/******/ module.loaded = true;
-/******/
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-/******/
-/******/
-/******/ // expose the modules object (__webpack_modules__)
-/******/ __webpack_require__.m = modules;
-/******/
-/******/ // expose the module cache
-/******/ __webpack_require__.c = installedModules;
-/******/
-/******/ // __webpack_public_path__
-/******/ __webpack_require__.p = "";
-/******/
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(0);
-/******/ })
-/************************************************************************/
-/******/ ([
-/* 0 */
-/***/ function(module, exports, __webpack_require__) {
-
- module.exports = __webpack_require__(1);
-
-
-/***/ },
-/* 1 */
-/***/ function(module, exports, __webpack_require__) {
-
- 'use strict';
-
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
- var _Highlighter = __webpack_require__(2);
-
- var _Highlighter2 = _interopRequireDefault(_Highlighter);
-
- var _utils = __webpack_require__(4);
-
- exports['default'] = _Highlighter2['default'];
- exports.combineChunks = _utils.combineChunks;
- exports.fillInChunks = _utils.fillInChunks;
- exports.findAll = _utils.findAll;
- exports.findChunks = _utils.findChunks;
-
-/***/ },
-/* 2 */
-/***/ function(module, exports, __webpack_require__) {
-
- 'use strict';
-
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- exports['default'] = Highlighter;
-
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
- var _react = __webpack_require__(3);
-
- var _react2 = _interopRequireDefault(_react);
-
- var _utilsJs = __webpack_require__(4);
-
- var Chunks = _interopRequireWildcard(_utilsJs);
-
- Highlighter.propTypes = {
- highlightClassName: _react.PropTypes.string,
- highlightStyle: _react.PropTypes.object,
- searchWords: _react.PropTypes.arrayOf(_react.PropTypes.string).isRequired,
- textToHighlight: _react.PropTypes.string.isRequired,
- sanitize: _react.PropTypes.func
- };
-
- /**
- * Highlights all occurrences of search terms (searchText) within a string (textToHighlight).
- * This function returns an array of strings and s (wrapping highlighted words).
- */
-
- function Highlighter(_ref) {
- var _ref$highlightClassName = _ref.highlightClassName;
- var highlightClassName = _ref$highlightClassName === undefined ? '' : _ref$highlightClassName;
- var _ref$highlightStyle = _ref.highlightStyle;
- var highlightStyle = _ref$highlightStyle === undefined ? {} : _ref$highlightStyle;
- var searchWords = _ref.searchWords;
- var textToHighlight = _ref.textToHighlight;
- var sanitize = _ref.sanitize;
-
- var chunks = Chunks.findAll(textToHighlight, searchWords, sanitize);
-
- return _react2['default'].createElement(
- 'span',
- null,
- chunks.map(function (chunk, index) {
- var text = textToHighlight.substr(chunk.start, chunk.end - chunk.start);
-
- if (chunk.highlight) {
- return _react2['default'].createElement(
- 'mark',
- {
- className: highlightClassName,
- key: index,
- style: highlightStyle
- },
- text
- );
- } else {
- return _react2['default'].createElement(
- 'span',
- { key: index },
- text
- );
- }
- })
- );
- }
-
- module.exports = exports['default'];
-
-/***/ },
-/* 3 */
-/***/ function(module, exports) {
-
- module.exports = require("react");
-
-/***/ },
-/* 4 */
-/***/ function(module, exports) {
-
- /**
- * Creates an array of chunk objects representing both higlightable and non highlightable pieces of text that match each search word.
- * @param searchWords string[]
- * @param textToSearch string
- * @return {start:number, end:number, highlight:boolean}[]
- */
- 'use strict';
-
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- var findAll = function findAll(textToSearch, wordsToFind, sanitize) {
- return fillInChunks(combineChunks(findChunks(textToSearch, wordsToFind, sanitize)), textToSearch.length);
- };
-
- exports.findAll = findAll;
- /**
- * Takes an array of {start:number, end:number} objects and combines chunks that overlap into single chunks.
- * @param chunks {start:number, end:number}[]
- * @return {start:number, end:number}[]
- */
- var combineChunks = function combineChunks(chunks) {
- chunks = chunks.sort(function (first, second) {
- return first.start - second.start;
- }).reduce(function (processedChunks, nextChunk) {
- // First chunk just goes straight in the array...
- if (processedChunks.length === 0) {
- return [nextChunk];
- } else {
- // ... subsequent chunks get checked to see if they overlap...
- var prevChunk = processedChunks.pop();
- if (nextChunk.start <= prevChunk.end) {
- // It may be the case that prevChunk completely surrounds nextChunk, so take the
- // largest of the end indeces.
- var endIndex = Math.max(prevChunk.end, nextChunk.end);
- processedChunks.push({ start: prevChunk.start, end: endIndex });
- } else {
- processedChunks.push(prevChunk, nextChunk);
- }
- return processedChunks;
- }
- }, []);
-
- return chunks;
- };
-
- exports.combineChunks = combineChunks;
- /**
- * Examine textToSearch for any matches.
- * If we find matches, add them to the returned array as a "chunk" object ({start:number, end:number}).
- * @param textToSearch string
- * @param wordsToFind string[]
- * @param sanitize Process and optionally modify textToSearch and wordsToFind before comparison; this can be used to eg. remove accents
- * @return {start:number, end:number}[]
- */
- var findChunks = function findChunks(textToSearch, wordsToFind) {
- var sanitize = arguments.length <= 2 || arguments[2] === undefined ? identity : arguments[2];
- return wordsToFind.filter(function (searchWord) {
- return searchWord;
- }) // Remove empty words
- .reduce(function (chunks, searchWord) {
- var normalizedWord = sanitize(searchWord);
- var normalizedText = sanitize(textToSearch);
- var regex = new RegExp(normalizedWord, 'gi');
- var match = undefined;
- while ((match = regex.exec(normalizedText)) != null) {
- chunks.push({ start: match.index, end: regex.lastIndex });
- }
- return chunks;
- }, []);
- };
-
- exports.findChunks = findChunks;
- /**
- * Given a set of chunks to highlight, create an additional set of chunks
- * to represent the bits of text between the highlighted text.
- * @param chunksToHighlight {start:number, end:number}[]
- * @param totalLength number
- * @return {start:number, end:number, highlight:boolean}[]
- */
- var fillInChunks = function fillInChunks(chunksToHighlight, totalLength) {
- var allChunks = [];
- var append = function append(start, end, highlight) {
- if (end - start > 0) {
- allChunks.push({ start: start, end: end, highlight: highlight });
- }
- };
-
- if (chunksToHighlight.length === 0) {
- append(0, totalLength, false);
- } else {
- (function () {
- var lastIndex = 0;
- chunksToHighlight.forEach(function (chunk) {
- append(lastIndex, chunk.start, false);
- append(chunk.start, chunk.end, true);
- lastIndex = chunk.end;
- });
- append(lastIndex, totalLength, false);
- })();
- }
- return allChunks;
- };
-
- exports.fillInChunks = fillInChunks;
- function identity(value) {
- return value;
- }
-
-/***/ }
-/******/ ]);
-
-},{"react":undefined}],33:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactSelect = require('react-select');
-
-var _reactSelect2 = _interopRequireDefault(_reactSelect);
-
-var _reactVirtualized = require('react-virtualized');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var VirtualizedSelect = function (_Component) {
- _inherits(VirtualizedSelect, _Component);
-
- function VirtualizedSelect(props, context) {
- _classCallCheck(this, VirtualizedSelect);
-
- var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(VirtualizedSelect).call(this, props, context));
-
- _this._renderMenu = _this._renderMenu.bind(_this);
- _this._optionRenderer = _this._optionRenderer.bind(_this);
- return _this;
- }
-
- /** See VirtualScroll#recomputeRowHeights */
-
-
- _createClass(VirtualizedSelect, [{
- key: 'recomputeOptionHeights',
- value: function recomputeOptionHeights() {
- var index = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
-
- if (this._virtualScroll) {
- this._virtualScroll.recomputeRowHeights(index);
- }
- }
- }, {
- key: 'render',
- value: function render() {
- var SelectComponent = this._getSelectComponent();
-
- return _react2.default.createElement(SelectComponent, _extends({}, this.props, {
- menuRenderer: this._renderMenu,
- menuStyle: { overflow: 'hidden' }
- }));
- }
-
- // See https://github.com/JedWatson/react-select/#effeciently-rendering-large-lists-with-windowing
-
- }, {
- key: '_renderMenu',
- value: function _renderMenu(_ref) {
- var _this2 = this;
-
- var focusedOption = _ref.focusedOption;
- var focusOption = _ref.focusOption;
- var labelKey = _ref.labelKey;
- var options = _ref.options;
- var selectValue = _ref.selectValue;
- var valueArray = _ref.valueArray;
- var optionRenderer = this.props.optionRenderer;
-
- var focusedOptionIndex = options.indexOf(focusedOption);
- var height = this._calculateVirtualScrollHeight({ options: options });
- var innerRowRenderer = optionRenderer || this._optionRenderer;
-
- function wrappedRowRenderer(_ref2) {
- var index = _ref2.index;
-
- var option = options[index];
-
- return innerRowRenderer({
- focusedOption: focusedOption,
- focusedOptionIndex: focusedOptionIndex,
- focusOption: focusOption,
- labelKey: labelKey,
- option: option,
- optionIndex: index,
- options: options,
- selectValue: selectValue,
- valueArray: valueArray
- });
- }
-
- return _react2.default.createElement(
- _reactVirtualized.AutoSizer,
- { disableHeight: true },
- function (_ref3) {
- var width = _ref3.width;
- return _react2.default.createElement(_reactVirtualized.VirtualScroll, {
- className: 'VirtualSelectGrid',
- height: height,
- ref: function ref(_ref5) {
- return _this2._virtualScroll = _ref5;
- },
- rowCount: options.length,
- rowHeight: function rowHeight(_ref4) {
- var index = _ref4.index;
- return _this2._getOptionHeight({
- option: options[index]
- });
- },
- rowRenderer: wrappedRowRenderer,
- scrollToIndex: focusedOptionIndex,
- width: width
- });
- }
- );
- }
- }, {
- key: '_calculateVirtualScrollHeight',
- value: function _calculateVirtualScrollHeight(_ref6) {
- var options = _ref6.options;
- var maxHeight = this.props.maxHeight;
-
-
- var height = 0;
-
- for (var optionIndex = 0; optionIndex < options.length; optionIndex++) {
- var option = options[optionIndex];
-
- height += this._getOptionHeight({ option: option });
-
- if (height > maxHeight) {
- return maxHeight;
- }
- }
-
- return height;
- }
- }, {
- key: '_getOptionHeight',
- value: function _getOptionHeight(_ref7) {
- var option = _ref7.option;
- var optionHeight = this.props.optionHeight;
-
-
- return optionHeight instanceof Function ? optionHeight({ option: option }) : optionHeight;
- }
- }, {
- key: '_getSelectComponent',
- value: function _getSelectComponent() {
- var _props = this.props;
- var async = _props.async;
- var selectComponent = _props.selectComponent;
-
-
- if (selectComponent) {
- return selectComponent;
- } else if (async) {
- return _reactSelect2.default.Async;
- } else {
- return _reactSelect2.default;
- }
- }
- }, {
- key: '_optionRenderer',
- value: function _optionRenderer(_ref8) {
- var focusedOption = _ref8.focusedOption;
- var focusOption = _ref8.focusOption;
- var labelKey = _ref8.labelKey;
- var option = _ref8.option;
- var selectValue = _ref8.selectValue;
-
- var height = this._getOptionHeight({ option: option });
-
- var className = ['VirtualizedSelectOption'];
-
- if (option === focusedOption) {
- className.push('VirtualizedSelectFocusedOption');
- }
-
- if (option.disabled) {
- className.push('VirtualizedSelectDisabledOption');
- }
-
- var events = option.disabled ? {} : {
- onClick: function onClick() {
- return selectValue(option);
- },
- onMouseOver: function onMouseOver() {
- return focusOption(option);
- }
- };
-
- return _react2.default.createElement(
- 'div',
- _extends({
- className: className.join(' '),
- style: { height: height }
- }, events),
- option[labelKey]
- );
- }
- }]);
-
- return VirtualizedSelect;
-}(_react.Component);
-
-VirtualizedSelect.propTypes = {
- async: _react.PropTypes.bool,
- maxHeight: _react.PropTypes.number.isRequired,
- optionHeight: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.func]).isRequired,
- optionRenderer: _react.PropTypes.func,
- selectComponent: _react.PropTypes.func
-};
-VirtualizedSelect.defaultProps = {
- async: false,
- maxHeight: 200,
- optionHeight: 35
-};
-exports.default = VirtualizedSelect;
-},{"react":undefined,"react-select":undefined,"react-virtualized":77}],34:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = undefined;
-
-var _VirtualizedSelect = require('./VirtualizedSelect');
-
-var _VirtualizedSelect2 = _interopRequireDefault(_VirtualizedSelect);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _VirtualizedSelect2.default;
-},{"./VirtualizedSelect":33}],35:[function(require,module,exports){
-arguments[4][34][0].apply(exports,arguments)
-},{"./VirtualizedSelect":34,"dup":34}],36:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * This HOC decorates a virtualized component and responds to arrow-key events by scrolling one row or column at a time.
- */
-var ArrowKeyStepper = function (_Component) {
- _inherits(ArrowKeyStepper, _Component);
-
- function ArrowKeyStepper(props, context) {
- _classCallCheck(this, ArrowKeyStepper);
-
- var _this = _possibleConstructorReturn(this, (ArrowKeyStepper.__proto__ || Object.getPrototypeOf(ArrowKeyStepper)).call(this, props, context));
-
- _this.state = {
- scrollToColumn: 0,
- scrollToRow: 0
- };
-
- _this._columnStartIndex = 0;
- _this._columnStopIndex = 0;
- _this._rowStartIndex = 0;
- _this._rowStopIndex = 0;
-
- _this._onKeyDown = _this._onKeyDown.bind(_this);
- _this._onSectionRendered = _this._onSectionRendered.bind(_this);
- return _this;
- }
-
- _createClass(ArrowKeyStepper, [{
- key: 'render',
- value: function render() {
- var _props = this.props;
- var className = _props.className;
- var children = _props.children;
- var _state = this.state;
- var scrollToColumn = _state.scrollToColumn;
- var scrollToRow = _state.scrollToRow;
-
-
- return _react2.default.createElement(
- 'div',
- {
- className: className,
- onKeyDown: this._onKeyDown
- },
- children({
- onSectionRendered: this._onSectionRendered,
- scrollToColumn: scrollToColumn,
- scrollToRow: scrollToRow
- })
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_onKeyDown',
- value: function _onKeyDown(event) {
- var _props2 = this.props;
- var columnCount = _props2.columnCount;
- var rowCount = _props2.rowCount;
-
- // The above cases all prevent default event event behavior.
- // This is to keep the grid from scrolling after the snap-to update.
-
- switch (event.key) {
- case 'ArrowDown':
- event.preventDefault();
- this.setState({
- scrollToRow: Math.min(this._rowStopIndex + 1, rowCount - 1)
- });
- break;
- case 'ArrowLeft':
- event.preventDefault();
- this.setState({
- scrollToColumn: Math.max(this._columnStartIndex - 1, 0)
- });
- break;
- case 'ArrowRight':
- event.preventDefault();
- this.setState({
- scrollToColumn: Math.min(this._columnStopIndex + 1, columnCount - 1)
- });
- break;
- case 'ArrowUp':
- event.preventDefault();
- this.setState({
- scrollToRow: Math.max(this._rowStartIndex - 1, 0)
- });
- break;
- }
- }
- }, {
- key: '_onSectionRendered',
- value: function _onSectionRendered(_ref) {
- var columnStartIndex = _ref.columnStartIndex;
- var columnStopIndex = _ref.columnStopIndex;
- var rowStartIndex = _ref.rowStartIndex;
- var rowStopIndex = _ref.rowStopIndex;
-
- this._columnStartIndex = columnStartIndex;
- this._columnStopIndex = columnStopIndex;
- this._rowStartIndex = rowStartIndex;
- this._rowStopIndex = rowStopIndex;
- }
- }]);
-
- return ArrowKeyStepper;
-}(_react.Component);
-
-ArrowKeyStepper.propTypes = {
- children: _react.PropTypes.func.isRequired,
- className: _react.PropTypes.string,
- columnCount: _react.PropTypes.number.isRequired,
- rowCount: _react.PropTypes.number.isRequired
-};
-exports.default = ArrowKeyStepper;
-},{"react":undefined,"react-addons-shallow-compare":30}],37:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.ArrowKeyStepper = exports.default = undefined;
-
-var _ArrowKeyStepper2 = require('./ArrowKeyStepper');
-
-var _ArrowKeyStepper3 = _interopRequireDefault(_ArrowKeyStepper2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _ArrowKeyStepper3.default;
-exports.ArrowKeyStepper = _ArrowKeyStepper3.default;
-},{"./ArrowKeyStepper":36}],38:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Decorator component that automatically adjusts the width and height of a single child.
- * Child component should not be declared as a child but should rather be specified by a `ChildComponent` property.
- * All other properties will be passed through to the child component.
- */
-var AutoSizer = function (_Component) {
- _inherits(AutoSizer, _Component);
-
- function AutoSizer(props) {
- _classCallCheck(this, AutoSizer);
-
- var _this = _possibleConstructorReturn(this, (AutoSizer.__proto__ || Object.getPrototypeOf(AutoSizer)).call(this, props));
-
- _this.state = {
- height: 0,
- width: 0
- };
-
- _this._onResize = _this._onResize.bind(_this);
- _this._onScroll = _this._onScroll.bind(_this);
- _this._setRef = _this._setRef.bind(_this);
- return _this;
- }
-
- _createClass(AutoSizer, [{
- key: 'componentDidMount',
- value: function componentDidMount() {
- // Delay access of parentNode until mount.
- // This handles edge-cases where the component has already been unmounted before its ref has been set,
- // As well as libraries like react-lite which have a slightly different lifecycle.
- this._parentNode = this._autoSizer.parentNode;
-
- // Defer requiring resize handler in order to support server-side rendering.
- // See issue #41
- this._detectElementResize = require('../vendor/detectElementResize');
- this._detectElementResize.addResizeListener(this._parentNode, this._onResize);
-
- this._onResize();
- }
- }, {
- key: 'componentWillUnmount',
- value: function componentWillUnmount() {
- if (this._detectElementResize) {
- this._detectElementResize.removeResizeListener(this._parentNode, this._onResize);
- }
- }
- }, {
- key: 'render',
- value: function render() {
- var _props = this.props;
- var children = _props.children;
- var disableHeight = _props.disableHeight;
- var disableWidth = _props.disableWidth;
- var _state = this.state;
- var height = _state.height;
- var width = _state.width;
-
- // Outer div should not force width/height since that may prevent containers from shrinking.
- // Inner component should overflow and use calculated width/height.
- // See issue #68 for more information.
-
- var outerStyle = { overflow: 'visible' };
-
- if (!disableHeight) {
- outerStyle.height = 0;
- }
-
- if (!disableWidth) {
- outerStyle.width = 0;
- }
-
- return _react2.default.createElement(
- 'div',
- {
- ref: this._setRef,
- onScroll: this._onScroll,
- style: outerStyle
- },
- children({ height: height, width: width })
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_onResize',
- value: function _onResize() {
- var onResize = this.props.onResize;
-
- // Gaurd against AutoSizer component being removed from the DOM immediately after being added.
- // This can result in invalid style values which can result in NaN values if we don't handle them.
- // See issue #150 for more context.
-
- var boundingRect = this._parentNode.getBoundingClientRect();
- var height = boundingRect.height || 0;
- var width = boundingRect.width || 0;
-
- var style = getComputedStyle(this._parentNode);
- var paddingLeft = parseInt(style.paddingLeft, 10) || 0;
- var paddingRight = parseInt(style.paddingRight, 10) || 0;
- var paddingTop = parseInt(style.paddingTop, 10) || 0;
- var paddingBottom = parseInt(style.paddingBottom, 10) || 0;
-
- this.setState({
- height: height - paddingTop - paddingBottom,
- width: width - paddingLeft - paddingRight
- });
-
- onResize({ height: height, width: width });
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(event) {
- // Prevent detectElementResize library from being triggered by this scroll event.
- event.stopPropagation();
- }
- }, {
- key: '_setRef',
- value: function _setRef(autoSizer) {
- this._autoSizer = autoSizer;
- }
- }]);
-
- return AutoSizer;
-}(_react.Component);
-
-AutoSizer.propTypes = {
- /**
- * Function respondible for rendering children.
- * This function should implement the following signature:
- * ({ height, width }) => PropTypes.element
- */
- children: _react.PropTypes.func.isRequired,
-
- /** Disable dynamic :height property */
- disableHeight: _react.PropTypes.bool,
-
- /** Disable dynamic :width property */
- disableWidth: _react.PropTypes.bool,
-
- /** Callback to be invoked on-resize: ({ height, width }) */
- onResize: _react.PropTypes.func.isRequired
-};
-AutoSizer.defaultProps = {
- onResize: function onResize() {}
-};
-exports.default = AutoSizer;
-},{"../vendor/detectElementResize":80,"react":undefined,"react-addons-shallow-compare":30}],39:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.AutoSizer = exports.default = undefined;
-
-var _AutoSizer2 = require('./AutoSizer');
-
-var _AutoSizer3 = _interopRequireDefault(_AutoSizer2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _AutoSizer3.default;
-exports.AutoSizer = _AutoSizer3.default;
-},{"./AutoSizer":38}],40:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _reactDom = require('react-dom');
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _defaultCellSizeCache = require('./defaultCellSizeCache');
-
-var _defaultCellSizeCache2 = _interopRequireDefault(_defaultCellSizeCache);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Measures a Grid cell's contents by rendering them in a way that is not visible to the user.
- * Either a fixed width or height may be provided if it is desirable to measure only in one direction.
- */
-var CellMeasurer = function (_Component) {
- _inherits(CellMeasurer, _Component);
-
- function CellMeasurer(props, state) {
- _classCallCheck(this, CellMeasurer);
-
- var _this = _possibleConstructorReturn(this, (CellMeasurer.__proto__ || Object.getPrototypeOf(CellMeasurer)).call(this, props, state));
-
- _this._cellSizeCache = props.cellSizeCache || new _defaultCellSizeCache2.default();
-
- _this.getColumnWidth = _this.getColumnWidth.bind(_this);
- _this.getRowHeight = _this.getRowHeight.bind(_this);
- _this.resetMeasurements = _this.resetMeasurements.bind(_this);
- _this.resetMeasurementForColumn = _this.resetMeasurementForColumn.bind(_this);
- _this.resetMeasurementForRow = _this.resetMeasurementForRow.bind(_this);
- return _this;
- }
-
- _createClass(CellMeasurer, [{
- key: 'getColumnWidth',
- value: function getColumnWidth(_ref) {
- var index = _ref.index;
-
- if (this._cellSizeCache.hasColumnWidth(index)) {
- return this._cellSizeCache.getColumnWidth(index);
- }
-
- var rowCount = this.props.rowCount;
-
-
- var maxWidth = 0;
-
- for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
- var _measureCell2 = this._measureCell({
- clientWidth: true,
- columnIndex: index,
- rowIndex: rowIndex
- });
-
- var width = _measureCell2.width;
-
-
- maxWidth = Math.max(maxWidth, width);
- }
-
- this._cellSizeCache.setColumnWidth(index, maxWidth);
-
- return maxWidth;
- }
- }, {
- key: 'getRowHeight',
- value: function getRowHeight(_ref2) {
- var index = _ref2.index;
-
- if (this._cellSizeCache.hasRowHeight(index)) {
- return this._cellSizeCache.getRowHeight(index);
- }
-
- var columnCount = this.props.columnCount;
-
-
- var maxHeight = 0;
-
- for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) {
- var _measureCell3 = this._measureCell({
- clientHeight: true,
- columnIndex: columnIndex,
- rowIndex: index
- });
-
- var height = _measureCell3.height;
-
-
- maxHeight = Math.max(maxHeight, height);
- }
-
- this._cellSizeCache.setRowHeight(index, maxHeight);
-
- return maxHeight;
- }
- }, {
- key: 'resetMeasurementForColumn',
- value: function resetMeasurementForColumn(columnIndex) {
- this._cellSizeCache.clearColumnWidth(columnIndex);
- }
- }, {
- key: 'resetMeasurementForRow',
- value: function resetMeasurementForRow(rowIndex) {
- this._cellSizeCache.clearRowHeight(rowIndex);
- }
- }, {
- key: 'resetMeasurements',
- value: function resetMeasurements() {
- this._cellSizeCache.clearAllColumnWidths();
- this._cellSizeCache.clearAllRowHeights();
- }
- }, {
- key: 'componentDidMount',
- value: function componentDidMount() {
- this._renderAndMount();
- }
- }, {
- key: 'componentWillReceiveProps',
- value: function componentWillReceiveProps(nextProps) {
- var cellSizeCache = this.props.cellSizeCache;
-
-
- if (cellSizeCache !== nextProps.cellSizeCache) {
- this._cellSizeCache = nextProps.cellSizeCache;
- }
-
- this._updateDivDimensions(nextProps);
- }
- }, {
- key: 'componentWillUnmount',
- value: function componentWillUnmount() {
- this._unmountContainer();
- }
- }, {
- key: 'render',
- value: function render() {
- var children = this.props.children;
-
-
- return children({
- getColumnWidth: this.getColumnWidth,
- getRowHeight: this.getRowHeight,
- resetMeasurements: this.resetMeasurements,
- resetMeasurementForColumn: this.resetMeasurementForColumn,
- resetMeasurementForRow: this.resetMeasurementForRow
- });
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_getContainerNode',
- value: function _getContainerNode(props) {
- var container = props.container;
-
-
- if (container) {
- return _reactDom2.default.findDOMNode(typeof container === 'function' ? container() : container);
- } else {
- return document.body;
- }
- }
- }, {
- key: '_measureCell',
- value: function _measureCell(_ref3) {
- var _ref3$clientHeight = _ref3.clientHeight;
- var clientHeight = _ref3$clientHeight === undefined ? false : _ref3$clientHeight;
- var _ref3$clientWidth = _ref3.clientWidth;
- var clientWidth = _ref3$clientWidth === undefined ? true : _ref3$clientWidth;
- var columnIndex = _ref3.columnIndex;
- var rowIndex = _ref3.rowIndex;
- var cellRenderer = this.props.cellRenderer;
-
-
- var rendered = cellRenderer({
- columnIndex: columnIndex,
- rowIndex: rowIndex
- });
-
- // Handle edge case where this method is called before the CellMeasurer has completed its initial render (and mounted).
- this._renderAndMount();
-
- // @TODO Keep an eye on this for future React updates as the interface may change:
- // https://twitter.com/soprano/status/737316379712331776
- _reactDom2.default.unstable_renderSubtreeIntoContainer(this, rendered, this._div);
-
- var measurements = {
- height: clientHeight && this._div.clientHeight,
- width: clientWidth && this._div.clientWidth
- };
-
- _reactDom2.default.unmountComponentAtNode(this._div);
-
- return measurements;
- }
- }, {
- key: '_renderAndMount',
- value: function _renderAndMount() {
- if (!this._div) {
- this._div = document.createElement('div');
- this._div.style.display = 'inline-block';
- this._div.style.position = 'absolute';
- this._div.style.visibility = 'hidden';
- this._div.style.zIndex = -1;
-
- this._updateDivDimensions(this.props);
-
- this._containerNode = this._getContainerNode(this.props);
- this._containerNode.appendChild(this._div);
- }
- }
- }, {
- key: '_unmountContainer',
- value: function _unmountContainer() {
- if (this._div) {
- this._containerNode.removeChild(this._div);
-
- this._div = null;
- }
-
- this._containerNode = null;
- }
- }, {
- key: '_updateDivDimensions',
- value: function _updateDivDimensions(props) {
- var height = props.height;
- var width = props.width;
-
-
- if (height && height !== this._divHeight) {
- this._divHeight = height;
- this._div.style.height = height + 'px';
- }
-
- if (width && width !== this._divWidth) {
- this._divWidth = width;
- this._div.style.width = width + 'px';
- }
- }
- }]);
-
- return CellMeasurer;
-}(_react.Component);
-
-CellMeasurer.propTypes = {
- /**
- * Renders a cell given its indices.
- * Should implement the following interface: ({ columnIndex: number, rowIndex: number }): PropTypes.node
- */
- cellRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Optional, custom caching strategy for cell sizes.
- */
- cellSizeCache: _react.PropTypes.object,
-
- /**
- * Function respondible for rendering a virtualized component.
- * This function should implement the following signature:
- * ({ getColumnWidth, getRowHeight, resetMeasurements }) => PropTypes.element
- */
- children: _react.PropTypes.func.isRequired,
-
- /**
- * Number of columns in grid.
- */
- columnCount: _react.PropTypes.number.isRequired,
-
- /**
- * A Node, Component instance, or function that returns either.
- * If this property is not specified the document body will be used.
- */
- container: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.func, _react2.default.PropTypes.node]),
-
- /**
- * Assign a fixed :height in order to measure dynamic text :width only.
- */
- height: _react.PropTypes.number,
-
- /**
- * Number of rows in grid.
- */
- rowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Assign a fixed :width in order to measure dynamic text :height only.
- */
- width: _react.PropTypes.number
-};
-exports.default = CellMeasurer;
-},{"./defaultCellSizeCache":41,"react":undefined,"react-addons-shallow-compare":30,"react-dom":undefined}],41:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/**
- * Default CellMeasurer `cellSizeCache` implementation.
- * Permanently caches all cell sizes (identified by column and row index) unless explicitly cleared.
- * Can be configured to handle uniform cell widths and/or heights as a way of optimizing certain use cases.
- */
-var CellSizeCache = function () {
- function CellSizeCache() {
- var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
-
- var _ref$uniformRowHeight = _ref.uniformRowHeight;
- var uniformRowHeight = _ref$uniformRowHeight === undefined ? false : _ref$uniformRowHeight;
- var _ref$uniformColumnWid = _ref.uniformColumnWidth;
- var uniformColumnWidth = _ref$uniformColumnWid === undefined ? false : _ref$uniformColumnWid;
-
- _classCallCheck(this, CellSizeCache);
-
- this._uniformRowHeight = uniformRowHeight;
- this._uniformColumnWidth = uniformColumnWidth;
-
- this._cachedColumnWidths = {};
- this._cachedRowHeights = {};
- }
-
- _createClass(CellSizeCache, [{
- key: "clearAllColumnWidths",
- value: function clearAllColumnWidths() {
- this._cachedColumnWidth = undefined;
- this._cachedColumnWidths = {};
- }
- }, {
- key: "clearAllRowHeights",
- value: function clearAllRowHeights() {
- this._cachedRowHeight = undefined;
- this._cachedRowHeights = {};
- }
- }, {
- key: "clearColumnWidth",
- value: function clearColumnWidth(index) {
- this._cachedColumnWidth = undefined;
-
- delete this._cachedColumnWidths[index];
- }
- }, {
- key: "clearRowHeight",
- value: function clearRowHeight(index) {
- this._cachedRowHeight = undefined;
-
- delete this._cachedRowHeights[index];
- }
- }, {
- key: "getColumnWidth",
- value: function getColumnWidth(index) {
- return this._uniformColumnWidth ? this._cachedColumnWidth : this._cachedColumnWidths[index];
- }
- }, {
- key: "getRowHeight",
- value: function getRowHeight(index) {
- return this._uniformRowHeight ? this._cachedRowHeight : this._cachedRowHeights[index];
- }
- }, {
- key: "hasColumnWidth",
- value: function hasColumnWidth(index) {
- return this._uniformColumnWidth ? !!this._cachedColumnWidth : !!this._cachedColumnWidths[index];
- }
- }, {
- key: "hasRowHeight",
- value: function hasRowHeight(index) {
- return this._uniformRowHeight ? !!this._cachedRowHeight : !!this._cachedRowHeights[index];
- }
- }, {
- key: "setColumnWidth",
- value: function setColumnWidth(index, width) {
- this._cachedColumnWidth = width;
- this._cachedColumnWidths[index] = width;
- }
- }, {
- key: "setRowHeight",
- value: function setRowHeight(index, height) {
- this._cachedRowHeight = height;
- this._cachedRowHeights[index] = height;
- }
- }]);
-
- return CellSizeCache;
-}();
-
-exports.default = CellSizeCache;
-},{}],42:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.defaultCellSizeCache = exports.CellMeasurer = exports.default = undefined;
-
-var _CellMeasurer2 = require('./CellMeasurer');
-
-var _CellMeasurer3 = _interopRequireDefault(_CellMeasurer2);
-
-var _defaultCellSizeCache2 = require('./defaultCellSizeCache');
-
-var _defaultCellSizeCache3 = _interopRequireDefault(_defaultCellSizeCache2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _CellMeasurer3.default;
-exports.CellMeasurer = _CellMeasurer3.default;
-exports.defaultCellSizeCache = _defaultCellSizeCache3.default;
-},{"./CellMeasurer":40,"./defaultCellSizeCache":41}],43:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _CollectionView = require('./CollectionView');
-
-var _CollectionView2 = _interopRequireDefault(_CollectionView);
-
-var _calculateSizeAndPositionData2 = require('./utils/calculateSizeAndPositionData');
-
-var _calculateSizeAndPositionData3 = _interopRequireDefault(_calculateSizeAndPositionData2);
-
-var _getUpdatedOffsetForIndex = require('../utils/getUpdatedOffsetForIndex');
-
-var _getUpdatedOffsetForIndex2 = _interopRequireDefault(_getUpdatedOffsetForIndex);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Renders scattered or non-linear data.
- * Unlike Grid, which renders checkerboard data, Collection can render arbitrarily positioned- even overlapping- data.
- */
-var Collection = function (_Component) {
- _inherits(Collection, _Component);
-
- function Collection(props, context) {
- _classCallCheck(this, Collection);
-
- var _this = _possibleConstructorReturn(this, (Collection.__proto__ || Object.getPrototypeOf(Collection)).call(this, props, context));
-
- _this._cellMetadata = [];
- _this._lastRenderedCellIndices = [];
-
- // Cell cache during scroll (for perforamnce)
- _this._cellCache = [];
-
- _this._isScrollingChange = _this._isScrollingChange.bind(_this);
- return _this;
- }
-
- /** See Collection#recomputeCellSizesAndPositions */
-
-
- _createClass(Collection, [{
- key: 'recomputeCellSizesAndPositions',
- value: function recomputeCellSizesAndPositions() {
- this._cellCache = [];
- this._collectionView.recomputeCellSizesAndPositions();
- }
-
- /** React lifecycle methods */
-
- }, {
- key: 'render',
- value: function render() {
- var _this2 = this;
-
- var props = _objectWithoutProperties(this.props, []);
-
- return _react2.default.createElement(_CollectionView2.default, _extends({
- cellLayoutManager: this,
- isScrollingChange: this._isScrollingChange,
- ref: function ref(_ref) {
- _this2._collectionView = _ref;
- }
- }, props));
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
-
- /** CellLayoutManager interface */
-
- }, {
- key: 'calculateSizeAndPositionData',
- value: function calculateSizeAndPositionData() {
- var _props = this.props;
- var cellCount = _props.cellCount;
- var cellSizeAndPositionGetter = _props.cellSizeAndPositionGetter;
- var sectionSize = _props.sectionSize;
-
-
- var data = (0, _calculateSizeAndPositionData3.default)({
- cellCount: cellCount,
- cellSizeAndPositionGetter: cellSizeAndPositionGetter,
- sectionSize: sectionSize
- });
-
- this._cellMetadata = data.cellMetadata;
- this._sectionManager = data.sectionManager;
- this._height = data.height;
- this._width = data.width;
- }
-
- /**
- * Returns the most recently rendered set of cell indices.
- */
-
- }, {
- key: 'getLastRenderedIndices',
- value: function getLastRenderedIndices() {
- return this._lastRenderedCellIndices;
- }
-
- /**
- * Calculates the minimum amount of change from the current scroll position to ensure the specified cell is (fully) visible.
- */
-
- }, {
- key: 'getScrollPositionForCell',
- value: function getScrollPositionForCell(_ref2) {
- var align = _ref2.align;
- var cellIndex = _ref2.cellIndex;
- var height = _ref2.height;
- var scrollLeft = _ref2.scrollLeft;
- var scrollTop = _ref2.scrollTop;
- var width = _ref2.width;
- var cellCount = this.props.cellCount;
-
-
- if (cellIndex >= 0 && cellIndex < cellCount) {
- var cellMetadata = this._cellMetadata[cellIndex];
-
- scrollLeft = (0, _getUpdatedOffsetForIndex2.default)({
- align: align,
- cellOffset: cellMetadata.x,
- cellSize: cellMetadata.width,
- containerSize: width,
- currentOffset: scrollLeft,
- targetIndex: cellIndex
- });
-
- scrollTop = (0, _getUpdatedOffsetForIndex2.default)({
- align: align,
- cellOffset: cellMetadata.y,
- cellSize: cellMetadata.height,
- containerSize: height,
- currentOffset: scrollTop,
- targetIndex: cellIndex
- });
- }
-
- return {
- scrollLeft: scrollLeft,
- scrollTop: scrollTop
- };
- }
- }, {
- key: 'getTotalSize',
- value: function getTotalSize() {
- return {
- height: this._height,
- width: this._width
- };
- }
- }, {
- key: 'cellRenderers',
- value: function cellRenderers(_ref3) {
- var _this3 = this;
-
- var height = _ref3.height;
- var isScrolling = _ref3.isScrolling;
- var width = _ref3.width;
- var x = _ref3.x;
- var y = _ref3.y;
- var _props2 = this.props;
- var cellGroupRenderer = _props2.cellGroupRenderer;
- var cellRenderer = _props2.cellRenderer;
-
- // Store for later calls to getLastRenderedIndices()
-
- this._lastRenderedCellIndices = this._sectionManager.getCellIndices({
- height: height,
- width: width,
- x: x,
- y: y
- });
-
- return cellGroupRenderer({
- cellCache: this._cellCache,
- cellRenderer: cellRenderer,
- cellSizeAndPositionGetter: function cellSizeAndPositionGetter(_ref4) {
- var index = _ref4.index;
- return _this3._sectionManager.getCellMetadata({ index: index });
- },
- indices: this._lastRenderedCellIndices,
- isScrolling: isScrolling
- });
- }
- }, {
- key: '_isScrollingChange',
- value: function _isScrollingChange(isScrolling) {
- if (!isScrolling) {
- this._cellCache = [];
- }
- }
- }]);
-
- return Collection;
-}(_react.Component);
-
-Collection.propTypes = {
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Number of cells in Collection.
- */
- cellCount: _react.PropTypes.number.isRequired,
-
- /**
- * Responsible for rendering a group of cells given their indices.
- * Should implement the following interface: ({
- * cellSizeAndPositionGetter:Function,
- * indices: Array,
- * cellRenderer: Function
- * }): Array
- */
- cellGroupRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Responsible for rendering a cell given an row and column index.
- * Should implement the following interface: ({ index: number }): PropTypes.element
- */
- cellRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Callback responsible for returning size and offset/position information for a given cell (index).
- * ({ index: number }): { height: number, width: number, x: number, y: number }
- */
- cellSizeAndPositionGetter: _react.PropTypes.func.isRequired,
-
- /**
- * Optionally override the size of the sections a Collection's cells are split into.
- */
- sectionSize: _react.PropTypes.number
-};
-Collection.defaultProps = {
- 'aria-label': 'grid',
- cellGroupRenderer: defaultCellGroupRenderer
-};
-exports.default = Collection;
-
-
-function defaultCellGroupRenderer(_ref5) {
- var cellCache = _ref5.cellCache;
- var cellRenderer = _ref5.cellRenderer;
- var cellSizeAndPositionGetter = _ref5.cellSizeAndPositionGetter;
- var indices = _ref5.indices;
- var isScrolling = _ref5.isScrolling;
-
- return indices.map(function (index) {
- var cellMetadata = cellSizeAndPositionGetter({ index: index });
-
- // Avoid re-creating cells while scrolling.
- // This can lead to the same cell being created many times and can cause performance issues for "heavy" cells.
- // If a scroll is in progress- cache and reuse cells.
- // This cache will be thrown away once scrolling complets.
- var renderedCell = void 0;
-
- if (isScrolling) {
- if (!(index in cellCache)) {
- cellCache[index] = cellRenderer({
- index: index,
- isScrolling: isScrolling
- });
- }
-
- renderedCell = cellCache[index];
- } else {
- renderedCell = cellRenderer({
- index: index,
- isScrolling: isScrolling
- });
- }
-
- if (renderedCell == null || renderedCell === false) {
- return null;
- }
-
- return _react2.default.createElement(
- 'div',
- {
- className: 'Collection__cell',
- key: index,
- style: {
- height: cellMetadata.height,
- left: cellMetadata.x,
- top: cellMetadata.y,
- width: cellMetadata.width
- }
- },
- renderedCell
- );
- }).filter(function (renderedCell) {
- return !!renderedCell;
- });
-}
-},{"../utils/getUpdatedOffsetForIndex":79,"./CollectionView":44,"./utils/calculateSizeAndPositionData":48,"react":undefined,"react-addons-shallow-compare":30}],44:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _createCallbackMemoizer = require('../utils/createCallbackMemoizer');
-
-var _createCallbackMemoizer2 = _interopRequireDefault(_createCallbackMemoizer);
-
-var _scrollbarSize = require('dom-helpers/util/scrollbarSize');
-
-var _scrollbarSize2 = _interopRequireDefault(_scrollbarSize);
-
-var _raf = require('raf');
-
-var _raf2 = _interopRequireDefault(_raf);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-// @TODO It would be nice to refactor Grid to use this code as well.
-
-/**
- * Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress.
- * This improves performance and makes scrolling smoother.
- */
-var IS_SCROLLING_TIMEOUT = 150;
-
-/**
- * Controls whether the Grid updates the DOM element's scrollLeft/scrollTop based on the current state or just observes it.
- * This prevents Grid from interrupting mouse-wheel animations (see issue #2).
- */
-var SCROLL_POSITION_CHANGE_REASONS = {
- OBSERVED: 'observed',
- REQUESTED: 'requested'
-};
-
-/**
- * Monitors changes in properties (eg. cellCount) and state (eg. scroll offsets) to determine when rendering needs to occur.
- * This component does not render any visible content itself; it defers to the specified :cellLayoutManager.
- */
-
-var CollectionView = function (_Component) {
- _inherits(CollectionView, _Component);
-
- function CollectionView(props, context) {
- _classCallCheck(this, CollectionView);
-
- var _this = _possibleConstructorReturn(this, (CollectionView.__proto__ || Object.getPrototypeOf(CollectionView)).call(this, props, context));
-
- _this.state = {
- calculateSizeAndPositionDataOnNextUpdate: false,
- isScrolling: false,
- scrollLeft: 0,
- scrollTop: 0
- };
-
- // Invokes callbacks only when their values have changed.
- _this._onSectionRenderedMemoizer = (0, _createCallbackMemoizer2.default)();
- _this._onScrollMemoizer = (0, _createCallbackMemoizer2.default)(false);
-
- // Bind functions to instance so they don't lose context when passed around.
- _this._invokeOnSectionRenderedHelper = _this._invokeOnSectionRenderedHelper.bind(_this);
- _this._onScroll = _this._onScroll.bind(_this);
- _this._updateScrollPositionForScrollToCell = _this._updateScrollPositionForScrollToCell.bind(_this);
- return _this;
- }
-
- /**
- * Forced recompute of cell sizes and positions.
- * This function should be called if cell sizes have changed but nothing else has.
- * Since cell positions are calculated by callbacks, the collection view has no way of detecting when the underlying data has changed.
- */
-
-
- _createClass(CollectionView, [{
- key: 'recomputeCellSizesAndPositions',
- value: function recomputeCellSizesAndPositions() {
- this.setState({
- calculateSizeAndPositionDataOnNextUpdate: true
- });
- }
-
- /* ---------------------------- Component lifecycle methods ---------------------------- */
-
- }, {
- key: 'componentDidMount',
- value: function componentDidMount() {
- var _props = this.props;
- var cellLayoutManager = _props.cellLayoutManager;
- var scrollLeft = _props.scrollLeft;
- var scrollToCell = _props.scrollToCell;
- var scrollTop = _props.scrollTop;
-
- // If this component was first rendered server-side, scrollbar size will be undefined.
- // In that event we need to remeasure.
-
- if (!this._scrollbarSizeMeasured) {
- this._scrollbarSize = (0, _scrollbarSize2.default)();
- this._scrollbarSizeMeasured = true;
- this.setState({});
- }
-
- if (scrollToCell >= 0) {
- this._updateScrollPositionForScrollToCell();
- } else if (scrollLeft >= 0 || scrollTop >= 0) {
- this._setScrollPosition({ scrollLeft: scrollLeft, scrollTop: scrollTop });
- }
-
- // Update onSectionRendered callback.
- this._invokeOnSectionRenderedHelper();
-
- var _cellLayoutManager$ge = cellLayoutManager.getTotalSize();
-
- var totalHeight = _cellLayoutManager$ge.height;
- var totalWidth = _cellLayoutManager$ge.width;
-
- // Initialize onScroll callback.
-
- this._invokeOnScrollMemoizer({
- scrollLeft: scrollLeft || 0,
- scrollTop: scrollTop || 0,
- totalHeight: totalHeight,
- totalWidth: totalWidth
- });
- }
- }, {
- key: 'componentDidUpdate',
- value: function componentDidUpdate(prevProps, prevState) {
- var _props2 = this.props;
- var height = _props2.height;
- var scrollToCell = _props2.scrollToCell;
- var width = _props2.width;
- var _state = this.state;
- var scrollLeft = _state.scrollLeft;
- var scrollPositionChangeReason = _state.scrollPositionChangeReason;
- var scrollToAlignment = _state.scrollToAlignment;
- var scrollTop = _state.scrollTop;
-
- // Make sure requested changes to :scrollLeft or :scrollTop get applied.
- // Assigning to scrollLeft/scrollTop tells the browser to interrupt any running scroll animations,
- // And to discard any pending async changes to the scroll position that may have happened in the meantime (e.g. on a separate scrolling thread).
- // So we only set these when we require an adjustment of the scroll position.
- // See issue #2 for more information.
-
- if (scrollPositionChangeReason === SCROLL_POSITION_CHANGE_REASONS.REQUESTED) {
- if (scrollLeft >= 0 && scrollLeft !== prevState.scrollLeft && scrollLeft !== this._scrollingContainer.scrollLeft) {
- this._scrollingContainer.scrollLeft = scrollLeft;
- }
- if (scrollTop >= 0 && scrollTop !== prevState.scrollTop && scrollTop !== this._scrollingContainer.scrollTop) {
- this._scrollingContainer.scrollTop = scrollTop;
- }
- }
-
- // Update scroll offsets if the current :scrollToCell values requires it
- if (height !== prevProps.height || scrollToAlignment !== prevProps.scrollToAlignment || scrollToCell !== prevProps.scrollToCell || width !== prevProps.width) {
- this._updateScrollPositionForScrollToCell();
- }
-
- // Update onRowsRendered callback if start/stop indices have changed
- this._invokeOnSectionRenderedHelper();
- }
- }, {
- key: 'componentWillMount',
- value: function componentWillMount() {
- var cellLayoutManager = this.props.cellLayoutManager;
-
-
- cellLayoutManager.calculateSizeAndPositionData();
-
- // If this component is being rendered server-side, getScrollbarSize() will return undefined.
- // We handle this case in componentDidMount()
- this._scrollbarSize = (0, _scrollbarSize2.default)();
- if (this._scrollbarSize === undefined) {
- this._scrollbarSizeMeasured = false;
- this._scrollbarSize = 0;
- } else {
- this._scrollbarSizeMeasured = true;
- }
- }
- }, {
- key: 'componentWillUnmount',
- value: function componentWillUnmount() {
- if (this._disablePointerEventsTimeoutId) {
- clearTimeout(this._disablePointerEventsTimeoutId);
- }
-
- if (this._setNextStateAnimationFrameId) {
- _raf2.default.cancel(this._setNextStateAnimationFrameId);
- }
- }
-
- /**
- * @private
- * This method updates scrollLeft/scrollTop in state for the following conditions:
- * 1) Empty content (0 rows or columns)
- * 2) New scroll props overriding the current state
- * 3) Cells-count or cells-size has changed, making previous scroll offsets invalid
- */
-
- }, {
- key: 'componentWillUpdate',
- value: function componentWillUpdate(nextProps, nextState) {
- if (nextProps.cellCount === 0 && (nextState.scrollLeft !== 0 || nextState.scrollTop !== 0)) {
- this._setScrollPosition({
- scrollLeft: 0,
- scrollTop: 0
- });
- } else if (nextProps.scrollLeft !== this.props.scrollLeft || nextProps.scrollTop !== this.props.scrollTop) {
- this._setScrollPosition({
- scrollLeft: nextProps.scrollLeft,
- scrollTop: nextProps.scrollTop
- });
- }
-
- if (nextProps.cellCount !== this.props.cellCount || nextProps.cellLayoutManager !== this.props.cellLayoutManager || nextState.calculateSizeAndPositionDataOnNextUpdate) {
- nextProps.cellLayoutManager.calculateSizeAndPositionData();
- }
-
- if (nextState.calculateSizeAndPositionDataOnNextUpdate) {
- this.setState({
- calculateSizeAndPositionDataOnNextUpdate: false
- });
- }
- }
- }, {
- key: 'render',
- value: function render() {
- var _this2 = this;
-
- var _props3 = this.props;
- var autoHeight = _props3.autoHeight;
- var cellCount = _props3.cellCount;
- var cellLayoutManager = _props3.cellLayoutManager;
- var className = _props3.className;
- var height = _props3.height;
- var horizontalOverscanSize = _props3.horizontalOverscanSize;
- var noContentRenderer = _props3.noContentRenderer;
- var style = _props3.style;
- var verticalOverscanSize = _props3.verticalOverscanSize;
- var width = _props3.width;
- var _state2 = this.state;
- var isScrolling = _state2.isScrolling;
- var scrollLeft = _state2.scrollLeft;
- var scrollTop = _state2.scrollTop;
-
- var _cellLayoutManager$ge2 = cellLayoutManager.getTotalSize();
-
- var totalHeight = _cellLayoutManager$ge2.height;
- var totalWidth = _cellLayoutManager$ge2.width;
-
- // Safely expand the rendered area by the specified overscan amount
-
- var left = Math.max(0, scrollLeft - horizontalOverscanSize);
- var top = Math.max(0, scrollTop - verticalOverscanSize);
- var right = Math.min(totalWidth, scrollLeft + width + horizontalOverscanSize);
- var bottom = Math.min(totalHeight, scrollTop + height + verticalOverscanSize);
-
- var childrenToDisplay = height > 0 && width > 0 ? cellLayoutManager.cellRenderers({
- height: bottom - top,
- isScrolling: isScrolling,
- width: right - left,
- x: left,
- y: top
- }) : [];
-
- var collectionStyle = {
- height: autoHeight ? 'auto' : height,
- width: width
- };
-
- // Force browser to hide scrollbars when we know they aren't necessary.
- // Otherwise once scrollbars appear they may not disappear again.
- // For more info see issue #116
- var verticalScrollBarSize = totalHeight > height ? this._scrollbarSize : 0;
- var horizontalScrollBarSize = totalWidth > width ? this._scrollbarSize : 0;
- if (totalWidth + verticalScrollBarSize <= width) {
- collectionStyle.overflowX = 'hidden';
- }
- if (totalHeight + horizontalScrollBarSize <= height) {
- collectionStyle.overflowY = 'hidden';
- }
-
- return _react2.default.createElement(
- 'div',
- {
- ref: function ref(_ref) {
- _this2._scrollingContainer = _ref;
- },
- 'aria-label': this.props['aria-label'],
- className: (0, _classnames2.default)('Collection', className),
- onScroll: this._onScroll,
- role: 'grid',
- style: _extends({}, collectionStyle, style),
- tabIndex: 0
- },
- cellCount > 0 && _react2.default.createElement(
- 'div',
- {
- className: 'Collection__innerScrollContainer',
- style: {
- height: totalHeight,
- maxHeight: totalHeight,
- maxWidth: totalWidth,
- pointerEvents: isScrolling ? 'none' : '',
- width: totalWidth
- }
- },
- childrenToDisplay
- ),
- cellCount === 0 && noContentRenderer()
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
-
- /* ---------------------------- Helper methods ---------------------------- */
-
- /**
- * Sets an :isScrolling flag for a small window of time.
- * This flag is used to disable pointer events on the scrollable portion of the Collection.
- * This prevents jerky/stuttery mouse-wheel scrolling.
- */
-
- }, {
- key: '_enablePointerEventsAfterDelay',
- value: function _enablePointerEventsAfterDelay() {
- var _this3 = this;
-
- if (this._disablePointerEventsTimeoutId) {
- clearTimeout(this._disablePointerEventsTimeoutId);
- }
-
- this._disablePointerEventsTimeoutId = setTimeout(function () {
- var isScrollingChange = _this3.props.isScrollingChange;
-
-
- isScrollingChange(false);
-
- _this3._disablePointerEventsTimeoutId = null;
- _this3.setState({
- isScrolling: false
- });
- }, IS_SCROLLING_TIMEOUT);
- }
- }, {
- key: '_invokeOnSectionRenderedHelper',
- value: function _invokeOnSectionRenderedHelper() {
- var _props4 = this.props;
- var cellLayoutManager = _props4.cellLayoutManager;
- var onSectionRendered = _props4.onSectionRendered;
-
-
- this._onSectionRenderedMemoizer({
- callback: onSectionRendered,
- indices: {
- indices: cellLayoutManager.getLastRenderedIndices()
- }
- });
- }
- }, {
- key: '_invokeOnScrollMemoizer',
- value: function _invokeOnScrollMemoizer(_ref2) {
- var _this4 = this;
-
- var scrollLeft = _ref2.scrollLeft;
- var scrollTop = _ref2.scrollTop;
- var totalHeight = _ref2.totalHeight;
- var totalWidth = _ref2.totalWidth;
-
- this._onScrollMemoizer({
- callback: function callback(_ref3) {
- var scrollLeft = _ref3.scrollLeft;
- var scrollTop = _ref3.scrollTop;
- var _props5 = _this4.props;
- var height = _props5.height;
- var onScroll = _props5.onScroll;
- var width = _props5.width;
-
-
- onScroll({
- clientHeight: height,
- clientWidth: width,
- scrollHeight: totalHeight,
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- scrollWidth: totalWidth
- });
- },
- indices: {
- scrollLeft: scrollLeft,
- scrollTop: scrollTop
- }
- });
- }
-
- /**
- * Updates the state during the next animation frame.
- * Use this method to avoid multiple renders in a small span of time.
- * This helps performance for bursty events (like onScroll).
- */
-
- }, {
- key: '_setNextState',
- value: function _setNextState(state) {
- var _this5 = this;
-
- if (this._setNextStateAnimationFrameId) {
- _raf2.default.cancel(this._setNextStateAnimationFrameId);
- }
-
- this._setNextStateAnimationFrameId = (0, _raf2.default)(function () {
- _this5._setNextStateAnimationFrameId = null;
- _this5.setState(state);
- });
- }
- }, {
- key: '_setScrollPosition',
- value: function _setScrollPosition(_ref4) {
- var scrollLeft = _ref4.scrollLeft;
- var scrollTop = _ref4.scrollTop;
-
- var newState = {
- scrollPositionChangeReason: SCROLL_POSITION_CHANGE_REASONS.REQUESTED
- };
-
- if (scrollLeft >= 0) {
- newState.scrollLeft = scrollLeft;
- }
-
- if (scrollTop >= 0) {
- newState.scrollTop = scrollTop;
- }
-
- if (scrollLeft >= 0 && scrollLeft !== this.state.scrollLeft || scrollTop >= 0 && scrollTop !== this.state.scrollTop) {
- this.setState(newState);
- }
- }
- }, {
- key: '_updateScrollPositionForScrollToCell',
- value: function _updateScrollPositionForScrollToCell() {
- var _props6 = this.props;
- var cellLayoutManager = _props6.cellLayoutManager;
- var height = _props6.height;
- var scrollToAlignment = _props6.scrollToAlignment;
- var scrollToCell = _props6.scrollToCell;
- var width = _props6.width;
- var _state3 = this.state;
- var scrollLeft = _state3.scrollLeft;
- var scrollTop = _state3.scrollTop;
-
-
- if (scrollToCell >= 0) {
- var scrollPosition = cellLayoutManager.getScrollPositionForCell({
- align: scrollToAlignment,
- cellIndex: scrollToCell,
- height: height,
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- width: width
- });
-
- if (scrollPosition.scrollLeft !== scrollLeft || scrollPosition.scrollTop !== scrollTop) {
- this._setScrollPosition(scrollPosition);
- }
- }
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(event) {
- // In certain edge-cases React dispatches an onScroll event with an invalid target.scrollLeft / target.scrollTop.
- // This invalid event can be detected by comparing event.target to this component's scrollable DOM element.
- // See issue #404 for more information.
- if (event.target !== this._scrollingContainer) {
- return;
- }
-
- // Prevent pointer events from interrupting a smooth scroll
- this._enablePointerEventsAfterDelay();
-
- // When this component is shrunk drastically, React dispatches a series of back-to-back scroll events,
- // Gradually converging on a scrollTop that is within the bounds of the new, smaller height.
- // This causes a series of rapid renders that is slow for long lists.
- // We can avoid that by doing some simple bounds checking to ensure that scrollTop never exceeds the total height.
- var _props7 = this.props;
- var cellLayoutManager = _props7.cellLayoutManager;
- var height = _props7.height;
- var isScrollingChange = _props7.isScrollingChange;
- var width = _props7.width;
-
- var scrollbarSize = this._scrollbarSize;
-
- var _cellLayoutManager$ge3 = cellLayoutManager.getTotalSize();
-
- var totalHeight = _cellLayoutManager$ge3.height;
- var totalWidth = _cellLayoutManager$ge3.width;
-
- var scrollLeft = Math.max(0, Math.min(totalWidth - width + scrollbarSize, event.target.scrollLeft));
- var scrollTop = Math.max(0, Math.min(totalHeight - height + scrollbarSize, event.target.scrollTop));
-
- // Certain devices (like Apple touchpad) rapid-fire duplicate events.
- // Don't force a re-render if this is the case.
- // The mouse may move faster then the animation frame does.
- // Use requestAnimationFrame to avoid over-updating.
- if (this.state.scrollLeft !== scrollLeft || this.state.scrollTop !== scrollTop) {
- // Browsers with cancelable scroll events (eg. Firefox) interrupt scrolling animations if scrollTop/scrollLeft is set.
- // Other browsers (eg. Safari) don't scroll as well without the help under certain conditions (DOM or style changes during scrolling).
- // All things considered, this seems to be the best current work around that I'm aware of.
- // For more information see https://github.com/bvaughn/react-virtualized/pull/124
- var scrollPositionChangeReason = event.cancelable ? SCROLL_POSITION_CHANGE_REASONS.OBSERVED : SCROLL_POSITION_CHANGE_REASONS.REQUESTED;
-
- // Synchronously set :isScrolling the first time (since _setNextState will reschedule its animation frame each time it's called)
- if (!this.state.isScrolling) {
- isScrollingChange(true);
-
- this.setState({
- isScrolling: true
- });
- }
-
- this._setNextState({
- isScrolling: true,
- scrollLeft: scrollLeft,
- scrollPositionChangeReason: scrollPositionChangeReason,
- scrollTop: scrollTop
- });
- }
-
- this._invokeOnScrollMemoizer({
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- totalWidth: totalWidth,
- totalHeight: totalHeight
- });
- }
- }]);
-
- return CollectionView;
-}(_react.Component);
-
-CollectionView.propTypes = {
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Removes fixed height from the scrollingContainer so that the total height
- * of rows can stretch the window. Intended for use with WindowScroller
- */
- autoHeight: _react.PropTypes.bool,
-
- /**
- * Number of cells in collection.
- */
- cellCount: _react.PropTypes.number.isRequired,
-
- /**
- * Calculates cell sizes and positions and manages rendering the appropriate cells given a specified window.
- */
- cellLayoutManager: _react.PropTypes.object.isRequired,
-
- /**
- * Optional custom CSS class name to attach to root Collection element.
- */
- className: _react.PropTypes.string,
-
- /**
- * Height of Collection; this property determines the number of visible (vs virtualized) rows.
- */
- height: _react.PropTypes.number.isRequired,
-
- /**
- * Enables the `Collection` to horiontally "overscan" its content similar to how `Grid` does.
- * This can reduce flicker around the edges when a user scrolls quickly.
- */
- horizontalOverscanSize: _react.PropTypes.number.isRequired,
-
- isScrollingChange: _react.PropTypes.func,
-
- /**
- * Optional renderer to be used in place of rows when either :rowCount or :cellCount is 0.
- */
- noContentRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Callback invoked whenever the scroll offset changes within the inner scrollable region.
- * This callback can be used to sync scrolling between lists, tables, or grids.
- * ({ clientHeight, clientWidth, scrollHeight, scrollLeft, scrollTop, scrollWidth }): void
- */
- onScroll: _react.PropTypes.func.isRequired,
-
- /**
- * Callback invoked with information about the section of the Collection that was just rendered.
- * This callback is passed a named :indices parameter which is an Array of the most recently rendered section indices.
- */
- onSectionRendered: _react.PropTypes.func.isRequired,
-
- /**
- * Horizontal offset.
- */
- scrollLeft: _react.PropTypes.number,
-
- /**
- * Controls scroll-to-cell behavior of the Grid.
- * The default ("auto") scrolls the least amount possible to ensure that the specified cell is fully visible.
- * Use "start" to align cells to the top/left of the Grid and "end" to align bottom/right.
- */
- scrollToAlignment: _react.PropTypes.oneOf(['auto', 'end', 'start', 'center']).isRequired,
-
- /**
- * Cell index to ensure visible (by forcefully scrolling if necessary).
- */
- scrollToCell: _react.PropTypes.number,
-
- /**
- * Vertical offset.
- */
- scrollTop: _react.PropTypes.number,
-
- /**
- * Optional custom inline style to attach to root Collection element.
- */
- style: _react.PropTypes.object,
-
- /**
- * Enables the `Collection` to vertically "overscan" its content similar to how `Grid` does.
- * This can reduce flicker around the edges when a user scrolls quickly.
- */
- verticalOverscanSize: _react.PropTypes.number.isRequired,
-
- /**
- * Width of Collection; this property determines the number of visible (vs virtualized) columns.
- */
- width: _react.PropTypes.number.isRequired
-};
-CollectionView.defaultProps = {
- 'aria-label': 'grid',
- horizontalOverscanSize: 0,
- noContentRenderer: function noContentRenderer() {
- return null;
- },
- onScroll: function onScroll() {
- return null;
- },
- onSectionRendered: function onSectionRendered() {
- return null;
- },
- scrollToAlignment: 'auto',
- style: {},
- verticalOverscanSize: 0
-};
-exports.default = CollectionView;
-},{"../utils/createCallbackMemoizer":78,"classnames":undefined,"dom-helpers/util/scrollbarSize":19,"raf":29,"react":undefined,"react-addons-shallow-compare":30}],45:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/**
- * A section of the Window.
- * Window Sections are used to group nearby cells.
- * This enables us to more quickly determine which cells to display in a given region of the Window.
- * Sections have a fixed size and contain 0 to many cells (tracked by their indices).
- */
-var Section = function () {
- function Section(_ref) {
- var height = _ref.height;
- var width = _ref.width;
- var x = _ref.x;
- var y = _ref.y;
-
- _classCallCheck(this, Section);
-
- this.height = height;
- this.width = width;
- this.x = x;
- this.y = y;
-
- this._indexMap = {};
- this._indices = [];
- }
-
- /** Add a cell to this section. */
-
-
- _createClass(Section, [{
- key: 'addCellIndex',
- value: function addCellIndex(_ref2) {
- var index = _ref2.index;
-
- if (!this._indexMap[index]) {
- this._indexMap[index] = true;
- this._indices.push(index);
- }
- }
-
- /** Get all cell indices that have been added to this section. */
-
- }, {
- key: 'getCellIndices',
- value: function getCellIndices() {
- return this._indices;
- }
-
- /** Intended for debugger/test purposes only */
-
- }, {
- key: 'toString',
- value: function toString() {
- return this.x + ',' + this.y + ' ' + this.width + 'x' + this.height;
- }
- }]);
-
- return Section;
-}(); /** @rlow */
-
-
-exports.default = Section;
-},{}],46:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
- * Window Sections are used to group nearby cells.
- * This enables us to more quickly determine which cells to display in a given region of the Window.
- *
- */
-
-
-var _Section = require('./Section');
-
-var _Section2 = _interopRequireDefault(_Section);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-var SECTION_SIZE = 100;
-
-/**
- * Contains 0 to many Sections.
- * Grows (and adds Sections) dynamically as cells are registered.
- * Automatically adds cells to the appropriate Section(s).
- */
-var SectionManager = function () {
- function SectionManager() {
- var sectionSize = arguments.length <= 0 || arguments[0] === undefined ? SECTION_SIZE : arguments[0];
-
- _classCallCheck(this, SectionManager);
-
- this._sectionSize = sectionSize;
-
- this._cellMetadata = [];
- this._sections = {};
- }
-
- /**
- * Gets all cell indices contained in the specified region.
- * A region may encompass 1 or more Sections.
- */
-
-
- _createClass(SectionManager, [{
- key: 'getCellIndices',
- value: function getCellIndices(_ref) {
- var height = _ref.height;
- var width = _ref.width;
- var x = _ref.x;
- var y = _ref.y;
-
- var indices = {};
-
- this.getSections({ height: height, width: width, x: x, y: y }).forEach(function (section) {
- return section.getCellIndices().forEach(function (index) {
- indices[index] = index;
- });
- });
-
- // Object keys are strings; this function returns numbers
- return Object.keys(indices).map(function (index) {
- return indices[index];
- });
- }
-
- /** Get size and position information for the cell specified. */
-
- }, {
- key: 'getCellMetadata',
- value: function getCellMetadata(_ref2) {
- var index = _ref2.index;
-
- return this._cellMetadata[index];
- }
-
- /** Get all Sections overlapping the specified region. */
-
- }, {
- key: 'getSections',
- value: function getSections(_ref3) {
- var height = _ref3.height;
- var width = _ref3.width;
- var x = _ref3.x;
- var y = _ref3.y;
-
- var sectionXStart = Math.floor(x / this._sectionSize);
- var sectionXStop = Math.floor((x + width - 1) / this._sectionSize);
- var sectionYStart = Math.floor(y / this._sectionSize);
- var sectionYStop = Math.floor((y + height - 1) / this._sectionSize);
-
- var sections = [];
-
- for (var sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) {
- for (var sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) {
- var key = sectionX + '.' + sectionY;
-
- if (!this._sections[key]) {
- this._sections[key] = new _Section2.default({
- height: this._sectionSize,
- width: this._sectionSize,
- x: sectionX * this._sectionSize,
- y: sectionY * this._sectionSize
- });
- }
-
- sections.push(this._sections[key]);
- }
- }
-
- return sections;
- }
-
- /** Total number of Sections based on the currently registered cells. */
-
- }, {
- key: 'getTotalSectionCount',
- value: function getTotalSectionCount() {
- return Object.keys(this._sections).length;
- }
-
- /** Intended for debugger/test purposes only */
-
- }, {
- key: 'toString',
- value: function toString() {
- var _this = this;
-
- return Object.keys(this._sections).map(function (index) {
- return _this._sections[index].toString();
- });
- }
-
- /** Adds a cell to the appropriate Sections and registers it metadata for later retrievable. */
-
- }, {
- key: 'registerCell',
- value: function registerCell(_ref4) {
- var cellMetadatum = _ref4.cellMetadatum;
- var index = _ref4.index;
-
- this._cellMetadata[index] = cellMetadatum;
-
- this.getSections(cellMetadatum).forEach(function (section) {
- return section.addCellIndex({ index: index });
- });
- }
- }]);
-
- return SectionManager;
-}();
-
-exports.default = SectionManager;
-},{"./Section":45}],47:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.Collection = exports.default = undefined;
-
-var _Collection2 = require('./Collection');
-
-var _Collection3 = _interopRequireDefault(_Collection2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _Collection3.default;
-exports.Collection = _Collection3.default;
-},{"./Collection":43}],48:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = calculateSizeAndPositionData;
-
-var _SectionManager = require('../SectionManager');
-
-var _SectionManager2 = _interopRequireDefault(_SectionManager);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function calculateSizeAndPositionData(_ref) {
- var cellCount = _ref.cellCount;
- var cellSizeAndPositionGetter = _ref.cellSizeAndPositionGetter;
- var sectionSize = _ref.sectionSize;
-
- var cellMetadata = [];
- var sectionManager = new _SectionManager2.default(sectionSize);
- var height = 0;
- var width = 0;
-
- for (var index = 0; index < cellCount; index++) {
- var cellMetadatum = cellSizeAndPositionGetter({ index: index });
-
- if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.x == null || isNaN(cellMetadatum.x) || cellMetadatum.y == null || isNaN(cellMetadatum.y)) {
- throw Error('Invalid metadata returned for cell ' + index + ':\n x:' + cellMetadatum.x + ', y:' + cellMetadatum.y + ', width:' + cellMetadatum.width + ', height:' + cellMetadatum.height);
- }
-
- height = Math.max(height, cellMetadatum.y + cellMetadatum.height);
- width = Math.max(width, cellMetadatum.x + cellMetadatum.width);
-
- cellMetadata[index] = cellMetadatum;
- sectionManager.registerCell({
- cellMetadatum: cellMetadatum,
- index: index
- });
- }
-
- return {
- cellMetadata: cellMetadata,
- height: height,
- sectionManager: sectionManager,
- width: width
- };
-}
-},{"../SectionManager":46}],49:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _Grid = require('../Grid');
-
-var _Grid2 = _interopRequireDefault(_Grid);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * High-order component that auto-calculates column-widths for `Grid` cells.
- */
-var ColumnSizer = function (_Component) {
- _inherits(ColumnSizer, _Component);
-
- function ColumnSizer(props, context) {
- _classCallCheck(this, ColumnSizer);
-
- var _this = _possibleConstructorReturn(this, (ColumnSizer.__proto__ || Object.getPrototypeOf(ColumnSizer)).call(this, props, context));
-
- _this._registerChild = _this._registerChild.bind(_this);
- return _this;
- }
-
- _createClass(ColumnSizer, [{
- key: 'componentDidUpdate',
- value: function componentDidUpdate(prevProps, prevState) {
- var _props = this.props;
- var columnMaxWidth = _props.columnMaxWidth;
- var columnMinWidth = _props.columnMinWidth;
- var columnCount = _props.columnCount;
- var width = _props.width;
-
-
- if (columnMaxWidth !== prevProps.columnMaxWidth || columnMinWidth !== prevProps.columnMinWidth || columnCount !== prevProps.columnCount || width !== prevProps.width) {
- if (this._registeredChild) {
- this._registeredChild.recomputeGridSize();
- }
- }
- }
- }, {
- key: 'render',
- value: function render() {
- var _props2 = this.props;
- var children = _props2.children;
- var columnMaxWidth = _props2.columnMaxWidth;
- var columnMinWidth = _props2.columnMinWidth;
- var columnCount = _props2.columnCount;
- var width = _props2.width;
-
-
- var safeColumnMinWidth = columnMinWidth || 1;
-
- var safeColumnMaxWidth = columnMaxWidth ? Math.min(columnMaxWidth, width) : width;
-
- var columnWidth = width / columnCount;
- columnWidth = Math.max(safeColumnMinWidth, columnWidth);
- columnWidth = Math.min(safeColumnMaxWidth, columnWidth);
- columnWidth = Math.floor(columnWidth);
-
- var adjustedWidth = Math.min(width, columnWidth * columnCount);
-
- return children({
- adjustedWidth: adjustedWidth,
- getColumnWidth: function getColumnWidth() {
- return columnWidth;
- },
- registerChild: this._registerChild
- });
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_registerChild',
- value: function _registerChild(child) {
- if (child !== null && !(child instanceof _Grid2.default)) {
- throw Error('Unexpected child type registered; only Grid children are supported.');
- }
-
- this._registeredChild = child;
-
- if (this._registeredChild) {
- this._registeredChild.recomputeGridSize();
- }
- }
- }]);
-
- return ColumnSizer;
-}(_react.Component);
-
-ColumnSizer.propTypes = {
- /**
- * Function respondible for rendering a virtualized Grid.
- * This function should implement the following signature:
- * ({ adjustedWidth, getColumnWidth, registerChild }) => PropTypes.element
- *
- * The specified :getColumnWidth function should be passed to the Grid's :columnWidth property.
- * The :registerChild should be passed to the Grid's :ref property.
- * The :adjustedWidth property is optional; it reflects the lesser of the overall width or the width of all columns.
- */
- children: _react.PropTypes.func.isRequired,
-
- /** Optional maximum allowed column width */
- columnMaxWidth: _react.PropTypes.number,
-
- /** Optional minimum allowed column width */
- columnMinWidth: _react.PropTypes.number,
-
- /** Number of columns in Grid or FlexTable child */
- columnCount: _react.PropTypes.number.isRequired,
-
- /** Width of Grid or FlexTable child */
- width: _react.PropTypes.number.isRequired
-};
-exports.default = ColumnSizer;
-},{"../Grid":62,"react":undefined,"react-addons-shallow-compare":30}],50:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.ColumnSizer = exports.default = undefined;
-
-var _ColumnSizer2 = require('./ColumnSizer');
-
-var _ColumnSizer3 = _interopRequireDefault(_ColumnSizer2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _ColumnSizer3.default;
-exports.ColumnSizer = _ColumnSizer3.default;
-},{"./ColumnSizer":49}],51:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _react = require('react');
-
-var _defaultHeaderRenderer = require('./defaultHeaderRenderer');
-
-var _defaultHeaderRenderer2 = _interopRequireDefault(_defaultHeaderRenderer);
-
-var _defaultCellRenderer = require('./defaultCellRenderer');
-
-var _defaultCellRenderer2 = _interopRequireDefault(_defaultCellRenderer);
-
-var _defaultCellDataGetter = require('./defaultCellDataGetter');
-
-var _defaultCellDataGetter2 = _interopRequireDefault(_defaultCellDataGetter);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Describes the header and cell contents of a table column.
- */
-var Column = function (_Component) {
- _inherits(Column, _Component);
-
- function Column() {
- _classCallCheck(this, Column);
-
- return _possibleConstructorReturn(this, (Column.__proto__ || Object.getPrototypeOf(Column)).apply(this, arguments));
- }
-
- return Column;
-}(_react.Component);
-
-Column.defaultProps = {
- cellDataGetter: _defaultCellDataGetter2.default,
- cellRenderer: _defaultCellRenderer2.default,
- flexGrow: 0,
- flexShrink: 1,
- headerRenderer: _defaultHeaderRenderer2.default,
- style: {}
-};
-Column.propTypes = {
- /** Optional aria-label value to set on the column header */
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Callback responsible for returning a cell's data, given its :dataKey
- * ({ columnData: any, dataKey: string, rowData: any }): any
- */
- cellDataGetter: _react.PropTypes.func,
-
- /**
- * Callback responsible for rendering a cell's contents.
- * ({ cellData: any, columnData: any, dataKey: string, rowData: any, rowIndex: number }): node
- */
- cellRenderer: _react.PropTypes.func,
-
- /** Optional CSS class to apply to cell */
- className: _react.PropTypes.string,
-
- /** Optional additional data passed to this column's :cellDataGetter */
- columnData: _react.PropTypes.object,
-
- /** Uniquely identifies the row-data attribute correspnding to this cell */
- dataKey: _react.PropTypes.any.isRequired,
-
- /** If sort is enabled for the table at large, disable it for this column */
- disableSort: _react.PropTypes.bool,
-
- /** Flex grow style; defaults to 0 */
- flexGrow: _react.PropTypes.number,
-
- /** Flex shrink style; defaults to 1 */
- flexShrink: _react.PropTypes.number,
-
- /** Optional CSS class to apply to this column's header */
- headerClassName: _react.PropTypes.string,
-
- /**
- * Optional callback responsible for rendering a column header contents.
- * ({ columnData: object, dataKey: string, disableSort: boolean, label: string, sortBy: string, sortDirection: string }): PropTypes.node
- */
- headerRenderer: _react.PropTypes.func.isRequired,
-
- /** Header label for this column */
- label: _react.PropTypes.string,
-
- /** Maximum width of column; this property will only be used if :flexGrow is > 0. */
- maxWidth: _react.PropTypes.number,
-
- /** Minimum width of column. */
- minWidth: _react.PropTypes.number,
-
- /** Optional inline style to apply to cell */
- style: _react.PropTypes.object,
-
- /** Flex basis (width) for this column; This value can grow or shrink based on :flexGrow and :flexShrink properties. */
- width: _react.PropTypes.number.isRequired
-};
-exports.default = Column;
-},{"./defaultCellDataGetter":55,"./defaultCellRenderer":56,"./defaultHeaderRenderer":57,"react":undefined}],52:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _FlexColumn = require('./FlexColumn');
-
-var _FlexColumn2 = _interopRequireDefault(_FlexColumn);
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = require('react-dom');
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _Grid = require('../Grid');
-
-var _Grid2 = _interopRequireDefault(_Grid);
-
-var _defaultRowRenderer = require('./defaultRowRenderer');
-
-var _defaultRowRenderer2 = _interopRequireDefault(_defaultRowRenderer);
-
-var _SortDirection = require('./SortDirection');
-
-var _SortDirection2 = _interopRequireDefault(_SortDirection);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Table component with fixed headers and virtualized rows for improved performance with large data sets.
- * This component expects explicit width, height, and padding parameters.
- */
-var FlexTable = function (_Component) {
- _inherits(FlexTable, _Component);
-
- function FlexTable(props) {
- _classCallCheck(this, FlexTable);
-
- var _this = _possibleConstructorReturn(this, (FlexTable.__proto__ || Object.getPrototypeOf(FlexTable)).call(this, props));
-
- _this.state = {
- scrollbarWidth: 0
- };
-
- _this._cellClassName = _this._cellClassName.bind(_this);
- _this._cellStyle = _this._cellStyle.bind(_this);
- _this._createColumn = _this._createColumn.bind(_this);
- _this._createRow = _this._createRow.bind(_this);
- _this._onScroll = _this._onScroll.bind(_this);
- _this._onSectionRendered = _this._onSectionRendered.bind(_this);
- return _this;
- }
-
- _createClass(FlexTable, [{
- key: 'forceUpdateGrid',
- value: function forceUpdateGrid() {
- this.Grid.forceUpdate();
- }
-
- /** See Grid#measureAllCells */
-
- }, {
- key: 'measureAllRows',
- value: function measureAllRows() {
- this.Grid.measureAllCells();
- }
-
- /** See Grid#recomputeGridSize */
-
- }, {
- key: 'recomputeRowHeights',
- value: function recomputeRowHeights() {
- var index = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
-
- this.Grid.recomputeGridSize({
- rowIndex: index
- });
- this.forceUpdateGrid();
- }
- }, {
- key: 'componentDidMount',
- value: function componentDidMount() {
- this._setScrollbarWidth();
- }
- }, {
- key: 'componentDidUpdate',
- value: function componentDidUpdate() {
- this._setScrollbarWidth();
- }
- }, {
- key: 'render',
- value: function render() {
- var _this2 = this;
-
- var _props = this.props;
- var children = _props.children;
- var className = _props.className;
- var disableHeader = _props.disableHeader;
- var gridClassName = _props.gridClassName;
- var gridStyle = _props.gridStyle;
- var headerHeight = _props.headerHeight;
- var height = _props.height;
- var noRowsRenderer = _props.noRowsRenderer;
- var rowClassName = _props.rowClassName;
- var rowStyle = _props.rowStyle;
- var scrollToIndex = _props.scrollToIndex;
- var style = _props.style;
- var width = _props.width;
- var scrollbarWidth = this.state.scrollbarWidth;
-
-
- var availableRowsHeight = height - headerHeight;
-
- var rowClass = rowClassName instanceof Function ? rowClassName({ index: -1 }) : rowClassName;
- var rowStyleObject = rowStyle instanceof Function ? rowStyle({ index: -1 }) : rowStyle;
-
- // Precompute and cache column styles before rendering rows and columns to speed things up
- this._cachedColumnStyles = [];
- _react2.default.Children.toArray(children).forEach(function (column, index) {
- _this2._cachedColumnStyles[index] = _this2._getFlexStyleForColumn(column, column.props.style);
- });
-
- // Note that we specify :numChildren, :scrollbarWidth, :sortBy, and :sortDirection as properties on Grid even though these have nothing to do with Grid.
- // This is done because Grid is a pure component and won't update unless its properties or state has changed.
- // Any property that should trigger a re-render of Grid then is specified here to avoid a stale display.
- return _react2.default.createElement(
- 'div',
- {
- className: (0, _classnames2.default)('FlexTable', className),
- style: style
- },
- !disableHeader && _react2.default.createElement(
- 'div',
- {
- className: (0, _classnames2.default)('FlexTable__headerRow', rowClass),
- style: _extends({}, rowStyleObject, {
- height: headerHeight,
- paddingRight: scrollbarWidth,
- width: width
- })
- },
- this._getRenderedHeaderRow()
- ),
- _react2.default.createElement(_Grid2.default, _extends({}, this.props, {
- autoContainerWidth: true,
- className: (0, _classnames2.default)('FlexTable__Grid', gridClassName),
- cellClassName: this._cellClassName,
- cellRenderer: this._createRow,
- cellStyle: this._cellStyle,
- columnWidth: width,
- columnCount: 1,
- height: availableRowsHeight,
- noContentRenderer: noRowsRenderer,
- onScroll: this._onScroll,
- onSectionRendered: this._onSectionRendered,
- ref: function ref(_ref) {
- _this2.Grid = _ref;
- },
- scrollbarWidth: scrollbarWidth,
- scrollToRow: scrollToIndex,
- style: gridStyle
- }))
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_cellClassName',
- value: function _cellClassName(_ref2) {
- var rowIndex = _ref2.rowIndex;
- var rowWrapperClassName = this.props.rowWrapperClassName;
-
-
- return rowWrapperClassName instanceof Function ? rowWrapperClassName({ index: rowIndex - 1 }) : rowWrapperClassName;
- }
- }, {
- key: '_cellStyle',
- value: function _cellStyle(_ref3) {
- var rowIndex = _ref3.rowIndex;
- var rowWrapperStyle = this.props.rowWrapperStyle;
-
-
- return rowWrapperStyle instanceof Function ? rowWrapperStyle({ index: rowIndex - 1 }) : rowWrapperStyle;
- }
- }, {
- key: '_createColumn',
- value: function _createColumn(_ref4) {
- var column = _ref4.column;
- var columnIndex = _ref4.columnIndex;
- var isScrolling = _ref4.isScrolling;
- var rowData = _ref4.rowData;
- var rowIndex = _ref4.rowIndex;
- var _column$props = column.props;
- var cellDataGetter = _column$props.cellDataGetter;
- var cellRenderer = _column$props.cellRenderer;
- var className = _column$props.className;
- var columnData = _column$props.columnData;
- var dataKey = _column$props.dataKey;
-
-
- var cellData = cellDataGetter({ columnData: columnData, dataKey: dataKey, rowData: rowData });
- var renderedCell = cellRenderer({ cellData: cellData, columnData: columnData, dataKey: dataKey, isScrolling: isScrolling, rowData: rowData, rowIndex: rowIndex });
-
- var style = this._cachedColumnStyles[columnIndex];
-
- var title = typeof renderedCell === 'string' ? renderedCell : null;
-
- return _react2.default.createElement(
- 'div',
- {
- key: 'Row' + rowIndex + '-Col' + columnIndex,
- className: (0, _classnames2.default)('FlexTable__rowColumn', className),
- style: style,
- title: title
- },
- renderedCell
- );
- }
- }, {
- key: '_createHeader',
- value: function _createHeader(_ref5) {
- var column = _ref5.column;
- var index = _ref5.index;
- var _props2 = this.props;
- var headerClassName = _props2.headerClassName;
- var headerStyle = _props2.headerStyle;
- var onHeaderClick = _props2.onHeaderClick;
- var sort = _props2.sort;
- var sortBy = _props2.sortBy;
- var sortDirection = _props2.sortDirection;
- var _column$props2 = column.props;
- var dataKey = _column$props2.dataKey;
- var disableSort = _column$props2.disableSort;
- var headerRenderer = _column$props2.headerRenderer;
- var label = _column$props2.label;
- var columnData = _column$props2.columnData;
-
- var sortEnabled = !disableSort && sort;
-
- var classNames = (0, _classnames2.default)('FlexTable__headerColumn', headerClassName, column.props.headerClassName, {
- 'FlexTable__sortableHeaderColumn': sortEnabled
- });
- var style = this._getFlexStyleForColumn(column, headerStyle);
-
- var renderedHeader = headerRenderer({
- columnData: columnData,
- dataKey: dataKey,
- disableSort: disableSort,
- label: label,
- sortBy: sortBy,
- sortDirection: sortDirection
- });
-
- var a11yProps = {};
-
- if (sortEnabled || onHeaderClick) {
- (function () {
- // If this is a sortable header, clicking it should update the table data's sorting.
- var newSortDirection = sortBy !== dataKey || sortDirection === _SortDirection2.default.DESC ? _SortDirection2.default.ASC : _SortDirection2.default.DESC;
-
- var onClick = function onClick() {
- sortEnabled && sort({
- sortBy: dataKey,
- sortDirection: newSortDirection
- });
- onHeaderClick && onHeaderClick({ columnData: columnData, dataKey: dataKey });
- };
-
- var onKeyDown = function onKeyDown(event) {
- if (event.key === 'Enter' || event.key === ' ') {
- onClick();
- }
- };
-
- a11yProps['aria-label'] = column.props['aria-label'] || label || dataKey;
- a11yProps.role = 'rowheader';
- a11yProps.tabIndex = 0;
- a11yProps.onClick = onClick;
- a11yProps.onKeyDown = onKeyDown;
- })();
- }
-
- return _react2.default.createElement(
- 'div',
- _extends({}, a11yProps, {
- key: 'Header-Col' + index,
- className: classNames,
- style: style
- }),
- renderedHeader
- );
- }
- }, {
- key: '_createRow',
- value: function _createRow(_ref6) {
- var _this3 = this;
-
- var index = _ref6.rowIndex;
- var isScrolling = _ref6.isScrolling;
- var _props3 = this.props;
- var children = _props3.children;
- var onRowClick = _props3.onRowClick;
- var onRowDoubleClick = _props3.onRowDoubleClick;
- var onRowMouseOver = _props3.onRowMouseOver;
- var onRowMouseOut = _props3.onRowMouseOut;
- var rowClassName = _props3.rowClassName;
- var rowGetter = _props3.rowGetter;
- var rowRenderer = _props3.rowRenderer;
- var rowStyle = _props3.rowStyle;
- var scrollbarWidth = this.state.scrollbarWidth;
-
-
- var rowClass = rowClassName instanceof Function ? rowClassName({ index: index }) : rowClassName;
- var rowStyleObject = rowStyle instanceof Function ? rowStyle({ index: index }) : rowStyle;
- var rowData = rowGetter({ index: index });
-
- var columns = _react2.default.Children.toArray(children).map(function (column, columnIndex) {
- return _this3._createColumn({
- column: column,
- columnIndex: columnIndex,
- isScrolling: isScrolling,
- rowData: rowData,
- rowIndex: index,
- scrollbarWidth: scrollbarWidth
- });
- });
-
- var className = (0, _classnames2.default)('FlexTable__row', rowClass);
- var style = _extends({}, rowStyleObject, {
- height: this._getRowHeight(index),
- paddingRight: scrollbarWidth
- });
-
- return rowRenderer({
- className: className,
- columns: columns,
- index: index,
- isScrolling: isScrolling,
- onRowClick: onRowClick,
- onRowDoubleClick: onRowDoubleClick,
- onRowMouseOver: onRowMouseOver,
- onRowMouseOut: onRowMouseOut,
- rowData: rowData,
- style: style
- });
- }
-
- /**
- * Determines the flex-shrink, flex-grow, and width values for a cell (header or column).
- */
-
- }, {
- key: '_getFlexStyleForColumn',
- value: function _getFlexStyleForColumn(column) {
- var customStyle = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
- var flexValue = column.props.flexGrow + ' ' + column.props.flexShrink + ' ' + column.props.width + 'px';
-
- var style = _extends({}, customStyle, {
- flex: flexValue,
- msFlex: flexValue,
- WebkitFlex: flexValue
- });
-
- if (column.props.maxWidth) {
- style.maxWidth = column.props.maxWidth;
- }
-
- if (column.props.minWidth) {
- style.minWidth = column.props.minWidth;
- }
-
- return style;
- }
- }, {
- key: '_getRenderedHeaderRow',
- value: function _getRenderedHeaderRow() {
- var _this4 = this;
-
- var _props4 = this.props;
- var children = _props4.children;
- var disableHeader = _props4.disableHeader;
-
- var items = disableHeader ? [] : _react2.default.Children.toArray(children);
-
- return items.map(function (column, index) {
- return _this4._createHeader({ column: column, index: index });
- });
- }
- }, {
- key: '_getRowHeight',
- value: function _getRowHeight(rowIndex) {
- var rowHeight = this.props.rowHeight;
-
-
- return rowHeight instanceof Function ? rowHeight({ index: rowIndex }) : rowHeight;
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(_ref7) {
- var clientHeight = _ref7.clientHeight;
- var scrollHeight = _ref7.scrollHeight;
- var scrollTop = _ref7.scrollTop;
- var onScroll = this.props.onScroll;
-
-
- onScroll({ clientHeight: clientHeight, scrollHeight: scrollHeight, scrollTop: scrollTop });
- }
- }, {
- key: '_onSectionRendered',
- value: function _onSectionRendered(_ref8) {
- var rowOverscanStartIndex = _ref8.rowOverscanStartIndex;
- var rowOverscanStopIndex = _ref8.rowOverscanStopIndex;
- var rowStartIndex = _ref8.rowStartIndex;
- var rowStopIndex = _ref8.rowStopIndex;
- var onRowsRendered = this.props.onRowsRendered;
-
-
- onRowsRendered({
- overscanStartIndex: rowOverscanStartIndex,
- overscanStopIndex: rowOverscanStopIndex,
- startIndex: rowStartIndex,
- stopIndex: rowStopIndex
- });
- }
- }, {
- key: '_setScrollbarWidth',
- value: function _setScrollbarWidth() {
- var Grid = (0, _reactDom.findDOMNode)(this.Grid);
- var clientWidth = Grid.clientWidth || 0;
- var offsetWidth = Grid.offsetWidth || 0;
- var scrollbarWidth = offsetWidth - clientWidth;
-
- this.setState({ scrollbarWidth: scrollbarWidth });
- }
- }]);
-
- return FlexTable;
-}(_react.Component);
-
-FlexTable.propTypes = {
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Removes fixed height from the scrollingContainer so that the total height
- * of rows can stretch the window. Intended for use with WindowScroller
- */
- autoHeight: _react.PropTypes.bool,
-
- /** One or more FlexColumns describing the data displayed in this row */
- children: function children(props, propName, componentName) {
- var children = _react2.default.Children.toArray(props.children);
- for (var i = 0; i < children.length; i++) {
- if (children[i].type !== _FlexColumn2.default) {
- return new Error('FlexTable only accepts children of type FlexColumn');
- }
- }
- },
-
- /** Optional CSS class name */
- className: _react.PropTypes.string,
-
- /** Disable rendering the header at all */
- disableHeader: _react.PropTypes.bool,
-
- /**
- * Used to estimate the total height of a FlexTable before all of its rows have actually been measured.
- * The estimated total height is adjusted as rows are rendered.
- */
- estimatedRowSize: _react.PropTypes.number.isRequired,
-
- /** Optional custom CSS class name to attach to inner Grid element. */
- gridClassName: _react.PropTypes.string,
-
- /** Optional inline style to attach to inner Grid element. */
- gridStyle: _react.PropTypes.object,
-
- /** Optional CSS class to apply to all column headers */
- headerClassName: _react.PropTypes.string,
-
- /** Fixed height of header row */
- headerHeight: _react.PropTypes.number.isRequired,
-
- /** Fixed/available height for out DOM element */
- height: _react.PropTypes.number.isRequired,
-
- /** Optional renderer to be used in place of table body rows when rowCount is 0 */
- noRowsRenderer: _react.PropTypes.func,
-
- /**
- * Optional callback when a column's header is clicked.
- * ({ columnData: any, dataKey: string }): void
- */
- onHeaderClick: _react.PropTypes.func,
-
- /** Optional custom inline style to attach to table header columns. */
- headerStyle: _react.PropTypes.object,
-
- /**
- * Callback invoked when a user clicks on a table row.
- * ({ index: number }): void
- */
- onRowClick: _react.PropTypes.func,
-
- /**
- * Callback invoked when a user double-clicks on a table row.
- * ({ index: number }): void
- */
- onRowDoubleClick: _react.PropTypes.func,
-
- /**
- * Callback invoked when the mouse leaves a table row.
- * ({ index: number }): void
- */
- onRowMouseOut: _react.PropTypes.func,
-
- /**
- * Callback invoked when a user moves the mouse over a table row.
- * ({ index: number }): void
- */
- onRowMouseOver: _react.PropTypes.func,
-
- /**
- * Callback invoked with information about the slice of rows that were just rendered.
- * ({ startIndex, stopIndex }): void
- */
- onRowsRendered: _react.PropTypes.func,
-
- /**
- * Callback invoked whenever the scroll offset changes within the inner scrollable region.
- * This callback can be used to sync scrolling between lists, tables, or grids.
- * ({ clientHeight, scrollHeight, scrollTop }): void
- */
- onScroll: _react.PropTypes.func.isRequired,
-
- /**
- * Number of rows to render above/below the visible bounds of the list.
- * These rows can help for smoother scrolling on touch devices.
- */
- overscanRowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Optional CSS class to apply to all table rows (including the header row).
- * This property can be a CSS class name (string) or a function that returns a class name.
- * If a function is provided its signature should be: ({ index: number }): string
- */
- rowClassName: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]),
-
- /**
- * Callback responsible for returning a data row given an index.
- * ({ index: number }): any
- */
- rowGetter: _react.PropTypes.func.isRequired,
-
- /**
- * Either a fixed row height (number) or a function that returns the height of a row given its index.
- * ({ index: number }): number
- */
- rowHeight: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.func]).isRequired,
-
- /** Number of rows in table. */
- rowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Responsible for rendering a table row given an array of columns:
- * Should implement the following interface: ({
- * className: string,
- * columns: Array,
- * index: number,
- * isScrolling: boolean,
- * onRowClick: ?Function,
- * onRowDoubleClick: ?Function,
- * onRowMouseOver: ?Function,
- * onRowMouseOut: ?Function,
- * rowData: any,
- * style: any
- * }): PropTypes.node
- */
- rowRenderer: _react.PropTypes.func,
-
- /** Optional custom inline style to attach to table rows. */
- rowStyle: _react.PropTypes.oneOfType([_react.PropTypes.object, _react.PropTypes.func]).isRequired,
-
- /** Optional custom CSS class for individual rows */
- rowWrapperClassName: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]),
-
- /** Optional custom CSS class for individual rows */
- rowWrapperStyle: _react.PropTypes.oneOfType([_react.PropTypes.object, _react.PropTypes.func]),
-
- /** See Grid#scrollToAlignment */
- scrollToAlignment: _react.PropTypes.oneOf(['auto', 'end', 'start', 'center']).isRequired,
-
- /** Row index to ensure visible (by forcefully scrolling if necessary) */
- scrollToIndex: _react.PropTypes.number,
-
- /** Vertical offset. */
- scrollTop: _react.PropTypes.number,
-
- /**
- * Sort function to be called if a sortable header is clicked.
- * ({ sortBy: string, sortDirection: SortDirection }): void
- */
- sort: _react.PropTypes.func,
-
- /** FlexTable data is currently sorted by this :dataKey (if it is sorted at all) */
- sortBy: _react.PropTypes.string,
-
- /** FlexTable data is currently sorted in this direction (if it is sorted at all) */
- sortDirection: _react.PropTypes.oneOf([_SortDirection2.default.ASC, _SortDirection2.default.DESC]),
-
- /** Optional inline style */
- style: _react.PropTypes.object,
-
- /** Tab index for focus */
- tabIndex: _react.PropTypes.number,
-
- /** Width of list */
- width: _react.PropTypes.number.isRequired
-};
-FlexTable.defaultProps = {
- disableHeader: false,
- estimatedRowSize: 30,
- headerHeight: 0,
- headerStyle: {},
- noRowsRenderer: function noRowsRenderer() {
- return null;
- },
- onRowsRendered: function onRowsRendered() {
- return null;
- },
- onScroll: function onScroll() {
- return null;
- },
- overscanRowCount: 10,
- rowRenderer: _defaultRowRenderer2.default,
- rowStyle: {},
- scrollToAlignment: 'auto',
- style: {}
-};
-exports.default = FlexTable;
-},{"../Grid":62,"./FlexColumn":51,"./SortDirection":53,"./defaultRowRenderer":58,"classnames":undefined,"react":undefined,"react-addons-shallow-compare":30,"react-dom":undefined}],53:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-var SortDirection = {
- /**
- * Sort items in ascending order.
- * This means arranging from the lowest value to the highest (e.g. a-z, 0-9).
- */
- ASC: 'ASC',
-
- /**
- * Sort items in descending order.
- * This means arranging from the highest value to the lowest (e.g. z-a, 9-0).
- */
- DESC: 'DESC'
-};
-
-exports.default = SortDirection;
-},{}],54:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = SortIndicator;
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _SortDirection = require('./SortDirection');
-
-var _SortDirection2 = _interopRequireDefault(_SortDirection);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/**
- * Displayed beside a header to indicate that a FlexTable is currently sorted by this column.
- */
-function SortIndicator(_ref) {
- var sortDirection = _ref.sortDirection;
-
- var classNames = (0, _classnames2.default)('FlexTable__sortableHeaderIcon', {
- 'FlexTable__sortableHeaderIcon--ASC': sortDirection === _SortDirection2.default.ASC,
- 'FlexTable__sortableHeaderIcon--DESC': sortDirection === _SortDirection2.default.DESC
- });
-
- return _react2.default.createElement(
- 'svg',
- {
- className: classNames,
- width: 18,
- height: 18,
- viewBox: '0 0 24 24'
- },
- sortDirection === _SortDirection2.default.ASC ? _react2.default.createElement('path', { d: 'M7 14l5-5 5 5z' }) : _react2.default.createElement('path', { d: 'M7 10l5 5 5-5z' }),
- _react2.default.createElement('path', { d: 'M0 0h24v24H0z', fill: 'none' })
- );
-}
-SortIndicator.propTypes = {
- sortDirection: _react.PropTypes.oneOf([_SortDirection2.default.ASC, _SortDirection2.default.DESC])
-};
-},{"./SortDirection":53,"classnames":undefined,"react":undefined}],55:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = defaultCellDataGetter;
-
-
-/**
- * Default accessor for returning a cell value for a given attribute.
- * This function expects to operate on either a vanilla Object or an Immutable Map.
- * You should override the column's cellDataGetter if your data is some other type of object.
- */
-function defaultCellDataGetter(_ref) {
- var columnData = _ref.columnData;
- var dataKey = _ref.dataKey;
- var rowData = _ref.rowData;
-
- if (rowData.get instanceof Function) {
- return rowData.get(dataKey);
- } else {
- return rowData[dataKey];
- }
-}
-},{}],56:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = defaultCellRenderer;
-
-
-/**
- * Default cell renderer that displays an attribute as a simple string
- * You should override the column's cellRenderer if your data is some other type of object.
- */
-function defaultCellRenderer(_ref) {
- var cellData = _ref.cellData;
- var cellDataKey = _ref.cellDataKey;
- var columnData = _ref.columnData;
- var rowData = _ref.rowData;
- var rowIndex = _ref.rowIndex;
-
- if (cellData == null) {
- return '';
- } else {
- return String(cellData);
- }
-}
-},{}],57:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = defaultHeaderRenderer;
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _SortIndicator = require('./SortIndicator');
-
-var _SortIndicator2 = _interopRequireDefault(_SortIndicator);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/**
- * Default table header renderer.
- */
-function defaultHeaderRenderer(_ref) {
- var columnData = _ref.columnData;
- var dataKey = _ref.dataKey;
- var disableSort = _ref.disableSort;
- var label = _ref.label;
- var sortBy = _ref.sortBy;
- var sortDirection = _ref.sortDirection;
-
- var showSortIndicator = sortBy === dataKey;
- var children = [_react2.default.createElement(
- 'span',
- {
- className: 'FlexTable__headerTruncatedText',
- key: 'label',
- title: label
- },
- label
- )];
-
- if (showSortIndicator) {
- children.push(_react2.default.createElement(_SortIndicator2.default, {
- key: 'SortIndicator',
- sortDirection: sortDirection
- }));
- }
-
- return children;
-}
-},{"./SortIndicator":54,"react":undefined}],58:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-exports.default = defaultRowRenderer;
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/**
- * Default row renderer for FlexTable.
- */
-function defaultRowRenderer(_ref) {
- var className = _ref.className;
- var columns = _ref.columns;
- var index = _ref.index;
- var isScrolling = _ref.isScrolling;
- var onRowClick = _ref.onRowClick;
- var onRowDoubleClick = _ref.onRowDoubleClick;
- var onRowMouseOver = _ref.onRowMouseOver;
- var onRowMouseOut = _ref.onRowMouseOut;
- var rowData = _ref.rowData;
- var style = _ref.style;
-
- var a11yProps = {};
-
- if (onRowClick || onRowDoubleClick || onRowMouseOver || onRowMouseOut) {
- a11yProps['aria-label'] = 'row';
- a11yProps.role = 'row';
- a11yProps.tabIndex = 0;
-
- if (onRowClick) {
- a11yProps.onClick = function () {
- return onRowClick({ index: index });
- };
- }
- if (onRowDoubleClick) {
- a11yProps.onDoubleClick = function () {
- return onRowDoubleClick({ index: index });
- };
- }
- if (onRowMouseOut) {
- a11yProps.onMouseOut = function () {
- return onRowMouseOut({ index: index });
- };
- }
- if (onRowMouseOver) {
- a11yProps.onMouseOver = function () {
- return onRowMouseOver({ index: index });
- };
- }
- }
-
- return _react2.default.createElement(
- 'div',
- _extends({}, a11yProps, {
- className: className,
- style: style
- }),
- columns
- );
-}
-},{"react":undefined}],59:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.SortIndicator = exports.SortDirection = exports.FlexColumn = exports.FlexTable = exports.defaultRowRenderer = exports.defaultHeaderRenderer = exports.defaultCellRenderer = exports.defaultCellDataGetter = exports.default = undefined;
-
-var _FlexTable2 = require('./FlexTable');
-
-var _FlexTable3 = _interopRequireDefault(_FlexTable2);
-
-var _defaultCellDataGetter2 = require('./defaultCellDataGetter');
-
-var _defaultCellDataGetter3 = _interopRequireDefault(_defaultCellDataGetter2);
-
-var _defaultCellRenderer2 = require('./defaultCellRenderer');
-
-var _defaultCellRenderer3 = _interopRequireDefault(_defaultCellRenderer2);
-
-var _defaultHeaderRenderer2 = require('./defaultHeaderRenderer');
-
-var _defaultHeaderRenderer3 = _interopRequireDefault(_defaultHeaderRenderer2);
-
-var _defaultRowRenderer2 = require('./defaultRowRenderer');
-
-var _defaultRowRenderer3 = _interopRequireDefault(_defaultRowRenderer2);
-
-var _FlexColumn2 = require('./FlexColumn');
-
-var _FlexColumn3 = _interopRequireDefault(_FlexColumn2);
-
-var _SortDirection2 = require('./SortDirection');
-
-var _SortDirection3 = _interopRequireDefault(_SortDirection2);
-
-var _SortIndicator2 = require('./SortIndicator');
-
-var _SortIndicator3 = _interopRequireDefault(_SortIndicator2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _FlexTable3.default;
-exports.defaultCellDataGetter = _defaultCellDataGetter3.default;
-exports.defaultCellRenderer = _defaultCellRenderer3.default;
-exports.defaultHeaderRenderer = _defaultHeaderRenderer3.default;
-exports.defaultRowRenderer = _defaultRowRenderer3.default;
-exports.FlexTable = _FlexTable3.default;
-exports.FlexColumn = _FlexColumn3.default;
-exports.SortDirection = _SortDirection3.default;
-exports.SortIndicator = _SortIndicator3.default;
-},{"./FlexColumn":51,"./FlexTable":52,"./SortDirection":53,"./SortIndicator":54,"./defaultCellDataGetter":55,"./defaultCellRenderer":56,"./defaultHeaderRenderer":57,"./defaultRowRenderer":58}],60:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.DEFAULT_SCROLLING_RESET_TIME_INTERVAL = undefined;
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _calculateSizeAndPositionDataAndUpdateScrollOffset = require('./utils/calculateSizeAndPositionDataAndUpdateScrollOffset');
-
-var _calculateSizeAndPositionDataAndUpdateScrollOffset2 = _interopRequireDefault(_calculateSizeAndPositionDataAndUpdateScrollOffset);
-
-var _ScalingCellSizeAndPositionManager = require('./utils/ScalingCellSizeAndPositionManager');
-
-var _ScalingCellSizeAndPositionManager2 = _interopRequireDefault(_ScalingCellSizeAndPositionManager);
-
-var _createCallbackMemoizer = require('../utils/createCallbackMemoizer');
-
-var _createCallbackMemoizer2 = _interopRequireDefault(_createCallbackMemoizer);
-
-var _getOverscanIndices = require('./utils/getOverscanIndices');
-
-var _getOverscanIndices2 = _interopRequireDefault(_getOverscanIndices);
-
-var _scrollbarSize = require('dom-helpers/util/scrollbarSize');
-
-var _scrollbarSize2 = _interopRequireDefault(_scrollbarSize);
-
-var _raf = require('raf');
-
-var _raf2 = _interopRequireDefault(_raf);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _updateScrollIndexHelper = require('./utils/updateScrollIndexHelper');
-
-var _updateScrollIndexHelper2 = _interopRequireDefault(_updateScrollIndexHelper);
-
-var _defaultCellRangeRenderer = require('./defaultCellRangeRenderer');
-
-var _defaultCellRangeRenderer2 = _interopRequireDefault(_defaultCellRangeRenderer);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress.
- * This improves performance and makes scrolling smoother.
- */
-var DEFAULT_SCROLLING_RESET_TIME_INTERVAL = exports.DEFAULT_SCROLLING_RESET_TIME_INTERVAL = 150;
-
-/**
- * Controls whether the Grid updates the DOM element's scrollLeft/scrollTop based on the current state or just observes it.
- * This prevents Grid from interrupting mouse-wheel animations (see issue #2).
- */
-var SCROLL_POSITION_CHANGE_REASONS = {
- OBSERVED: 'observed',
- REQUESTED: 'requested'
-};
-
-/**
- * Renders tabular data with virtualization along the vertical and horizontal axes.
- * Row heights and column widths must be known ahead of time and specified as properties.
- */
-
-var Grid = function (_Component) {
- _inherits(Grid, _Component);
-
- function Grid(props, context) {
- _classCallCheck(this, Grid);
-
- var _this = _possibleConstructorReturn(this, (Grid.__proto__ || Object.getPrototypeOf(Grid)).call(this, props, context));
-
- _this.state = {
- isScrolling: false,
- scrollDirectionHorizontal: _getOverscanIndices.SCROLL_DIRECTION_FIXED,
- scrollDirectionVertical: _getOverscanIndices.SCROLL_DIRECTION_FIXED,
- scrollLeft: 0,
- scrollTop: 0
- };
-
- // Invokes onSectionRendered callback only when start/stop row or column indices change
- _this._onGridRenderedMemoizer = (0, _createCallbackMemoizer2.default)();
- _this._onScrollMemoizer = (0, _createCallbackMemoizer2.default)(false);
-
- // Bind functions to instance so they don't lose context when passed around
- _this._enablePointerEventsAfterDelayCallback = _this._enablePointerEventsAfterDelayCallback.bind(_this);
- _this._invokeOnGridRenderedHelper = _this._invokeOnGridRenderedHelper.bind(_this);
- _this._onScroll = _this._onScroll.bind(_this);
- _this._setNextStateCallback = _this._setNextStateCallback.bind(_this);
- _this._updateScrollLeftForScrollToColumn = _this._updateScrollLeftForScrollToColumn.bind(_this);
- _this._updateScrollTopForScrollToRow = _this._updateScrollTopForScrollToRow.bind(_this);
-
- _this._columnWidthGetter = _this._wrapSizeGetter(props.columnWidth);
- _this._rowHeightGetter = _this._wrapSizeGetter(props.rowHeight);
-
- _this._columnSizeAndPositionManager = new _ScalingCellSizeAndPositionManager2.default({
- cellCount: props.columnCount,
- cellSizeGetter: function cellSizeGetter(index) {
- return _this._columnWidthGetter(index);
- },
- estimatedCellSize: _this._getEstimatedColumnSize(props)
- });
- _this._rowSizeAndPositionManager = new _ScalingCellSizeAndPositionManager2.default({
- cellCount: props.rowCount,
- cellSizeGetter: function cellSizeGetter(index) {
- return _this._rowHeightGetter(index);
- },
- estimatedCellSize: _this._getEstimatedRowSize(props)
- });
-
- // See defaultCellRangeRenderer() for more information on the usage of this cache
- _this._cellCache = {};
- return _this;
- }
-
- /**
- * Pre-measure all columns and rows in a Grid.
- * Typically cells are only measured as needed and estimated sizes are used for cells that have not yet been measured.
- * This method ensures that the next call to getTotalSize() returns an exact size (as opposed to just an estimated one).
- */
-
-
- _createClass(Grid, [{
- key: 'measureAllCells',
- value: function measureAllCells() {
- var _props = this.props;
- var columnCount = _props.columnCount;
- var rowCount = _props.rowCount;
-
-
- this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnCount - 1);
- this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowCount - 1);
- }
-
- /**
- * Forced recompute of row heights and column widths.
- * This function should be called if dynamic column or row sizes have changed but nothing else has.
- * Since Grid only receives :columnCount and :rowCount it has no way of detecting when the underlying data changes.
- */
-
- }, {
- key: 'recomputeGridSize',
- value: function recomputeGridSize() {
- var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
-
- var _ref$columnIndex = _ref.columnIndex;
- var columnIndex = _ref$columnIndex === undefined ? 0 : _ref$columnIndex;
- var _ref$rowIndex = _ref.rowIndex;
- var rowIndex = _ref$rowIndex === undefined ? 0 : _ref$rowIndex;
-
- this._columnSizeAndPositionManager.resetCell(columnIndex);
- this._rowSizeAndPositionManager.resetCell(rowIndex);
-
- // Clear cell cache in case we are scrolling;
- // Invalid row heights likely mean invalid cached content as well.
- this._cellCache = {};
-
- this.forceUpdate();
- }
- }, {
- key: 'componentDidMount',
- value: function componentDidMount() {
- var _props2 = this.props;
- var scrollLeft = _props2.scrollLeft;
- var scrollToColumn = _props2.scrollToColumn;
- var scrollTop = _props2.scrollTop;
- var scrollToRow = _props2.scrollToRow;
-
- // If this component was first rendered server-side, scrollbar size will be undefined.
- // In that event we need to remeasure.
-
- if (!this._scrollbarSizeMeasured) {
- this._scrollbarSize = (0, _scrollbarSize2.default)();
- this._scrollbarSizeMeasured = true;
- this.setState({});
- }
-
- if (scrollLeft >= 0 || scrollTop >= 0) {
- this._setScrollPosition({ scrollLeft: scrollLeft, scrollTop: scrollTop });
- }
-
- if (scrollToColumn >= 0 || scrollToRow >= 0) {
- this._updateScrollLeftForScrollToColumn();
- this._updateScrollTopForScrollToRow();
- }
-
- // Update onRowsRendered callback
- this._invokeOnGridRenderedHelper();
-
- // Initialize onScroll callback
- this._invokeOnScrollMemoizer({
- scrollLeft: scrollLeft || 0,
- scrollTop: scrollTop || 0,
- totalColumnsWidth: this._columnSizeAndPositionManager.getTotalSize(),
- totalRowsHeight: this._rowSizeAndPositionManager.getTotalSize()
- });
- }
-
- /**
- * @private
- * This method updates scrollLeft/scrollTop in state for the following conditions:
- * 1) New scroll-to-cell props have been set
- */
-
- }, {
- key: 'componentDidUpdate',
- value: function componentDidUpdate(prevProps, prevState) {
- var _this2 = this;
-
- var _props3 = this.props;
- var autoHeight = _props3.autoHeight;
- var columnCount = _props3.columnCount;
- var height = _props3.height;
- var rowCount = _props3.rowCount;
- var scrollToAlignment = _props3.scrollToAlignment;
- var scrollToColumn = _props3.scrollToColumn;
- var scrollToRow = _props3.scrollToRow;
- var width = _props3.width;
- var _state = this.state;
- var scrollLeft = _state.scrollLeft;
- var scrollPositionChangeReason = _state.scrollPositionChangeReason;
- var scrollTop = _state.scrollTop;
-
- // Handle edge case where column or row count has only just increased over 0.
- // In this case we may have to restore a previously-specified scroll offset.
- // For more info see bvaughn/react-virtualized/issues/218
-
- var columnOrRowCountJustIncreasedFromZero = columnCount > 0 && prevProps.columnCount === 0 || rowCount > 0 && prevProps.rowCount === 0;
-
- // Make sure requested changes to :scrollLeft or :scrollTop get applied.
- // Assigning to scrollLeft/scrollTop tells the browser to interrupt any running scroll animations,
- // And to discard any pending async changes to the scroll position that may have happened in the meantime (e.g. on a separate scrolling thread).
- // So we only set these when we require an adjustment of the scroll position.
- // See issue #2 for more information.
- if (scrollPositionChangeReason === SCROLL_POSITION_CHANGE_REASONS.REQUESTED) {
- if (scrollLeft >= 0 && (scrollLeft !== prevState.scrollLeft && scrollLeft !== this._scrollingContainer.scrollLeft || columnOrRowCountJustIncreasedFromZero)) {
- this._scrollingContainer.scrollLeft = scrollLeft;
- }
-
- // @TRICKY :autoHeight property instructs Grid to leave :scrollTop management to an external HOC (eg WindowScroller).
- // In this case we should avoid checking scrollingContainer.scrollTop since it forces layout/flow.
- if (!autoHeight && scrollTop >= 0 && (scrollTop !== prevState.scrollTop && scrollTop !== this._scrollingContainer.scrollTop || columnOrRowCountJustIncreasedFromZero)) {
- this._scrollingContainer.scrollTop = scrollTop;
- }
- }
-
- // Update scroll offsets if the current :scrollToColumn or :scrollToRow values requires it
- // @TODO Do we also need this check or can the one in componentWillUpdate() suffice?
- (0, _updateScrollIndexHelper2.default)({
- cellSizeAndPositionManager: this._columnSizeAndPositionManager,
- previousCellsCount: prevProps.columnCount,
- previousCellSize: prevProps.columnWidth,
- previousScrollToAlignment: prevProps.scrollToAlignment,
- previousScrollToIndex: prevProps.scrollToColumn,
- previousSize: prevProps.width,
- scrollOffset: scrollLeft,
- scrollToAlignment: scrollToAlignment,
- scrollToIndex: scrollToColumn,
- size: width,
- updateScrollIndexCallback: function updateScrollIndexCallback(scrollToColumn) {
- return _this2._updateScrollLeftForScrollToColumn(_extends({}, _this2.props, { scrollToColumn: scrollToColumn }));
- }
- });
- (0, _updateScrollIndexHelper2.default)({
- cellSizeAndPositionManager: this._rowSizeAndPositionManager,
- previousCellsCount: prevProps.rowCount,
- previousCellSize: prevProps.rowHeight,
- previousScrollToAlignment: prevProps.scrollToAlignment,
- previousScrollToIndex: prevProps.scrollToRow,
- previousSize: prevProps.height,
- scrollOffset: scrollTop,
- scrollToAlignment: scrollToAlignment,
- scrollToIndex: scrollToRow,
- size: height,
- updateScrollIndexCallback: function updateScrollIndexCallback(scrollToRow) {
- return _this2._updateScrollTopForScrollToRow(_extends({}, _this2.props, { scrollToRow: scrollToRow }));
- }
- });
-
- // Update onRowsRendered callback if start/stop indices have changed
- this._invokeOnGridRenderedHelper();
- }
- }, {
- key: 'componentWillMount',
- value: function componentWillMount() {
- // If this component is being rendered server-side, getScrollbarSize() will return undefined.
- // We handle this case in componentDidMount()
- this._scrollbarSize = (0, _scrollbarSize2.default)();
- if (this._scrollbarSize === undefined) {
- this._scrollbarSizeMeasured = false;
- this._scrollbarSize = 0;
- } else {
- this._scrollbarSizeMeasured = true;
- }
-
- this._calculateChildrenToRender();
- }
- }, {
- key: 'componentWillUnmount',
- value: function componentWillUnmount() {
- if (this._disablePointerEventsTimeoutId) {
- clearTimeout(this._disablePointerEventsTimeoutId);
- }
-
- if (this._setNextStateAnimationFrameId) {
- _raf2.default.cancel(this._setNextStateAnimationFrameId);
- }
- }
-
- /**
- * @private
- * This method updates scrollLeft/scrollTop in state for the following conditions:
- * 1) Empty content (0 rows or columns)
- * 2) New scroll props overriding the current state
- * 3) Cells-count or cells-size has changed, making previous scroll offsets invalid
- */
-
- }, {
- key: 'componentWillUpdate',
- value: function componentWillUpdate(nextProps, nextState) {
- var _this3 = this;
-
- if (nextProps.columnCount === 0 && nextState.scrollLeft !== 0 || nextProps.rowCount === 0 && nextState.scrollTop !== 0) {
- this._setScrollPosition({
- scrollLeft: 0,
- scrollTop: 0
- });
- } else if (nextProps.scrollLeft !== this.props.scrollLeft || nextProps.scrollTop !== this.props.scrollTop) {
- this._setScrollPosition({
- scrollLeft: nextProps.scrollLeft,
- scrollTop: nextProps.scrollTop
- });
- }
-
- this._columnWidthGetter = this._wrapSizeGetter(nextProps.columnWidth);
- this._rowHeightGetter = this._wrapSizeGetter(nextProps.rowHeight);
-
- this._columnSizeAndPositionManager.configure({
- cellCount: nextProps.columnCount,
- estimatedCellSize: this._getEstimatedColumnSize(nextProps)
- });
- this._rowSizeAndPositionManager.configure({
- cellCount: nextProps.rowCount,
- estimatedCellSize: this._getEstimatedRowSize(nextProps)
- });
-
- // Update scroll offsets if the size or number of cells have changed, invalidating the previous value
- (0, _calculateSizeAndPositionDataAndUpdateScrollOffset2.default)({
- cellCount: this.props.columnCount,
- cellSize: this.props.columnWidth,
- computeMetadataCallback: function computeMetadataCallback() {
- return _this3._columnSizeAndPositionManager.resetCell(0);
- },
- computeMetadataCallbackProps: nextProps,
- nextCellsCount: nextProps.columnCount,
- nextCellSize: nextProps.columnWidth,
- nextScrollToIndex: nextProps.scrollToColumn,
- scrollToIndex: this.props.scrollToColumn,
- updateScrollOffsetForScrollToIndex: function updateScrollOffsetForScrollToIndex() {
- return _this3._updateScrollLeftForScrollToColumn(nextProps, nextState);
- }
- });
- (0, _calculateSizeAndPositionDataAndUpdateScrollOffset2.default)({
- cellCount: this.props.rowCount,
- cellSize: this.props.rowHeight,
- computeMetadataCallback: function computeMetadataCallback() {
- return _this3._rowSizeAndPositionManager.resetCell(0);
- },
- computeMetadataCallbackProps: nextProps,
- nextCellsCount: nextProps.rowCount,
- nextCellSize: nextProps.rowHeight,
- nextScrollToIndex: nextProps.scrollToRow,
- scrollToIndex: this.props.scrollToRow,
- updateScrollOffsetForScrollToIndex: function updateScrollOffsetForScrollToIndex() {
- return _this3._updateScrollTopForScrollToRow(nextProps, nextState);
- }
- });
-
- this._calculateChildrenToRender(nextProps, nextState);
- }
- }, {
- key: 'render',
- value: function render() {
- var _this4 = this;
-
- var _props4 = this.props;
- var autoContainerWidth = _props4.autoContainerWidth;
- var autoHeight = _props4.autoHeight;
- var className = _props4.className;
- var height = _props4.height;
- var noContentRenderer = _props4.noContentRenderer;
- var style = _props4.style;
- var tabIndex = _props4.tabIndex;
- var width = _props4.width;
- var isScrolling = this.state.isScrolling;
-
-
- var gridStyle = {
- height: autoHeight ? 'auto' : height,
- width: width
- };
-
- var totalColumnsWidth = this._columnSizeAndPositionManager.getTotalSize();
- var totalRowsHeight = this._rowSizeAndPositionManager.getTotalSize();
-
- // Force browser to hide scrollbars when we know they aren't necessary.
- // Otherwise once scrollbars appear they may not disappear again.
- // For more info see issue #116
- var verticalScrollBarSize = totalRowsHeight > height ? this._scrollbarSize : 0;
- var horizontalScrollBarSize = totalColumnsWidth > width ? this._scrollbarSize : 0;
-
- // Also explicitly init styles to 'auto' if scrollbars are required.
- // This works around an obscure edge case where external CSS styles have not yet been loaded,
- // But an initial scroll index of offset is set as an external prop.
- // Without this style, Grid would render the correct range of cells but would NOT update its internal offset.
- // This was originally reported via clauderic/react-infinite-calendar/issues/23
- gridStyle.overflowX = totalColumnsWidth + verticalScrollBarSize <= width ? 'hidden' : 'auto';
- gridStyle.overflowY = totalRowsHeight + horizontalScrollBarSize <= height ? 'hidden' : 'auto';
-
- var childrenToDisplay = this._childrenToDisplay;
-
- var showNoContentRenderer = childrenToDisplay.length === 0 && height > 0 && width > 0;
-
- return _react2.default.createElement(
- 'div',
- {
- ref: function ref(_ref2) {
- _this4._scrollingContainer = _ref2;
- },
- 'aria-label': this.props['aria-label'],
- className: (0, _classnames2.default)('Grid', className),
- onScroll: this._onScroll,
- role: 'grid',
- style: _extends({}, gridStyle, style),
- tabIndex: tabIndex
- },
- childrenToDisplay.length > 0 && _react2.default.createElement(
- 'div',
- {
- className: 'Grid__innerScrollContainer',
- style: {
- width: autoContainerWidth ? 'auto' : totalColumnsWidth,
- height: totalRowsHeight,
- maxWidth: totalColumnsWidth,
- maxHeight: totalRowsHeight,
- pointerEvents: isScrolling ? 'none' : ''
- }
- },
- childrenToDisplay
- ),
- showNoContentRenderer && noContentRenderer()
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
-
- /* ---------------------------- Helper methods ---------------------------- */
-
- }, {
- key: '_calculateChildrenToRender',
- value: function _calculateChildrenToRender() {
- var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
- var state = arguments.length <= 1 || arguments[1] === undefined ? this.state : arguments[1];
- var cellClassName = props.cellClassName;
- var cellRenderer = props.cellRenderer;
- var cellRangeRenderer = props.cellRangeRenderer;
- var cellStyle = props.cellStyle;
- var columnCount = props.columnCount;
- var height = props.height;
- var overscanColumnCount = props.overscanColumnCount;
- var overscanRowCount = props.overscanRowCount;
- var rowCount = props.rowCount;
- var width = props.width;
- var isScrolling = state.isScrolling;
- var scrollDirectionHorizontal = state.scrollDirectionHorizontal;
- var scrollDirectionVertical = state.scrollDirectionVertical;
- var scrollLeft = state.scrollLeft;
- var scrollTop = state.scrollTop;
-
-
- this._childrenToDisplay = [];
-
- // Render only enough columns and rows to cover the visible area of the grid.
- if (height > 0 && width > 0) {
- var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange({
- containerSize: width,
- offset: scrollLeft
- });
- var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange({
- containerSize: height,
- offset: scrollTop
- });
-
- var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment({
- containerSize: width,
- offset: scrollLeft
- });
- var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment({
- containerSize: height,
- offset: scrollTop
- });
-
- // Store for _invokeOnGridRenderedHelper()
- this._renderedColumnStartIndex = visibleColumnIndices.start;
- this._renderedColumnStopIndex = visibleColumnIndices.stop;
- this._renderedRowStartIndex = visibleRowIndices.start;
- this._renderedRowStopIndex = visibleRowIndices.stop;
-
- var overscanColumnIndices = (0, _getOverscanIndices2.default)({
- cellCount: columnCount,
- overscanCellsCount: overscanColumnCount,
- scrollDirection: scrollDirectionHorizontal,
- startIndex: this._renderedColumnStartIndex,
- stopIndex: this._renderedColumnStopIndex
- });
-
- var overscanRowIndices = (0, _getOverscanIndices2.default)({
- cellCount: rowCount,
- overscanCellsCount: overscanRowCount,
- scrollDirection: scrollDirectionVertical,
- startIndex: this._renderedRowStartIndex,
- stopIndex: this._renderedRowStopIndex
- });
-
- // Store for _invokeOnGridRenderedHelper()
- this._columnStartIndex = overscanColumnIndices.overscanStartIndex;
- this._columnStopIndex = overscanColumnIndices.overscanStopIndex;
- this._rowStartIndex = overscanRowIndices.overscanStartIndex;
- this._rowStopIndex = overscanRowIndices.overscanStopIndex;
-
- this._childrenToDisplay = cellRangeRenderer({
- cellCache: this._cellCache,
- cellClassName: this._wrapCellClassNameGetter(cellClassName),
- cellRenderer: cellRenderer,
- cellStyle: this._wrapCellStyleGetter(cellStyle),
- columnSizeAndPositionManager: this._columnSizeAndPositionManager,
- columnStartIndex: this._columnStartIndex,
- columnStopIndex: this._columnStopIndex,
- horizontalOffsetAdjustment: horizontalOffsetAdjustment,
- isScrolling: isScrolling,
- rowSizeAndPositionManager: this._rowSizeAndPositionManager,
- rowStartIndex: this._rowStartIndex,
- rowStopIndex: this._rowStopIndex,
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- verticalOffsetAdjustment: verticalOffsetAdjustment
- });
- }
- }
-
- /**
- * Sets an :isScrolling flag for a small window of time.
- * This flag is used to disable pointer events on the scrollable portion of the Grid.
- * This prevents jerky/stuttery mouse-wheel scrolling.
- */
-
- }, {
- key: '_enablePointerEventsAfterDelay',
- value: function _enablePointerEventsAfterDelay() {
- var scrollingResetTimeInterval = this.props.scrollingResetTimeInterval;
-
-
- if (this._disablePointerEventsTimeoutId) {
- clearTimeout(this._disablePointerEventsTimeoutId);
- }
-
- this._disablePointerEventsTimeoutId = setTimeout(this._enablePointerEventsAfterDelayCallback, scrollingResetTimeInterval);
- }
- }, {
- key: '_enablePointerEventsAfterDelayCallback',
- value: function _enablePointerEventsAfterDelayCallback() {
- this._disablePointerEventsTimeoutId = null;
-
- // Throw away cell cache once scrolling is complete
- this._cellCache = {};
-
- this.setState({
- isScrolling: false,
- scrollDirectionHorizontal: _getOverscanIndices.SCROLL_DIRECTION_FIXED,
- scrollDirectionVertical: _getOverscanIndices.SCROLL_DIRECTION_FIXED
- });
- }
- }, {
- key: '_getEstimatedColumnSize',
- value: function _getEstimatedColumnSize(props) {
- return typeof props.columnWidth === 'number' ? props.columnWidth : props.estimatedColumnSize;
- }
- }, {
- key: '_getEstimatedRowSize',
- value: function _getEstimatedRowSize(props) {
- return typeof props.rowHeight === 'number' ? props.rowHeight : props.estimatedRowSize;
- }
- }, {
- key: '_invokeOnGridRenderedHelper',
- value: function _invokeOnGridRenderedHelper() {
- var onSectionRendered = this.props.onSectionRendered;
-
-
- this._onGridRenderedMemoizer({
- callback: onSectionRendered,
- indices: {
- columnOverscanStartIndex: this._columnStartIndex,
- columnOverscanStopIndex: this._columnStopIndex,
- columnStartIndex: this._renderedColumnStartIndex,
- columnStopIndex: this._renderedColumnStopIndex,
- rowOverscanStartIndex: this._rowStartIndex,
- rowOverscanStopIndex: this._rowStopIndex,
- rowStartIndex: this._renderedRowStartIndex,
- rowStopIndex: this._renderedRowStopIndex
- }
- });
- }
- }, {
- key: '_invokeOnScrollMemoizer',
- value: function _invokeOnScrollMemoizer(_ref3) {
- var _this5 = this;
-
- var scrollLeft = _ref3.scrollLeft;
- var scrollTop = _ref3.scrollTop;
- var totalColumnsWidth = _ref3.totalColumnsWidth;
- var totalRowsHeight = _ref3.totalRowsHeight;
-
- this._onScrollMemoizer({
- callback: function callback(_ref4) {
- var scrollLeft = _ref4.scrollLeft;
- var scrollTop = _ref4.scrollTop;
- var _props5 = _this5.props;
- var height = _props5.height;
- var onScroll = _props5.onScroll;
- var width = _props5.width;
-
-
- onScroll({
- clientHeight: height,
- clientWidth: width,
- scrollHeight: totalRowsHeight,
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- scrollWidth: totalColumnsWidth
- });
- },
- indices: {
- scrollLeft: scrollLeft,
- scrollTop: scrollTop
- }
- });
- }
-
- /**
- * Updates the state during the next animation frame.
- * Use this method to avoid multiple renders in a small span of time.
- * This helps performance for bursty events (like onScroll).
- */
-
- }, {
- key: '_setNextState',
- value: function _setNextState(state) {
- this._nextState = state;
-
- if (!this._setNextStateAnimationFrameId) {
- this._setNextStateAnimationFrameId = (0, _raf2.default)(this._setNextStateCallback);
- }
- }
- }, {
- key: '_setNextStateCallback',
- value: function _setNextStateCallback() {
- var state = this._nextState;
-
- this._setNextStateAnimationFrameId = null;
- this._nextState = null;
-
- this.setState(state);
- }
- }, {
- key: '_setScrollPosition',
- value: function _setScrollPosition(_ref5) {
- var scrollLeft = _ref5.scrollLeft;
- var scrollTop = _ref5.scrollTop;
-
- var newState = {
- scrollPositionChangeReason: SCROLL_POSITION_CHANGE_REASONS.REQUESTED
- };
-
- if (scrollLeft >= 0) {
- newState.scrollLeft = scrollLeft;
- }
-
- if (scrollTop >= 0) {
- newState.scrollTop = scrollTop;
- }
-
- if (scrollLeft >= 0 && scrollLeft !== this.state.scrollLeft || scrollTop >= 0 && scrollTop !== this.state.scrollTop) {
- this.setState(newState);
- }
- }
- }, {
- key: '_wrapCellClassNameGetter',
- value: function _wrapCellClassNameGetter(className) {
- return this._wrapPropertyGetter(className);
- }
- }, {
- key: '_wrapCellStyleGetter',
- value: function _wrapCellStyleGetter(style) {
- return this._wrapPropertyGetter(style);
- }
- }, {
- key: '_wrapPropertyGetter',
- value: function _wrapPropertyGetter(value) {
- return value instanceof Function ? value : function () {
- return value;
- };
- }
- }, {
- key: '_wrapSizeGetter',
- value: function _wrapSizeGetter(size) {
- return this._wrapPropertyGetter(size);
- }
- }, {
- key: '_updateScrollLeftForScrollToColumn',
- value: function _updateScrollLeftForScrollToColumn() {
- var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
- var state = arguments.length <= 1 || arguments[1] === undefined ? this.state : arguments[1];
- var columnCount = props.columnCount;
- var scrollToAlignment = props.scrollToAlignment;
- var scrollToColumn = props.scrollToColumn;
- var width = props.width;
- var scrollLeft = state.scrollLeft;
-
-
- if (scrollToColumn >= 0 && columnCount > 0) {
- var targetIndex = Math.max(0, Math.min(columnCount - 1, scrollToColumn));
-
- var calculatedScrollLeft = this._columnSizeAndPositionManager.getUpdatedOffsetForIndex({
- align: scrollToAlignment,
- containerSize: width,
- currentOffset: scrollLeft,
- targetIndex: targetIndex
- });
-
- if (scrollLeft !== calculatedScrollLeft) {
- this._setScrollPosition({
- scrollLeft: calculatedScrollLeft
- });
- }
- }
- }
- }, {
- key: '_updateScrollTopForScrollToRow',
- value: function _updateScrollTopForScrollToRow() {
- var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
- var state = arguments.length <= 1 || arguments[1] === undefined ? this.state : arguments[1];
- var height = props.height;
- var rowCount = props.rowCount;
- var scrollToAlignment = props.scrollToAlignment;
- var scrollToRow = props.scrollToRow;
- var scrollTop = state.scrollTop;
-
-
- if (scrollToRow >= 0 && rowCount > 0) {
- var targetIndex = Math.max(0, Math.min(rowCount - 1, scrollToRow));
-
- var calculatedScrollTop = this._rowSizeAndPositionManager.getUpdatedOffsetForIndex({
- align: scrollToAlignment,
- containerSize: height,
- currentOffset: scrollTop,
- targetIndex: targetIndex
- });
-
- if (scrollTop !== calculatedScrollTop) {
- this._setScrollPosition({
- scrollTop: calculatedScrollTop
- });
- }
- }
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(event) {
- // In certain edge-cases React dispatches an onScroll event with an invalid target.scrollLeft / target.scrollTop.
- // This invalid event can be detected by comparing event.target to this component's scrollable DOM element.
- // See issue #404 for more information.
- if (event.target !== this._scrollingContainer) {
- return;
- }
-
- // Prevent pointer events from interrupting a smooth scroll
- this._enablePointerEventsAfterDelay();
-
- // When this component is shrunk drastically, React dispatches a series of back-to-back scroll events,
- // Gradually converging on a scrollTop that is within the bounds of the new, smaller height.
- // This causes a series of rapid renders that is slow for long lists.
- // We can avoid that by doing some simple bounds checking to ensure that scrollTop never exceeds the total height.
- var _props6 = this.props;
- var height = _props6.height;
- var width = _props6.width;
-
- var scrollbarSize = this._scrollbarSize;
- var totalRowsHeight = this._rowSizeAndPositionManager.getTotalSize();
- var totalColumnsWidth = this._columnSizeAndPositionManager.getTotalSize();
- var scrollLeft = Math.min(Math.max(0, totalColumnsWidth - width + scrollbarSize), event.target.scrollLeft);
- var scrollTop = Math.min(Math.max(0, totalRowsHeight - height + scrollbarSize), event.target.scrollTop);
-
- // Certain devices (like Apple touchpad) rapid-fire duplicate events.
- // Don't force a re-render if this is the case.
- // The mouse may move faster then the animation frame does.
- // Use requestAnimationFrame to avoid over-updating.
- if (this.state.scrollLeft !== scrollLeft || this.state.scrollTop !== scrollTop) {
- // Browsers with cancelable scroll events (eg. Firefox) interrupt scrolling animations if scrollTop/scrollLeft is set.
- // Other browsers (eg. Safari) don't scroll as well without the help under certain conditions (DOM or style changes during scrolling).
- // All things considered, this seems to be the best current work around that I'm aware of.
- // For more information see https://github.com/bvaughn/react-virtualized/pull/124
- var scrollPositionChangeReason = event.cancelable ? SCROLL_POSITION_CHANGE_REASONS.OBSERVED : SCROLL_POSITION_CHANGE_REASONS.REQUESTED;
-
- // Track scrolling direction so we can more efficiently overscan rows to reduce empty space around the edges while scrolling.
- var scrollDirectionVertical = scrollTop > this.state.scrollTop ? _getOverscanIndices.SCROLL_DIRECTION_FORWARD : _getOverscanIndices.SCROLL_DIRECTION_BACKWARD;
- var scrollDirectionHorizontal = scrollLeft > this.state.scrollLeft ? _getOverscanIndices.SCROLL_DIRECTION_FORWARD : _getOverscanIndices.SCROLL_DIRECTION_BACKWARD;
-
- if (!this.state.isScrolling) {
- this.setState({
- isScrolling: true
- });
- }
-
- this._setNextState({
- isScrolling: true,
- scrollDirectionHorizontal: scrollDirectionHorizontal,
- scrollDirectionVertical: scrollDirectionVertical,
- scrollLeft: scrollLeft,
- scrollPositionChangeReason: scrollPositionChangeReason,
- scrollTop: scrollTop
- });
- }
-
- this._invokeOnScrollMemoizer({ scrollLeft: scrollLeft, scrollTop: scrollTop, totalColumnsWidth: totalColumnsWidth, totalRowsHeight: totalRowsHeight });
- }
- }]);
-
- return Grid;
-}(_react.Component);
-
-Grid.propTypes = {
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Set the width of the inner scrollable container to 'auto'.
- * This is useful for single-column Grids to ensure that the column doesn't extend below a vertical scrollbar.
- */
- autoContainerWidth: _react.PropTypes.bool,
-
- /**
- * Removes fixed height from the scrollingContainer so that the total height
- * of rows can stretch the window. Intended for use with WindowScroller
- */
- autoHeight: _react.PropTypes.bool,
-
- /** Optional custom CSS class for individual cells */
- cellClassName: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]),
-
- /** Optional custom styles for individual cells */
- cellStyle: _react.PropTypes.oneOfType([_react.PropTypes.object, _react.PropTypes.func]),
-
- /**
- * Responsible for rendering a cell given an row and column index.
- * Should implement the following interface: ({ columnIndex: number, rowIndex: number }): PropTypes.node
- */
- cellRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Responsible for rendering a group of cells given their index ranges.
- * Should implement the following interface: ({
- * cellCache: Map,
- * cellRenderer: Function,
- * columnSizeAndPositionManager: CellSizeAndPositionManager,
- * columnStartIndex: number,
- * columnStopIndex: number,
- * isScrolling: boolean,
- * rowSizeAndPositionManager: CellSizeAndPositionManager,
- * rowStartIndex: number,
- * rowStopIndex: number,
- * scrollLeft: number,
- * scrollTop: number
- * }): Array
- */
- cellRangeRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Optional custom CSS class name to attach to root Grid element.
- */
- className: _react.PropTypes.string,
-
- /**
- * Number of columns in grid.
- */
- columnCount: _react.PropTypes.number.isRequired,
-
- /**
- * Either a fixed column width (number) or a function that returns the width of a column given its index.
- * Should implement the following interface: (index: number): number
- */
- columnWidth: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.func]).isRequired,
-
- /**
- * Used to estimate the total width of a Grid before all of its columns have actually been measured.
- * The estimated total width is adjusted as columns are rendered.
- */
- estimatedColumnSize: _react.PropTypes.number.isRequired,
-
- /**
- * Used to estimate the total height of a Grid before all of its rows have actually been measured.
- * The estimated total height is adjusted as rows are rendered.
- */
- estimatedRowSize: _react.PropTypes.number.isRequired,
-
- /**
- * Height of Grid; this property determines the number of visible (vs virtualized) rows.
- */
- height: _react.PropTypes.number.isRequired,
-
- /**
- * Optional renderer to be used in place of rows when either :rowCount or :columnCount is 0.
- */
- noContentRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Callback invoked whenever the scroll offset changes within the inner scrollable region.
- * This callback can be used to sync scrolling between lists, tables, or grids.
- * ({ clientHeight, clientWidth, scrollHeight, scrollLeft, scrollTop, scrollWidth }): void
- */
- onScroll: _react.PropTypes.func.isRequired,
-
- /**
- * Callback invoked with information about the section of the Grid that was just rendered.
- * ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }): void
- */
- onSectionRendered: _react.PropTypes.func.isRequired,
-
- /**
- * Number of columns to render before/after the visible section of the grid.
- * These columns can help for smoother scrolling on touch devices or browsers that send scroll events infrequently.
- */
- overscanColumnCount: _react.PropTypes.number.isRequired,
-
- /**
- * Number of rows to render above/below the visible section of the grid.
- * These rows can help for smoother scrolling on touch devices or browsers that send scroll events infrequently.
- */
- overscanRowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Either a fixed row height (number) or a function that returns the height of a row given its index.
- * Should implement the following interface: ({ index: number }): number
- */
- rowHeight: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.func]).isRequired,
-
- /**
- * Number of rows in grid.
- */
- rowCount: _react.PropTypes.number.isRequired,
-
- /** Wait this amount of time after the last scroll event before resetting Grid `pointer-events`. */
- scrollingResetTimeInterval: _react.PropTypes.number,
-
- /** Horizontal offset. */
- scrollLeft: _react.PropTypes.number,
-
- /**
- * Controls scroll-to-cell behavior of the Grid.
- * The default ("auto") scrolls the least amount possible to ensure that the specified cell is fully visible.
- * Use "start" to align cells to the top/left of the Grid and "end" to align bottom/right.
- */
- scrollToAlignment: _react.PropTypes.oneOf(['auto', 'end', 'start', 'center']).isRequired,
-
- /**
- * Column index to ensure visible (by forcefully scrolling if necessary)
- */
- scrollToColumn: _react.PropTypes.number,
-
- /** Vertical offset. */
- scrollTop: _react.PropTypes.number,
-
- /**
- * Row index to ensure visible (by forcefully scrolling if necessary)
- */
- scrollToRow: _react.PropTypes.number,
-
- /** Optional inline style */
- style: _react.PropTypes.object,
-
- /** Tab index for focus */
- tabIndex: _react.PropTypes.number,
-
- /**
- * Width of Grid; this property determines the number of visible (vs virtualized) columns.
- */
- width: _react.PropTypes.number.isRequired
-};
-Grid.defaultProps = {
- 'aria-label': 'grid',
- cellStyle: {},
- cellRangeRenderer: _defaultCellRangeRenderer2.default,
- estimatedColumnSize: 100,
- estimatedRowSize: 30,
- noContentRenderer: function noContentRenderer() {
- return null;
- },
- onScroll: function onScroll() {
- return null;
- },
- onSectionRendered: function onSectionRendered() {
- return null;
- },
- overscanColumnCount: 0,
- overscanRowCount: 10,
- scrollingResetTimeInterval: DEFAULT_SCROLLING_RESET_TIME_INTERVAL,
- scrollToAlignment: 'auto',
- style: {},
- tabIndex: 0
-};
-exports.default = Grid;
-},{"../utils/createCallbackMemoizer":78,"./defaultCellRangeRenderer":61,"./utils/ScalingCellSizeAndPositionManager":64,"./utils/calculateSizeAndPositionDataAndUpdateScrollOffset":65,"./utils/getOverscanIndices":66,"./utils/updateScrollIndexHelper":67,"classnames":undefined,"dom-helpers/util/scrollbarSize":19,"raf":29,"react":undefined,"react-addons-shallow-compare":30}],61:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-exports.default = defaultCellRangeRenderer;
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/**
- * Default implementation of cellRangeRenderer used by Grid.
- * This renderer supports cell-caching while the user is scrolling.
- */
-function defaultCellRangeRenderer(_ref) {
- var cellCache = _ref.cellCache;
- var cellClassName = _ref.cellClassName;
- var cellRenderer = _ref.cellRenderer;
- var cellStyle = _ref.cellStyle;
- var columnSizeAndPositionManager = _ref.columnSizeAndPositionManager;
- var columnStartIndex = _ref.columnStartIndex;
- var columnStopIndex = _ref.columnStopIndex;
- var horizontalOffsetAdjustment = _ref.horizontalOffsetAdjustment;
- var isScrolling = _ref.isScrolling;
- var rowSizeAndPositionManager = _ref.rowSizeAndPositionManager;
- var rowStartIndex = _ref.rowStartIndex;
- var rowStopIndex = _ref.rowStopIndex;
- var scrollLeft = _ref.scrollLeft;
- var scrollTop = _ref.scrollTop;
- var verticalOffsetAdjustment = _ref.verticalOffsetAdjustment;
-
- var renderedCells = [];
-
- for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
- var rowDatum = rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex);
-
- for (var columnIndex = columnStartIndex; columnIndex <= columnStopIndex; columnIndex++) {
- var columnDatum = columnSizeAndPositionManager.getSizeAndPositionOfCell(columnIndex);
- var key = rowIndex + '-' + columnIndex;
- var cellStyleObject = cellStyle({ rowIndex: rowIndex, columnIndex: columnIndex });
- var renderedCell = void 0;
-
- // Avoid re-creating cells while scrolling.
- // This can lead to the same cell being created many times and can cause performance issues for "heavy" cells.
- // If a scroll is in progress- cache and reuse cells.
- // This cache will be thrown away once scrolling complets.
- if (isScrolling) {
- if (!cellCache[key]) {
- cellCache[key] = cellRenderer({
- columnIndex: columnIndex,
- isScrolling: isScrolling,
- rowIndex: rowIndex
- });
- }
- renderedCell = cellCache[key];
- // If the user is no longer scrolling, don't cache cells.
- // This makes dynamic cell content difficult for users and would also lead to a heavier memory footprint.
- } else {
- renderedCell = cellRenderer({
- columnIndex: columnIndex,
- isScrolling: isScrolling,
- rowIndex: rowIndex
- });
- }
-
- if (renderedCell == null || renderedCell === false) {
- continue;
- }
-
- var className = cellClassName({ columnIndex: columnIndex, rowIndex: rowIndex });
-
- var child = _react2.default.createElement(
- 'div',
- {
- key: key,
- className: (0, _classnames2.default)('Grid__cell', className),
- style: _extends({
- height: rowDatum.size,
- left: columnDatum.offset + horizontalOffsetAdjustment,
- top: rowDatum.offset + verticalOffsetAdjustment,
- width: columnDatum.size
- }, cellStyleObject)
- },
- renderedCell
- );
-
- renderedCells.push(child);
- }
- }
-
- return renderedCells;
-}
-},{"classnames":undefined,"react":undefined}],62:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.defaultCellRangeRenderer = exports.Grid = exports.default = undefined;
-
-var _Grid2 = require('./Grid');
-
-var _Grid3 = _interopRequireDefault(_Grid2);
-
-var _defaultCellRangeRenderer2 = require('./defaultCellRangeRenderer');
-
-var _defaultCellRangeRenderer3 = _interopRequireDefault(_defaultCellRangeRenderer2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _Grid3.default;
-exports.Grid = _Grid3.default;
-exports.defaultCellRangeRenderer = _defaultCellRangeRenderer3.default;
-},{"./Grid":60,"./defaultCellRangeRenderer":61}],63:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/**
- * Just-in-time calculates and caches size and position information for a collection of cells.
- */
-var CellSizeAndPositionManager = function () {
- function CellSizeAndPositionManager(_ref) {
- var cellCount = _ref.cellCount;
- var cellSizeGetter = _ref.cellSizeGetter;
- var estimatedCellSize = _ref.estimatedCellSize;
-
- _classCallCheck(this, CellSizeAndPositionManager);
-
- this._cellSizeGetter = cellSizeGetter;
- this._cellCount = cellCount;
- this._estimatedCellSize = estimatedCellSize;
-
- // Cache of size and position data for cells, mapped by cell index.
- // Note that invalid values may exist in this map so only rely on cells up to this._lastMeasuredIndex
- this._cellSizeAndPositionData = {};
-
- // Measurements for cells up to this index can be trusted; cells afterward should be estimated.
- this._lastMeasuredIndex = -1;
- }
-
- _createClass(CellSizeAndPositionManager, [{
- key: 'configure',
- value: function configure(_ref2) {
- var cellCount = _ref2.cellCount;
- var estimatedCellSize = _ref2.estimatedCellSize;
-
- this._cellCount = cellCount;
- this._estimatedCellSize = estimatedCellSize;
- }
- }, {
- key: 'getCellCount',
- value: function getCellCount() {
- return this._cellCount;
- }
- }, {
- key: 'getEstimatedCellSize',
- value: function getEstimatedCellSize() {
- return this._estimatedCellSize;
- }
- }, {
- key: 'getLastMeasuredIndex',
- value: function getLastMeasuredIndex() {
- return this._lastMeasuredIndex;
- }
-
- /**
- * This method returns the size and position for the cell at the specified index.
- * It just-in-time calculates (or used cached values) for cells leading up to the index.
- */
-
- }, {
- key: 'getSizeAndPositionOfCell',
- value: function getSizeAndPositionOfCell(index) {
- if (index < 0 || index >= this._cellCount) {
- throw Error('Requested index ' + index + ' is outside of range 0..' + this._cellCount);
- }
-
- if (index > this._lastMeasuredIndex) {
- var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
- var _offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size;
-
- for (var i = this._lastMeasuredIndex + 1; i <= index; i++) {
- var _size = this._cellSizeGetter({ index: i });
-
- if (_size == null || isNaN(_size)) {
- throw Error('Invalid size returned for cell ' + i + ' of value ' + _size);
- }
-
- this._cellSizeAndPositionData[i] = {
- offset: _offset,
- size: _size
- };
-
- _offset += _size;
- }
-
- this._lastMeasuredIndex = index;
- }
-
- return this._cellSizeAndPositionData[index];
- }
- }, {
- key: 'getSizeAndPositionOfLastMeasuredCell',
- value: function getSizeAndPositionOfLastMeasuredCell() {
- return this._lastMeasuredIndex >= 0 ? this._cellSizeAndPositionData[this._lastMeasuredIndex] : {
- offset: 0,
- size: 0
- };
- }
-
- /**
- * Total size of all cells being measured.
- * This value will be completedly estimated initially.
- * As cells as measured the estimate will be updated.
- */
-
- }, {
- key: 'getTotalSize',
- value: function getTotalSize() {
- var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
-
- return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize;
- }
-
- /**
- * Determines a new offset that ensures a certain cell is visible, given the current offset.
- * If the cell is already visible then the current offset will be returned.
- * If the current offset is too great or small, it will be adjusted just enough to ensure the specified index is visible.
- *
- * @param align Desired alignment within container; one of "auto" (default), "start", or "end"
- * @param containerSize Size (width or height) of the container viewport
- * @param currentOffset Container's current (x or y) offset
- * @param totalSize Total size (width or height) of all cells
- * @return Offset to use to ensure the specified cell is visible
- */
-
- }, {
- key: 'getUpdatedOffsetForIndex',
- value: function getUpdatedOffsetForIndex(_ref3) {
- var _ref3$align = _ref3.align;
- var align = _ref3$align === undefined ? 'auto' : _ref3$align;
- var containerSize = _ref3.containerSize;
- var currentOffset = _ref3.currentOffset;
- var targetIndex = _ref3.targetIndex;
-
- var datum = this.getSizeAndPositionOfCell(targetIndex);
- var maxOffset = datum.offset;
- var minOffset = maxOffset - containerSize + datum.size;
-
- var idealOffset = void 0;
-
- switch (align) {
- case 'start':
- idealOffset = maxOffset;
- break;
- case 'end':
- idealOffset = minOffset;
- break;
- case 'center':
- idealOffset = maxOffset - (containerSize - datum.size) / 2;
- break;
- default:
- idealOffset = Math.max(minOffset, Math.min(maxOffset, currentOffset));
- break;
- }
-
- var totalSize = this.getTotalSize();
-
- return Math.max(0, Math.min(totalSize - containerSize, idealOffset));
- }
- }, {
- key: 'getVisibleCellRange',
- value: function getVisibleCellRange(_ref4) {
- var containerSize = _ref4.containerSize;
- var offset = _ref4.offset;
-
- var totalSize = this.getTotalSize();
-
- if (totalSize === 0) {
- return {};
- }
-
- var maxOffset = offset + containerSize;
- var start = this._findNearestCell(offset);
-
- var datum = this.getSizeAndPositionOfCell(start);
- offset = datum.offset + datum.size;
-
- var stop = start;
-
- while (offset < maxOffset && stop < this._cellCount - 1) {
- stop++;
-
- offset += this.getSizeAndPositionOfCell(stop).size;
- }
-
- return {
- start: start,
- stop: stop
- };
- }
-
- /**
- * Clear all cached values for cells after the specified index.
- * This method should be called for any cell that has changed its size.
- * It will not immediately perform any calculations; they'll be performed the next time getSizeAndPositionOfCell() is called.
- */
-
- }, {
- key: 'resetCell',
- value: function resetCell(index) {
- this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1);
- }
- }, {
- key: '_binarySearch',
- value: function _binarySearch(_ref5) {
- var high = _ref5.high;
- var low = _ref5.low;
- var offset = _ref5.offset;
-
- var middle = void 0;
- var currentOffset = void 0;
-
- while (low <= high) {
- middle = low + Math.floor((high - low) / 2);
- currentOffset = this.getSizeAndPositionOfCell(middle).offset;
-
- if (currentOffset === offset) {
- return middle;
- } else if (currentOffset < offset) {
- low = middle + 1;
- } else if (currentOffset > offset) {
- high = middle - 1;
- }
- }
-
- if (low > 0) {
- return low - 1;
- }
- }
- }, {
- key: '_exponentialSearch',
- value: function _exponentialSearch(_ref6) {
- var index = _ref6.index;
- var offset = _ref6.offset;
-
- var interval = 1;
-
- while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) {
- index += interval;
- interval *= 2;
- }
-
- return this._binarySearch({
- high: Math.min(index, this._cellCount - 1),
- low: Math.floor(index / 2),
- offset: offset
- });
- }
-
- /**
- * Searches for the cell (index) nearest the specified offset.
- *
- * If no exact match is found the next lowest cell index will be returned.
- * This allows partially visible cells (with offsets just before/above the fold) to be visible.
- */
-
- }, {
- key: '_findNearestCell',
- value: function _findNearestCell(offset) {
- if (isNaN(offset)) {
- throw Error('Invalid offset ' + offset + ' specified');
- }
-
- // Our search algorithms find the nearest match at or below the specified offset.
- // So make sure the offset is at least 0 or no match will be found.
- offset = Math.max(0, offset);
-
- var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
- var lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex);
-
- if (lastMeasuredCellSizeAndPosition.offset >= offset) {
- // If we've already measured cells within this range just use a binary search as it's faster.
- return this._binarySearch({
- high: lastMeasuredIndex,
- low: 0,
- offset: offset
- });
- } else {
- // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
- // The exponential search avoids pre-computing sizes for the full set of cells as a binary search would.
- // The overall complexity for this approach is O(log n).
- return this._exponentialSearch({
- index: lastMeasuredIndex,
- offset: offset
- });
- }
- }
- }]);
-
- return CellSizeAndPositionManager;
-}();
-
-exports.default = CellSizeAndPositionManager;
-},{}],64:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.DEFAULT_MAX_SCROLL_SIZE = undefined;
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _CellSizeAndPositionManager = require('./CellSizeAndPositionManager');
-
-var _CellSizeAndPositionManager2 = _interopRequireDefault(_CellSizeAndPositionManager);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/**
- * Browsers have scroll offset limitations (eg Chrome stops scrolling at ~33.5M pixels where as Edge tops out at ~1.5M pixels).
- * After a certain position, the browser won't allow the user to scroll further (even via JavaScript scroll offset adjustments).
- * This util picks a lower ceiling for max size and artificially adjusts positions within to make it transparent for users.
- */
-var DEFAULT_MAX_SCROLL_SIZE = exports.DEFAULT_MAX_SCROLL_SIZE = 1500000;
-
-/**
- * Extends CellSizeAndPositionManager and adds scaling behavior for lists that are too large to fit within a browser's native limits.
- */
-
-var ScalingCellSizeAndPositionManager = function () {
- function ScalingCellSizeAndPositionManager(_ref) {
- var _ref$maxScrollSize = _ref.maxScrollSize;
- var maxScrollSize = _ref$maxScrollSize === undefined ? DEFAULT_MAX_SCROLL_SIZE : _ref$maxScrollSize;
-
- var params = _objectWithoutProperties(_ref, ['maxScrollSize']);
-
- _classCallCheck(this, ScalingCellSizeAndPositionManager);
-
- // Favor composition over inheritance to simplify IE10 support
- this._cellSizeAndPositionManager = new _CellSizeAndPositionManager2.default(params);
- this._maxScrollSize = maxScrollSize;
- }
-
- _createClass(ScalingCellSizeAndPositionManager, [{
- key: 'configure',
- value: function configure(params) {
- this._cellSizeAndPositionManager.configure(params);
- }
- }, {
- key: 'getCellCount',
- value: function getCellCount() {
- return this._cellSizeAndPositionManager.getCellCount();
- }
- }, {
- key: 'getEstimatedCellSize',
- value: function getEstimatedCellSize() {
- return this._cellSizeAndPositionManager.getEstimatedCellSize();
- }
- }, {
- key: 'getLastMeasuredIndex',
- value: function getLastMeasuredIndex() {
- return this._cellSizeAndPositionManager.getLastMeasuredIndex();
- }
-
- /**
- * Number of pixels a cell at the given position (offset) should be shifted in order to fit within the scaled container.
- * The offset passed to this function is scalled (safe) as well.
- */
-
- }, {
- key: 'getOffsetAdjustment',
- value: function getOffsetAdjustment(_ref2) {
- var containerSize = _ref2.containerSize;
- var offset = _ref2.offset;
-
- var totalSize = this._cellSizeAndPositionManager.getTotalSize();
- var safeTotalSize = this.getTotalSize();
- var offsetPercentage = this._getOffsetPercentage({
- containerSize: containerSize,
- offset: offset,
- totalSize: safeTotalSize
- });
-
- return Math.round(offsetPercentage * (safeTotalSize - totalSize));
- }
- }, {
- key: 'getSizeAndPositionOfCell',
- value: function getSizeAndPositionOfCell(index) {
- return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index);
- }
- }, {
- key: 'getSizeAndPositionOfLastMeasuredCell',
- value: function getSizeAndPositionOfLastMeasuredCell() {
- return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell();
- }
-
- /** See CellSizeAndPositionManager#getTotalSize */
-
- }, {
- key: 'getTotalSize',
- value: function getTotalSize() {
- return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize());
- }
-
- /** See CellSizeAndPositionManager#getUpdatedOffsetForIndex */
-
- }, {
- key: 'getUpdatedOffsetForIndex',
- value: function getUpdatedOffsetForIndex(_ref3) {
- var _ref3$align = _ref3.align;
- var align = _ref3$align === undefined ? 'auto' : _ref3$align;
- var containerSize = _ref3.containerSize;
- var currentOffset = _ref3.currentOffset;
- var targetIndex = _ref3.targetIndex;
- var totalSize = _ref3.totalSize;
-
- currentOffset = this._safeOffsetToOffset({
- containerSize: containerSize,
- offset: currentOffset
- });
-
- var offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex({
- align: align,
- containerSize: containerSize,
- currentOffset: currentOffset,
- targetIndex: targetIndex,
- totalSize: totalSize
- });
-
- return this._offsetToSafeOffset({
- containerSize: containerSize,
- offset: offset
- });
- }
-
- /** See CellSizeAndPositionManager#getVisibleCellRange */
-
- }, {
- key: 'getVisibleCellRange',
- value: function getVisibleCellRange(_ref4) {
- var containerSize = _ref4.containerSize;
- var offset = _ref4.offset;
-
- offset = this._safeOffsetToOffset({
- containerSize: containerSize,
- offset: offset
- });
-
- return this._cellSizeAndPositionManager.getVisibleCellRange({
- containerSize: containerSize,
- offset: offset
- });
- }
- }, {
- key: 'resetCell',
- value: function resetCell(index) {
- this._cellSizeAndPositionManager.resetCell(index);
- }
- }, {
- key: '_getOffsetPercentage',
- value: function _getOffsetPercentage(_ref5) {
- var containerSize = _ref5.containerSize;
- var offset = _ref5.offset;
- var totalSize = _ref5.totalSize;
-
- return totalSize <= containerSize ? 0 : offset / (totalSize - containerSize);
- }
- }, {
- key: '_offsetToSafeOffset',
- value: function _offsetToSafeOffset(_ref6) {
- var containerSize = _ref6.containerSize;
- var offset = _ref6.offset;
-
- var totalSize = this._cellSizeAndPositionManager.getTotalSize();
- var safeTotalSize = this.getTotalSize();
-
- if (totalSize === safeTotalSize) {
- return offset;
- } else {
- var offsetPercentage = this._getOffsetPercentage({
- containerSize: containerSize,
- offset: offset,
- totalSize: totalSize
- });
-
- return Math.round(offsetPercentage * (safeTotalSize - containerSize));
- }
- }
- }, {
- key: '_safeOffsetToOffset',
- value: function _safeOffsetToOffset(_ref7) {
- var containerSize = _ref7.containerSize;
- var offset = _ref7.offset;
-
- var totalSize = this._cellSizeAndPositionManager.getTotalSize();
- var safeTotalSize = this.getTotalSize();
-
- if (totalSize === safeTotalSize) {
- return offset;
- } else {
- var offsetPercentage = this._getOffsetPercentage({
- containerSize: containerSize,
- offset: offset,
- totalSize: safeTotalSize
- });
-
- return Math.round(offsetPercentage * (totalSize - containerSize));
- }
- }
- }]);
-
- return ScalingCellSizeAndPositionManager;
-}();
-
-exports.default = ScalingCellSizeAndPositionManager;
-},{"./CellSizeAndPositionManager":63}],65:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = calculateSizeAndPositionDataAndUpdateScrollOffset;
-/**
- * Helper method that determines when to recalculate row or column metadata.
- *
- * @param cellCount Number of rows or columns in the current axis
- * @param cellsSize Width or height of cells for the current axis
- * @param computeMetadataCallback Method to invoke if cell metadata should be recalculated
- * @param computeMetadataCallbackProps Parameters to pass to :computeMetadataCallback
- * @param nextCellsCount Newly updated number of rows or columns in the current axis
- * @param nextCellsSize Newly updated width or height of cells for the current axis
- * @param nextScrollToIndex Newly updated scroll-to-index
- * @param scrollToIndex Scroll-to-index
- * @param updateScrollOffsetForScrollToIndex Callback to invoke if the scroll position should be recalculated
- */
-function calculateSizeAndPositionDataAndUpdateScrollOffset(_ref) {
- var cellCount = _ref.cellCount;
- var cellSize = _ref.cellSize;
- var computeMetadataCallback = _ref.computeMetadataCallback;
- var computeMetadataCallbackProps = _ref.computeMetadataCallbackProps;
- var nextCellsCount = _ref.nextCellsCount;
- var nextCellSize = _ref.nextCellSize;
- var nextScrollToIndex = _ref.nextScrollToIndex;
- var scrollToIndex = _ref.scrollToIndex;
- var updateScrollOffsetForScrollToIndex = _ref.updateScrollOffsetForScrollToIndex;
-
- // Don't compare cell sizes if they are functions because inline functions would cause infinite loops.
- // In that event users should use the manual recompute methods to inform of changes.
- if (cellCount !== nextCellsCount || (typeof cellSize === 'number' || typeof nextCellSize === 'number') && cellSize !== nextCellSize) {
- computeMetadataCallback(computeMetadataCallbackProps);
-
- // Updated cell metadata may have hidden the previous scrolled-to item.
- // In this case we should also update the scrollTop to ensure it stays visible.
- if (scrollToIndex >= 0 && scrollToIndex === nextScrollToIndex) {
- updateScrollOffsetForScrollToIndex();
- }
- }
-}
-},{}],66:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = getOverscanIndices;
-var SCROLL_DIRECTION_BACKWARD = exports.SCROLL_DIRECTION_BACKWARD = -1;
-var SCROLL_DIRECTION_FIXED = exports.SCROLL_DIRECTION_FIXED = 0;
-var SCROLL_DIRECTION_FORWARD = exports.SCROLL_DIRECTION_FORWARD = 1;
-
-/**
- * Calculates the number of cells to overscan before and after a specified range.
- * This function ensures that overscanning doesn't exceed the available cells.
- *
- * @param cellCount Number of rows or columns in the current axis
- * @param scrollDirection One of SCROLL_DIRECTION_BACKWARD
- * @param overscanCellsCount Maximum number of cells to over-render in either direction
- * @param startIndex Begin of range of visible cells
- * @param stopIndex End of range of visible cells
- */
-function getOverscanIndices(_ref) {
- var cellCount = _ref.cellCount;
- var overscanCellsCount = _ref.overscanCellsCount;
- var scrollDirection = _ref.scrollDirection;
- var startIndex = _ref.startIndex;
- var stopIndex = _ref.stopIndex;
-
- var overscanStartIndex = void 0;
- var overscanStopIndex = void 0;
-
- if (scrollDirection === SCROLL_DIRECTION_FORWARD) {
- overscanStartIndex = startIndex;
- overscanStopIndex = stopIndex + overscanCellsCount * 2;
- } else if (scrollDirection === SCROLL_DIRECTION_BACKWARD) {
- overscanStartIndex = startIndex - overscanCellsCount * 2;
- overscanStopIndex = stopIndex;
- } else {
- overscanStartIndex = startIndex - overscanCellsCount;
- overscanStopIndex = stopIndex + overscanCellsCount;
- }
-
- return {
- overscanStartIndex: Math.max(0, overscanStartIndex),
- overscanStopIndex: Math.min(cellCount - 1, overscanStopIndex)
- };
-}
-},{}],67:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = updateScrollIndexHelper;
-/**
- * Helper function that determines when to update scroll offsets to ensure that a scroll-to-index remains visible.
- * This function also ensures that the scroll ofset isn't past the last column/row of cells.
- *
- * @param cellsSize Width or height of cells for the current axis
- * @param cellSizeAndPositionManager Manages size and position metadata of cells
- * @param previousCellsCount Previous number of rows or columns
- * @param previousCellsSize Previous width or height of cells
- * @param previousScrollToIndex Previous scroll-to-index
- * @param previousSize Previous width or height of the virtualized container
- * @param scrollOffset Current scrollLeft or scrollTop
- * @param scrollToIndex Scroll-to-index
- * @param size Width or height of the virtualized container
- * @param updateScrollIndexCallback Callback to invoke with an scroll-to-index value
- */
-function updateScrollIndexHelper(_ref) {
- var cellSize = _ref.cellSize;
- var cellSizeAndPositionManager = _ref.cellSizeAndPositionManager;
- var previousCellsCount = _ref.previousCellsCount;
- var previousCellSize = _ref.previousCellSize;
- var previousScrollToAlignment = _ref.previousScrollToAlignment;
- var previousScrollToIndex = _ref.previousScrollToIndex;
- var previousSize = _ref.previousSize;
- var scrollOffset = _ref.scrollOffset;
- var scrollToAlignment = _ref.scrollToAlignment;
- var scrollToIndex = _ref.scrollToIndex;
- var size = _ref.size;
- var updateScrollIndexCallback = _ref.updateScrollIndexCallback;
-
- var cellCount = cellSizeAndPositionManager.getCellCount();
- var hasScrollToIndex = scrollToIndex >= 0 && scrollToIndex < cellCount;
- var sizeHasChanged = size !== previousSize || !previousCellSize || typeof cellSize === 'number' && cellSize !== previousCellSize;
-
- // If we have a new scroll target OR if height/row-height has changed,
- // We should ensure that the scroll target is visible.
- if (hasScrollToIndex && (sizeHasChanged || scrollToAlignment !== previousScrollToAlignment || scrollToIndex !== previousScrollToIndex)) {
- updateScrollIndexCallback(scrollToIndex);
-
- // If we don't have a selected item but list size or number of children have decreased,
- // Make sure we aren't scrolled too far past the current content.
- } else if (!hasScrollToIndex && cellCount > 0 && (size < previousSize || cellCount < previousCellsCount)) {
- // We need to ensure that the current scroll offset is still within the collection's range.
- // To do this, we don't need to measure everything; CellMeasurer would perform poorly.
- // Just check to make sure we're still okay.
- // Only adjust the scroll position if we've scrolled below the last set of rows.
- if (scrollOffset > cellSizeAndPositionManager.getTotalSize() - size) {
- updateScrollIndexCallback(cellCount - 1);
- }
- }
-}
-},{}],68:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-exports.isRangeVisible = isRangeVisible;
-exports.scanForUnloadedRanges = scanForUnloadedRanges;
-exports.forceUpdateReactVirtualizedComponent = forceUpdateReactVirtualizedComponent;
-
-var _react = require('react');
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _createCallbackMemoizer = require('../utils/createCallbackMemoizer');
-
-var _createCallbackMemoizer2 = _interopRequireDefault(_createCallbackMemoizer);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * Higher-order component that manages lazy-loading for "infinite" data.
- * This component decorates a virtual component and just-in-time prefetches rows as a user scrolls.
- * It is intended as a convenience component; fork it if you'd like finer-grained control over data-loading.
- */
-var InfiniteLoader = function (_Component) {
- _inherits(InfiniteLoader, _Component);
-
- function InfiniteLoader(props, context) {
- _classCallCheck(this, InfiniteLoader);
-
- var _this = _possibleConstructorReturn(this, (InfiniteLoader.__proto__ || Object.getPrototypeOf(InfiniteLoader)).call(this, props, context));
-
- _this._loadMoreRowsMemoizer = (0, _createCallbackMemoizer2.default)();
-
- _this._onRowsRendered = _this._onRowsRendered.bind(_this);
- _this._registerChild = _this._registerChild.bind(_this);
- return _this;
- }
-
- _createClass(InfiniteLoader, [{
- key: 'render',
- value: function render() {
- var children = this.props.children;
-
-
- return children({
- onRowsRendered: this._onRowsRendered,
- registerChild: this._registerChild
- });
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_loadUnloadedRanges',
- value: function _loadUnloadedRanges(unloadedRanges) {
- var _this2 = this;
-
- var loadMoreRows = this.props.loadMoreRows;
-
-
- unloadedRanges.forEach(function (unloadedRange) {
- var promise = loadMoreRows(unloadedRange);
- if (promise) {
- promise.then(function () {
- // Refresh the visible rows if any of them have just been loaded.
- // Otherwise they will remain in their unloaded visual state.
- if (isRangeVisible({
- lastRenderedStartIndex: _this2._lastRenderedStartIndex,
- lastRenderedStopIndex: _this2._lastRenderedStopIndex,
- startIndex: unloadedRange.startIndex,
- stopIndex: unloadedRange.stopIndex
- })) {
- if (_this2._registeredChild) {
- forceUpdateReactVirtualizedComponent(_this2._registeredChild);
- }
- }
- });
- }
- });
- }
- }, {
- key: '_onRowsRendered',
- value: function _onRowsRendered(_ref) {
- var _this3 = this;
-
- var startIndex = _ref.startIndex;
- var stopIndex = _ref.stopIndex;
- var _props = this.props;
- var isRowLoaded = _props.isRowLoaded;
- var minimumBatchSize = _props.minimumBatchSize;
- var rowCount = _props.rowCount;
- var threshold = _props.threshold;
-
-
- this._lastRenderedStartIndex = startIndex;
- this._lastRenderedStopIndex = stopIndex;
-
- var unloadedRanges = scanForUnloadedRanges({
- isRowLoaded: isRowLoaded,
- minimumBatchSize: minimumBatchSize,
- rowCount: rowCount,
- startIndex: Math.max(0, startIndex - threshold),
- stopIndex: Math.min(rowCount - 1, stopIndex + threshold)
- });
-
- // For memoize comparison
- var squashedUnloadedRanges = unloadedRanges.reduce(function (reduced, unloadedRange) {
- return reduced.concat([unloadedRange.startIndex, unloadedRange.stopIndex]);
- }, []);
-
- this._loadMoreRowsMemoizer({
- callback: function callback() {
- _this3._loadUnloadedRanges(unloadedRanges);
- },
- indices: { squashedUnloadedRanges: squashedUnloadedRanges }
- });
- }
- }, {
- key: '_registerChild',
- value: function _registerChild(registeredChild) {
- this._registeredChild = registeredChild;
- }
- }]);
-
- return InfiniteLoader;
-}(_react.Component);
-
-/**
- * Determines if the specified start/stop range is visible based on the most recently rendered range.
- */
-
-
-InfiniteLoader.propTypes = {
- /**
- * Function respondible for rendering a virtualized component.
- * This function should implement the following signature:
- * ({ onRowsRendered, registerChild }) => PropTypes.element
- *
- * The specified :onRowsRendered function should be passed through to the child's :onRowsRendered property.
- * The :registerChild callback should be set as the virtualized component's :ref.
- */
- children: _react.PropTypes.func.isRequired,
-
- /**
- * Function responsible for tracking the loaded state of each row.
- * It should implement the following signature: ({ index: number }): boolean
- */
- isRowLoaded: _react.PropTypes.func.isRequired,
-
- /**
- * Callback to be invoked when more rows must be loaded.
- * It should implement the following signature: ({ startIndex, stopIndex }): Promise
- * The returned Promise should be resolved once row data has finished loading.
- * It will be used to determine when to refresh the list with the newly-loaded data.
- * This callback may be called multiple times in reaction to a single scroll event.
- */
- loadMoreRows: _react.PropTypes.func.isRequired,
-
- /**
- * Minimum number of rows to be loaded at a time.
- * This property can be used to batch requests to reduce HTTP requests.
- */
- minimumBatchSize: _react.PropTypes.number.isRequired,
-
- /**
- * Number of rows in list; can be arbitrary high number if actual number is unknown.
- */
- rowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Threshold at which to pre-fetch data.
- * A threshold X means that data will start loading when a user scrolls within X rows.
- * This value defaults to 15.
- */
- threshold: _react.PropTypes.number.isRequired
-};
-InfiniteLoader.defaultProps = {
- minimumBatchSize: 10,
- rowCount: 0,
- threshold: 15
-};
-exports.default = InfiniteLoader;
-function isRangeVisible(_ref2) {
- var lastRenderedStartIndex = _ref2.lastRenderedStartIndex;
- var lastRenderedStopIndex = _ref2.lastRenderedStopIndex;
- var startIndex = _ref2.startIndex;
- var stopIndex = _ref2.stopIndex;
-
- return !(startIndex > lastRenderedStopIndex || stopIndex < lastRenderedStartIndex);
-}
-
-/**
- * Returns all of the ranges within a larger range that contain unloaded rows.
- */
-function scanForUnloadedRanges(_ref3) {
- var isRowLoaded = _ref3.isRowLoaded;
- var minimumBatchSize = _ref3.minimumBatchSize;
- var rowCount = _ref3.rowCount;
- var startIndex = _ref3.startIndex;
- var stopIndex = _ref3.stopIndex;
-
- var unloadedRanges = [];
-
- var rangeStartIndex = null;
- var rangeStopIndex = null;
-
- for (var index = startIndex; index <= stopIndex; index++) {
- var loaded = isRowLoaded({ index: index });
-
- if (!loaded) {
- rangeStopIndex = index;
- if (rangeStartIndex === null) {
- rangeStartIndex = index;
- }
- } else if (rangeStopIndex !== null) {
- unloadedRanges.push({
- startIndex: rangeStartIndex,
- stopIndex: rangeStopIndex
- });
-
- rangeStartIndex = rangeStopIndex = null;
- }
- }
-
- // If :rangeStopIndex is not null it means we haven't ran out of unloaded rows.
- // Scan forward to try filling our :minimumBatchSize.
- if (rangeStopIndex !== null) {
- var potentialStopIndex = Math.min(Math.max(rangeStopIndex, rangeStartIndex + minimumBatchSize - 1), rowCount - 1);
-
- for (var _index = rangeStopIndex + 1; _index <= potentialStopIndex; _index++) {
- if (!isRowLoaded({ index: _index })) {
- rangeStopIndex = _index;
- } else {
- break;
- }
- }
-
- unloadedRanges.push({
- startIndex: rangeStartIndex,
- stopIndex: rangeStopIndex
- });
- }
-
- // Check to see if our first range ended prematurely.
- // In this case we should scan backwards to try filling our :minimumBatchSize.
- if (unloadedRanges.length) {
- var firstUnloadedRange = unloadedRanges[0];
-
- while (firstUnloadedRange.stopIndex - firstUnloadedRange.startIndex + 1 < minimumBatchSize && firstUnloadedRange.startIndex > 0) {
- var _index2 = firstUnloadedRange.startIndex - 1;
-
- if (!isRowLoaded({ index: _index2 })) {
- firstUnloadedRange.startIndex = _index2;
- } else {
- break;
- }
- }
- }
-
- return unloadedRanges;
-}
-
-/**
- * Since RV components use shallowCompare we need to force a render (even though props haven't changed).
- * However InfiniteLoader may wrap a Grid or it may wrap a FlexTable or VirtualScroll.
- * In the first case the built-in React forceUpdate() method is sufficient to force a re-render,
- * But in the latter cases we need to use the RV-specific forceUpdateGrid() method.
- * Else the inner Grid will not be re-rendered and visuals may be stale.
- */
-function forceUpdateReactVirtualizedComponent(component) {
- typeof component.forceUpdateGrid === 'function' ? component.forceUpdateGrid() : component.forceUpdate();
-}
-},{"../utils/createCallbackMemoizer":78,"react":undefined,"react-addons-shallow-compare":30}],69:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.InfiniteLoader = exports.default = undefined;
-
-var _InfiniteLoader2 = require('./InfiniteLoader');
-
-var _InfiniteLoader3 = _interopRequireDefault(_InfiniteLoader2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _InfiniteLoader3.default;
-exports.InfiniteLoader = _InfiniteLoader3.default;
-},{"./InfiniteLoader":68}],70:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * HOC that simplifies the process of synchronizing scrolling between two or more virtualized components.
- */
-var ScrollSync = function (_Component) {
- _inherits(ScrollSync, _Component);
-
- function ScrollSync(props, context) {
- _classCallCheck(this, ScrollSync);
-
- var _this = _possibleConstructorReturn(this, (ScrollSync.__proto__ || Object.getPrototypeOf(ScrollSync)).call(this, props, context));
-
- _this.state = {
- clientHeight: 0,
- clientWidth: 0,
- scrollHeight: 0,
- scrollLeft: 0,
- scrollTop: 0,
- scrollWidth: 0
- };
-
- _this._onScroll = _this._onScroll.bind(_this);
- return _this;
- }
-
- _createClass(ScrollSync, [{
- key: 'render',
- value: function render() {
- var children = this.props.children;
- var _state = this.state;
- var clientHeight = _state.clientHeight;
- var clientWidth = _state.clientWidth;
- var scrollHeight = _state.scrollHeight;
- var scrollLeft = _state.scrollLeft;
- var scrollTop = _state.scrollTop;
- var scrollWidth = _state.scrollWidth;
-
-
- return children({
- clientHeight: clientHeight,
- clientWidth: clientWidth,
- onScroll: this._onScroll,
- scrollHeight: scrollHeight,
- scrollLeft: scrollLeft,
- scrollTop: scrollTop,
- scrollWidth: scrollWidth
- });
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(_ref) {
- var clientHeight = _ref.clientHeight;
- var clientWidth = _ref.clientWidth;
- var scrollHeight = _ref.scrollHeight;
- var scrollLeft = _ref.scrollLeft;
- var scrollTop = _ref.scrollTop;
- var scrollWidth = _ref.scrollWidth;
-
- this.setState({ clientHeight: clientHeight, clientWidth: clientWidth, scrollHeight: scrollHeight, scrollLeft: scrollLeft, scrollTop: scrollTop, scrollWidth: scrollWidth });
- }
- }]);
-
- return ScrollSync;
-}(_react.Component);
-
-ScrollSync.propTypes = {
- /**
- * Function respondible for rendering 2 or more virtualized components.
- * This function should implement the following signature:
- * ({ onScroll, scrollLeft, scrollTop }) => PropTypes.element
- */
- children: _react.PropTypes.func.isRequired
-};
-exports.default = ScrollSync;
-},{"react":undefined,"react-addons-shallow-compare":30}],71:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.ScrollSync = exports.default = undefined;
-
-var _ScrollSync2 = require('./ScrollSync');
-
-var _ScrollSync3 = _interopRequireDefault(_ScrollSync2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _ScrollSync3.default;
-exports.ScrollSync = _ScrollSync3.default;
-},{"./ScrollSync":70}],72:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _Grid = require('../Grid');
-
-var _Grid2 = _interopRequireDefault(_Grid);
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-/**
- * It is inefficient to create and manage a large list of DOM elements within a scrolling container
- * if only a few of those elements are visible. The primary purpose of this component is to improve
- * performance by only rendering the DOM nodes that a user is able to see based on their current
- * scroll position.
- *
- * This component renders a virtualized list of elements with either fixed or dynamic heights.
- */
-var VirtualScroll = function (_Component) {
- _inherits(VirtualScroll, _Component);
-
- function VirtualScroll(props, context) {
- _classCallCheck(this, VirtualScroll);
-
- var _this = _possibleConstructorReturn(this, (VirtualScroll.__proto__ || Object.getPrototypeOf(VirtualScroll)).call(this, props, context));
-
- _this._cellRenderer = _this._cellRenderer.bind(_this);
- _this._createRowClassNameGetter = _this._createRowClassNameGetter.bind(_this);
- _this._createRowStyleGetter = _this._createRowStyleGetter.bind(_this);
- _this._onScroll = _this._onScroll.bind(_this);
- _this._onSectionRendered = _this._onSectionRendered.bind(_this);
- return _this;
- }
-
- _createClass(VirtualScroll, [{
- key: 'forceUpdateGrid',
- value: function forceUpdateGrid() {
- this.Grid.forceUpdate();
- }
-
- /** See Grid#measureAllCells */
-
- }, {
- key: 'measureAllRows',
- value: function measureAllRows() {
- this.Grid.measureAllCells();
- }
-
- /** See Grid#recomputeGridSize */
-
- }, {
- key: 'recomputeRowHeights',
- value: function recomputeRowHeights() {
- var index = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
-
- this.Grid.recomputeGridSize({
- rowIndex: index
- });
- this.forceUpdateGrid();
- }
- }, {
- key: 'render',
- value: function render() {
- var _this2 = this;
-
- var _props = this.props;
- var className = _props.className;
- var noRowsRenderer = _props.noRowsRenderer;
- var scrollToIndex = _props.scrollToIndex;
- var width = _props.width;
-
-
- var classNames = (0, _classnames2.default)('VirtualScroll', className);
-
- return _react2.default.createElement(_Grid2.default, _extends({}, this.props, {
- autoContainerWidth: true,
- cellRenderer: this._cellRenderer,
- cellClassName: this._createRowClassNameGetter(),
- cellStyle: this._createRowStyleGetter(),
- className: classNames,
- columnWidth: width,
- columnCount: 1,
- noContentRenderer: noRowsRenderer,
- onScroll: this._onScroll,
- onSectionRendered: this._onSectionRendered,
- ref: function ref(_ref) {
- _this2.Grid = _ref;
- },
- scrollToRow: scrollToIndex
- }));
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_cellRenderer',
- value: function _cellRenderer(_ref2) {
- var columnIndex = _ref2.columnIndex;
- var isScrolling = _ref2.isScrolling;
- var rowIndex = _ref2.rowIndex;
- var rowRenderer = this.props.rowRenderer;
-
-
- return rowRenderer({
- index: rowIndex,
- isScrolling: isScrolling
- });
- }
- }, {
- key: '_createRowClassNameGetter',
- value: function _createRowClassNameGetter() {
- var rowClassName = this.props.rowClassName;
-
-
- return rowClassName instanceof Function ? function (_ref3) {
- var rowIndex = _ref3.rowIndex;
- return rowClassName({ index: rowIndex });
- } : function () {
- return rowClassName;
- };
- }
- }, {
- key: '_createRowStyleGetter',
- value: function _createRowStyleGetter() {
- var rowStyle = this.props.rowStyle;
-
-
- var wrapped = rowStyle instanceof Function ? rowStyle : function () {
- return rowStyle;
- };
-
- // Default width to 100% to prevent list rows from flowing under the vertical scrollbar
- return function (_ref4) {
- var rowIndex = _ref4.rowIndex;
- return _extends({
- width: '100%'
- }, wrapped({ index: rowIndex }));
- };
- }
- }, {
- key: '_onScroll',
- value: function _onScroll(_ref5) {
- var clientHeight = _ref5.clientHeight;
- var scrollHeight = _ref5.scrollHeight;
- var scrollTop = _ref5.scrollTop;
- var onScroll = this.props.onScroll;
-
-
- onScroll({ clientHeight: clientHeight, scrollHeight: scrollHeight, scrollTop: scrollTop });
- }
- }, {
- key: '_onSectionRendered',
- value: function _onSectionRendered(_ref6) {
- var rowOverscanStartIndex = _ref6.rowOverscanStartIndex;
- var rowOverscanStopIndex = _ref6.rowOverscanStopIndex;
- var rowStartIndex = _ref6.rowStartIndex;
- var rowStopIndex = _ref6.rowStopIndex;
- var onRowsRendered = this.props.onRowsRendered;
-
-
- onRowsRendered({
- overscanStartIndex: rowOverscanStartIndex,
- overscanStopIndex: rowOverscanStopIndex,
- startIndex: rowStartIndex,
- stopIndex: rowStopIndex
- });
- }
- }]);
-
- return VirtualScroll;
-}(_react.Component);
-
-VirtualScroll.propTypes = {
- 'aria-label': _react.PropTypes.string,
-
- /**
- * Removes fixed height from the scrollingContainer so that the total height
- * of rows can stretch the window. Intended for use with WindowScroller
- */
- autoHeight: _react.PropTypes.bool,
-
- /** Optional CSS class name */
- className: _react.PropTypes.string,
-
- /**
- * Used to estimate the total height of a VirtualScroll before all of its rows have actually been measured.
- * The estimated total height is adjusted as rows are rendered.
- */
- estimatedRowSize: _react.PropTypes.number.isRequired,
-
- /** Height constraint for list (determines how many actual rows are rendered) */
- height: _react.PropTypes.number.isRequired,
-
- /** Optional renderer to be used in place of rows when rowCount is 0 */
- noRowsRenderer: _react.PropTypes.func.isRequired,
-
- /**
- * Callback invoked with information about the slice of rows that were just rendered.
- * ({ startIndex, stopIndex }): void
- */
- onRowsRendered: _react.PropTypes.func.isRequired,
-
- /**
- * Number of rows to render above/below the visible bounds of the list.
- * These rows can help for smoother scrolling on touch devices.
- */
- overscanRowCount: _react.PropTypes.number.isRequired,
-
- /**
- * Callback invoked whenever the scroll offset changes within the inner scrollable region.
- * This callback can be used to sync scrolling between lists, tables, or grids.
- * ({ clientHeight, scrollHeight, scrollTop }): void
- */
- onScroll: _react.PropTypes.func.isRequired,
-
- /**
- * Either a fixed row height (number) or a function that returns the height of a row given its index.
- * ({ index: number }): number
- */
- rowHeight: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.func]).isRequired,
-
- /** Responsbile for rendering a row given an index; ({ index: number }): node */
- rowRenderer: _react.PropTypes.func.isRequired,
-
- /** Optional custom CSS class for individual rows */
- rowClassName: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]),
-
- /** Number of rows in list. */
- rowCount: _react.PropTypes.number.isRequired,
-
- /** Optional custom styles for individual cells */
- rowStyle: _react.PropTypes.oneOfType([_react.PropTypes.object, _react.PropTypes.func]),
-
- /** See Grid#scrollToAlignment */
- scrollToAlignment: _react.PropTypes.oneOf(['auto', 'end', 'start', 'center']).isRequired,
-
- /** Row index to ensure visible (by forcefully scrolling if necessary) */
- scrollToIndex: _react.PropTypes.number,
-
- /** Vertical offset. */
- scrollTop: _react.PropTypes.number,
-
- /** Optional inline style */
- style: _react.PropTypes.object,
-
- /** Tab index for focus */
- tabIndex: _react.PropTypes.number,
-
- /** Width of list */
- width: _react.PropTypes.number.isRequired
-};
-VirtualScroll.defaultProps = {
- estimatedRowSize: 30,
- noRowsRenderer: function noRowsRenderer() {
- return null;
- },
- onRowsRendered: function onRowsRendered() {
- return null;
- },
- onScroll: function onScroll() {
- return null;
- },
- overscanRowCount: 10,
- scrollToAlignment: 'auto',
- style: {}
-};
-exports.default = VirtualScroll;
-},{"../Grid":62,"classnames":undefined,"react":undefined,"react-addons-shallow-compare":30}],73:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.VirtualScroll = exports.default = undefined;
-
-var _VirtualScroll2 = require('./VirtualScroll');
-
-var _VirtualScroll3 = _interopRequireDefault(_VirtualScroll2);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _VirtualScroll3.default;
-exports.VirtualScroll = _VirtualScroll3.default;
-},{"./VirtualScroll":72}],74:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = require('react-dom');
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
-
-var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
-
-var _raf = require('raf');
-
-var _raf2 = _interopRequireDefault(_raf);
-
-var _onScroll = require('./utils/onScroll');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var WindowScroller = function (_Component) {
- _inherits(WindowScroller, _Component);
-
- function WindowScroller(props) {
- _classCallCheck(this, WindowScroller);
-
- var _this = _possibleConstructorReturn(this, (WindowScroller.__proto__ || Object.getPrototypeOf(WindowScroller)).call(this, props));
-
- var height = typeof window !== 'undefined' ? window.innerHeight : 0;
-
- _this.state = {
- isScrolling: false,
- height: height,
- scrollTop: 0
- };
-
- _this._onScrollWindow = _this._onScrollWindow.bind(_this);
- _this._onResizeWindow = _this._onResizeWindow.bind(_this);
- _this._enablePointerEventsAfterDelayCallback = _this._enablePointerEventsAfterDelayCallback.bind(_this);
- return _this;
- }
-
- _createClass(WindowScroller, [{
- key: 'componentDidMount',
- value: function componentDidMount() {
- var height = this.state.height;
-
- // Subtract documentElement top to handle edge-case where a user is navigating back (history) from an already-scrolled bage.
- // In this case the body's top position will be a negative number and this element's top will be increased (by that amount).
-
- this._positionFromTop = _reactDom2.default.findDOMNode(this).getBoundingClientRect().top - document.documentElement.getBoundingClientRect().top;
-
- if (height !== window.innerHeight) {
- this.setState({
- height: window.innerHeight
- });
- }
-
- (0, _onScroll.registerScrollListener)(this);
- window.addEventListener('resize', this._onResizeWindow, false);
- }
- }, {
- key: 'componentWillUnmount',
- value: function componentWillUnmount() {
- (0, _onScroll.unregisterScrollListener)(this);
-
- window.removeEventListener('resize', this._onResizeWindow, false);
- }
-
- /**
- * Updates the state during the next animation frame.
- * Use this method to avoid multiple renders in a small span of time.
- * This helps performance for bursty events (like onScroll).
- */
-
- }, {
- key: '_setNextState',
- value: function _setNextState(state) {
- var _this2 = this;
-
- if (this._setNextStateAnimationFrameId) {
- _raf2.default.cancel(this._setNextStateAnimationFrameId);
- }
-
- this._setNextStateAnimationFrameId = (0, _raf2.default)(function () {
- _this2._setNextStateAnimationFrameId = null;
- _this2.setState(state);
- });
- }
- }, {
- key: 'render',
- value: function render() {
- var children = this.props.children;
- var _state = this.state;
- var isScrolling = _state.isScrolling;
- var scrollTop = _state.scrollTop;
- var height = _state.height;
-
-
- return _react2.default.createElement(
- 'div',
- null,
- children({
- height: height,
- isScrolling: isScrolling,
- scrollTop: scrollTop
- })
- );
- }
- }, {
- key: 'shouldComponentUpdate',
- value: function shouldComponentUpdate(nextProps, nextState) {
- return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
- }
- }, {
- key: '_enablePointerEventsAfterDelayCallback',
- value: function _enablePointerEventsAfterDelayCallback() {
- this.setState({
- isScrolling: false
- });
- }
- }, {
- key: '_onResizeWindow',
- value: function _onResizeWindow(event) {
- var onResize = this.props.onResize;
-
-
- var height = window.innerHeight || 0;
-
- this.setState({ height: height });
-
- onResize({ height: height });
- }
- }, {
- key: '_onScrollWindow',
- value: function _onScrollWindow(event) {
- var onScroll = this.props.onScroll;
-
- // In IE10+ scrollY is undefined, so we replace that with the latter
-
- var scrollY = 'scrollY' in window ? window.scrollY : document.documentElement.scrollTop;
-
- var scrollTop = Math.max(0, scrollY - this._positionFromTop);
-
- var state = {
- isScrolling: true,
- scrollTop: scrollTop
- };
-
- if (!this.state.isScrolling) {
- this.setState(state);
- } else {
- this._setNextState(state);
- }
-
- onScroll({ scrollTop: scrollTop });
- }
- }]);
-
- return WindowScroller;
-}(_react.Component);
-
-WindowScroller.propTypes = {
- /**
- * Function respondible for rendering children.
- * This function should implement the following signature:
- * ({ height, scrollTop }) => PropTypes.element
- */
- children: _react.PropTypes.func.isRequired,
-
- /** Callback to be invoked on-resize: ({ height }) */
- onResize: _react.PropTypes.func.isRequired,
-
- /** Callback to be invoked on-scroll: ({ scrollTop }) */
- onScroll: _react.PropTypes.func.isRequired
-};
-WindowScroller.defaultProps = {
- onResize: function onResize() {},
- onScroll: function onScroll() {}
-};
-exports.default = WindowScroller;
-},{"./utils/onScroll":76,"raf":29,"react":undefined,"react-addons-shallow-compare":30,"react-dom":undefined}],75:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.IS_SCROLLING_TIMEOUT = exports.WindowScroller = exports.default = undefined;
-
-var _WindowScroller2 = require('./WindowScroller');
-
-var _WindowScroller3 = _interopRequireDefault(_WindowScroller2);
-
-var _onScroll = require('./utils/onScroll');
-
-var _onScroll2 = _interopRequireDefault(_onScroll);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _WindowScroller3.default;
-exports.WindowScroller = _WindowScroller3.default;
-exports.IS_SCROLLING_TIMEOUT = _onScroll2.default;
-},{"./WindowScroller":74,"./utils/onScroll":76}],76:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.registerScrollListener = registerScrollListener;
-exports.unregisterScrollListener = unregisterScrollListener;
-var mountedInstances = [];
-var originalBodyPointerEvents = null;
-var disablePointerEventsTimeoutId = null;
-
-/**
- * Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress.
- * This improves performance and makes scrolling smoother.
- */
-var IS_SCROLLING_TIMEOUT = exports.IS_SCROLLING_TIMEOUT = 150;
-
-function enablePointerEventsIfDisabled() {
- if (disablePointerEventsTimeoutId) {
- disablePointerEventsTimeoutId = null;
-
- document.body.style.pointerEvents = originalBodyPointerEvents;
-
- originalBodyPointerEvents = null;
- }
-}
-
-function enablePointerEventsAfterDelayCallback() {
- enablePointerEventsIfDisabled();
- mountedInstances.forEach(function (component) {
- return component._enablePointerEventsAfterDelayCallback();
- });
-}
-
-function enablePointerEventsAfterDelay() {
- if (disablePointerEventsTimeoutId) {
- clearTimeout(disablePointerEventsTimeoutId);
- }
-
- disablePointerEventsTimeoutId = setTimeout(enablePointerEventsAfterDelayCallback, IS_SCROLLING_TIMEOUT);
-}
-
-function onScrollWindow(event) {
- if (originalBodyPointerEvents == null) {
- originalBodyPointerEvents = document.body.style.pointerEvents;
-
- document.body.style.pointerEvents = 'none';
-
- enablePointerEventsAfterDelay();
- }
- mountedInstances.forEach(function (component) {
- return component._onScrollWindow(event);
- });
-}
-
-function registerScrollListener(component) {
- if (!mountedInstances.length) {
- window.addEventListener('scroll', onScrollWindow);
- }
- mountedInstances.push(component);
-}
-
-function unregisterScrollListener(component) {
- mountedInstances = mountedInstances.filter(function (c) {
- return c !== component;
- });
- if (!mountedInstances.length) {
- window.removeEventListener('scroll', onScrollWindow);
- if (disablePointerEventsTimeoutId) {
- clearTimeout(disablePointerEventsTimeoutId);
- enablePointerEventsIfDisabled();
- }
- }
-}
-},{}],77:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _ArrowKeyStepper = require('./ArrowKeyStepper');
-
-Object.defineProperty(exports, 'ArrowKeyStepper', {
- enumerable: true,
- get: function get() {
- return _ArrowKeyStepper.ArrowKeyStepper;
- }
-});
-
-var _AutoSizer = require('./AutoSizer');
-
-Object.defineProperty(exports, 'AutoSizer', {
- enumerable: true,
- get: function get() {
- return _AutoSizer.AutoSizer;
- }
-});
-
-var _CellMeasurer = require('./CellMeasurer');
-
-Object.defineProperty(exports, 'CellMeasurer', {
- enumerable: true,
- get: function get() {
- return _CellMeasurer.CellMeasurer;
- }
-});
-Object.defineProperty(exports, 'defaultCellMeasurerCellSizeCache', {
- enumerable: true,
- get: function get() {
- return _CellMeasurer.defaultCellSizeCache;
- }
-});
-Object.defineProperty(exports, 'uniformSizeCellMeasurerCellSizeCache', {
- enumerable: true,
- get: function get() {
- return _CellMeasurer.defaultCellSizeCache;
- }
-});
-
-var _Collection = require('./Collection');
-
-Object.defineProperty(exports, 'Collection', {
- enumerable: true,
- get: function get() {
- return _Collection.Collection;
- }
-});
-
-var _ColumnSizer = require('./ColumnSizer');
-
-Object.defineProperty(exports, 'ColumnSizer', {
- enumerable: true,
- get: function get() {
- return _ColumnSizer.ColumnSizer;
- }
-});
-
-var _FlexTable = require('./FlexTable');
-
-Object.defineProperty(exports, 'defaultFlexTableCellDataGetter', {
- enumerable: true,
- get: function get() {
- return _FlexTable.defaultCellDataGetter;
- }
-});
-Object.defineProperty(exports, 'defaultFlexTableCellRenderer', {
- enumerable: true,
- get: function get() {
- return _FlexTable.defaultCellRenderer;
- }
-});
-Object.defineProperty(exports, 'defaultFlexTableHeaderRenderer', {
- enumerable: true,
- get: function get() {
- return _FlexTable.defaultHeaderRenderer;
- }
-});
-Object.defineProperty(exports, 'defaultFlexTableRowRenderer', {
- enumerable: true,
- get: function get() {
- return _FlexTable.defaultRowRenderer;
- }
-});
-Object.defineProperty(exports, 'FlexTable', {
- enumerable: true,
- get: function get() {
- return _FlexTable.FlexTable;
- }
-});
-Object.defineProperty(exports, 'FlexColumn', {
- enumerable: true,
- get: function get() {
- return _FlexTable.FlexColumn;
- }
-});
-Object.defineProperty(exports, 'SortDirection', {
- enumerable: true,
- get: function get() {
- return _FlexTable.SortDirection;
- }
-});
-Object.defineProperty(exports, 'SortIndicator', {
- enumerable: true,
- get: function get() {
- return _FlexTable.SortIndicator;
- }
-});
-
-var _Grid = require('./Grid');
-
-Object.defineProperty(exports, 'defaultCellRangeRenderer', {
- enumerable: true,
- get: function get() {
- return _Grid.defaultCellRangeRenderer;
- }
-});
-Object.defineProperty(exports, 'Grid', {
- enumerable: true,
- get: function get() {
- return _Grid.Grid;
- }
-});
-
-var _InfiniteLoader = require('./InfiniteLoader');
-
-Object.defineProperty(exports, 'InfiniteLoader', {
- enumerable: true,
- get: function get() {
- return _InfiniteLoader.InfiniteLoader;
- }
-});
-
-var _ScrollSync = require('./ScrollSync');
-
-Object.defineProperty(exports, 'ScrollSync', {
- enumerable: true,
- get: function get() {
- return _ScrollSync.ScrollSync;
- }
-});
-
-var _VirtualScroll = require('./VirtualScroll');
-
-Object.defineProperty(exports, 'VirtualScroll', {
- enumerable: true,
- get: function get() {
- return _VirtualScroll.VirtualScroll;
- }
-});
-
-var _WindowScroller = require('./WindowScroller');
-
-Object.defineProperty(exports, 'WindowScroller', {
- enumerable: true,
- get: function get() {
- return _WindowScroller.WindowScroller;
- }
-});
-},{"./ArrowKeyStepper":37,"./AutoSizer":39,"./CellMeasurer":42,"./Collection":47,"./ColumnSizer":50,"./FlexTable":59,"./Grid":62,"./InfiniteLoader":69,"./ScrollSync":71,"./VirtualScroll":73,"./WindowScroller":75}],78:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = createCallbackMemoizer;
-/**
- * Helper utility that updates the specified callback whenever any of the specified indices have changed.
- */
-function createCallbackMemoizer() {
- var requireAllKeys = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
-
- var cachedIndices = {};
-
- return function (_ref) {
- var callback = _ref.callback;
- var indices = _ref.indices;
-
- var keys = Object.keys(indices);
- var allInitialized = !requireAllKeys || keys.every(function (key) {
- var value = indices[key];
- return Array.isArray(value) ? value.length > 0 : value >= 0;
- });
- var indexChanged = keys.length !== Object.keys(cachedIndices).length || keys.some(function (key) {
- var cachedValue = cachedIndices[key];
- var value = indices[key];
-
- return Array.isArray(value) ? cachedValue.join(',') !== value.join(',') : cachedValue !== value;
- });
-
- cachedIndices = indices;
-
- if (allInitialized && indexChanged) {
- callback(indices);
- }
- };
-}
-},{}],79:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.default = getUpdatedOffsetForIndex;
-/**
- * Determines a new offset that ensures a certain cell is visible, given the current offset.
- * If the cell is already visible then the current offset will be returned.
- * If the current offset is too great or small, it will be adjusted just enough to ensure the specified index is visible.
- *
- * @param align Desired alignment within container; one of "auto" (default), "start", or "end"
- * @param cellOffset Offset (x or y) position for cell
- * @param cellSize Size (width or height) of cell
- * @param containerSize Total size (width or height) of the container
- * @param currentOffset Container's current (x or y) offset
- * @return Offset to use to ensure the specified cell is visible
- */
-function getUpdatedOffsetForIndex(_ref) {
- var _ref$align = _ref.align;
- var align = _ref$align === undefined ? 'auto' : _ref$align;
- var cellOffset = _ref.cellOffset;
- var cellSize = _ref.cellSize;
- var containerSize = _ref.containerSize;
- var currentOffset = _ref.currentOffset;
-
- var maxOffset = cellOffset;
- var minOffset = maxOffset - containerSize + cellSize;
-
- switch (align) {
- case 'start':
- return maxOffset;
- case 'end':
- return minOffset;
- case 'center':
- return maxOffset - (containerSize - cellSize) / 2;
- default:
- return Math.max(minOffset, Math.min(maxOffset, currentOffset));
- }
-}
-},{}],80:[function(require,module,exports){
-'use strict';
-
-/**
-* Detect Element Resize.
-* Forked in order to guard against unsafe 'window' and 'document' references.
-*
-* https://github.com/sdecima/javascript-detect-element-resize
-* Sebastian Decima
-*
-* version: 0.5.3
-**/
-
-// Check `document` and `window` in case of server-side rendering
-var _window;
-if (typeof window !== 'undefined') {
- _window = window;
-} else if (typeof self !== 'undefined') {
- _window = self;
-} else {
- _window = undefined;
-}
-
-var attachEvent = typeof document !== 'undefined' && document.attachEvent;
-var stylesCreated = false;
-
-if (!attachEvent) {
- var requestFrame = function () {
- var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame || function (fn) {
- return _window.setTimeout(fn, 20);
- };
- return function (fn) {
- return raf(fn);
- };
- }();
-
- var cancelFrame = function () {
- var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame || _window.clearTimeout;
- return function (id) {
- return cancel(id);
- };
- }();
-
- var resetTriggers = function resetTriggers(element) {
- var triggers = element.__resizeTriggers__,
- expand = triggers.firstElementChild,
- contract = triggers.lastElementChild,
- expandChild = expand.firstElementChild;
- contract.scrollLeft = contract.scrollWidth;
- contract.scrollTop = contract.scrollHeight;
- expandChild.style.width = expand.offsetWidth + 1 + 'px';
- expandChild.style.height = expand.offsetHeight + 1 + 'px';
- expand.scrollLeft = expand.scrollWidth;
- expand.scrollTop = expand.scrollHeight;
- };
-
- var checkTriggers = function checkTriggers(element) {
- return element.offsetWidth != element.__resizeLast__.width || element.offsetHeight != element.__resizeLast__.height;
- };
-
- var scrollListener = function scrollListener(e) {
- var element = this;
- resetTriggers(this);
- if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
- this.__resizeRAF__ = requestFrame(function () {
- if (checkTriggers(element)) {
- element.__resizeLast__.width = element.offsetWidth;
- element.__resizeLast__.height = element.offsetHeight;
- element.__resizeListeners__.forEach(function (fn) {
- fn.call(element, e);
- });
- }
- });
- };
-
- /* Detect CSS Animations support to detect element display/re-attach */
- var animation = false,
- animationstring = 'animation',
- keyframeprefix = '',
- animationstartevent = 'animationstart',
- domPrefixes = 'Webkit Moz O ms'.split(' '),
- startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
- pfx = '';
- {
- var elm = document.createElement('fakeelement');
- if (elm.style.animationName !== undefined) {
- animation = true;
- }
-
- if (animation === false) {
- for (var i = 0; i < domPrefixes.length; i++) {
- if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
- pfx = domPrefixes[i];
- animationstring = pfx + 'Animation';
- keyframeprefix = '-' + pfx.toLowerCase() + '-';
- animationstartevent = startEvents[i];
- animation = true;
- break;
- }
- }
- }
- }
-
- var animationName = 'resizeanim';
- var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
- var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
-}
-
-var createStyles = function createStyles() {
- if (!stylesCreated) {
- //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
- var css = (animationKeyframes ? animationKeyframes : '') + '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' + '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
- head = document.head || document.getElementsByTagName('head')[0],
- style = document.createElement('style');
-
- style.type = 'text/css';
- if (style.styleSheet) {
- style.styleSheet.cssText = css;
- } else {
- style.appendChild(document.createTextNode(css));
- }
-
- head.appendChild(style);
- stylesCreated = true;
- }
-};
-
-var addResizeListener = function addResizeListener(element, fn) {
- if (attachEvent) element.attachEvent('onresize', fn);else {
- if (!element.__resizeTriggers__) {
- if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
- createStyles();
- element.__resizeLast__ = {};
- element.__resizeListeners__ = [];
- (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
- element.__resizeTriggers__.innerHTML = '' + '
';
- element.appendChild(element.__resizeTriggers__);
- resetTriggers(element);
- element.addEventListener('scroll', scrollListener, true);
-
- /* Listen for a css animation to detect element display/re-attach */
- animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function (e) {
- if (e.animationName == animationName) resetTriggers(element);
- });
- }
- element.__resizeListeners__.push(fn);
- }
-};
-
-var removeResizeListener = function removeResizeListener(element, fn) {
- if (attachEvent) element.detachEvent('onresize', fn);else {
- element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
- if (!element.__resizeListeners__.length) {
- element.removeEventListener('scroll', scrollListener, true);
- element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
- }
- }
-};
-
-module.exports = {
- addResizeListener: addResizeListener,
- removeResizeListener: removeResizeListener
-};
-},{}],81:[function(require,module,exports){
-/**
- * Copyright 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-'use strict';
-
-var shallowEqual = require('fbjs/lib/shallowEqual');
-
-/**
- * Does a shallow comparison for props and state.
- * See ReactComponentWithPureRenderMixin
- * See also https://facebook.github.io/react/docs/shallow-compare.html
- */
-function shallowCompare(instance, nextProps, nextState) {
- return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
-}
-
-module.exports = shallowCompare;
-},{"fbjs/lib/shallowEqual":20}],82:[function(require,module,exports){
-'use strict';
-module.exports = function (str) {
- return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
- return '%' + c.charCodeAt(0).toString(16).toUpperCase();
- });
-};
-
-},{}],83:[function(require,module,exports){
-(function(self) {
- 'use strict';
-
- if (self.fetch) {
- return
- }
-
- var support = {
- searchParams: 'URLSearchParams' in self,
- iterable: 'Symbol' in self && 'iterator' in Symbol,
- blob: 'FileReader' in self && 'Blob' in self && (function() {
- try {
- new Blob()
- return true
- } catch(e) {
- return false
- }
- })(),
- formData: 'FormData' in self,
- arrayBuffer: 'ArrayBuffer' in self
- }
-
- if (support.arrayBuffer) {
- var viewClasses = [
- '[object Int8Array]',
- '[object Uint8Array]',
- '[object Uint8ClampedArray]',
- '[object Int16Array]',
- '[object Uint16Array]',
- '[object Int32Array]',
- '[object Uint32Array]',
- '[object Float32Array]',
- '[object Float64Array]'
- ]
-
- var isDataView = function(obj) {
- return obj && DataView.prototype.isPrototypeOf(obj)
- }
-
- var isArrayBufferView = ArrayBuffer.isView || function(obj) {
- return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
- }
- }
-
- function normalizeName(name) {
- if (typeof name !== 'string') {
- name = String(name)
- }
- if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
- throw new TypeError('Invalid character in header field name')
- }
- return name.toLowerCase()
- }
-
- function normalizeValue(value) {
- if (typeof value !== 'string') {
- value = String(value)
- }
- return value
- }
-
- // Build a destructive iterator for the value list
- function iteratorFor(items) {
- var iterator = {
- next: function() {
- var value = items.shift()
- return {done: value === undefined, value: value}
- }
- }
-
- if (support.iterable) {
- iterator[Symbol.iterator] = function() {
- return iterator
- }
- }
-
- return iterator
- }
-
- function Headers(headers) {
- this.map = {}
-
- if (headers instanceof Headers) {
- headers.forEach(function(value, name) {
- this.append(name, value)
- }, this)
-
- } else if (headers) {
- Object.getOwnPropertyNames(headers).forEach(function(name) {
- this.append(name, headers[name])
- }, this)
- }
- }
-
- Headers.prototype.append = function(name, value) {
- name = normalizeName(name)
- value = normalizeValue(value)
- var oldValue = this.map[name]
- this.map[name] = oldValue ? oldValue+','+value : value
- }
-
- Headers.prototype['delete'] = function(name) {
- delete this.map[normalizeName(name)]
- }
-
- Headers.prototype.get = function(name) {
- name = normalizeName(name)
- return this.has(name) ? this.map[name] : null
- }
-
- Headers.prototype.has = function(name) {
- return this.map.hasOwnProperty(normalizeName(name))
- }
-
- Headers.prototype.set = function(name, value) {
- this.map[normalizeName(name)] = normalizeValue(value)
- }
-
- Headers.prototype.forEach = function(callback, thisArg) {
- for (var name in this.map) {
- if (this.map.hasOwnProperty(name)) {
- callback.call(thisArg, this.map[name], name, this)
- }
- }
- }
-
- Headers.prototype.keys = function() {
- var items = []
- this.forEach(function(value, name) { items.push(name) })
- return iteratorFor(items)
- }
-
- Headers.prototype.values = function() {
- var items = []
- this.forEach(function(value) { items.push(value) })
- return iteratorFor(items)
- }
-
- Headers.prototype.entries = function() {
- var items = []
- this.forEach(function(value, name) { items.push([name, value]) })
- return iteratorFor(items)
- }
-
- if (support.iterable) {
- Headers.prototype[Symbol.iterator] = Headers.prototype.entries
- }
-
- function consumed(body) {
- if (body.bodyUsed) {
- return Promise.reject(new TypeError('Already read'))
- }
- body.bodyUsed = true
- }
-
- function fileReaderReady(reader) {
- return new Promise(function(resolve, reject) {
- reader.onload = function() {
- resolve(reader.result)
- }
- reader.onerror = function() {
- reject(reader.error)
- }
- })
- }
-
- function readBlobAsArrayBuffer(blob) {
- var reader = new FileReader()
- var promise = fileReaderReady(reader)
- reader.readAsArrayBuffer(blob)
- return promise
- }
-
- function readBlobAsText(blob) {
- var reader = new FileReader()
- var promise = fileReaderReady(reader)
- reader.readAsText(blob)
- return promise
- }
-
- function readArrayBufferAsText(buf) {
- var view = new Uint8Array(buf)
- var chars = new Array(view.length)
-
- for (var i = 0; i < view.length; i++) {
- chars[i] = String.fromCharCode(view[i])
- }
- return chars.join('')
- }
-
- function bufferClone(buf) {
- if (buf.slice) {
- return buf.slice(0)
- } else {
- var view = new Uint8Array(buf.byteLength)
- view.set(new Uint8Array(buf))
- return view.buffer
- }
- }
-
- function Body() {
- this.bodyUsed = false
-
- this._initBody = function(body) {
- this._bodyInit = body
- if (!body) {
- this._bodyText = ''
- } else if (typeof body === 'string') {
- this._bodyText = body
- } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
- this._bodyBlob = body
- } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
- this._bodyFormData = body
- } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
- this._bodyText = body.toString()
- } else if (support.arrayBuffer && support.blob && isDataView(body)) {
- this._bodyArrayBuffer = bufferClone(body.buffer)
- // IE 10-11 can't handle a DataView body.
- this._bodyInit = new Blob([this._bodyArrayBuffer])
- } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
- this._bodyArrayBuffer = bufferClone(body)
- } else {
- throw new Error('unsupported BodyInit type')
- }
-
- if (!this.headers.get('content-type')) {
- if (typeof body === 'string') {
- this.headers.set('content-type', 'text/plain;charset=UTF-8')
- } else if (this._bodyBlob && this._bodyBlob.type) {
- this.headers.set('content-type', this._bodyBlob.type)
- } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
- this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
- }
- }
- }
-
- if (support.blob) {
- this.blob = function() {
- var rejected = consumed(this)
- if (rejected) {
- return rejected
- }
-
- if (this._bodyBlob) {
- return Promise.resolve(this._bodyBlob)
- } else if (this._bodyArrayBuffer) {
- return Promise.resolve(new Blob([this._bodyArrayBuffer]))
- } else if (this._bodyFormData) {
- throw new Error('could not read FormData body as blob')
- } else {
- return Promise.resolve(new Blob([this._bodyText]))
- }
- }
-
- this.arrayBuffer = function() {
- if (this._bodyArrayBuffer) {
- return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
- } else {
- return this.blob().then(readBlobAsArrayBuffer)
- }
- }
- }
-
- this.text = function() {
- var rejected = consumed(this)
- if (rejected) {
- return rejected
- }
-
- if (this._bodyBlob) {
- return readBlobAsText(this._bodyBlob)
- } else if (this._bodyArrayBuffer) {
- return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
- } else if (this._bodyFormData) {
- throw new Error('could not read FormData body as text')
- } else {
- return Promise.resolve(this._bodyText)
- }
- }
-
- if (support.formData) {
- this.formData = function() {
- return this.text().then(decode)
- }
- }
-
- this.json = function() {
- return this.text().then(JSON.parse)
- }
-
- return this
- }
-
- // HTTP methods whose capitalization should be normalized
- var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
-
- function normalizeMethod(method) {
- var upcased = method.toUpperCase()
- return (methods.indexOf(upcased) > -1) ? upcased : method
- }
-
- function Request(input, options) {
- options = options || {}
- var body = options.body
-
- if (input instanceof Request) {
- if (input.bodyUsed) {
- throw new TypeError('Already read')
- }
- this.url = input.url
- this.credentials = input.credentials
- if (!options.headers) {
- this.headers = new Headers(input.headers)
- }
- this.method = input.method
- this.mode = input.mode
- if (!body && input._bodyInit != null) {
- body = input._bodyInit
- input.bodyUsed = true
- }
- } else {
- this.url = String(input)
- }
-
- this.credentials = options.credentials || this.credentials || 'omit'
- if (options.headers || !this.headers) {
- this.headers = new Headers(options.headers)
- }
- this.method = normalizeMethod(options.method || this.method || 'GET')
- this.mode = options.mode || this.mode || null
- this.referrer = null
-
- if ((this.method === 'GET' || this.method === 'HEAD') && body) {
- throw new TypeError('Body not allowed for GET or HEAD requests')
- }
- this._initBody(body)
- }
-
- Request.prototype.clone = function() {
- return new Request(this, { body: this._bodyInit })
- }
-
- function decode(body) {
- var form = new FormData()
- body.trim().split('&').forEach(function(bytes) {
- if (bytes) {
- var split = bytes.split('=')
- var name = split.shift().replace(/\+/g, ' ')
- var value = split.join('=').replace(/\+/g, ' ')
- form.append(decodeURIComponent(name), decodeURIComponent(value))
- }
- })
- return form
- }
-
- function parseHeaders(rawHeaders) {
- var headers = new Headers()
- rawHeaders.split(/\r?\n/).forEach(function(line) {
- var parts = line.split(':')
- var key = parts.shift().trim()
- if (key) {
- var value = parts.join(':').trim()
- headers.append(key, value)
- }
- })
- return headers
- }
-
- Body.call(Request.prototype)
-
- function Response(bodyInit, options) {
- if (!options) {
- options = {}
- }
-
- this.type = 'default'
- this.status = 'status' in options ? options.status : 200
- this.ok = this.status >= 200 && this.status < 300
- this.statusText = 'statusText' in options ? options.statusText : 'OK'
- this.headers = new Headers(options.headers)
- this.url = options.url || ''
- this._initBody(bodyInit)
- }
-
- Body.call(Response.prototype)
-
- Response.prototype.clone = function() {
- return new Response(this._bodyInit, {
- status: this.status,
- statusText: this.statusText,
- headers: new Headers(this.headers),
- url: this.url
- })
- }
-
- Response.error = function() {
- var response = new Response(null, {status: 0, statusText: ''})
- response.type = 'error'
- return response
- }
-
- var redirectStatuses = [301, 302, 303, 307, 308]
-
- Response.redirect = function(url, status) {
- if (redirectStatuses.indexOf(status) === -1) {
- throw new RangeError('Invalid status code')
- }
-
- return new Response(null, {status: status, headers: {location: url}})
- }
-
- self.Headers = Headers
- self.Request = Request
- self.Response = Response
-
- self.fetch = function(input, init) {
- return new Promise(function(resolve, reject) {
- var request = new Request(input, init)
- var xhr = new XMLHttpRequest()
-
- xhr.onload = function() {
- var options = {
- status: xhr.status,
- statusText: xhr.statusText,
- headers: parseHeaders(xhr.getAllResponseHeaders() || '')
- }
- options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
- var body = 'response' in xhr ? xhr.response : xhr.responseText
- resolve(new Response(body, options))
- }
-
- xhr.onerror = function() {
- reject(new TypeError('Network request failed'))
- }
-
- xhr.ontimeout = function() {
- reject(new TypeError('Network request failed'))
- }
-
- xhr.open(request.method, request.url, true)
-
- if (request.credentials === 'include') {
- xhr.withCredentials = true
- }
-
- if ('responseType' in xhr && support.blob) {
- xhr.responseType = 'blob'
- }
-
- request.headers.forEach(function(value, name) {
- xhr.setRequestHeader(name, value)
- })
-
- xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
- })
- }
- self.fetch.polyfill = true
-})(typeof self !== 'undefined' ? self : this);
-
-},{}]},{},[1]);
diff --git a/examples/dist/bundle.js b/examples/dist/bundle.js
deleted file mode 100644
index e437b98604..0000000000
--- a/examples/dist/bundle.js
+++ /dev/null
@@ -1,2263 +0,0 @@
-require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o _this3.props.value.length) {
- _this3.clearOptions();
- }
- _this3.props.onChange(newValues);
- }
- };
-
- return children(_extends({}, this.props, props, {
- isLoading: isLoading,
- onInputChange: this._onInputChange
- }));
- }
- }]);
-
- return Async;
-})(_react.Component);
-
-exports['default'] = Async;
-
-Async.propTypes = propTypes;
-Async.defaultProps = defaultProps;
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-module.exports = exports['default'];
-
-},{"./Select":"react-select","./utils/stripDiacritics":10,"react":undefined}],2:[function(require,module,exports){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-function reduce(obj) {
- var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
- return Object.keys(obj).reduce(function (props, key) {
- var value = obj[key];
- if (value !== undefined) props[key] = value;
- return props;
- }, props);
-}
-
-var AsyncCreatable = _react2['default'].createClass({
- displayName: 'AsyncCreatableSelect',
-
- render: function render() {
- var _this = this;
-
- return _react2['default'].createElement(
- _Select2['default'].Async,
- this.props,
- function (asyncProps) {
- return _react2['default'].createElement(
- _Select2['default'].Creatable,
- _this.props,
- function (creatableProps) {
- return _react2['default'].createElement(_Select2['default'], _extends({}, reduce(asyncProps, reduce(creatableProps, {})), {
- onInputChange: function (input) {
- creatableProps.onInputChange(input);
- return asyncProps.onInputChange(input);
- },
- ref: function (ref) {
- creatableProps.ref(ref);
- asyncProps.ref(ref);
- }
- }));
- }
- );
- }
- );
- }
-});
-
-module.exports = AsyncCreatable;
-
-},{"./Select":"react-select","react":undefined}],3:[function(require,module,exports){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var Creatable = _react2['default'].createClass({
- displayName: 'CreatableSelect',
-
- propTypes: {
- // Child function responsible for creating the inner Select component
- // This component can be used to compose HOCs (eg Creatable and Async)
- // (props: Object): PropTypes.element
- children: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.filterOptions
- filterOptions: _react2['default'].PropTypes.any,
-
- // Searches for any matching option within the set of options.
- // This function prevents duplicate options from being created.
- // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean
- isOptionUnique: _react2['default'].PropTypes.func,
-
- // Determines if the current input text represents a valid option.
- // ({ label: string }): boolean
- isValidNewOption: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.menuRenderer
- menuRenderer: _react2['default'].PropTypes.any,
-
- // Factory to create new option.
- // ({ label: string, labelKey: string, valueKey: string }): Object
- newOptionCreator: _react2['default'].PropTypes.func,
-
- // input change handler: function (inputValue) {}
- onInputChange: _react2['default'].PropTypes.func,
-
- // input keyDown handler: function (event) {}
- onInputKeyDown: _react2['default'].PropTypes.func,
-
- // new option click handler: function (option) {}
- onNewOptionClick: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.options
- options: _react2['default'].PropTypes.array,
-
- // Creates prompt/placeholder option text.
- // (filterText: string): string
- promptTextCreator: _react2['default'].PropTypes.func,
-
- // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option.
- shouldKeyDownEventCreateNewOption: _react2['default'].PropTypes.func
- },
-
- // Default prop methods
- statics: {
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- },
-
- getDefaultProps: function getDefaultProps() {
- return {
- filterOptions: _utilsDefaultFilterOptions2['default'],
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- };
- },
-
- createNewOption: function createNewOption() {
- var _props = this.props;
- var isValidNewOption = _props.isValidNewOption;
- var newOptionCreator = _props.newOptionCreator;
- var onNewOptionClick = _props.onNewOptionClick;
- var _props$options = _props.options;
- var options = _props$options === undefined ? [] : _props$options;
- var shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption;
-
- if (isValidNewOption({ label: this.inputValue })) {
- var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey });
- var _isOptionUnique = this.isOptionUnique({ option: option });
-
- // Don't add the same option twice.
- if (_isOptionUnique) {
- if (onNewOptionClick) {
- onNewOptionClick(option);
- } else {
- options.unshift(option);
-
- this.select.selectValue(option);
- }
- }
- }
- },
-
- filterOptions: function filterOptions() {
- var _props2 = this.props;
- var filterOptions = _props2.filterOptions;
- var isValidNewOption = _props2.isValidNewOption;
- var options = _props2.options;
- var promptTextCreator = _props2.promptTextCreator;
-
- // TRICKY Check currently selected options as well.
- // Don't display a create-prompt for a value that's selected.
- // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array.
- var excludeOptions = arguments[2] || [];
-
- var filteredOptions = filterOptions.apply(undefined, arguments) || [];
-
- if (isValidNewOption({ label: this.inputValue })) {
- var _newOptionCreator = this.props.newOptionCreator;
-
- var option = _newOptionCreator({
- label: this.inputValue,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- // TRICKY Compare to all options (not just filtered options) in case option has already been selected).
- // For multi-selects, this would remove it from the filtered list.
- var _isOptionUnique2 = this.isOptionUnique({
- option: option,
- options: excludeOptions.concat(filteredOptions)
- });
-
- if (_isOptionUnique2) {
- var _prompt = promptTextCreator(this.inputValue);
-
- this._createPlaceholderOption = _newOptionCreator({
- label: _prompt,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- filteredOptions.unshift(this._createPlaceholderOption);
- }
- }
-
- return filteredOptions;
- },
-
- isOptionUnique: function isOptionUnique(_ref2) {
- var option = _ref2.option;
- var options = _ref2.options;
- var isOptionUnique = this.props.isOptionUnique;
-
- options = options || this.select.filterOptions();
-
- return isOptionUnique({
- labelKey: this.labelKey,
- option: option,
- options: options,
- valueKey: this.valueKey
- });
- },
-
- menuRenderer: function menuRenderer(params) {
- var menuRenderer = this.props.menuRenderer;
-
- return menuRenderer(_extends({}, params, {
- onSelect: this.onOptionSelect,
- selectValue: this.onOptionSelect
- }));
- },
-
- onInputChange: function onInputChange(input) {
- var onInputChange = this.props.onInputChange;
-
- if (onInputChange) {
- onInputChange(input);
- }
-
- // This value may be needed in between Select mounts (when this.select is null)
- this.inputValue = input;
- },
-
- onInputKeyDown: function onInputKeyDown(event) {
- var _props3 = this.props;
- var shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption;
- var onInputKeyDown = _props3.onInputKeyDown;
-
- var focusedOption = this.select.getFocusedOption();
-
- if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) {
- this.createNewOption();
-
- // Prevent decorated Select from doing anything additional with this keyDown event
- event.preventDefault();
- } else if (onInputKeyDown) {
- onInputKeyDown(event);
- }
- },
-
- onOptionSelect: function onOptionSelect(option, event) {
- if (option === this._createPlaceholderOption) {
- this.createNewOption();
- } else {
- this.select.selectValue(option);
- }
- },
-
- render: function render() {
- var _this = this;
-
- var _props4 = this.props;
- var newOptionCreator = _props4.newOptionCreator;
- var shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption;
-
- var restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']);
-
- var children = this.props.children;
-
- // We can't use destructuring default values to set the children,
- // because it won't apply work if `children` is null. A falsy check is
- // more reliable in real world use-cases.
- if (!children) {
- children = defaultChildren;
- }
-
- var props = _extends({}, restProps, {
- allowCreate: true,
- filterOptions: this.filterOptions,
- menuRenderer: this.menuRenderer,
- onInputChange: this.onInputChange,
- onInputKeyDown: this.onInputKeyDown,
- ref: function ref(_ref) {
- _this.select = _ref;
-
- // These values may be needed in between Select mounts (when this.select is null)
- if (_ref) {
- _this.labelKey = _ref.props.labelKey;
- _this.valueKey = _ref.props.valueKey;
- }
- }
- });
-
- return children(props);
- }
-});
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-
-function isOptionUnique(_ref3) {
- var option = _ref3.option;
- var options = _ref3.options;
- var labelKey = _ref3.labelKey;
- var valueKey = _ref3.valueKey;
-
- return options.filter(function (existingOption) {
- return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey];
- }).length === 0;
-};
-
-function isValidNewOption(_ref4) {
- var label = _ref4.label;
-
- return !!label;
-};
-
-function newOptionCreator(_ref5) {
- var label = _ref5.label;
- var labelKey = _ref5.labelKey;
- var valueKey = _ref5.valueKey;
-
- var option = {};
- option[valueKey] = label;
- option[labelKey] = label;
- option.className = 'Select-create-option-placeholder';
- return option;
-};
-
-function promptTextCreator(label) {
- return 'Create option "' + label + '"';
-}
-
-function shouldKeyDownEventCreateNewOption(_ref6) {
- var keyCode = _ref6.keyCode;
-
- switch (keyCode) {
- case 9: // TAB
- case 13: // ENTER
- case 188:
- // COMMA
- return true;
- }
-
- return false;
-};
-
-module.exports = Creatable;
-
-},{"./Select":"react-select","./utils/defaultFilterOptions":8,"./utils/defaultMenuRenderer":9,"react":undefined}],4:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Option = _react2['default'].createClass({
- displayName: 'Option',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- className: _react2['default'].PropTypes.string, // className (based on mouse position)
- instancePrefix: _react2['default'].PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
- isDisabled: _react2['default'].PropTypes.bool, // the option is disabled
- isFocused: _react2['default'].PropTypes.bool, // the option is focused
- isSelected: _react2['default'].PropTypes.bool, // the option is selected
- onFocus: _react2['default'].PropTypes.func, // method to handle mouseEnter on option element
- onSelect: _react2['default'].PropTypes.func, // method to handle click on option element
- onUnfocus: _react2['default'].PropTypes.func, // method to handle mouseLeave on option element
- option: _react2['default'].PropTypes.object.isRequired, // object that is base for that option
- optionIndex: _react2['default'].PropTypes.number },
- // index of the option, used to generate unique ids for aria
- blockEvent: function blockEvent(event) {
- event.preventDefault();
- event.stopPropagation();
- if (event.target.tagName !== 'A' || !('href' in event.target)) {
- return;
- }
- if (event.target.target) {
- window.open(event.target.href, event.target.target);
- } else {
- window.location.href = event.target.href;
- }
- },
-
- handleMouseDown: function handleMouseDown(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
-
- handleMouseEnter: function handleMouseEnter(event) {
- this.onFocus(event);
- },
-
- handleMouseMove: function handleMouseMove(event) {
- this.onFocus(event);
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- this.handleMouseDown(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- onFocus: function onFocus(event) {
- if (!this.props.isFocused) {
- this.props.onFocus(this.props.option, event);
- }
- },
- render: function render() {
- var _props = this.props;
- var option = _props.option;
- var instancePrefix = _props.instancePrefix;
- var optionIndex = _props.optionIndex;
-
- var className = (0, _classnames2['default'])(this.props.className, option.className);
-
- return option.disabled ? _react2['default'].createElement(
- 'div',
- { className: className,
- onMouseDown: this.blockEvent,
- onClick: this.blockEvent },
- this.props.children
- ) : _react2['default'].createElement(
- 'div',
- { className: className,
- style: option.style,
- role: 'option',
- onMouseDown: this.handleMouseDown,
- onMouseEnter: this.handleMouseEnter,
- onMouseMove: this.handleMouseMove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEnd,
- id: instancePrefix + '-option-' + optionIndex,
- title: option.title },
- this.props.children
- );
- }
-});
-
-module.exports = Option;
-
-},{"classnames":undefined,"react":undefined}],5:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Value = _react2['default'].createClass({
-
- displayName: 'Value',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- disabled: _react2['default'].PropTypes.bool, // disabled prop passed to ReactSelect
- id: _react2['default'].PropTypes.string, // Unique id for the value - used for aria
- onClick: _react2['default'].PropTypes.func, // method to handle click on value label
- onRemove: _react2['default'].PropTypes.func, // method to handle removal of the value
- value: _react2['default'].PropTypes.object.isRequired },
-
- // the option object for this value
- handleMouseDown: function handleMouseDown(event) {
- if (event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- if (this.props.onClick) {
- event.stopPropagation();
- this.props.onClick(this.props.value, event);
- return;
- }
- if (this.props.value.href) {
- event.stopPropagation();
- }
- },
-
- onRemove: function onRemove(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onRemove(this.props.value);
- },
-
- handleTouchEndRemove: function handleTouchEndRemove(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.onRemove(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- renderRemoveIcon: function renderRemoveIcon() {
- if (this.props.disabled || !this.props.onRemove) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-value-icon',
- 'aria-hidden': 'true',
- onMouseDown: this.onRemove,
- onTouchEnd: this.handleTouchEndRemove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove },
- '×'
- );
- },
-
- renderLabel: function renderLabel() {
- var className = 'Select-value-label';
- return this.props.onClick || this.props.value.href ? _react2['default'].createElement(
- 'a',
- { className: className, href: this.props.value.href, target: this.props.value.target, onMouseDown: this.handleMouseDown, onTouchEnd: this.handleMouseDown },
- this.props.children
- ) : _react2['default'].createElement(
- 'span',
- { className: className, role: 'option', 'aria-selected': 'true', id: this.props.id },
- this.props.children
- );
- },
-
- render: function render() {
- return _react2['default'].createElement(
- 'div',
- { className: (0, _classnames2['default'])('Select-value', this.props.value.className),
- style: this.props.value.style,
- title: this.props.value.title
- },
- this.renderRemoveIcon(),
- this.renderLabel()
- );
- }
-
-});
-
-module.exports = Value;
-
-},{"classnames":undefined,"react":undefined}],6:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports["default"] = arrowRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function arrowRenderer(_ref) {
- var onMouseDown = _ref.onMouseDown;
-
- return _react2["default"].createElement("span", {
- className: "Select-arrow",
- onMouseDown: onMouseDown
- });
-}
-
-;
-module.exports = exports["default"];
-
-},{"react":undefined}],7:[function(require,module,exports){
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-exports['default'] = clearRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function clearRenderer() {
- return _react2['default'].createElement('span', {
- className: 'Select-clear',
- dangerouslySetInnerHTML: { __html: '×' }
- });
-}
-
-;
-module.exports = exports['default'];
-
-},{"react":undefined}],8:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _stripDiacritics = require('./stripDiacritics');
-
-var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics);
-
-function filterOptions(options, filterValue, excludeOptions, props) {
- var _this = this;
-
- if (props.ignoreAccents) {
- filterValue = (0, _stripDiacritics2['default'])(filterValue);
- }
-
- if (props.ignoreCase) {
- filterValue = filterValue.toLowerCase();
- }
-
- if (excludeOptions) excludeOptions = excludeOptions.map(function (i) {
- return i[props.valueKey];
- });
-
- return options.filter(function (option) {
- if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false;
- if (props.filterOption) return props.filterOption.call(_this, option, filterValue);
- if (!filterValue) return true;
- var valueTest = String(option[props.valueKey]);
- var labelTest = String(option[props.labelKey]);
- if (props.ignoreAccents) {
- if (props.matchProp !== 'label') valueTest = (0, _stripDiacritics2['default'])(valueTest);
- if (props.matchProp !== 'value') labelTest = (0, _stripDiacritics2['default'])(labelTest);
- }
- if (props.ignoreCase) {
- if (props.matchProp !== 'label') valueTest = valueTest.toLowerCase();
- if (props.matchProp !== 'value') labelTest = labelTest.toLowerCase();
- }
- return props.matchPos === 'start' ? props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue || props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue : props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0 || props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0;
- });
-}
-
-module.exports = filterOptions;
-
-},{"./stripDiacritics":10}],9:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function menuRenderer(_ref) {
- var focusedOption = _ref.focusedOption;
- var instancePrefix = _ref.instancePrefix;
- var labelKey = _ref.labelKey;
- var onFocus = _ref.onFocus;
- var onSelect = _ref.onSelect;
- var optionClassName = _ref.optionClassName;
- var optionComponent = _ref.optionComponent;
- var optionRenderer = _ref.optionRenderer;
- var options = _ref.options;
- var valueArray = _ref.valueArray;
- var valueKey = _ref.valueKey;
- var onOptionRef = _ref.onOptionRef;
-
- var Option = optionComponent;
-
- return options.map(function (option, i) {
- var isSelected = valueArray && valueArray.indexOf(option) > -1;
- var isFocused = option === focusedOption;
- var optionClass = (0, _classnames2['default'])(optionClassName, {
- 'Select-option': true,
- 'is-selected': isSelected,
- 'is-focused': isFocused,
- 'is-disabled': option.disabled
- });
-
- return _react2['default'].createElement(
- Option,
- {
- className: optionClass,
- instancePrefix: instancePrefix,
- isDisabled: option.disabled,
- isFocused: isFocused,
- isSelected: isSelected,
- key: 'option-' + i + '-' + option[valueKey],
- onFocus: onFocus,
- onSelect: onSelect,
- option: option,
- optionIndex: i,
- ref: function (ref) {
- onOptionRef(ref, isFocused);
- }
- },
- optionRenderer(option, i)
- );
- });
-}
-
-module.exports = menuRenderer;
-
-},{"classnames":undefined,"react":undefined}],10:[function(require,module,exports){
-'use strict';
-
-var map = [{ 'base': 'A', 'letters': /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g }, { 'base': 'AA', 'letters': /[\uA732]/g }, { 'base': 'AE', 'letters': /[\u00C6\u01FC\u01E2]/g }, { 'base': 'AO', 'letters': /[\uA734]/g }, { 'base': 'AU', 'letters': /[\uA736]/g }, { 'base': 'AV', 'letters': /[\uA738\uA73A]/g }, { 'base': 'AY', 'letters': /[\uA73C]/g }, { 'base': 'B', 'letters': /[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g }, { 'base': 'C', 'letters': /[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g }, { 'base': 'D', 'letters': /[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g }, { 'base': 'DZ', 'letters': /[\u01F1\u01C4]/g }, { 'base': 'Dz', 'letters': /[\u01F2\u01C5]/g }, { 'base': 'E', 'letters': /[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g }, { 'base': 'F', 'letters': /[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g }, { 'base': 'G', 'letters': /[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g }, { 'base': 'H', 'letters': /[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g }, { 'base': 'I', 'letters': /[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g }, { 'base': 'J', 'letters': /[\u004A\u24BF\uFF2A\u0134\u0248]/g }, { 'base': 'K', 'letters': /[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g }, { 'base': 'L', 'letters': /[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g }, { 'base': 'LJ', 'letters': /[\u01C7]/g }, { 'base': 'Lj', 'letters': /[\u01C8]/g }, { 'base': 'M', 'letters': /[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g }, { 'base': 'N', 'letters': /[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g }, { 'base': 'NJ', 'letters': /[\u01CA]/g }, { 'base': 'Nj', 'letters': /[\u01CB]/g }, { 'base': 'O', 'letters': /[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g }, { 'base': 'OI', 'letters': /[\u01A2]/g }, { 'base': 'OO', 'letters': /[\uA74E]/g }, { 'base': 'OU', 'letters': /[\u0222]/g }, { 'base': 'P', 'letters': /[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g }, { 'base': 'Q', 'letters': /[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g }, { 'base': 'R', 'letters': /[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g }, { 'base': 'S', 'letters': /[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g }, { 'base': 'T', 'letters': /[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g }, { 'base': 'TZ', 'letters': /[\uA728]/g }, { 'base': 'U', 'letters': /[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g }, { 'base': 'V', 'letters': /[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g }, { 'base': 'VY', 'letters': /[\uA760]/g }, { 'base': 'W', 'letters': /[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g }, { 'base': 'X', 'letters': /[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g }, { 'base': 'Y', 'letters': /[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g }, { 'base': 'Z', 'letters': /[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g }, { 'base': 'a', 'letters': /[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g }, { 'base': 'aa', 'letters': /[\uA733]/g }, { 'base': 'ae', 'letters': /[\u00E6\u01FD\u01E3]/g }, { 'base': 'ao', 'letters': /[\uA735]/g }, { 'base': 'au', 'letters': /[\uA737]/g }, { 'base': 'av', 'letters': /[\uA739\uA73B]/g }, { 'base': 'ay', 'letters': /[\uA73D]/g }, { 'base': 'b', 'letters': /[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g }, { 'base': 'c', 'letters': /[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g }, { 'base': 'd', 'letters': /[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g }, { 'base': 'dz', 'letters': /[\u01F3\u01C6]/g }, { 'base': 'e', 'letters': /[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g }, { 'base': 'f', 'letters': /[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g }, { 'base': 'g', 'letters': /[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g }, { 'base': 'h', 'letters': /[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g }, { 'base': 'hv', 'letters': /[\u0195]/g }, { 'base': 'i', 'letters': /[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g }, { 'base': 'j', 'letters': /[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g }, { 'base': 'k', 'letters': /[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g }, { 'base': 'l', 'letters': /[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g }, { 'base': 'lj', 'letters': /[\u01C9]/g }, { 'base': 'm', 'letters': /[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g }, { 'base': 'n', 'letters': /[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g }, { 'base': 'nj', 'letters': /[\u01CC]/g }, { 'base': 'o', 'letters': /[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g }, { 'base': 'oi', 'letters': /[\u01A3]/g }, { 'base': 'ou', 'letters': /[\u0223]/g }, { 'base': 'oo', 'letters': /[\uA74F]/g }, { 'base': 'p', 'letters': /[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g }, { 'base': 'q', 'letters': /[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g }, { 'base': 'r', 'letters': /[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g }, { 'base': 's', 'letters': /[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g }, { 'base': 't', 'letters': /[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g }, { 'base': 'tz', 'letters': /[\uA729]/g }, { 'base': 'u', 'letters': /[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g }, { 'base': 'v', 'letters': /[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g }, { 'base': 'vy', 'letters': /[\uA761]/g }, { 'base': 'w', 'letters': /[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g }, { 'base': 'x', 'letters': /[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g }, { 'base': 'y', 'letters': /[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g }, { 'base': 'z', 'letters': /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g }];
-
-module.exports = function stripDiacritics(str) {
- for (var i = 0; i < map.length; i++) {
- str = str.replace(map[i].letters, map[i].base);
- }
- return str;
-};
-
-},{}],"react-select":[function(require,module,exports){
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/react-select
-*/
-
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = require('react-dom');
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _reactInputAutosize = require('react-input-autosize');
-
-var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _utilsDefaultArrowRenderer = require('./utils/defaultArrowRenderer');
-
-var _utilsDefaultArrowRenderer2 = _interopRequireDefault(_utilsDefaultArrowRenderer);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var _utilsDefaultClearRenderer = require('./utils/defaultClearRenderer');
-
-var _utilsDefaultClearRenderer2 = _interopRequireDefault(_utilsDefaultClearRenderer);
-
-var _Async = require('./Async');
-
-var _Async2 = _interopRequireDefault(_Async);
-
-var _AsyncCreatable = require('./AsyncCreatable');
-
-var _AsyncCreatable2 = _interopRequireDefault(_AsyncCreatable);
-
-var _Creatable = require('./Creatable');
-
-var _Creatable2 = _interopRequireDefault(_Creatable);
-
-var _Option = require('./Option');
-
-var _Option2 = _interopRequireDefault(_Option);
-
-var _Value = require('./Value');
-
-var _Value2 = _interopRequireDefault(_Value);
-
-function stringifyValue(value) {
- var valueType = typeof value;
- if (valueType === 'string') {
- return value;
- } else if (valueType === 'object') {
- return JSON.stringify(value);
- } else if (valueType === 'number' || valueType === 'boolean') {
- return String(value);
- } else {
- return '';
- }
-}
-
-var stringOrNode = _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.string, _react2['default'].PropTypes.node]);
-
-var instanceId = 1;
-
-var Select = _react2['default'].createClass({
-
- displayName: 'Select',
-
- propTypes: {
- addLabelText: _react2['default'].PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input
- 'aria-label': _react2['default'].PropTypes.string, // Aria label (for assistive tech)
- 'aria-labelledby': _react2['default'].PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
- arrowRenderer: _react2['default'].PropTypes.func, // Create drop-down caret element
- autoBlur: _react2['default'].PropTypes.bool, // automatically blur the component when an option is selected
- autofocus: _react2['default'].PropTypes.bool, // autofocus the component on mount
- autosize: _react2['default'].PropTypes.bool, // whether to enable autosizing or not
- backspaceRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- backspaceToRemoveMessage: _react2['default'].PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
- className: _react2['default'].PropTypes.string, // className for the outer element
- clearAllText: stringOrNode, // title for the "clear" control when multi: true
- clearRenderer: _react2['default'].PropTypes.func, // create clearable x element
- clearValueText: stringOrNode, // title for the "clear" control
- clearable: _react2['default'].PropTypes.bool, // should it be possible to reset value
- deleteRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- delimiter: _react2['default'].PropTypes.string, // delimiter to use to join multiple values for the hidden field value
- disabled: _react2['default'].PropTypes.bool, // whether the Select is disabled or not
- escapeClearsValue: _react2['default'].PropTypes.bool, // whether escape clears the value when the menu is closed
- filterOption: _react2['default'].PropTypes.func, // method to filter a single option (option, filterString)
- filterOptions: _react2['default'].PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
- ignoreAccents: _react2['default'].PropTypes.bool, // whether to strip diacritics when filtering
- ignoreCase: _react2['default'].PropTypes.bool, // whether to perform case-insensitive filtering
- inputProps: _react2['default'].PropTypes.object, // custom attributes for the Input
- inputRenderer: _react2['default'].PropTypes.func, // returns a custom input component
- instanceId: _react2['default'].PropTypes.string, // set the components instanceId
- isLoading: _react2['default'].PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded)
- joinValues: _react2['default'].PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
- labelKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- matchPos: _react2['default'].PropTypes.string, // (any|start) match the start or entire string when filtering
- matchProp: _react2['default'].PropTypes.string, // (any|label|value) which option property to filter on
- menuBuffer: _react2['default'].PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
- menuContainerStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu container
- menuRenderer: _react2['default'].PropTypes.func, // renders a custom menu with options
- menuStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu
- multi: _react2['default'].PropTypes.bool, // multi-value input
- name: _react2['default'].PropTypes.string, // generates a hidden tag with this field name for html forms
- noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
- onBlur: _react2['default'].PropTypes.func, // onBlur handler: function (event) {}
- onBlurResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared on blur
- onChange: _react2['default'].PropTypes.func, // onChange handler: function (newValue) {}
- onClose: _react2['default'].PropTypes.func, // fires when the menu is closed
- onCloseResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared when menu is closed through the arrow
- onFocus: _react2['default'].PropTypes.func, // onFocus handler: function (event) {}
- onInputChange: _react2['default'].PropTypes.func, // onInputChange handler: function (inputValue) {}
- onInputKeyDown: _react2['default'].PropTypes.func, // input keyDown handler: function (event) {}
- onMenuScrollToBottom: _react2['default'].PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
- onOpen: _react2['default'].PropTypes.func, // fires when the menu is opened
- onValueClick: _react2['default'].PropTypes.func, // onClick handler for value labels: function (value, event) {}
- openAfterFocus: _react2['default'].PropTypes.bool, // boolean to enable opening dropdown when focused
- openOnFocus: _react2['default'].PropTypes.bool, // always open options menu on focus
- optionClassName: _react2['default'].PropTypes.string, // additional class(es) to apply to the elements
- optionComponent: _react2['default'].PropTypes.func, // option component to render in dropdown
- optionRenderer: _react2['default'].PropTypes.func, // optionRenderer: function (option) {}
- options: _react2['default'].PropTypes.array, // array of options
- pageSize: _react2['default'].PropTypes.number, // number of entries to page when using page up/down keys
- placeholder: stringOrNode, // field placeholder, displayed when there's no value
- required: _react2['default'].PropTypes.bool, // applies HTML5 required attribute when needed
- resetValue: _react2['default'].PropTypes.any, // value to use when you clear the control
- scrollMenuIntoView: _react2['default'].PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
- searchable: _react2['default'].PropTypes.bool, // whether to enable searching feature or not
- simpleValue: _react2['default'].PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
- style: _react2['default'].PropTypes.object, // optional style to apply to the control
- tabIndex: _react2['default'].PropTypes.string, // optional tab index of the control
- tabSelectsValue: _react2['default'].PropTypes.bool, // whether to treat tabbing out while focused to be value selection
- value: _react2['default'].PropTypes.any, // initial field value
- valueComponent: _react2['default'].PropTypes.func, // value component to render
- valueKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- valueRenderer: _react2['default'].PropTypes.func, // valueRenderer: function (option) {}
- wrapperStyle: _react2['default'].PropTypes.object },
-
- // optional style to apply to the component wrapper
- statics: { Async: _Async2['default'], AsyncCreatable: _AsyncCreatable2['default'], Creatable: _Creatable2['default'] },
-
- getDefaultProps: function getDefaultProps() {
- return {
- addLabelText: 'Add "{label}"?',
- arrowRenderer: _utilsDefaultArrowRenderer2['default'],
- autosize: true,
- backspaceRemoves: true,
- backspaceToRemoveMessage: 'Press backspace to remove {label}',
- clearable: true,
- clearAllText: 'Clear all',
- clearRenderer: _utilsDefaultClearRenderer2['default'],
- clearValueText: 'Clear value',
- deleteRemoves: true,
- delimiter: ',',
- disabled: false,
- escapeClearsValue: true,
- filterOptions: _utilsDefaultFilterOptions2['default'],
- ignoreAccents: true,
- ignoreCase: true,
- inputProps: {},
- isLoading: false,
- joinValues: false,
- labelKey: 'label',
- matchPos: 'any',
- matchProp: 'any',
- menuBuffer: 0,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- multi: false,
- noResultsText: 'No results found',
- onBlurResetsInput: true,
- onCloseResetsInput: true,
- openAfterFocus: false,
- optionComponent: _Option2['default'],
- pageSize: 5,
- placeholder: 'Select...',
- required: false,
- scrollMenuIntoView: true,
- searchable: true,
- simpleValue: false,
- tabSelectsValue: true,
- valueComponent: _Value2['default'],
- valueKey: 'value'
- };
- },
-
- getInitialState: function getInitialState() {
- return {
- inputValue: '',
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- required: false
- };
- },
-
- componentWillMount: function componentWillMount() {
- this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
- var valueArray = this.getValueArray(this.props.value);
-
- if (this.props.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], this.props.multi)
- });
- }
- },
-
- componentDidMount: function componentDidMount() {
- if (this.props.autofocus) {
- this.focus();
- }
- },
-
- componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
- var valueArray = this.getValueArray(nextProps.value, nextProps);
-
- if (nextProps.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], nextProps.multi)
- });
- }
- },
-
- componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
- if (nextState.isOpen !== this.state.isOpen) {
- this.toggleTouchOutsideEvent(nextState.isOpen);
- var handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose;
- handler && handler();
- }
- },
-
- componentDidUpdate: function componentDidUpdate(prevProps, prevState) {
- // focus to the selected option
- if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
- var focusedOptionNode = _reactDom2['default'].findDOMNode(this.focused);
- var menuNode = _reactDom2['default'].findDOMNode(this.menu);
- menuNode.scrollTop = focusedOptionNode.offsetTop;
- this.hasScrolledToOption = true;
- } else if (!this.state.isOpen) {
- this.hasScrolledToOption = false;
- }
-
- if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
- this._scrollToFocusedOptionOnUpdate = false;
- var focusedDOM = _reactDom2['default'].findDOMNode(this.focused);
- var menuDOM = _reactDom2['default'].findDOMNode(this.menu);
- var focusedRect = focusedDOM.getBoundingClientRect();
- var menuRect = menuDOM.getBoundingClientRect();
- if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) {
- menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight;
- }
- }
- if (this.props.scrollMenuIntoView && this.menuContainer) {
- var menuContainerRect = this.menuContainer.getBoundingClientRect();
- if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
- window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
- }
- }
- if (prevProps.disabled !== this.props.disabled) {
- this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
- this.closeMenu();
- }
- },
-
- componentWillUnmount: function componentWillUnmount() {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- },
-
- toggleTouchOutsideEvent: function toggleTouchOutsideEvent(enabled) {
- if (enabled) {
- if (!document.addEventListener && document.attachEvent) {
- document.attachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.addEventListener('touchstart', this.handleTouchOutside);
- }
- } else {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- }
- },
-
- handleTouchOutside: function handleTouchOutside(event) {
- // handle touch outside on ios to dismiss menu
- if (this.wrapper && !this.wrapper.contains(event.target)) {
- this.closeMenu();
- }
- },
-
- focus: function focus() {
- if (!this.input) return;
- this.input.focus();
-
- if (this.props.openAfterFocus) {
- this.setState({
- isOpen: true
- });
- }
- },
-
- blurInput: function blurInput() {
- if (!this.input) return;
- this.input.blur();
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.handleMouseDown(event);
- },
-
- handleTouchEndClearValue: function handleTouchEndClearValue(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Clear the value
- this.clearValue(event);
- },
-
- handleMouseDown: function handleMouseDown(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
-
- if (event.target.tagName === 'INPUT') {
- return;
- }
-
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
-
- // for the non-searchable select, toggle the menu
- if (!this.props.searchable) {
- this.focus();
- return this.setState({
- isOpen: !this.state.isOpen
- });
- }
-
- if (this.state.isFocused) {
- // On iOS, we can get into a state where we think the input is focused but it isn't really,
- // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
- // Call focus() again here to be safe.
- this.focus();
-
- var input = this.input;
- if (typeof input.getInput === 'function') {
- // Get the actual DOM input if the ref is an component
- input = input.getInput();
- }
-
- // clears the value so that the cursor will be at the end of input when the component re-renders
- input.value = '';
-
- // if the input is focused, ensure the menu is open
- this.setState({
- isOpen: true,
- isPseudoFocused: false
- });
- } else {
- // otherwise, focus the input and open the menu
- this._openAfterFocus = true;
- this.focus();
- }
- },
-
- handleMouseDownOnArrow: function handleMouseDownOnArrow(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- // If the menu isn't open, let the event bubble to the main handleMouseDown
- if (!this.state.isOpen) {
- return;
- }
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
- // close the menu
- this.closeMenu();
- },
-
- handleMouseDownOnMenu: function handleMouseDownOnMenu(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- this._openAfterFocus = true;
- this.focus();
- },
-
- closeMenu: function closeMenu() {
- if (this.props.onCloseResetsInput) {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: ''
- });
- } else {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: this.state.inputValue
- });
- }
- this.hasScrolledToOption = false;
- },
-
- handleInputFocus: function handleInputFocus(event) {
- if (this.props.disabled) return;
- var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
- if (this.props.onFocus) {
- this.props.onFocus(event);
- }
- this.setState({
- isFocused: true,
- isOpen: isOpen
- });
- this._openAfterFocus = false;
- },
-
- handleInputBlur: function handleInputBlur(event) {
- // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
- if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
- this.focus();
- return;
- }
-
- if (this.props.onBlur) {
- this.props.onBlur(event);
- }
- var onBlurredState = {
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false
- };
- if (this.props.onBlurResetsInput) {
- onBlurredState.inputValue = '';
- }
- this.setState(onBlurredState);
- },
-
- handleInputChange: function handleInputChange(event) {
- var newInputValue = event.target.value;
-
- if (this.state.inputValue !== event.target.value && this.props.onInputChange) {
- var nextState = this.props.onInputChange(newInputValue);
- // Note: != used deliberately here to catch undefined and null
- if (nextState != null && typeof nextState !== 'object') {
- newInputValue = '' + nextState;
- }
- }
-
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- inputValue: newInputValue
- });
- },
-
- handleKeyDown: function handleKeyDown(event) {
- if (this.props.disabled) return;
-
- if (typeof this.props.onInputKeyDown === 'function') {
- this.props.onInputKeyDown(event);
- if (event.defaultPrevented) {
- return;
- }
- }
-
- switch (event.keyCode) {
- case 8:
- // backspace
- if (!this.state.inputValue && this.props.backspaceRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- case 9:
- // tab
- if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
- return;
- }
- this.selectFocusedOption();
- return;
- case 13:
- // enter
- if (!this.state.isOpen) return;
- event.stopPropagation();
- this.selectFocusedOption();
- break;
- case 27:
- // escape
- if (this.state.isOpen) {
- this.closeMenu();
- event.stopPropagation();
- } else if (this.props.clearable && this.props.escapeClearsValue) {
- this.clearValue(event);
- event.stopPropagation();
- }
- break;
- case 38:
- // up
- this.focusPreviousOption();
- break;
- case 40:
- // down
- this.focusNextOption();
- break;
- case 33:
- // page up
- this.focusPageUpOption();
- break;
- case 34:
- // page down
- this.focusPageDownOption();
- break;
- case 35:
- // end key
- if (event.shiftKey) {
- return;
- }
- this.focusEndOption();
- break;
- case 36:
- // home key
- if (event.shiftKey) {
- return;
- }
- this.focusStartOption();
- break;
- case 46:
- // backspace
- if (!this.state.inputValue && this.props.deleteRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- default:
- return;
- }
- event.preventDefault();
- },
-
- handleValueClick: function handleValueClick(option, event) {
- if (!this.props.onValueClick) return;
- this.props.onValueClick(option, event);
- },
-
- handleMenuScroll: function handleMenuScroll(event) {
- if (!this.props.onMenuScrollToBottom) return;
- var target = event.target;
-
- if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) {
- this.props.onMenuScrollToBottom();
- }
- },
-
- handleRequired: function handleRequired(value, multi) {
- if (!value) return true;
- return multi ? value.length === 0 : Object.keys(value).length === 0;
- },
-
- getOptionLabel: function getOptionLabel(op) {
- return op[this.props.labelKey];
- },
-
- /**
- * Turns a value into an array from the given options
- * @param {String|Number|Array} value - the value of the select input
- * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
- * @returns {Array} the value of the select represented in an array
- */
- getValueArray: function getValueArray(value, nextProps) {
- var _this = this;
-
- /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
- var props = typeof nextProps === 'object' ? nextProps : this.props;
- if (props.multi) {
- if (typeof value === 'string') value = value.split(props.delimiter);
- if (!Array.isArray(value)) {
- if (value === null || value === undefined) return [];
- value = [value];
- }
- return value.map(function (value) {
- return _this.expandValue(value, props);
- }).filter(function (i) {
- return i;
- });
- }
- var expandedValue = this.expandValue(value, props);
- return expandedValue ? [expandedValue] : [];
- },
-
- /**
- * Retrieve a value from the given options and valueKey
- * @param {String|Number|Array} value - the selected value(s)
- * @param {Object} props - the Select component's props (or nextProps)
- */
- expandValue: function expandValue(value, props) {
- var valueType = typeof value;
- if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
- var options = props.options;
- var valueKey = props.valueKey;
-
- if (!options) return;
- for (var i = 0; i < options.length; i++) {
- if (options[i][valueKey] === value) return options[i];
- }
- },
-
- setValue: function setValue(value) {
- var _this2 = this;
-
- if (this.props.autoBlur) {
- this.blurInput();
- }
- if (!this.props.onChange) return;
- if (this.props.required) {
- var required = this.handleRequired(value, this.props.multi);
- this.setState({ required: required });
- }
- if (this.props.simpleValue && value) {
- value = this.props.multi ? value.map(function (i) {
- return i[_this2.props.valueKey];
- }).join(this.props.delimiter) : value[this.props.valueKey];
- }
- this.props.onChange(value);
- },
-
- selectValue: function selectValue(value) {
- var _this3 = this;
-
- //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise)
- this.hasScrolledToOption = false;
- if (this.props.multi) {
- this.setState({
- inputValue: '',
- focusedIndex: null
- }, function () {
- _this3.addValue(value);
- });
- } else {
- this.setState({
- isOpen: false,
- inputValue: '',
- isPseudoFocused: this.state.isFocused
- }, function () {
- _this3.setValue(value);
- });
- }
- },
-
- addValue: function addValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- var visibleOptions = this._visibleOptions.filter(function (val) {
- return !val.disabled;
- });
- var lastValueIndex = visibleOptions.indexOf(value);
- this.setValue(valueArray.concat(value));
- if (visibleOptions.length - 1 === lastValueIndex) {
- // the last option was selected; focus the second-last one
- this.focusOption(visibleOptions[lastValueIndex - 1]);
- } else if (visibleOptions.length > lastValueIndex) {
- // focus the option below the selected one
- this.focusOption(visibleOptions[lastValueIndex + 1]);
- }
- },
-
- popValue: function popValue() {
- var valueArray = this.getValueArray(this.props.value);
- if (!valueArray.length) return;
- if (valueArray[valueArray.length - 1].clearableValue === false) return;
- this.setValue(valueArray.slice(0, valueArray.length - 1));
- },
-
- removeValue: function removeValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- this.setValue(valueArray.filter(function (i) {
- return i !== value;
- }));
- this.focus();
- },
-
- clearValue: function clearValue(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, ignore it.
- if (event && event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
- this.setValue(this.getResetValue());
- this.setState({
- isOpen: false,
- inputValue: ''
- }, this.focus);
- },
-
- getResetValue: function getResetValue() {
- if (this.props.resetValue !== undefined) {
- return this.props.resetValue;
- } else if (this.props.multi) {
- return [];
- } else {
- return null;
- }
- },
-
- focusOption: function focusOption(option) {
- this.setState({
- focusedOption: option
- });
- },
-
- focusNextOption: function focusNextOption() {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption: function focusPreviousOption() {
- this.focusAdjacentOption('previous');
- },
-
- focusPageUpOption: function focusPageUpOption() {
- this.focusAdjacentOption('page_up');
- },
-
- focusPageDownOption: function focusPageDownOption() {
- this.focusAdjacentOption('page_down');
- },
-
- focusStartOption: function focusStartOption() {
- this.focusAdjacentOption('start');
- },
-
- focusEndOption: function focusEndOption() {
- this.focusAdjacentOption('end');
- },
-
- focusAdjacentOption: function focusAdjacentOption(dir) {
- var options = this._visibleOptions.map(function (option, index) {
- return { option: option, index: index };
- }).filter(function (option) {
- return !option.option.disabled;
- });
- this._scrollToFocusedOptionOnUpdate = true;
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: '',
- focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
- });
- return;
- }
- if (!options.length) return;
- var focusedIndex = -1;
- for (var i = 0; i < options.length; i++) {
- if (this._focusedOption === options[i].option) {
- focusedIndex = i;
- break;
- }
- }
- if (dir === 'next' && focusedIndex !== -1) {
- focusedIndex = (focusedIndex + 1) % options.length;
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedIndex = focusedIndex - 1;
- } else {
- focusedIndex = options.length - 1;
- }
- } else if (dir === 'start') {
- focusedIndex = 0;
- } else if (dir === 'end') {
- focusedIndex = options.length - 1;
- } else if (dir === 'page_up') {
- var potentialIndex = focusedIndex - this.props.pageSize;
- if (potentialIndex < 0) {
- focusedIndex = 0;
- } else {
- focusedIndex = potentialIndex;
- }
- } else if (dir === 'page_down') {
- var potentialIndex = focusedIndex + this.props.pageSize;
- if (potentialIndex > options.length - 1) {
- focusedIndex = options.length - 1;
- } else {
- focusedIndex = potentialIndex;
- }
- }
-
- if (focusedIndex === -1) {
- focusedIndex = 0;
- }
-
- this.setState({
- focusedIndex: options[focusedIndex].index,
- focusedOption: options[focusedIndex].option
- });
- },
-
- getFocusedOption: function getFocusedOption() {
- return this._focusedOption;
- },
-
- getInputValue: function getInputValue() {
- return this.state.inputValue;
- },
-
- selectFocusedOption: function selectFocusedOption() {
- if (this._focusedOption) {
- return this.selectValue(this._focusedOption);
- }
- },
-
- renderLoading: function renderLoading() {
- if (!this.props.isLoading) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-loading-zone', 'aria-hidden': 'true' },
- _react2['default'].createElement('span', { className: 'Select-loading' })
- );
- },
-
- renderValue: function renderValue(valueArray, isOpen) {
- var _this4 = this;
-
- var renderLabel = this.props.valueRenderer || this.getOptionLabel;
- var ValueComponent = this.props.valueComponent;
- if (!valueArray.length) {
- return !this.state.inputValue ? _react2['default'].createElement(
- 'div',
- { className: 'Select-placeholder' },
- this.props.placeholder
- ) : null;
- }
- var onClick = this.props.onValueClick ? this.handleValueClick : null;
- if (this.props.multi) {
- return valueArray.map(function (value, i) {
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: _this4._instancePrefix + '-value-' + i,
- instancePrefix: _this4._instancePrefix,
- disabled: _this4.props.disabled || value.clearableValue === false,
- key: 'value-' + i + '-' + value[_this4.props.valueKey],
- onClick: onClick,
- onRemove: _this4.removeValue,
- value: value
- },
- renderLabel(value, i),
- _react2['default'].createElement(
- 'span',
- { className: 'Select-aria-only' },
- ' '
- )
- );
- });
- } else if (!this.state.inputValue) {
- if (isOpen) onClick = null;
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: this._instancePrefix + '-value-item',
- disabled: this.props.disabled,
- instancePrefix: this._instancePrefix,
- onClick: onClick,
- value: valueArray[0]
- },
- renderLabel(valueArray[0])
- );
- }
- },
-
- renderInput: function renderInput(valueArray, focusedOptionIndex) {
- var _classNames,
- _this5 = this;
-
- var className = (0, _classnames2['default'])('Select-input', this.props.inputProps.className);
- var isOpen = !!this.state.isOpen;
-
- var ariaOwns = (0, _classnames2['default'])((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames));
-
- // TODO: Check how this project includes Object.assign()
- var inputProps = _extends({}, this.props.inputProps, {
- role: 'combobox',
- 'aria-expanded': '' + isOpen,
- 'aria-owns': ariaOwns,
- 'aria-haspopup': '' + isOpen,
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- 'aria-labelledby': this.props['aria-labelledby'],
- 'aria-label': this.props['aria-label'],
- className: className,
- tabIndex: this.props.tabIndex,
- onBlur: this.handleInputBlur,
- onChange: this.handleInputChange,
- onFocus: this.handleInputFocus,
- ref: function ref(_ref) {
- return _this5.input = _ref;
- },
- required: this.state.required,
- value: this.state.inputValue
- });
-
- if (this.props.inputRenderer) {
- return this.props.inputRenderer(inputProps);
- }
-
- if (this.props.disabled || !this.props.searchable) {
- var _props$inputProps = this.props.inputProps;
- var inputClassName = _props$inputProps.inputClassName;
-
- var divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']);
-
- return _react2['default'].createElement('div', _extends({}, divProps, {
- role: 'combobox',
- 'aria-expanded': isOpen,
- 'aria-owns': isOpen ? this._instancePrefix + '-list' : this._instancePrefix + '-value',
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- className: className,
- tabIndex: this.props.tabIndex || 0,
- onBlur: this.handleInputBlur,
- onFocus: this.handleInputFocus,
- ref: function (ref) {
- return _this5.input = ref;
- },
- 'aria-readonly': '' + !!this.props.disabled,
- style: { border: 0, width: 1, display: 'inline-block' } }));
- }
-
- if (this.props.autosize) {
- return _react2['default'].createElement(_reactInputAutosize2['default'], _extends({}, inputProps, { minWidth: '5' }));
- }
- return _react2['default'].createElement(
- 'div',
- { className: className },
- _react2['default'].createElement('input', inputProps)
- );
- },
-
- renderClear: function renderClear() {
- if (!this.props.clearable || !this.props.value || this.props.value === 0 || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return;
- var clear = this.props.clearRenderer();
-
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- onMouseDown: this.clearValue,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEndClearValue
- },
- clear
- );
- },
-
- renderArrow: function renderArrow() {
- var onMouseDown = this.handleMouseDownOnArrow;
- var isOpen = this.state.isOpen;
- var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen });
-
- return _react2['default'].createElement(
- 'span',
- {
- className: 'Select-arrow-zone',
- onMouseDown: onMouseDown
- },
- arrow
- );
- },
-
- filterOptions: function filterOptions(excludeOptions) {
- var filterValue = this.state.inputValue;
- var options = this.props.options || [];
- if (this.props.filterOptions) {
- // Maintain backwards compatibility with boolean attribute
- var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _utilsDefaultFilterOptions2['default'];
-
- return filterOptions(options, filterValue, excludeOptions, {
- filterOption: this.props.filterOption,
- ignoreAccents: this.props.ignoreAccents,
- ignoreCase: this.props.ignoreCase,
- labelKey: this.props.labelKey,
- matchPos: this.props.matchPos,
- matchProp: this.props.matchProp,
- valueKey: this.props.valueKey
- });
- } else {
- return options;
- }
- },
-
- onOptionRef: function onOptionRef(ref, isFocused) {
- if (isFocused) {
- this.focused = ref;
- }
- },
-
- renderMenu: function renderMenu(options, valueArray, focusedOption) {
- if (options && options.length) {
- return this.props.menuRenderer({
- focusedOption: focusedOption,
- focusOption: this.focusOption,
- instancePrefix: this._instancePrefix,
- labelKey: this.props.labelKey,
- onFocus: this.focusOption,
- onSelect: this.selectValue,
- optionClassName: this.props.optionClassName,
- optionComponent: this.props.optionComponent,
- optionRenderer: this.props.optionRenderer || this.getOptionLabel,
- options: options,
- selectValue: this.selectValue,
- valueArray: valueArray,
- valueKey: this.props.valueKey,
- onOptionRef: this.onOptionRef
- });
- } else if (this.props.noResultsText) {
- return _react2['default'].createElement(
- 'div',
- { className: 'Select-noresults' },
- this.props.noResultsText
- );
- } else {
- return null;
- }
- },
-
- renderHiddenField: function renderHiddenField(valueArray) {
- var _this6 = this;
-
- if (!this.props.name) return;
- if (this.props.joinValues) {
- var value = valueArray.map(function (i) {
- return stringifyValue(i[_this6.props.valueKey]);
- }).join(this.props.delimiter);
- return _react2['default'].createElement('input', {
- type: 'hidden',
- ref: function (ref) {
- return _this6.value = ref;
- },
- name: this.props.name,
- value: value,
- disabled: this.props.disabled });
- }
- return valueArray.map(function (item, index) {
- return _react2['default'].createElement('input', { key: 'hidden.' + index,
- type: 'hidden',
- ref: 'value' + index,
- name: _this6.props.name,
- value: stringifyValue(item[_this6.props.valueKey]),
- disabled: _this6.props.disabled });
- });
- },
-
- getFocusableOptionIndex: function getFocusableOptionIndex(selectedOption) {
- var options = this._visibleOptions;
- if (!options.length) return null;
-
- var focusedOption = this.state.focusedOption || selectedOption;
- if (focusedOption && !focusedOption.disabled) {
- var focusedOptionIndex = options.indexOf(focusedOption);
- if (focusedOptionIndex !== -1) {
- return focusedOptionIndex;
- }
- }
-
- for (var i = 0; i < options.length; i++) {
- if (!options[i].disabled) return i;
- }
- return null;
- },
-
- renderOuter: function renderOuter(options, valueArray, focusedOption) {
- var _this7 = this;
-
- var menu = this.renderMenu(options, valueArray, focusedOption);
- if (!menu) {
- return null;
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menuContainer = ref;
- }, className: 'Select-menu-outer', style: this.props.menuContainerStyle },
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menu = ref;
- }, role: 'listbox', className: 'Select-menu', id: this._instancePrefix + '-list',
- style: this.props.menuStyle,
- onScroll: this.handleMenuScroll,
- onMouseDown: this.handleMouseDownOnMenu },
- menu
- )
- );
- },
-
- render: function render() {
- var _this8 = this;
-
- var valueArray = this.getValueArray(this.props.value);
- var options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null);
- var isOpen = this.state.isOpen;
- if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
- var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
-
- var focusedOption = null;
- if (focusedOptionIndex !== null) {
- focusedOption = this._focusedOption = options[focusedOptionIndex];
- } else {
- focusedOption = this._focusedOption = null;
- }
- var className = (0, _classnames2['default'])('Select', this.props.className, {
- 'Select--multi': this.props.multi,
- 'Select--single': !this.props.multi,
- 'is-disabled': this.props.disabled,
- 'is-focused': this.state.isFocused,
- 'is-loading': this.props.isLoading,
- 'is-open': isOpen,
- 'is-pseudo-focused': this.state.isPseudoFocused,
- 'is-searchable': this.props.searchable,
- 'has-value': valueArray.length
- });
-
- var removeMessage = null;
- if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) {
- removeMessage = _react2['default'].createElement(
- 'span',
- { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' },
- this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])
- );
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.wrapper = ref;
- },
- className: className,
- style: this.props.wrapperStyle },
- this.renderHiddenField(valueArray),
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.control = ref;
- },
- className: 'Select-control',
- style: this.props.style,
- onKeyDown: this.handleKeyDown,
- onMouseDown: this.handleMouseDown,
- onTouchEnd: this.handleTouchEnd,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove
- },
- _react2['default'].createElement(
- 'span',
- { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' },
- this.renderValue(valueArray, isOpen),
- this.renderInput(valueArray, focusedOptionIndex)
- ),
- removeMessage,
- this.renderLoading(),
- this.renderClear(),
- this.renderArrow()
- ),
- isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null
- );
- }
-
-});
-
-exports['default'] = Select;
-module.exports = exports['default'];
-
-},{"./Async":1,"./AsyncCreatable":2,"./Creatable":3,"./Option":4,"./Value":5,"./utils/defaultArrowRenderer":6,"./utils/defaultClearRenderer":7,"./utils/defaultFilterOptions":8,"./utils/defaultMenuRenderer":9,"classnames":undefined,"react":undefined,"react-dom":undefined,"react-input-autosize":undefined}]},{},[]);
diff --git a/examples/dist/common.js b/examples/dist/common.js
deleted file mode 100644
index 164c27ac52..0000000000
--- a/examples/dist/common.js
+++ /dev/null
@@ -1,20527 +0,0 @@
-require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o camelize('background-color')
- * < "backgroundColor"
- *
- * @param {string} string
- * @return {string}
- */
-function camelize(string) {
- return string.replace(_hyphenPattern, function (_, character) {
- return character.toUpperCase();
- });
-}
-
-module.exports = camelize;
-},{}],4:[function(require,module,exports){
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- */
-
-'use strict';
-
-var camelize = require('./camelize');
-
-var msPattern = /^-ms-/;
-
-/**
- * Camelcases a hyphenated CSS property name, for example:
- *
- * > camelizeStyleName('background-color')
- * < "backgroundColor"
- * > camelizeStyleName('-moz-transition')
- * < "MozTransition"
- * > camelizeStyleName('-ms-transition')
- * < "msTransition"
- *
- * As Andi Smith suggests
- * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
- * is converted to lowercase `ms`.
- *
- * @param {string} string
- * @return {string}
- */
-function camelizeStyleName(string) {
- return camelize(string.replace(msPattern, 'ms-'));
-}
-
-module.exports = camelizeStyleName;
-},{"./camelize":3}],5:[function(require,module,exports){
-'use strict';
-
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- *
- */
-
-var isTextNode = require('./isTextNode');
-
-/*eslint-disable no-bitwise */
-
-/**
- * Checks if a given DOM node contains or is another DOM node.
- */
-function containsNode(outerNode, innerNode) {
- if (!outerNode || !innerNode) {
- return false;
- } else if (outerNode === innerNode) {
- return true;
- } else if (isTextNode(outerNode)) {
- return false;
- } else if (isTextNode(innerNode)) {
- return containsNode(outerNode, innerNode.parentNode);
- } else if ('contains' in outerNode) {
- return outerNode.contains(innerNode);
- } else if (outerNode.compareDocumentPosition) {
- return !!(outerNode.compareDocumentPosition(innerNode) & 16);
- } else {
- return false;
- }
-}
-
-module.exports = containsNode;
-},{"./isTextNode":18}],6:[function(require,module,exports){
-'use strict';
-
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- */
-
-var invariant = require('./invariant');
-
-/**
- * Convert array-like objects to arrays.
- *
- * This API assumes the caller knows the contents of the data type. For less
- * well defined inputs use createArrayFromMixed.
- *
- * @param {object|function|filelist} obj
- * @return {array}
- */
-function toArray(obj) {
- var length = obj.length;
-
- // Some browsers builtin objects can report typeof 'function' (e.g. NodeList
- // in old versions of Safari).
- !(!Array.isArray(obj) && (typeof obj === 'object' || typeof obj === 'function')) ? "production" !== 'production' ? invariant(false, 'toArray: Array-like object expected') : invariant(false) : void 0;
-
- !(typeof length === 'number') ? "production" !== 'production' ? invariant(false, 'toArray: Object needs a length property') : invariant(false) : void 0;
-
- !(length === 0 || length - 1 in obj) ? "production" !== 'production' ? invariant(false, 'toArray: Object should have keys for indices') : invariant(false) : void 0;
-
- !(typeof obj.callee !== 'function') ? "production" !== 'production' ? invariant(false, 'toArray: Object can\'t be `arguments`. Use rest params ' + '(function(...args) {}) or Array.from() instead.') : invariant(false) : void 0;
-
- // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
- // without method will throw during the slice call and skip straight to the
- // fallback.
- if (obj.hasOwnProperty) {
- try {
- return Array.prototype.slice.call(obj);
- } catch (e) {
- // IE < 9 does not support Array#slice on collections objects
- }
- }
-
- // Fall back to copying key by key. This assumes all keys have a value,
- // so will not preserve sparsely populated inputs.
- var ret = Array(length);
- for (var ii = 0; ii < length; ii++) {
- ret[ii] = obj[ii];
- }
- return ret;
-}
-
-/**
- * Perform a heuristic test to determine if an object is "array-like".
- *
- * A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
- * Joshu replied: "Mu."
- *
- * This function determines if its argument has "array nature": it returns
- * true if the argument is an actual array, an `arguments' object, or an
- * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
- *
- * It will return false for other array-like objects like Filelist.
- *
- * @param {*} obj
- * @return {boolean}
- */
-function hasArrayNature(obj) {
- return (
- // not null/false
- !!obj && (
- // arrays are objects, NodeLists are functions in Safari
- typeof obj == 'object' || typeof obj == 'function') &&
- // quacks like an array
- 'length' in obj &&
- // not window
- !('setInterval' in obj) &&
- // no DOM node should be considered an array-like
- // a 'select' element has 'length' and 'item' properties on IE8
- typeof obj.nodeType != 'number' && (
- // a real array
- Array.isArray(obj) ||
- // arguments
- 'callee' in obj ||
- // HTMLCollection/NodeList
- 'item' in obj)
- );
-}
-
-/**
- * Ensure that the argument is an array by wrapping it in an array if it is not.
- * Creates a copy of the argument if it is already an array.
- *
- * This is mostly useful idiomatically:
- *
- * var createArrayFromMixed = require('createArrayFromMixed');
- *
- * function takesOneOrMoreThings(things) {
- * things = createArrayFromMixed(things);
- * ...
- * }
- *
- * This allows you to treat `things' as an array, but accept scalars in the API.
- *
- * If you need to convert an array-like object, like `arguments`, into an array
- * use toArray instead.
- *
- * @param {*} obj
- * @return {array}
- */
-function createArrayFromMixed(obj) {
- if (!hasArrayNature(obj)) {
- return [obj];
- } else if (Array.isArray(obj)) {
- return obj.slice();
- } else {
- return toArray(obj);
- }
-}
-
-module.exports = createArrayFromMixed;
-},{"./invariant":16}],7:[function(require,module,exports){
-'use strict';
-
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks
- */
-
-/*eslint-disable fb-www/unsafe-html*/
-
-var ExecutionEnvironment = require('./ExecutionEnvironment');
-
-var createArrayFromMixed = require('./createArrayFromMixed');
-var getMarkupWrap = require('./getMarkupWrap');
-var invariant = require('./invariant');
-
-/**
- * Dummy container used to render all markup.
- */
-var dummyNode = ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
-
-/**
- * Pattern used by `getNodeName`.
- */
-var nodeNamePattern = /^\s*<(\w+)/;
-
-/**
- * Extracts the `nodeName` of the first element in a string of markup.
- *
- * @param {string} markup String of markup.
- * @return {?string} Node name of the supplied markup.
- */
-function getNodeName(markup) {
- var nodeNameMatch = markup.match(nodeNamePattern);
- return nodeNameMatch && nodeNameMatch[1].toLowerCase();
-}
-
-/**
- * Creates an array containing the nodes rendered from the supplied markup. The
- * optionally supplied `handleScript` function will be invoked once for each
- *
-
-
-
-
-
-
-
-
-
React Select
-
Standalone bulid
-
For usage without babel / browserify / webpack
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/dist/standalone.html b/examples/dist/standalone.html
deleted file mode 100644
index fccd81ccb9..0000000000
--- a/examples/dist/standalone.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
React-Select Example
-
-
-
diff --git a/examples/dist/standalone.js b/examples/dist/standalone.js
deleted file mode 100644
index caad9d23f4..0000000000
--- a/examples/dist/standalone.js
+++ /dev/null
@@ -1,2282 +0,0 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Select = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o _this3.props.value.length) {
- _this3.clearOptions();
- }
- _this3.props.onChange(newValues);
- }
- };
-
- return children(_extends({}, this.props, props, {
- isLoading: isLoading,
- onInputChange: this._onInputChange
- }));
- }
- }]);
-
- return Async;
-})(_react.Component);
-
-exports['default'] = Async;
-
-Async.propTypes = propTypes;
-Async.defaultProps = defaultProps;
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5,"./utils/stripDiacritics":11}],2:[function(require,module,exports){
-(function (global){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-function reduce(obj) {
- var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
- return Object.keys(obj).reduce(function (props, key) {
- var value = obj[key];
- if (value !== undefined) props[key] = value;
- return props;
- }, props);
-}
-
-var AsyncCreatable = _react2['default'].createClass({
- displayName: 'AsyncCreatableSelect',
-
- render: function render() {
- var _this = this;
-
- return _react2['default'].createElement(
- _Select2['default'].Async,
- this.props,
- function (asyncProps) {
- return _react2['default'].createElement(
- _Select2['default'].Creatable,
- _this.props,
- function (creatableProps) {
- return _react2['default'].createElement(_Select2['default'], _extends({}, reduce(asyncProps, reduce(creatableProps, {})), {
- onInputChange: function (input) {
- creatableProps.onInputChange(input);
- return asyncProps.onInputChange(input);
- },
- ref: function (ref) {
- creatableProps.ref(ref);
- asyncProps.ref(ref);
- }
- }));
- }
- );
- }
- );
- }
-});
-
-module.exports = AsyncCreatable;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5}],3:[function(require,module,exports){
-(function (global){
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var Creatable = _react2['default'].createClass({
- displayName: 'CreatableSelect',
-
- propTypes: {
- // Child function responsible for creating the inner Select component
- // This component can be used to compose HOCs (eg Creatable and Async)
- // (props: Object): PropTypes.element
- children: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.filterOptions
- filterOptions: _react2['default'].PropTypes.any,
-
- // Searches for any matching option within the set of options.
- // This function prevents duplicate options from being created.
- // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean
- isOptionUnique: _react2['default'].PropTypes.func,
-
- // Determines if the current input text represents a valid option.
- // ({ label: string }): boolean
- isValidNewOption: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.menuRenderer
- menuRenderer: _react2['default'].PropTypes.any,
-
- // Factory to create new option.
- // ({ label: string, labelKey: string, valueKey: string }): Object
- newOptionCreator: _react2['default'].PropTypes.func,
-
- // input change handler: function (inputValue) {}
- onInputChange: _react2['default'].PropTypes.func,
-
- // input keyDown handler: function (event) {}
- onInputKeyDown: _react2['default'].PropTypes.func,
-
- // new option click handler: function (option) {}
- onNewOptionClick: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.options
- options: _react2['default'].PropTypes.array,
-
- // Creates prompt/placeholder option text.
- // (filterText: string): string
- promptTextCreator: _react2['default'].PropTypes.func,
-
- // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option.
- shouldKeyDownEventCreateNewOption: _react2['default'].PropTypes.func
- },
-
- // Default prop methods
- statics: {
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- },
-
- getDefaultProps: function getDefaultProps() {
- return {
- filterOptions: _utilsDefaultFilterOptions2['default'],
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- };
- },
-
- createNewOption: function createNewOption() {
- var _props = this.props;
- var isValidNewOption = _props.isValidNewOption;
- var newOptionCreator = _props.newOptionCreator;
- var onNewOptionClick = _props.onNewOptionClick;
- var _props$options = _props.options;
- var options = _props$options === undefined ? [] : _props$options;
- var shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption;
-
- if (isValidNewOption({ label: this.inputValue })) {
- var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey });
- var _isOptionUnique = this.isOptionUnique({ option: option });
-
- // Don't add the same option twice.
- if (_isOptionUnique) {
- if (onNewOptionClick) {
- onNewOptionClick(option);
- } else {
- options.unshift(option);
-
- this.select.selectValue(option);
- }
- }
- }
- },
-
- filterOptions: function filterOptions() {
- var _props2 = this.props;
- var filterOptions = _props2.filterOptions;
- var isValidNewOption = _props2.isValidNewOption;
- var options = _props2.options;
- var promptTextCreator = _props2.promptTextCreator;
-
- // TRICKY Check currently selected options as well.
- // Don't display a create-prompt for a value that's selected.
- // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array.
- var excludeOptions = arguments[2] || [];
-
- var filteredOptions = filterOptions.apply(undefined, arguments) || [];
-
- if (isValidNewOption({ label: this.inputValue })) {
- var _newOptionCreator = this.props.newOptionCreator;
-
- var option = _newOptionCreator({
- label: this.inputValue,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- // TRICKY Compare to all options (not just filtered options) in case option has already been selected).
- // For multi-selects, this would remove it from the filtered list.
- var _isOptionUnique2 = this.isOptionUnique({
- option: option,
- options: excludeOptions.concat(filteredOptions)
- });
-
- if (_isOptionUnique2) {
- var _prompt = promptTextCreator(this.inputValue);
-
- this._createPlaceholderOption = _newOptionCreator({
- label: _prompt,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- filteredOptions.unshift(this._createPlaceholderOption);
- }
- }
-
- return filteredOptions;
- },
-
- isOptionUnique: function isOptionUnique(_ref2) {
- var option = _ref2.option;
- var options = _ref2.options;
- var isOptionUnique = this.props.isOptionUnique;
-
- options = options || this.select.filterOptions();
-
- return isOptionUnique({
- labelKey: this.labelKey,
- option: option,
- options: options,
- valueKey: this.valueKey
- });
- },
-
- menuRenderer: function menuRenderer(params) {
- var menuRenderer = this.props.menuRenderer;
-
- return menuRenderer(_extends({}, params, {
- onSelect: this.onOptionSelect,
- selectValue: this.onOptionSelect
- }));
- },
-
- onInputChange: function onInputChange(input) {
- var onInputChange = this.props.onInputChange;
-
- if (onInputChange) {
- onInputChange(input);
- }
-
- // This value may be needed in between Select mounts (when this.select is null)
- this.inputValue = input;
- },
-
- onInputKeyDown: function onInputKeyDown(event) {
- var _props3 = this.props;
- var shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption;
- var onInputKeyDown = _props3.onInputKeyDown;
-
- var focusedOption = this.select.getFocusedOption();
-
- if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) {
- this.createNewOption();
-
- // Prevent decorated Select from doing anything additional with this keyDown event
- event.preventDefault();
- } else if (onInputKeyDown) {
- onInputKeyDown(event);
- }
- },
-
- onOptionSelect: function onOptionSelect(option, event) {
- if (option === this._createPlaceholderOption) {
- this.createNewOption();
- } else {
- this.select.selectValue(option);
- }
- },
-
- render: function render() {
- var _this = this;
-
- var _props4 = this.props;
- var newOptionCreator = _props4.newOptionCreator;
- var shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption;
-
- var restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']);
-
- var children = this.props.children;
-
- // We can't use destructuring default values to set the children,
- // because it won't apply work if `children` is null. A falsy check is
- // more reliable in real world use-cases.
- if (!children) {
- children = defaultChildren;
- }
-
- var props = _extends({}, restProps, {
- allowCreate: true,
- filterOptions: this.filterOptions,
- menuRenderer: this.menuRenderer,
- onInputChange: this.onInputChange,
- onInputKeyDown: this.onInputKeyDown,
- ref: function ref(_ref) {
- _this.select = _ref;
-
- // These values may be needed in between Select mounts (when this.select is null)
- if (_ref) {
- _this.labelKey = _ref.props.labelKey;
- _this.valueKey = _ref.props.valueKey;
- }
- }
- });
-
- return children(props);
- }
-});
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-
-function isOptionUnique(_ref3) {
- var option = _ref3.option;
- var options = _ref3.options;
- var labelKey = _ref3.labelKey;
- var valueKey = _ref3.valueKey;
-
- return options.filter(function (existingOption) {
- return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey];
- }).length === 0;
-};
-
-function isValidNewOption(_ref4) {
- var label = _ref4.label;
-
- return !!label;
-};
-
-function newOptionCreator(_ref5) {
- var label = _ref5.label;
- var labelKey = _ref5.labelKey;
- var valueKey = _ref5.valueKey;
-
- var option = {};
- option[valueKey] = label;
- option[labelKey] = label;
- option.className = 'Select-create-option-placeholder';
- return option;
-};
-
-function promptTextCreator(label) {
- return 'Create option "' + label + '"';
-}
-
-function shouldKeyDownEventCreateNewOption(_ref6) {
- var keyCode = _ref6.keyCode;
-
- switch (keyCode) {
- case 9: // TAB
- case 13: // ENTER
- case 188:
- // COMMA
- return true;
- }
-
- return false;
-};
-
-module.exports = Creatable;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Select":5,"./utils/defaultFilterOptions":9,"./utils/defaultMenuRenderer":10}],4:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Option = _react2['default'].createClass({
- displayName: 'Option',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- className: _react2['default'].PropTypes.string, // className (based on mouse position)
- instancePrefix: _react2['default'].PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
- isDisabled: _react2['default'].PropTypes.bool, // the option is disabled
- isFocused: _react2['default'].PropTypes.bool, // the option is focused
- isSelected: _react2['default'].PropTypes.bool, // the option is selected
- onFocus: _react2['default'].PropTypes.func, // method to handle mouseEnter on option element
- onSelect: _react2['default'].PropTypes.func, // method to handle click on option element
- onUnfocus: _react2['default'].PropTypes.func, // method to handle mouseLeave on option element
- option: _react2['default'].PropTypes.object.isRequired, // object that is base for that option
- optionIndex: _react2['default'].PropTypes.number },
- // index of the option, used to generate unique ids for aria
- blockEvent: function blockEvent(event) {
- event.preventDefault();
- event.stopPropagation();
- if (event.target.tagName !== 'A' || !('href' in event.target)) {
- return;
- }
- if (event.target.target) {
- window.open(event.target.href, event.target.target);
- } else {
- window.location.href = event.target.href;
- }
- },
-
- handleMouseDown: function handleMouseDown(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
-
- handleMouseEnter: function handleMouseEnter(event) {
- this.onFocus(event);
- },
-
- handleMouseMove: function handleMouseMove(event) {
- this.onFocus(event);
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- this.handleMouseDown(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- onFocus: function onFocus(event) {
- if (!this.props.isFocused) {
- this.props.onFocus(this.props.option, event);
- }
- },
- render: function render() {
- var _props = this.props;
- var option = _props.option;
- var instancePrefix = _props.instancePrefix;
- var optionIndex = _props.optionIndex;
-
- var className = (0, _classnames2['default'])(this.props.className, option.className);
-
- return option.disabled ? _react2['default'].createElement(
- 'div',
- { className: className,
- onMouseDown: this.blockEvent,
- onClick: this.blockEvent },
- this.props.children
- ) : _react2['default'].createElement(
- 'div',
- { className: className,
- style: option.style,
- role: 'option',
- onMouseDown: this.handleMouseDown,
- onMouseEnter: this.handleMouseEnter,
- onMouseMove: this.handleMouseMove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEnd,
- id: instancePrefix + '-option-' + optionIndex,
- title: option.title },
- this.props.children
- );
- }
-});
-
-module.exports = Option;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],5:[function(require,module,exports){
-(function (global){
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/react-select
-*/
-
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = (typeof window !== "undefined" ? window['ReactDOM'] : typeof global !== "undefined" ? global['ReactDOM'] : null);
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _reactInputAutosize = (typeof window !== "undefined" ? window['AutosizeInput'] : typeof global !== "undefined" ? global['AutosizeInput'] : null);
-
-var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _utilsDefaultArrowRenderer = require('./utils/defaultArrowRenderer');
-
-var _utilsDefaultArrowRenderer2 = _interopRequireDefault(_utilsDefaultArrowRenderer);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var _utilsDefaultClearRenderer = require('./utils/defaultClearRenderer');
-
-var _utilsDefaultClearRenderer2 = _interopRequireDefault(_utilsDefaultClearRenderer);
-
-var _Async = require('./Async');
-
-var _Async2 = _interopRequireDefault(_Async);
-
-var _AsyncCreatable = require('./AsyncCreatable');
-
-var _AsyncCreatable2 = _interopRequireDefault(_AsyncCreatable);
-
-var _Creatable = require('./Creatable');
-
-var _Creatable2 = _interopRequireDefault(_Creatable);
-
-var _Option = require('./Option');
-
-var _Option2 = _interopRequireDefault(_Option);
-
-var _Value = require('./Value');
-
-var _Value2 = _interopRequireDefault(_Value);
-
-function stringifyValue(value) {
- var valueType = typeof value;
- if (valueType === 'string') {
- return value;
- } else if (valueType === 'object') {
- return JSON.stringify(value);
- } else if (valueType === 'number' || valueType === 'boolean') {
- return String(value);
- } else {
- return '';
- }
-}
-
-var stringOrNode = _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.string, _react2['default'].PropTypes.node]);
-
-var instanceId = 1;
-
-var Select = _react2['default'].createClass({
-
- displayName: 'Select',
-
- propTypes: {
- addLabelText: _react2['default'].PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input
- 'aria-label': _react2['default'].PropTypes.string, // Aria label (for assistive tech)
- 'aria-labelledby': _react2['default'].PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
- arrowRenderer: _react2['default'].PropTypes.func, // Create drop-down caret element
- autoBlur: _react2['default'].PropTypes.bool, // automatically blur the component when an option is selected
- autofocus: _react2['default'].PropTypes.bool, // autofocus the component on mount
- autosize: _react2['default'].PropTypes.bool, // whether to enable autosizing or not
- backspaceRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- backspaceToRemoveMessage: _react2['default'].PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
- className: _react2['default'].PropTypes.string, // className for the outer element
- clearAllText: stringOrNode, // title for the "clear" control when multi: true
- clearRenderer: _react2['default'].PropTypes.func, // create clearable x element
- clearValueText: stringOrNode, // title for the "clear" control
- clearable: _react2['default'].PropTypes.bool, // should it be possible to reset value
- deleteRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- delimiter: _react2['default'].PropTypes.string, // delimiter to use to join multiple values for the hidden field value
- disabled: _react2['default'].PropTypes.bool, // whether the Select is disabled or not
- escapeClearsValue: _react2['default'].PropTypes.bool, // whether escape clears the value when the menu is closed
- filterOption: _react2['default'].PropTypes.func, // method to filter a single option (option, filterString)
- filterOptions: _react2['default'].PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
- ignoreAccents: _react2['default'].PropTypes.bool, // whether to strip diacritics when filtering
- ignoreCase: _react2['default'].PropTypes.bool, // whether to perform case-insensitive filtering
- inputProps: _react2['default'].PropTypes.object, // custom attributes for the Input
- inputRenderer: _react2['default'].PropTypes.func, // returns a custom input component
- instanceId: _react2['default'].PropTypes.string, // set the components instanceId
- isLoading: _react2['default'].PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded)
- joinValues: _react2['default'].PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
- labelKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- matchPos: _react2['default'].PropTypes.string, // (any|start) match the start or entire string when filtering
- matchProp: _react2['default'].PropTypes.string, // (any|label|value) which option property to filter on
- menuBuffer: _react2['default'].PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
- menuContainerStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu container
- menuRenderer: _react2['default'].PropTypes.func, // renders a custom menu with options
- menuStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu
- multi: _react2['default'].PropTypes.bool, // multi-value input
- name: _react2['default'].PropTypes.string, // generates a hidden tag with this field name for html forms
- noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
- onBlur: _react2['default'].PropTypes.func, // onBlur handler: function (event) {}
- onBlurResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared on blur
- onChange: _react2['default'].PropTypes.func, // onChange handler: function (newValue) {}
- onClose: _react2['default'].PropTypes.func, // fires when the menu is closed
- onCloseResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared when menu is closed through the arrow
- onFocus: _react2['default'].PropTypes.func, // onFocus handler: function (event) {}
- onInputChange: _react2['default'].PropTypes.func, // onInputChange handler: function (inputValue) {}
- onInputKeyDown: _react2['default'].PropTypes.func, // input keyDown handler: function (event) {}
- onMenuScrollToBottom: _react2['default'].PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
- onOpen: _react2['default'].PropTypes.func, // fires when the menu is opened
- onValueClick: _react2['default'].PropTypes.func, // onClick handler for value labels: function (value, event) {}
- openAfterFocus: _react2['default'].PropTypes.bool, // boolean to enable opening dropdown when focused
- openOnFocus: _react2['default'].PropTypes.bool, // always open options menu on focus
- optionClassName: _react2['default'].PropTypes.string, // additional class(es) to apply to the elements
- optionComponent: _react2['default'].PropTypes.func, // option component to render in dropdown
- optionRenderer: _react2['default'].PropTypes.func, // optionRenderer: function (option) {}
- options: _react2['default'].PropTypes.array, // array of options
- pageSize: _react2['default'].PropTypes.number, // number of entries to page when using page up/down keys
- placeholder: stringOrNode, // field placeholder, displayed when there's no value
- required: _react2['default'].PropTypes.bool, // applies HTML5 required attribute when needed
- resetValue: _react2['default'].PropTypes.any, // value to use when you clear the control
- scrollMenuIntoView: _react2['default'].PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
- searchable: _react2['default'].PropTypes.bool, // whether to enable searching feature or not
- simpleValue: _react2['default'].PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
- style: _react2['default'].PropTypes.object, // optional style to apply to the control
- tabIndex: _react2['default'].PropTypes.string, // optional tab index of the control
- tabSelectsValue: _react2['default'].PropTypes.bool, // whether to treat tabbing out while focused to be value selection
- value: _react2['default'].PropTypes.any, // initial field value
- valueComponent: _react2['default'].PropTypes.func, // value component to render
- valueKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- valueRenderer: _react2['default'].PropTypes.func, // valueRenderer: function (option) {}
- wrapperStyle: _react2['default'].PropTypes.object },
-
- // optional style to apply to the component wrapper
- statics: { Async: _Async2['default'], AsyncCreatable: _AsyncCreatable2['default'], Creatable: _Creatable2['default'] },
-
- getDefaultProps: function getDefaultProps() {
- return {
- addLabelText: 'Add "{label}"?',
- arrowRenderer: _utilsDefaultArrowRenderer2['default'],
- autosize: true,
- backspaceRemoves: true,
- backspaceToRemoveMessage: 'Press backspace to remove {label}',
- clearable: true,
- clearAllText: 'Clear all',
- clearRenderer: _utilsDefaultClearRenderer2['default'],
- clearValueText: 'Clear value',
- deleteRemoves: true,
- delimiter: ',',
- disabled: false,
- escapeClearsValue: true,
- filterOptions: _utilsDefaultFilterOptions2['default'],
- ignoreAccents: true,
- ignoreCase: true,
- inputProps: {},
- isLoading: false,
- joinValues: false,
- labelKey: 'label',
- matchPos: 'any',
- matchProp: 'any',
- menuBuffer: 0,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- multi: false,
- noResultsText: 'No results found',
- onBlurResetsInput: true,
- onCloseResetsInput: true,
- openAfterFocus: false,
- optionComponent: _Option2['default'],
- pageSize: 5,
- placeholder: 'Select...',
- required: false,
- scrollMenuIntoView: true,
- searchable: true,
- simpleValue: false,
- tabSelectsValue: true,
- valueComponent: _Value2['default'],
- valueKey: 'value'
- };
- },
-
- getInitialState: function getInitialState() {
- return {
- inputValue: '',
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- required: false
- };
- },
-
- componentWillMount: function componentWillMount() {
- this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
- var valueArray = this.getValueArray(this.props.value);
-
- if (this.props.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], this.props.multi)
- });
- }
- },
-
- componentDidMount: function componentDidMount() {
- if (this.props.autofocus) {
- this.focus();
- }
- },
-
- componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
- var valueArray = this.getValueArray(nextProps.value, nextProps);
-
- if (nextProps.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], nextProps.multi)
- });
- }
- },
-
- componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
- if (nextState.isOpen !== this.state.isOpen) {
- this.toggleTouchOutsideEvent(nextState.isOpen);
- var handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose;
- handler && handler();
- }
- },
-
- componentDidUpdate: function componentDidUpdate(prevProps, prevState) {
- // focus to the selected option
- if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
- var focusedOptionNode = _reactDom2['default'].findDOMNode(this.focused);
- var menuNode = _reactDom2['default'].findDOMNode(this.menu);
- menuNode.scrollTop = focusedOptionNode.offsetTop;
- this.hasScrolledToOption = true;
- } else if (!this.state.isOpen) {
- this.hasScrolledToOption = false;
- }
-
- if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
- this._scrollToFocusedOptionOnUpdate = false;
- var focusedDOM = _reactDom2['default'].findDOMNode(this.focused);
- var menuDOM = _reactDom2['default'].findDOMNode(this.menu);
- var focusedRect = focusedDOM.getBoundingClientRect();
- var menuRect = menuDOM.getBoundingClientRect();
- if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) {
- menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight;
- }
- }
- if (this.props.scrollMenuIntoView && this.menuContainer) {
- var menuContainerRect = this.menuContainer.getBoundingClientRect();
- if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
- window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
- }
- }
- if (prevProps.disabled !== this.props.disabled) {
- this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
- this.closeMenu();
- }
- },
-
- componentWillUnmount: function componentWillUnmount() {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- },
-
- toggleTouchOutsideEvent: function toggleTouchOutsideEvent(enabled) {
- if (enabled) {
- if (!document.addEventListener && document.attachEvent) {
- document.attachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.addEventListener('touchstart', this.handleTouchOutside);
- }
- } else {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- }
- },
-
- handleTouchOutside: function handleTouchOutside(event) {
- // handle touch outside on ios to dismiss menu
- if (this.wrapper && !this.wrapper.contains(event.target)) {
- this.closeMenu();
- }
- },
-
- focus: function focus() {
- if (!this.input) return;
- this.input.focus();
-
- if (this.props.openAfterFocus) {
- this.setState({
- isOpen: true
- });
- }
- },
-
- blurInput: function blurInput() {
- if (!this.input) return;
- this.input.blur();
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.handleMouseDown(event);
- },
-
- handleTouchEndClearValue: function handleTouchEndClearValue(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Clear the value
- this.clearValue(event);
- },
-
- handleMouseDown: function handleMouseDown(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
-
- if (event.target.tagName === 'INPUT') {
- return;
- }
-
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
-
- // for the non-searchable select, toggle the menu
- if (!this.props.searchable) {
- this.focus();
- return this.setState({
- isOpen: !this.state.isOpen
- });
- }
-
- if (this.state.isFocused) {
- // On iOS, we can get into a state where we think the input is focused but it isn't really,
- // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
- // Call focus() again here to be safe.
- this.focus();
-
- var input = this.input;
- if (typeof input.getInput === 'function') {
- // Get the actual DOM input if the ref is an component
- input = input.getInput();
- }
-
- // clears the value so that the cursor will be at the end of input when the component re-renders
- input.value = '';
-
- // if the input is focused, ensure the menu is open
- this.setState({
- isOpen: true,
- isPseudoFocused: false
- });
- } else {
- // otherwise, focus the input and open the menu
- this._openAfterFocus = true;
- this.focus();
- }
- },
-
- handleMouseDownOnArrow: function handleMouseDownOnArrow(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- // If the menu isn't open, let the event bubble to the main handleMouseDown
- if (!this.state.isOpen) {
- return;
- }
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
- // close the menu
- this.closeMenu();
- },
-
- handleMouseDownOnMenu: function handleMouseDownOnMenu(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- this._openAfterFocus = true;
- this.focus();
- },
-
- closeMenu: function closeMenu() {
- if (this.props.onCloseResetsInput) {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: ''
- });
- } else {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: this.state.inputValue
- });
- }
- this.hasScrolledToOption = false;
- },
-
- handleInputFocus: function handleInputFocus(event) {
- if (this.props.disabled) return;
- var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
- if (this.props.onFocus) {
- this.props.onFocus(event);
- }
- this.setState({
- isFocused: true,
- isOpen: isOpen
- });
- this._openAfterFocus = false;
- },
-
- handleInputBlur: function handleInputBlur(event) {
- // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
- if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
- this.focus();
- return;
- }
-
- if (this.props.onBlur) {
- this.props.onBlur(event);
- }
- var onBlurredState = {
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false
- };
- if (this.props.onBlurResetsInput) {
- onBlurredState.inputValue = '';
- }
- this.setState(onBlurredState);
- },
-
- handleInputChange: function handleInputChange(event) {
- var newInputValue = event.target.value;
-
- if (this.state.inputValue !== event.target.value && this.props.onInputChange) {
- var nextState = this.props.onInputChange(newInputValue);
- // Note: != used deliberately here to catch undefined and null
- if (nextState != null && typeof nextState !== 'object') {
- newInputValue = '' + nextState;
- }
- }
-
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- inputValue: newInputValue
- });
- },
-
- handleKeyDown: function handleKeyDown(event) {
- if (this.props.disabled) return;
-
- if (typeof this.props.onInputKeyDown === 'function') {
- this.props.onInputKeyDown(event);
- if (event.defaultPrevented) {
- return;
- }
- }
-
- switch (event.keyCode) {
- case 8:
- // backspace
- if (!this.state.inputValue && this.props.backspaceRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- case 9:
- // tab
- if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
- return;
- }
- this.selectFocusedOption();
- return;
- case 13:
- // enter
- if (!this.state.isOpen) return;
- event.stopPropagation();
- this.selectFocusedOption();
- break;
- case 27:
- // escape
- if (this.state.isOpen) {
- this.closeMenu();
- event.stopPropagation();
- } else if (this.props.clearable && this.props.escapeClearsValue) {
- this.clearValue(event);
- event.stopPropagation();
- }
- break;
- case 38:
- // up
- this.focusPreviousOption();
- break;
- case 40:
- // down
- this.focusNextOption();
- break;
- case 33:
- // page up
- this.focusPageUpOption();
- break;
- case 34:
- // page down
- this.focusPageDownOption();
- break;
- case 35:
- // end key
- if (event.shiftKey) {
- return;
- }
- this.focusEndOption();
- break;
- case 36:
- // home key
- if (event.shiftKey) {
- return;
- }
- this.focusStartOption();
- break;
- case 46:
- // backspace
- if (!this.state.inputValue && this.props.deleteRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- default:
- return;
- }
- event.preventDefault();
- },
-
- handleValueClick: function handleValueClick(option, event) {
- if (!this.props.onValueClick) return;
- this.props.onValueClick(option, event);
- },
-
- handleMenuScroll: function handleMenuScroll(event) {
- if (!this.props.onMenuScrollToBottom) return;
- var target = event.target;
-
- if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) {
- this.props.onMenuScrollToBottom();
- }
- },
-
- handleRequired: function handleRequired(value, multi) {
- if (!value) return true;
- return multi ? value.length === 0 : Object.keys(value).length === 0;
- },
-
- getOptionLabel: function getOptionLabel(op) {
- return op[this.props.labelKey];
- },
-
- /**
- * Turns a value into an array from the given options
- * @param {String|Number|Array} value - the value of the select input
- * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
- * @returns {Array} the value of the select represented in an array
- */
- getValueArray: function getValueArray(value, nextProps) {
- var _this = this;
-
- /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
- var props = typeof nextProps === 'object' ? nextProps : this.props;
- if (props.multi) {
- if (typeof value === 'string') value = value.split(props.delimiter);
- if (!Array.isArray(value)) {
- if (value === null || value === undefined) return [];
- value = [value];
- }
- return value.map(function (value) {
- return _this.expandValue(value, props);
- }).filter(function (i) {
- return i;
- });
- }
- var expandedValue = this.expandValue(value, props);
- return expandedValue ? [expandedValue] : [];
- },
-
- /**
- * Retrieve a value from the given options and valueKey
- * @param {String|Number|Array} value - the selected value(s)
- * @param {Object} props - the Select component's props (or nextProps)
- */
- expandValue: function expandValue(value, props) {
- var valueType = typeof value;
- if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
- var options = props.options;
- var valueKey = props.valueKey;
-
- if (!options) return;
- for (var i = 0; i < options.length; i++) {
- if (options[i][valueKey] === value) return options[i];
- }
- },
-
- setValue: function setValue(value) {
- var _this2 = this;
-
- if (this.props.autoBlur) {
- this.blurInput();
- }
- if (!this.props.onChange) return;
- if (this.props.required) {
- var required = this.handleRequired(value, this.props.multi);
- this.setState({ required: required });
- }
- if (this.props.simpleValue && value) {
- value = this.props.multi ? value.map(function (i) {
- return i[_this2.props.valueKey];
- }).join(this.props.delimiter) : value[this.props.valueKey];
- }
- this.props.onChange(value);
- },
-
- selectValue: function selectValue(value) {
- var _this3 = this;
-
- //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise)
- this.hasScrolledToOption = false;
- if (this.props.multi) {
- this.setState({
- inputValue: '',
- focusedIndex: null
- }, function () {
- _this3.addValue(value);
- });
- } else {
- this.setState({
- isOpen: false,
- inputValue: '',
- isPseudoFocused: this.state.isFocused
- }, function () {
- _this3.setValue(value);
- });
- }
- },
-
- addValue: function addValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- var visibleOptions = this._visibleOptions.filter(function (val) {
- return !val.disabled;
- });
- var lastValueIndex = visibleOptions.indexOf(value);
- this.setValue(valueArray.concat(value));
- if (visibleOptions.length - 1 === lastValueIndex) {
- // the last option was selected; focus the second-last one
- this.focusOption(visibleOptions[lastValueIndex - 1]);
- } else if (visibleOptions.length > lastValueIndex) {
- // focus the option below the selected one
- this.focusOption(visibleOptions[lastValueIndex + 1]);
- }
- },
-
- popValue: function popValue() {
- var valueArray = this.getValueArray(this.props.value);
- if (!valueArray.length) return;
- if (valueArray[valueArray.length - 1].clearableValue === false) return;
- this.setValue(valueArray.slice(0, valueArray.length - 1));
- },
-
- removeValue: function removeValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- this.setValue(valueArray.filter(function (i) {
- return i !== value;
- }));
- this.focus();
- },
-
- clearValue: function clearValue(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, ignore it.
- if (event && event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
- this.setValue(this.getResetValue());
- this.setState({
- isOpen: false,
- inputValue: ''
- }, this.focus);
- },
-
- getResetValue: function getResetValue() {
- if (this.props.resetValue !== undefined) {
- return this.props.resetValue;
- } else if (this.props.multi) {
- return [];
- } else {
- return null;
- }
- },
-
- focusOption: function focusOption(option) {
- this.setState({
- focusedOption: option
- });
- },
-
- focusNextOption: function focusNextOption() {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption: function focusPreviousOption() {
- this.focusAdjacentOption('previous');
- },
-
- focusPageUpOption: function focusPageUpOption() {
- this.focusAdjacentOption('page_up');
- },
-
- focusPageDownOption: function focusPageDownOption() {
- this.focusAdjacentOption('page_down');
- },
-
- focusStartOption: function focusStartOption() {
- this.focusAdjacentOption('start');
- },
-
- focusEndOption: function focusEndOption() {
- this.focusAdjacentOption('end');
- },
-
- focusAdjacentOption: function focusAdjacentOption(dir) {
- var options = this._visibleOptions.map(function (option, index) {
- return { option: option, index: index };
- }).filter(function (option) {
- return !option.option.disabled;
- });
- this._scrollToFocusedOptionOnUpdate = true;
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: '',
- focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
- });
- return;
- }
- if (!options.length) return;
- var focusedIndex = -1;
- for (var i = 0; i < options.length; i++) {
- if (this._focusedOption === options[i].option) {
- focusedIndex = i;
- break;
- }
- }
- if (dir === 'next' && focusedIndex !== -1) {
- focusedIndex = (focusedIndex + 1) % options.length;
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedIndex = focusedIndex - 1;
- } else {
- focusedIndex = options.length - 1;
- }
- } else if (dir === 'start') {
- focusedIndex = 0;
- } else if (dir === 'end') {
- focusedIndex = options.length - 1;
- } else if (dir === 'page_up') {
- var potentialIndex = focusedIndex - this.props.pageSize;
- if (potentialIndex < 0) {
- focusedIndex = 0;
- } else {
- focusedIndex = potentialIndex;
- }
- } else if (dir === 'page_down') {
- var potentialIndex = focusedIndex + this.props.pageSize;
- if (potentialIndex > options.length - 1) {
- focusedIndex = options.length - 1;
- } else {
- focusedIndex = potentialIndex;
- }
- }
-
- if (focusedIndex === -1) {
- focusedIndex = 0;
- }
-
- this.setState({
- focusedIndex: options[focusedIndex].index,
- focusedOption: options[focusedIndex].option
- });
- },
-
- getFocusedOption: function getFocusedOption() {
- return this._focusedOption;
- },
-
- getInputValue: function getInputValue() {
- return this.state.inputValue;
- },
-
- selectFocusedOption: function selectFocusedOption() {
- if (this._focusedOption) {
- return this.selectValue(this._focusedOption);
- }
- },
-
- renderLoading: function renderLoading() {
- if (!this.props.isLoading) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-loading-zone', 'aria-hidden': 'true' },
- _react2['default'].createElement('span', { className: 'Select-loading' })
- );
- },
-
- renderValue: function renderValue(valueArray, isOpen) {
- var _this4 = this;
-
- var renderLabel = this.props.valueRenderer || this.getOptionLabel;
- var ValueComponent = this.props.valueComponent;
- if (!valueArray.length) {
- return !this.state.inputValue ? _react2['default'].createElement(
- 'div',
- { className: 'Select-placeholder' },
- this.props.placeholder
- ) : null;
- }
- var onClick = this.props.onValueClick ? this.handleValueClick : null;
- if (this.props.multi) {
- return valueArray.map(function (value, i) {
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: _this4._instancePrefix + '-value-' + i,
- instancePrefix: _this4._instancePrefix,
- disabled: _this4.props.disabled || value.clearableValue === false,
- key: 'value-' + i + '-' + value[_this4.props.valueKey],
- onClick: onClick,
- onRemove: _this4.removeValue,
- value: value
- },
- renderLabel(value, i),
- _react2['default'].createElement(
- 'span',
- { className: 'Select-aria-only' },
- ' '
- )
- );
- });
- } else if (!this.state.inputValue) {
- if (isOpen) onClick = null;
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: this._instancePrefix + '-value-item',
- disabled: this.props.disabled,
- instancePrefix: this._instancePrefix,
- onClick: onClick,
- value: valueArray[0]
- },
- renderLabel(valueArray[0])
- );
- }
- },
-
- renderInput: function renderInput(valueArray, focusedOptionIndex) {
- var _classNames,
- _this5 = this;
-
- var className = (0, _classnames2['default'])('Select-input', this.props.inputProps.className);
- var isOpen = !!this.state.isOpen;
-
- var ariaOwns = (0, _classnames2['default'])((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames));
-
- // TODO: Check how this project includes Object.assign()
- var inputProps = _extends({}, this.props.inputProps, {
- role: 'combobox',
- 'aria-expanded': '' + isOpen,
- 'aria-owns': ariaOwns,
- 'aria-haspopup': '' + isOpen,
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- 'aria-labelledby': this.props['aria-labelledby'],
- 'aria-label': this.props['aria-label'],
- className: className,
- tabIndex: this.props.tabIndex,
- onBlur: this.handleInputBlur,
- onChange: this.handleInputChange,
- onFocus: this.handleInputFocus,
- ref: function ref(_ref) {
- return _this5.input = _ref;
- },
- required: this.state.required,
- value: this.state.inputValue
- });
-
- if (this.props.inputRenderer) {
- return this.props.inputRenderer(inputProps);
- }
-
- if (this.props.disabled || !this.props.searchable) {
- var _props$inputProps = this.props.inputProps;
- var inputClassName = _props$inputProps.inputClassName;
-
- var divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']);
-
- return _react2['default'].createElement('div', _extends({}, divProps, {
- role: 'combobox',
- 'aria-expanded': isOpen,
- 'aria-owns': isOpen ? this._instancePrefix + '-list' : this._instancePrefix + '-value',
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- className: className,
- tabIndex: this.props.tabIndex || 0,
- onBlur: this.handleInputBlur,
- onFocus: this.handleInputFocus,
- ref: function (ref) {
- return _this5.input = ref;
- },
- 'aria-readonly': '' + !!this.props.disabled,
- style: { border: 0, width: 1, display: 'inline-block' } }));
- }
-
- if (this.props.autosize) {
- return _react2['default'].createElement(_reactInputAutosize2['default'], _extends({}, inputProps, { minWidth: '5' }));
- }
- return _react2['default'].createElement(
- 'div',
- { className: className },
- _react2['default'].createElement('input', inputProps)
- );
- },
-
- renderClear: function renderClear() {
- if (!this.props.clearable || !this.props.value || this.props.value === 0 || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return;
- var clear = this.props.clearRenderer();
-
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- onMouseDown: this.clearValue,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEndClearValue
- },
- clear
- );
- },
-
- renderArrow: function renderArrow() {
- var onMouseDown = this.handleMouseDownOnArrow;
- var isOpen = this.state.isOpen;
- var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen });
-
- return _react2['default'].createElement(
- 'span',
- {
- className: 'Select-arrow-zone',
- onMouseDown: onMouseDown
- },
- arrow
- );
- },
-
- filterOptions: function filterOptions(excludeOptions) {
- var filterValue = this.state.inputValue;
- var options = this.props.options || [];
- if (this.props.filterOptions) {
- // Maintain backwards compatibility with boolean attribute
- var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _utilsDefaultFilterOptions2['default'];
-
- return filterOptions(options, filterValue, excludeOptions, {
- filterOption: this.props.filterOption,
- ignoreAccents: this.props.ignoreAccents,
- ignoreCase: this.props.ignoreCase,
- labelKey: this.props.labelKey,
- matchPos: this.props.matchPos,
- matchProp: this.props.matchProp,
- valueKey: this.props.valueKey
- });
- } else {
- return options;
- }
- },
-
- onOptionRef: function onOptionRef(ref, isFocused) {
- if (isFocused) {
- this.focused = ref;
- }
- },
-
- renderMenu: function renderMenu(options, valueArray, focusedOption) {
- if (options && options.length) {
- return this.props.menuRenderer({
- focusedOption: focusedOption,
- focusOption: this.focusOption,
- instancePrefix: this._instancePrefix,
- labelKey: this.props.labelKey,
- onFocus: this.focusOption,
- onSelect: this.selectValue,
- optionClassName: this.props.optionClassName,
- optionComponent: this.props.optionComponent,
- optionRenderer: this.props.optionRenderer || this.getOptionLabel,
- options: options,
- selectValue: this.selectValue,
- valueArray: valueArray,
- valueKey: this.props.valueKey,
- onOptionRef: this.onOptionRef
- });
- } else if (this.props.noResultsText) {
- return _react2['default'].createElement(
- 'div',
- { className: 'Select-noresults' },
- this.props.noResultsText
- );
- } else {
- return null;
- }
- },
-
- renderHiddenField: function renderHiddenField(valueArray) {
- var _this6 = this;
-
- if (!this.props.name) return;
- if (this.props.joinValues) {
- var value = valueArray.map(function (i) {
- return stringifyValue(i[_this6.props.valueKey]);
- }).join(this.props.delimiter);
- return _react2['default'].createElement('input', {
- type: 'hidden',
- ref: function (ref) {
- return _this6.value = ref;
- },
- name: this.props.name,
- value: value,
- disabled: this.props.disabled });
- }
- return valueArray.map(function (item, index) {
- return _react2['default'].createElement('input', { key: 'hidden.' + index,
- type: 'hidden',
- ref: 'value' + index,
- name: _this6.props.name,
- value: stringifyValue(item[_this6.props.valueKey]),
- disabled: _this6.props.disabled });
- });
- },
-
- getFocusableOptionIndex: function getFocusableOptionIndex(selectedOption) {
- var options = this._visibleOptions;
- if (!options.length) return null;
-
- var focusedOption = this.state.focusedOption || selectedOption;
- if (focusedOption && !focusedOption.disabled) {
- var focusedOptionIndex = options.indexOf(focusedOption);
- if (focusedOptionIndex !== -1) {
- return focusedOptionIndex;
- }
- }
-
- for (var i = 0; i < options.length; i++) {
- if (!options[i].disabled) return i;
- }
- return null;
- },
-
- renderOuter: function renderOuter(options, valueArray, focusedOption) {
- var _this7 = this;
-
- var menu = this.renderMenu(options, valueArray, focusedOption);
- if (!menu) {
- return null;
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menuContainer = ref;
- }, className: 'Select-menu-outer', style: this.props.menuContainerStyle },
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menu = ref;
- }, role: 'listbox', className: 'Select-menu', id: this._instancePrefix + '-list',
- style: this.props.menuStyle,
- onScroll: this.handleMenuScroll,
- onMouseDown: this.handleMouseDownOnMenu },
- menu
- )
- );
- },
-
- render: function render() {
- var _this8 = this;
-
- var valueArray = this.getValueArray(this.props.value);
- var options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null);
- var isOpen = this.state.isOpen;
- if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
- var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
-
- var focusedOption = null;
- if (focusedOptionIndex !== null) {
- focusedOption = this._focusedOption = options[focusedOptionIndex];
- } else {
- focusedOption = this._focusedOption = null;
- }
- var className = (0, _classnames2['default'])('Select', this.props.className, {
- 'Select--multi': this.props.multi,
- 'Select--single': !this.props.multi,
- 'is-disabled': this.props.disabled,
- 'is-focused': this.state.isFocused,
- 'is-loading': this.props.isLoading,
- 'is-open': isOpen,
- 'is-pseudo-focused': this.state.isPseudoFocused,
- 'is-searchable': this.props.searchable,
- 'has-value': valueArray.length
- });
-
- var removeMessage = null;
- if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) {
- removeMessage = _react2['default'].createElement(
- 'span',
- { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' },
- this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])
- );
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.wrapper = ref;
- },
- className: className,
- style: this.props.wrapperStyle },
- this.renderHiddenField(valueArray),
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.control = ref;
- },
- className: 'Select-control',
- style: this.props.style,
- onKeyDown: this.handleKeyDown,
- onMouseDown: this.handleMouseDown,
- onTouchEnd: this.handleTouchEnd,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove
- },
- _react2['default'].createElement(
- 'span',
- { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' },
- this.renderValue(valueArray, isOpen),
- this.renderInput(valueArray, focusedOptionIndex)
- ),
- removeMessage,
- this.renderLoading(),
- this.renderClear(),
- this.renderArrow()
- ),
- isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null
- );
- }
-
-});
-
-exports['default'] = Select;
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Async":1,"./AsyncCreatable":2,"./Creatable":3,"./Option":4,"./Value":6,"./utils/defaultArrowRenderer":7,"./utils/defaultClearRenderer":8,"./utils/defaultFilterOptions":9,"./utils/defaultMenuRenderer":10}],6:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Value = _react2['default'].createClass({
-
- displayName: 'Value',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- disabled: _react2['default'].PropTypes.bool, // disabled prop passed to ReactSelect
- id: _react2['default'].PropTypes.string, // Unique id for the value - used for aria
- onClick: _react2['default'].PropTypes.func, // method to handle click on value label
- onRemove: _react2['default'].PropTypes.func, // method to handle removal of the value
- value: _react2['default'].PropTypes.object.isRequired },
-
- // the option object for this value
- handleMouseDown: function handleMouseDown(event) {
- if (event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- if (this.props.onClick) {
- event.stopPropagation();
- this.props.onClick(this.props.value, event);
- return;
- }
- if (this.props.value.href) {
- event.stopPropagation();
- }
- },
-
- onRemove: function onRemove(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onRemove(this.props.value);
- },
-
- handleTouchEndRemove: function handleTouchEndRemove(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.onRemove(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- renderRemoveIcon: function renderRemoveIcon() {
- if (this.props.disabled || !this.props.onRemove) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-value-icon',
- 'aria-hidden': 'true',
- onMouseDown: this.onRemove,
- onTouchEnd: this.handleTouchEndRemove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove },
- '×'
- );
- },
-
- renderLabel: function renderLabel() {
- var className = 'Select-value-label';
- return this.props.onClick || this.props.value.href ? _react2['default'].createElement(
- 'a',
- { className: className, href: this.props.value.href, target: this.props.value.target, onMouseDown: this.handleMouseDown, onTouchEnd: this.handleMouseDown },
- this.props.children
- ) : _react2['default'].createElement(
- 'span',
- { className: className, role: 'option', 'aria-selected': 'true', id: this.props.id },
- this.props.children
- );
- },
-
- render: function render() {
- return _react2['default'].createElement(
- 'div',
- { className: (0, _classnames2['default'])('Select-value', this.props.value.className),
- style: this.props.value.style,
- title: this.props.value.title
- },
- this.renderRemoveIcon(),
- this.renderLabel()
- );
- }
-
-});
-
-module.exports = Value;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],7:[function(require,module,exports){
-(function (global){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports["default"] = arrowRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function arrowRenderer(_ref) {
- var onMouseDown = _ref.onMouseDown;
-
- return _react2["default"].createElement("span", {
- className: "Select-arrow",
- onMouseDown: onMouseDown
- });
-}
-
-;
-module.exports = exports["default"];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],8:[function(require,module,exports){
-(function (global){
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-exports['default'] = clearRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function clearRenderer() {
- return _react2['default'].createElement('span', {
- className: 'Select-clear',
- dangerouslySetInnerHTML: { __html: '×' }
- });
-}
-
-;
-module.exports = exports['default'];
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],9:[function(require,module,exports){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _stripDiacritics = require('./stripDiacritics');
-
-var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics);
-
-function filterOptions(options, filterValue, excludeOptions, props) {
- var _this = this;
-
- if (props.ignoreAccents) {
- filterValue = (0, _stripDiacritics2['default'])(filterValue);
- }
-
- if (props.ignoreCase) {
- filterValue = filterValue.toLowerCase();
- }
-
- if (excludeOptions) excludeOptions = excludeOptions.map(function (i) {
- return i[props.valueKey];
- });
-
- return options.filter(function (option) {
- if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false;
- if (props.filterOption) return props.filterOption.call(_this, option, filterValue);
- if (!filterValue) return true;
- var valueTest = String(option[props.valueKey]);
- var labelTest = String(option[props.labelKey]);
- if (props.ignoreAccents) {
- if (props.matchProp !== 'label') valueTest = (0, _stripDiacritics2['default'])(valueTest);
- if (props.matchProp !== 'value') labelTest = (0, _stripDiacritics2['default'])(labelTest);
- }
- if (props.ignoreCase) {
- if (props.matchProp !== 'label') valueTest = valueTest.toLowerCase();
- if (props.matchProp !== 'value') labelTest = labelTest.toLowerCase();
- }
- return props.matchPos === 'start' ? props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue || props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue : props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0 || props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0;
- });
-}
-
-module.exports = filterOptions;
-
-},{"./stripDiacritics":11}],10:[function(require,module,exports){
-(function (global){
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _classnames = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
-
-var _react2 = _interopRequireDefault(_react);
-
-function menuRenderer(_ref) {
- var focusedOption = _ref.focusedOption;
- var instancePrefix = _ref.instancePrefix;
- var labelKey = _ref.labelKey;
- var onFocus = _ref.onFocus;
- var onSelect = _ref.onSelect;
- var optionClassName = _ref.optionClassName;
- var optionComponent = _ref.optionComponent;
- var optionRenderer = _ref.optionRenderer;
- var options = _ref.options;
- var valueArray = _ref.valueArray;
- var valueKey = _ref.valueKey;
- var onOptionRef = _ref.onOptionRef;
-
- var Option = optionComponent;
-
- return options.map(function (option, i) {
- var isSelected = valueArray && valueArray.indexOf(option) > -1;
- var isFocused = option === focusedOption;
- var optionClass = (0, _classnames2['default'])(optionClassName, {
- 'Select-option': true,
- 'is-selected': isSelected,
- 'is-focused': isFocused,
- 'is-disabled': option.disabled
- });
-
- return _react2['default'].createElement(
- Option,
- {
- className: optionClass,
- instancePrefix: instancePrefix,
- isDisabled: option.disabled,
- isFocused: isFocused,
- isSelected: isSelected,
- key: 'option-' + i + '-' + option[valueKey],
- onFocus: onFocus,
- onSelect: onSelect,
- option: option,
- optionIndex: i,
- ref: function (ref) {
- onOptionRef(ref, isFocused);
- }
- },
- optionRenderer(option, i)
- );
- });
-}
-
-module.exports = menuRenderer;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],11:[function(require,module,exports){
-'use strict';
-
-var map = [{ 'base': 'A', 'letters': /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g }, { 'base': 'AA', 'letters': /[\uA732]/g }, { 'base': 'AE', 'letters': /[\u00C6\u01FC\u01E2]/g }, { 'base': 'AO', 'letters': /[\uA734]/g }, { 'base': 'AU', 'letters': /[\uA736]/g }, { 'base': 'AV', 'letters': /[\uA738\uA73A]/g }, { 'base': 'AY', 'letters': /[\uA73C]/g }, { 'base': 'B', 'letters': /[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g }, { 'base': 'C', 'letters': /[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g }, { 'base': 'D', 'letters': /[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g }, { 'base': 'DZ', 'letters': /[\u01F1\u01C4]/g }, { 'base': 'Dz', 'letters': /[\u01F2\u01C5]/g }, { 'base': 'E', 'letters': /[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g }, { 'base': 'F', 'letters': /[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g }, { 'base': 'G', 'letters': /[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g }, { 'base': 'H', 'letters': /[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g }, { 'base': 'I', 'letters': /[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g }, { 'base': 'J', 'letters': /[\u004A\u24BF\uFF2A\u0134\u0248]/g }, { 'base': 'K', 'letters': /[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g }, { 'base': 'L', 'letters': /[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g }, { 'base': 'LJ', 'letters': /[\u01C7]/g }, { 'base': 'Lj', 'letters': /[\u01C8]/g }, { 'base': 'M', 'letters': /[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g }, { 'base': 'N', 'letters': /[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g }, { 'base': 'NJ', 'letters': /[\u01CA]/g }, { 'base': 'Nj', 'letters': /[\u01CB]/g }, { 'base': 'O', 'letters': /[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g }, { 'base': 'OI', 'letters': /[\u01A2]/g }, { 'base': 'OO', 'letters': /[\uA74E]/g }, { 'base': 'OU', 'letters': /[\u0222]/g }, { 'base': 'P', 'letters': /[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g }, { 'base': 'Q', 'letters': /[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g }, { 'base': 'R', 'letters': /[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g }, { 'base': 'S', 'letters': /[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g }, { 'base': 'T', 'letters': /[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g }, { 'base': 'TZ', 'letters': /[\uA728]/g }, { 'base': 'U', 'letters': /[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g }, { 'base': 'V', 'letters': /[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g }, { 'base': 'VY', 'letters': /[\uA760]/g }, { 'base': 'W', 'letters': /[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g }, { 'base': 'X', 'letters': /[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g }, { 'base': 'Y', 'letters': /[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g }, { 'base': 'Z', 'letters': /[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g }, { 'base': 'a', 'letters': /[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g }, { 'base': 'aa', 'letters': /[\uA733]/g }, { 'base': 'ae', 'letters': /[\u00E6\u01FD\u01E3]/g }, { 'base': 'ao', 'letters': /[\uA735]/g }, { 'base': 'au', 'letters': /[\uA737]/g }, { 'base': 'av', 'letters': /[\uA739\uA73B]/g }, { 'base': 'ay', 'letters': /[\uA73D]/g }, { 'base': 'b', 'letters': /[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g }, { 'base': 'c', 'letters': /[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g }, { 'base': 'd', 'letters': /[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g }, { 'base': 'dz', 'letters': /[\u01F3\u01C6]/g }, { 'base': 'e', 'letters': /[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g }, { 'base': 'f', 'letters': /[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g }, { 'base': 'g', 'letters': /[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g }, { 'base': 'h', 'letters': /[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g }, { 'base': 'hv', 'letters': /[\u0195]/g }, { 'base': 'i', 'letters': /[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g }, { 'base': 'j', 'letters': /[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g }, { 'base': 'k', 'letters': /[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g }, { 'base': 'l', 'letters': /[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g }, { 'base': 'lj', 'letters': /[\u01C9]/g }, { 'base': 'm', 'letters': /[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g }, { 'base': 'n', 'letters': /[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g }, { 'base': 'nj', 'letters': /[\u01CC]/g }, { 'base': 'o', 'letters': /[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g }, { 'base': 'oi', 'letters': /[\u01A3]/g }, { 'base': 'ou', 'letters': /[\u0223]/g }, { 'base': 'oo', 'letters': /[\uA74F]/g }, { 'base': 'p', 'letters': /[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g }, { 'base': 'q', 'letters': /[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g }, { 'base': 'r', 'letters': /[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g }, { 'base': 's', 'letters': /[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g }, { 'base': 't', 'letters': /[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g }, { 'base': 'tz', 'letters': /[\uA729]/g }, { 'base': 'u', 'letters': /[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g }, { 'base': 'v', 'letters': /[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g }, { 'base': 'vy', 'letters': /[\uA761]/g }, { 'base': 'w', 'letters': /[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g }, { 'base': 'x', 'letters': /[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g }, { 'base': 'y', 'letters': /[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g }, { 'base': 'z', 'letters': /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g }];
-
-module.exports = function stripDiacritics(str) {
- for (var i = 0; i < map.length; i++) {
- str = str.replace(map[i].letters, map[i].base);
- }
- return str;
-};
-
-},{}]},{},[5])(5)
-});
\ No newline at end of file
diff --git a/examples/src/.gitignore b/examples/src/.gitignore
deleted file mode 100644
index c33fa28330..0000000000
--- a/examples/src/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-## This file is here to ensure it is included in the gh-pages branch,
-## when `gulp deploy` is used to push updates to the demo site.
-
-# Dependency directory
-node_modules
diff --git a/examples/src/.npmignore b/examples/src/.npmignore
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/examples/src/app.js b/examples/src/app.js
deleted file mode 100644
index d8c83d7ce2..0000000000
--- a/examples/src/app.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/* eslint react/prop-types: 0 */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import Select from 'react-select';
-
-import Creatable from './components/Creatable';
-import Contributors from './components/Contributors';
-import GithubUsers from './components/GithubUsers';
-import CustomComponents from './components/CustomComponents';
-import CustomRender from './components/CustomRender';
-import Multiselect from './components/Multiselect';
-import NumericSelect from './components/NumericSelect';
-import BooleanSelect from './components/BooleanSelect';
-import Virtualized from './components/Virtualized';
-import States from './components/States';
-
-ReactDOM.render(
-
-
-
-
-
-
-
-
-
-
-
-
,
- document.getElementById('example')
-);
diff --git a/examples/src/components/BooleanSelect.js b/examples/src/components/BooleanSelect.js
deleted file mode 100644
index 31a87f0c48..0000000000
--- a/examples/src/components/BooleanSelect.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-var ValuesAsBooleansField = React.createClass({
- displayName: 'ValuesAsBooleansField',
- propTypes: {
- label: React.PropTypes.string
- },
- getInitialState () {
- return {
- options: [
- { value: true, label: 'Yes' },
- { value: false, label: 'No' }
- ],
- value: null
- };
- },
- onChange(value) {
- this.setState({ value });
- console.log('Boolean Select value changed to', value);
- },
- render () {
- return (
-
-
{this.props.label}
-
-
This example uses simple boolean values
-
- );
- }
-});
-
-module.exports = ValuesAsBooleansField;
diff --git a/examples/src/components/Contributors.js b/examples/src/components/Contributors.js
deleted file mode 100644
index 9aac1e5882..0000000000
--- a/examples/src/components/Contributors.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-const CONTRIBUTORS = require('../data/contributors');
-const MAX_CONTRIBUTORS = 6;
-const ASYNC_DELAY = 500;
-
-const Contributors = React.createClass({
- displayName: 'Contributors',
- propTypes: {
- label: React.PropTypes.string,
- },
- getInitialState () {
- return {
- multi: true,
- value: [CONTRIBUTORS[0]],
- };
- },
- onChange (value) {
- this.setState({
- value: value,
- });
- },
- switchToMulti () {
- this.setState({
- multi: true,
- value: [this.state.value],
- });
- },
- switchToSingle () {
- this.setState({
- multi: false,
- value: this.state.value[0],
- });
- },
- getContributors (input, callback) {
- input = input.toLowerCase();
- var options = CONTRIBUTORS.filter(i => {
- return i.github.substr(0, input.length) === input;
- });
- var data = {
- options: options.slice(0, MAX_CONTRIBUTORS),
- complete: options.length <= MAX_CONTRIBUTORS,
- };
- setTimeout(function() {
- callback(null, data);
- }, ASYNC_DELAY);
- },
- gotoContributor (value, event) {
- window.open('https://github.com/' + value.github);
- },
- render () {
- return (
-
-
{this.props.label}
-
-
-
-
- Multiselect
-
-
-
- Single Value
-
-
-
This example implements custom label and value properties, async options and opens the github profiles in a new window when values are clicked
-
- );
- }
-});
-
-module.exports = Contributors;
diff --git a/examples/src/components/Creatable.js b/examples/src/components/Creatable.js
deleted file mode 100644
index f2218f83a9..0000000000
--- a/examples/src/components/Creatable.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-var CreatableDemo = React.createClass({
- displayName: 'CreatableDemo',
- propTypes: {
- hint: React.PropTypes.string,
- label: React.PropTypes.string
- },
- getInitialState () {
- return {
- multi: true,
- multiValue: [],
- options: [
- { value: 'R', label: 'Red' },
- { value: 'G', label: 'Green' },
- { value: 'B', label: 'Blue' }
- ],
- value: undefined
- };
- },
- handleOnChange (value) {
- const { multi } = this.state;
- if (multi) {
- this.setState({ multiValue: value });
- } else {
- this.setState({ value });
- }
- },
- render () {
- const { multi, multiValue, options, value } = this.state;
- return (
-
-
{this.props.label}
-
-
{this.props.hint}
-
-
- this.setState({ multi: true })}
- />
- Multiselect
-
-
- this.setState({ multi: false })}
- />
- Single Value
-
-
-
- );
- }
-});
-
-module.exports = CreatableDemo;
diff --git a/examples/src/components/CustomComponents.js b/examples/src/components/CustomComponents.js
deleted file mode 100644
index 2fe57e3f5d..0000000000
--- a/examples/src/components/CustomComponents.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-import Gravatar from 'react-gravatar';
-
-const USERS = require('../data/users');
-const GRAVATAR_SIZE = 15;
-
-const GravatarOption = React.createClass({
- propTypes: {
- children: React.PropTypes.node,
- className: React.PropTypes.string,
- isDisabled: React.PropTypes.bool,
- isFocused: React.PropTypes.bool,
- isSelected: React.PropTypes.bool,
- onFocus: React.PropTypes.func,
- onSelect: React.PropTypes.func,
- option: React.PropTypes.object.isRequired,
- },
- handleMouseDown (event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
- handleMouseEnter (event) {
- this.props.onFocus(this.props.option, event);
- },
- handleMouseMove (event) {
- if (this.props.isFocused) return;
- this.props.onFocus(this.props.option, event);
- },
- render () {
- let gravatarStyle = {
- borderRadius: 3,
- display: 'inline-block',
- marginRight: 10,
- position: 'relative',
- top: -2,
- verticalAlign: 'middle',
- };
- return (
-
-
- {this.props.children}
-
- );
- }
-});
-
-const GravatarValue = React.createClass({
- propTypes: {
- children: React.PropTypes.node,
- placeholder: React.PropTypes.string,
- value: React.PropTypes.object
- },
- render () {
- var gravatarStyle = {
- borderRadius: 3,
- display: 'inline-block',
- marginRight: 10,
- position: 'relative',
- top: -2,
- verticalAlign: 'middle',
- };
- return (
-
-
-
- {this.props.children}
-
-
- );
- }
-});
-
-const UsersField = React.createClass({
- propTypes: {
- hint: React.PropTypes.string,
- label: React.PropTypes.string,
- },
- getInitialState () {
- return {};
- },
- setValue (value) {
- this.setState({ value });
- },
- render () {
- var placeholder = ☺ Select User ;
-
- return (
-
-
{this.props.label}
-
-
- This example implements custom Option and Value components to render a Gravatar image for each user based on their email.
- It also demonstrates rendering HTML elements as the placeholder.
-
-
- );
- }
-});
-
-function arrowRenderer () {
- return (
- +
- );
-}
-
-module.exports = UsersField;
diff --git a/examples/src/components/CustomRender.js b/examples/src/components/CustomRender.js
deleted file mode 100644
index 9990f12af6..0000000000
--- a/examples/src/components/CustomRender.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-import Highlighter from 'react-highlight-words';
-
-var DisabledUpsellOptions = React.createClass({
- displayName: 'DisabledUpsellOptions',
- propTypes: {
- label: React.PropTypes.string,
- },
- getInitialState () {
- return {};
- },
- setValue (value) {
- this.setState({ value });
- if (value) {
- console.log('Support level selected:', value.label);
- }
- },
- renderLink: function() {
- return Upgrade here! ;
- },
- renderOption: function(option) {
- return (
-
- );
- },
- renderValue: function(option) {
- return {option.label} ;
- },
- render: function() {
- var options = [
- { label: 'Basic customer support', value: 'basic', color: '#E31864' },
- { label: 'Premium customer support', value: 'premium', color: '#6216A3' },
- { label: 'Pro customer support', value: 'pro', disabled: true, link: this.renderLink() },
- ];
- return (
-
-
{this.props.label}
-
this._inputValue = inputValue}
- options={options}
- optionRenderer={this.renderOption}
- onChange={this.setValue}
- value={this.state.value}
- valueRenderer={this.renderValue}
- />
- This demonstates custom render methods and links in disabled options
-
- );
- }
-});
-module.exports = DisabledUpsellOptions;
diff --git a/examples/src/components/GithubUsers.js b/examples/src/components/GithubUsers.js
deleted file mode 100644
index 05939d7174..0000000000
--- a/examples/src/components/GithubUsers.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-import fetch from 'isomorphic-fetch';
-
-
-const GithubUsers = React.createClass({
- displayName: 'GithubUsers',
- propTypes: {
- label: React.PropTypes.string,
- },
- getInitialState () {
- return {
- backspaceRemoves: true,
- multi: true
- };
- },
- onChange (value) {
- this.setState({
- value: value,
- });
- },
- switchToMulti () {
- this.setState({
- multi: true,
- value: [this.state.value],
- });
- },
- switchToSingle () {
- this.setState({
- multi: false,
- value: this.state.value ? this.state.value[0] : null
- });
- },
- getUsers (input) {
- if (!input) {
- return Promise.resolve({ options: [] });
- }
-
- return fetch(`https://api.github.com/search/users?q=${input}`)
- .then((response) => response.json())
- .then((json) => {
- return { options: json.items };
- });
- },
- gotoUser (value, event) {
- window.open(value.html_url);
- },
- toggleBackspaceRemoves () {
- this.setState({
- backspaceRemoves: !this.state.backspaceRemoves
- });
- },
- toggleCreatable () {
- this.setState({
- creatable: !this.state.creatable
- });
- },
- render () {
- const AsyncComponent = this.state.creatable
- ? Select.AsyncCreatable
- : Select.Async;
-
- return (
-
- );
- }
-});
-
-module.exports = GithubUsers;
diff --git a/examples/src/components/Multiselect.js b/examples/src/components/Multiselect.js
deleted file mode 100644
index 3142e75ef9..0000000000
--- a/examples/src/components/Multiselect.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-const FLAVOURS = [
- { label: 'Chocolate', value: 'chocolate' },
- { label: 'Vanilla', value: 'vanilla' },
- { label: 'Strawberry', value: 'strawberry' },
- { label: 'Caramel', value: 'caramel' },
- { label: 'Cookies and Cream', value: 'cookiescream' },
- { label: 'Peppermint', value: 'peppermint' },
-];
-
-const WHY_WOULD_YOU = [
- { label: 'Chocolate (are you crazy?)', value: 'chocolate', disabled: true },
-].concat(FLAVOURS.slice(1));
-
-var MultiSelectField = React.createClass({
- displayName: 'MultiSelectField',
- propTypes: {
- label: React.PropTypes.string,
- },
- getInitialState () {
- return {
- disabled: false,
- crazy: false,
- options: FLAVOURS,
- value: [],
- };
- },
- handleSelectChange (value) {
- console.log('You\'ve selected:', value);
- this.setState({ value });
- },
- toggleDisabled (e) {
- this.setState({ disabled: e.target.checked });
- },
- toggleChocolate (e) {
- let crazy = e.target.checked;
- this.setState({
- crazy: crazy,
- options: crazy ? WHY_WOULD_YOU : FLAVOURS,
- });
- },
- render () {
- return (
-
- );
- }
-});
-
-module.exports = MultiSelectField;
diff --git a/examples/src/components/NumericSelect.js b/examples/src/components/NumericSelect.js
deleted file mode 100644
index 2dcbeb43b8..0000000000
--- a/examples/src/components/NumericSelect.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-var ValuesAsNumbersField = React.createClass({
- displayName: 'ValuesAsNumbersField',
- propTypes: {
- label: React.PropTypes.string
- },
- getInitialState () {
- return {
- options: [
- { value: 10, label: 'Ten' },
- { value: 11, label: 'Eleven' },
- { value: 12, label: 'Twelve' },
- { value: 23, label: 'Twenty-three' },
- { value: 24, label: 'Twenty-four' }
- ],
- matchPos: 'any',
- matchValue: true,
- matchLabel: true,
- value: null,
- multi: false
- };
- },
- onChangeMatchStart(event) {
- this.setState({
- matchPos: event.target.checked ? 'start' : 'any'
- });
- },
- onChangeMatchValue(event) {
- this.setState({
- matchValue: event.target.checked
- });
- },
- onChangeMatchLabel(event) {
- this.setState({
- matchLabel: event.target.checked
- });
- },
- onChange(value) {
- this.setState({ value });
- console.log('Numeric Select value changed to', value);
- },
- onChangeMulti(event) {
- this.setState({
- multi: event.target.checked
- });
- },
- render () {
- var matchProp = 'any';
- if (this.state.matchLabel && !this.state.matchValue) {
- matchProp = 'label';
- }
- if (!this.state.matchLabel && this.state.matchValue) {
- matchProp = 'value';
- }
- return (
-
- );
- }
-});
-
-module.exports = ValuesAsNumbersField;
diff --git a/examples/src/components/States.js b/examples/src/components/States.js
deleted file mode 100644
index 8103c2eb90..0000000000
--- a/examples/src/components/States.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-
-const STATES = require('../data/states');
-
-var StatesField = React.createClass({
- displayName: 'StatesField',
- propTypes: {
- label: React.PropTypes.string,
- searchable: React.PropTypes.bool,
- },
- getDefaultProps () {
- return {
- label: 'States:',
- searchable: true,
- };
- },
- getInitialState () {
- return {
- country: 'AU',
- disabled: false,
- searchable: this.props.searchable,
- selectValue: 'new-south-wales',
- clearable: true,
- };
- },
- switchCountry (e) {
- var newCountry = e.target.value;
- console.log('Country changed to ' + newCountry);
- this.setState({
- country: newCountry,
- selectValue: null
- });
- },
- updateValue (newValue) {
- console.log('State changed to ' + newValue);
- this.setState({
- selectValue: newValue
- });
- },
- focusStateSelect () {
- this.refs.stateSelect.focus();
- },
- toggleCheckbox (e) {
- let newState = {};
- newState[e.target.name] = e.target.checked;
- this.setState(newState);
- },
- render () {
- var options = STATES[this.state.country];
- return (
-
- );
- }
-});
-
-
-module.exports = StatesField;
diff --git a/examples/src/components/Virtualized.js b/examples/src/components/Virtualized.js
deleted file mode 100644
index a540083eb2..0000000000
--- a/examples/src/components/Virtualized.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import VirtualizedSelect from 'react-virtualized-select';
-
-const DATA = require('../data/cities');
-
-var CitiesField = React.createClass({
- displayName: 'CitiesField',
- getInitialState () {
- return {};
- },
- updateValue (newValue) {
- this.setState({
- selectValue: newValue
- });
- },
- render () {
- var options = DATA.CITIES;
- return (
-
-
Cities (Large Dataset)
-
-
-
- );
- }
-});
-
-
-module.exports = CitiesField;
diff --git a/examples/src/data/cities.js b/examples/src/data/cities.js
deleted file mode 100644
index 1060f39eee..0000000000
--- a/examples/src/data/cities.js
+++ /dev/null
@@ -1,1002 +0,0 @@
-exports.CITIES = [
- { name: 'Abilene' },
- { name: 'Addison' },
- { name: 'Akron' },
- { name: 'Alameda' },
- { name: 'Albany' },
- { name: 'Albany' },
- { name: 'Albany' },
- { name: 'Albuquerque' },
- { name: 'Alexandria' },
- { name: 'Alexandria' },
- { name: 'Alhambra' },
- { name: 'Aliso Viejo' },
- { name: 'Allen' },
- { name: 'Allentown' },
- { name: 'Alpharetta' },
- { name: 'Altamonte Springs' },
- { name: 'Altoona' },
- { name: 'Amarillo' },
- { name: 'Ames' },
- { name: 'Anaheim' },
- { name: 'Anchorage' },
- { name: 'Anderson' },
- { name: 'Ankeny' },
- { name: 'Ann Arbor' },
- { name: 'Annapolis' },
- { name: 'Antioch' },
- { name: 'Apache Junction' },
- { name: 'Apex' },
- { name: 'Apopka' },
- { name: 'Apple Valley' },
- { name: 'Apple Valley' },
- { name: 'Appleton' },
- { name: 'Arcadia' },
- { name: 'Arlington' },
- { name: 'Arlington Heights' },
- { name: 'Arvada' },
- { name: 'Asheville' },
- { name: 'Athens-Clarke County' },
- { name: 'Atlanta' },
- { name: 'Atlantic City' },
- { name: 'Attleboro' },
- { name: 'Auburn' },
- { name: 'Auburn' },
- { name: 'Augusta-Richmond County' },
- { name: 'Aurora' },
- { name: 'Aurora' },
- { name: 'Austin' },
- { name: 'Aventura' },
- { name: 'Avondale' },
- { name: 'Azusa' },
- { name: 'Bakersfield' },
- { name: 'Baldwin Park' },
- { name: 'Baltimore' },
- { name: 'Barnstable Town' },
- { name: 'Bartlett' },
- { name: 'Bartlett' },
- { name: 'Baton Rouge' },
- { name: 'Battle Creek' },
- { name: 'Bayonne' },
- { name: 'Baytown' },
- { name: 'Beaumont' },
- { name: 'Beaumont' },
- { name: 'Beavercreek' },
- { name: 'Beaverton' },
- { name: 'Bedford' },
- { name: 'Bell Gardens' },
- { name: 'Belleville' },
- { name: 'Bellevue' },
- { name: 'Bellevue' },
- { name: 'Bellflower' },
- { name: 'Bellingham' },
- { name: 'Beloit' },
- { name: 'Bend' },
- { name: 'Bentonville' },
- { name: 'Berkeley' },
- { name: 'Berwyn' },
- { name: 'Bethlehem' },
- { name: 'Beverly' },
- { name: 'Billings' },
- { name: 'Biloxi' },
- { name: 'Binghamton' },
- { name: 'Birmingham' },
- { name: 'Bismarck' },
- { name: 'Blacksburg' },
- { name: 'Blaine' },
- { name: 'Bloomington' },
- { name: 'Bloomington' },
- { name: 'Bloomington' },
- { name: 'Blue Springs' },
- { name: 'Boca Raton' },
- { name: 'Boise City' },
- { name: 'Bolingbrook' },
- { name: 'Bonita Springs' },
- { name: 'Bossier City' },
- { name: 'Boston' },
- { name: 'Boulder' },
- { name: 'Bountiful' },
- { name: 'Bowie' },
- { name: 'Bowling Green' },
- { name: 'Boynton Beach' },
- { name: 'Bozeman' },
- { name: 'Bradenton' },
- { name: 'Brea' },
- { name: 'Bremerton' },
- { name: 'Brentwood' },
- { name: 'Brentwood' },
- { name: 'Bridgeport' },
- { name: 'Bristol' },
- { name: 'Brockton' },
- { name: 'Broken Arrow' },
- { name: 'Brookfield' },
- { name: 'Brookhaven' },
- { name: 'Brooklyn Park' },
- { name: 'Broomfield' },
- { name: 'Brownsville' },
- { name: 'Bryan' },
- { name: 'Buckeye' },
- { name: 'Buena Park' },
- { name: 'Buffalo' },
- { name: 'Buffalo Grove' },
- { name: 'Bullhead City' },
- { name: 'Burbank' },
- { name: 'Burien' },
- { name: 'Burleson' },
- { name: 'Burlington' },
- { name: 'Burlington' },
- { name: 'Burnsville' },
- { name: 'Caldwell' },
- { name: 'Calexico' },
- { name: 'Calumet City' },
- { name: 'Camarillo' },
- { name: 'Cambridge' },
- { name: 'Camden' },
- { name: 'Campbell' },
- { name: 'Canton' },
- { name: 'Cape Coral' },
- { name: 'Cape Girardeau' },
- { name: 'Carlsbad' },
- { name: 'Carmel' },
- { name: 'Carol Stream' },
- { name: 'Carpentersville' },
- { name: 'Carrollton' },
- { name: 'Carson' },
- { name: 'Carson City' },
- { name: 'Cary' },
- { name: 'Casa Grande' },
- { name: 'Casper' },
- { name: 'Castle Rock' },
- { name: 'Cathedral City' },
- { name: 'Cedar Falls' },
- { name: 'Cedar Hill' },
- { name: 'Cedar Park' },
- { name: 'Cedar Rapids' },
- { name: 'Centennial' },
- { name: 'Ceres' },
- { name: 'Cerritos' },
- { name: 'Champaign' },
- { name: 'Chandler' },
- { name: 'Chapel Hill' },
- { name: 'Charleston' },
- { name: 'Charleston' },
- { name: 'Charlotte' },
- { name: 'Charlottesville' },
- { name: 'Chattanooga' },
- { name: 'Chelsea' },
- { name: 'Chesapeake' },
- { name: 'Chesterfield' },
- { name: 'Cheyenne' },
- { name: 'Chicago' },
- { name: 'Chico' },
- { name: 'Chicopee' },
- { name: 'Chino' },
- { name: 'Chino Hills' },
- { name: 'Chula Vista' },
- { name: 'Cicero' },
- { name: 'Cincinnati' },
- { name: 'Citrus Heights' },
- { name: 'Clarksville' },
- { name: 'Clearwater' },
- { name: 'Cleveland' },
- { name: 'Cleveland' },
- { name: 'Cleveland Heights' },
- { name: 'Clifton' },
- { name: 'Clovis' },
- { name: 'Clovis' },
- { name: 'Coachella' },
- { name: 'Coconut Creek' },
- { name: 'Coeur d\'Alene' },
- { name: 'College Station' },
- { name: 'Collierville' },
- { name: 'Colorado Springs' },
- { name: 'Colton' },
- { name: 'Columbia' },
- { name: 'Columbia' },
- { name: 'Columbus' },
- { name: 'Columbus' },
- { name: 'Columbus' },
- { name: 'Commerce City' },
- { name: 'Compton' },
- { name: 'Concord' },
- { name: 'Concord' },
- { name: 'Concord' },
- { name: 'Conroe' },
- { name: 'Conway' },
- { name: 'Coon Rapids' },
- { name: 'Coppell' },
- { name: 'Coral Gables' },
- { name: 'Coral Springs' },
- { name: 'Corona' },
- { name: 'Corpus Christi' },
- { name: 'Corvallis' },
- { name: 'Costa Mesa' },
- { name: 'Council Bluffs' },
- { name: 'Covina' },
- { name: 'Covington' },
- { name: 'Cranston' },
- { name: 'Crystal Lake' },
- { name: 'Culver City' },
- { name: 'Cupertino' },
- { name: 'Cutler Bay' },
- { name: 'Cuyahoga Falls' },
- { name: 'Cypress' },
- { name: 'Dallas' },
- { name: 'Daly City' },
- { name: 'Danbury' },
- { name: 'Danville' },
- { name: 'Danville' },
- { name: 'Davenport' },
- { name: 'Davie' },
- { name: 'Davis' },
- { name: 'Dayton' },
- { name: 'Daytona Beach' },
- { name: 'DeKalb' },
- { name: 'DeSoto' },
- { name: 'Dearborn' },
- { name: 'Dearborn Heights' },
- { name: 'Decatur' },
- { name: 'Decatur' },
- { name: 'Deerfield Beach' },
- { name: 'Delano' },
- { name: 'Delray Beach' },
- { name: 'Deltona' },
- { name: 'Denton' },
- { name: 'Denver' },
- { name: 'Des Moines' },
- { name: 'Des Plaines' },
- { name: 'Detroit' },
- { name: 'Diamond Bar' },
- { name: 'Doral' },
- { name: 'Dothan' },
- { name: 'Dover' },
- { name: 'Downers Grove' },
- { name: 'Downey' },
- { name: 'Draper' },
- { name: 'Dublin' },
- { name: 'Dublin' },
- { name: 'Dubuque' },
- { name: 'Duluth' },
- { name: 'Duncanville' },
- { name: 'Dunwoody' },
- { name: 'Durham' },
- { name: 'Eagan' },
- { name: 'East Lansing' },
- { name: 'East Orange' },
- { name: 'East Providence' },
- { name: 'Eastvale' },
- { name: 'Eau Claire' },
- { name: 'Eden Prairie' },
- { name: 'Edina' },
- { name: 'Edinburg' },
- { name: 'Edmond' },
- { name: 'Edmonds' },
- { name: 'El Cajon' },
- { name: 'El Centro' },
- { name: 'El Monte' },
- { name: 'El Paso' },
- { name: 'Elgin' },
- { name: 'Elizabeth' },
- { name: 'Elk Grove' },
- { name: 'Elkhart' },
- { name: 'Elmhurst' },
- { name: 'Elyria' },
- { name: 'Encinitas' },
- { name: 'Enid' },
- { name: 'Erie' },
- { name: 'Escondido' },
- { name: 'Euclid' },
- { name: 'Eugene' },
- { name: 'Euless' },
- { name: 'Evanston' },
- { name: 'Evansville' },
- { name: 'Everett' },
- { name: 'Everett' },
- { name: 'Fairfield' },
- { name: 'Fairfield' },
- { name: 'Fall River' },
- { name: 'Fargo' },
- { name: 'Farmington' },
- { name: 'Farmington Hills' },
- { name: 'Fayetteville' },
- { name: 'Fayetteville' },
- { name: 'Federal Way' },
- { name: 'Findlay' },
- { name: 'Fishers' },
- { name: 'Fitchburg' },
- { name: 'Flagstaff' },
- { name: 'Flint' },
- { name: 'Florence' },
- { name: 'Florence' },
- { name: 'Florissant' },
- { name: 'Flower Mound' },
- { name: 'Folsom' },
- { name: 'Fond du Lac' },
- { name: 'Fontana' },
- { name: 'Fort Collins' },
- { name: 'Fort Lauderdale' },
- { name: 'Fort Myers' },
- { name: 'Fort Pierce' },
- { name: 'Fort Smith' },
- { name: 'Fort Wayne' },
- { name: 'Fort Worth' },
- { name: 'Fountain Valley' },
- { name: 'Franklin' },
- { name: 'Frederick' },
- { name: 'Freeport' },
- { name: 'Fremont' },
- { name: 'Fresno' },
- { name: 'Friendswood' },
- { name: 'Frisco' },
- { name: 'Fullerton' },
- { name: 'Gainesville' },
- { name: 'Gaithersburg' },
- { name: 'Galveston' },
- { name: 'Garden Grove' },
- { name: 'Gardena' },
- { name: 'Garland' },
- { name: 'Gary' },
- { name: 'Gastonia' },
- { name: 'Georgetown' },
- { name: 'Germantown' },
- { name: 'Gilbert' },
- { name: 'Gilroy' },
- { name: 'Glendale' },
- { name: 'Glendale' },
- { name: 'Glendora' },
- { name: 'Glenview' },
- { name: 'Goodyear' },
- { name: 'Goose Creek' },
- { name: 'Grand Forks' },
- { name: 'Grand Island' },
- { name: 'Grand Junction' },
- { name: 'Grand Prairie' },
- { name: 'Grand Rapids' },
- { name: 'Grapevine' },
- { name: 'Great Falls' },
- { name: 'Greeley' },
- { name: 'Green Bay' },
- { name: 'Greenacres' },
- { name: 'Greenfield' },
- { name: 'Greensboro' },
- { name: 'Greenville' },
- { name: 'Greenville' },
- { name: 'Greenwood' },
- { name: 'Gresham' },
- { name: 'Grove City' },
- { name: 'Gulfport' },
- { name: 'Hackensack' },
- { name: 'Hagerstown' },
- { name: 'Hallandale Beach' },
- { name: 'Haltom City' },
- { name: 'Hamilton' },
- { name: 'Hammond' },
- { name: 'Hampton' },
- { name: 'Hanford' },
- { name: 'Hanover Park' },
- { name: 'Harlingen' },
- { name: 'Harrisburg' },
- { name: 'Harrisonburg' },
- { name: 'Hartford' },
- { name: 'Hattiesburg' },
- { name: 'Haverhill' },
- { name: 'Hawthorne' },
- { name: 'Hayward' },
- { name: 'Hemet' },
- { name: 'Hempstead' },
- { name: 'Henderson' },
- { name: 'Hendersonville' },
- { name: 'Hesperia' },
- { name: 'Hialeah' },
- { name: 'Hickory' },
- { name: 'High Point' },
- { name: 'Highland' },
- { name: 'Hillsboro' },
- { name: 'Hilton Head Island' },
- { name: 'Hoboken' },
- { name: 'Hoffman Estates' },
- { name: 'Hollywood' },
- { name: 'Holyoke' },
- { name: 'Homestead' },
- { name: 'Honolulu' },
- { name: 'Hoover' },
- { name: 'Houston' },
- { name: 'Huber Heights' },
- { name: 'Huntersville' },
- { name: 'Huntington' },
- { name: 'Huntington Beach' },
- { name: 'Huntington Park' },
- { name: 'Huntsville' },
- { name: 'Huntsville' },
- { name: 'Hurst' },
- { name: 'Hutchinson' },
- { name: 'Idaho Falls' },
- { name: 'Independence' },
- { name: 'Indianapolis' },
- { name: 'Indio' },
- { name: 'Inglewood' },
- { name: 'Iowa City' },
- { name: 'Irvine' },
- { name: 'Irving' },
- { name: 'Jackson' },
- { name: 'Jackson' },
- { name: 'Jacksonville' },
- { name: 'Jacksonville' },
- { name: 'Janesville' },
- { name: 'Jefferson City' },
- { name: 'Jeffersonville' },
- { name: 'Jersey City' },
- { name: 'Johns Creek' },
- { name: 'Johnson City' },
- { name: 'Joliet' },
- { name: 'Jonesboro' },
- { name: 'Joplin' },
- { name: 'Jupiter' },
- { name: 'Jurupa Valley' },
- { name: 'Kalamazoo' },
- { name: 'Kannapolis' },
- { name: 'Kansas City' },
- { name: 'Kansas City' },
- { name: 'Kearny' },
- { name: 'Keizer' },
- { name: 'Keller' },
- { name: 'Kenner' },
- { name: 'Kennewick' },
- { name: 'Kenosha' },
- { name: 'Kent' },
- { name: 'Kentwood' },
- { name: 'Kettering' },
- { name: 'Killeen' },
- { name: 'Kingsport' },
- { name: 'Kirkland' },
- { name: 'Kissimmee' },
- { name: 'Knoxville' },
- { name: 'Kokomo' },
- { name: 'La Crosse' },
- { name: 'La Habra' },
- { name: 'La Mesa' },
- { name: 'La Mirada' },
- { name: 'La Puente' },
- { name: 'La Quinta' },
- { name: 'Lacey' },
- { name: 'Lafayette' },
- { name: 'Lafayette' },
- { name: 'Laguna Niguel' },
- { name: 'Lake Charles' },
- { name: 'Lake Elsinore' },
- { name: 'Lake Forest' },
- { name: 'Lake Havasu City' },
- { name: 'Lake Oswego' },
- { name: 'Lakeland' },
- { name: 'Lakeville' },
- { name: 'Lakewood' },
- { name: 'Lakewood' },
- { name: 'Lakewood' },
- { name: 'Lakewood' },
- { name: 'Lancaster' },
- { name: 'Lancaster' },
- { name: 'Lancaster' },
- { name: 'Lancaster' },
- { name: 'Lansing' },
- { name: 'Laredo' },
- { name: 'Largo' },
- { name: 'Las Cruces' },
- { name: 'Las Vegas' },
- { name: 'Lauderhill' },
- { name: 'Lawrence' },
- { name: 'Lawrence' },
- { name: 'Lawrence' },
- { name: 'Lawton' },
- { name: 'Layton' },
- { name: 'League City' },
- { name: 'Lee\'s Summit' },
- { name: 'Leesburg' },
- { name: 'Lehi' },
- { name: 'Lenexa' },
- { name: 'Leominster' },
- { name: 'Lewisville' },
- { name: 'Lexington-Fayette' },
- { name: 'Lima' },
- { name: 'Lincoln' },
- { name: 'Lincoln' },
- { name: 'Lincoln Park' },
- { name: 'Linden' },
- { name: 'Little Rock' },
- { name: 'Littleton' },
- { name: 'Livermore' },
- { name: 'Livonia' },
- { name: 'Lodi' },
- { name: 'Logan' },
- { name: 'Lombard' },
- { name: 'Lompoc' },
- { name: 'Long Beach' },
- { name: 'Longmont' },
- { name: 'Longview' },
- { name: 'Lorain' },
- { name: 'Los Angeles' },
- { name: 'Louisville/Jefferson County' },
- { name: 'Loveland' },
- { name: 'Lowell' },
- { name: 'Lubbock' },
- { name: 'Lynchburg' },
- { name: 'Lynn' },
- { name: 'Lynwood' },
- { name: 'Macon' },
- { name: 'Madera' },
- { name: 'Madison' },
- { name: 'Madison' },
- { name: 'Malden' },
- { name: 'Manassas' },
- { name: 'Manchester' },
- { name: 'Manhattan' },
- { name: 'Mankato' },
- { name: 'Mansfield' },
- { name: 'Mansfield' },
- { name: 'Manteca' },
- { name: 'Maple Grove' },
- { name: 'Maplewood' },
- { name: 'Marana' },
- { name: 'Margate' },
- { name: 'Maricopa' },
- { name: 'Marietta' },
- { name: 'Marlborough' },
- { name: 'Martinez' },
- { name: 'Marysville' },
- { name: 'McAllen' },
- { name: 'McKinney' },
- { name: 'Medford' },
- { name: 'Medford' },
- { name: 'Melbourne' },
- { name: 'Memphis' },
- { name: 'Menifee' },
- { name: 'Mentor' },
- { name: 'Merced' },
- { name: 'Meriden' },
- { name: 'Meridian' },
- { name: 'Meridian' },
- { name: 'Mesa' },
- { name: 'Mesquite' },
- { name: 'Methuen' },
- { name: 'Miami' },
- { name: 'Miami Beach' },
- { name: 'Miami Gardens' },
- { name: 'Middletown' },
- { name: 'Middletown' },
- { name: 'Midland' },
- { name: 'Midland' },
- { name: 'Midwest City' },
- { name: 'Milford' },
- { name: 'Milpitas' },
- { name: 'Milwaukee' },
- { name: 'Minneapolis' },
- { name: 'Minnetonka' },
- { name: 'Minot' },
- { name: 'Miramar' },
- { name: 'Mishawaka' },
- { name: 'Mission' },
- { name: 'Mission Viejo' },
- { name: 'Missoula' },
- { name: 'Missouri City' },
- { name: 'Mobile' },
- { name: 'Modesto' },
- { name: 'Moline' },
- { name: 'Monroe' },
- { name: 'Monrovia' },
- { name: 'Montclair' },
- { name: 'Montebello' },
- { name: 'Monterey Park' },
- { name: 'Montgomery' },
- { name: 'Moore' },
- { name: 'Moorhead' },
- { name: 'Moreno Valley' },
- { name: 'Morgan Hill' },
- { name: 'Mount Pleasant' },
- { name: 'Mount Prospect' },
- { name: 'Mount Vernon' },
- { name: 'Mountain View' },
- { name: 'Muncie' },
- { name: 'Murfreesboro' },
- { name: 'Murray' },
- { name: 'Murrieta' },
- { name: 'Muskegon' },
- { name: 'Muskogee' },
- { name: 'Nampa' },
- { name: 'Napa' },
- { name: 'Naperville' },
- { name: 'Nashua' },
- { name: 'Nashville-Davidson' },
- { name: 'National City' },
- { name: 'New Bedford' },
- { name: 'New Berlin' },
- { name: 'New Braunfels' },
- { name: 'New Britain' },
- { name: 'New Brunswick' },
- { name: 'New Haven' },
- { name: 'New Orleans' },
- { name: 'New Rochelle' },
- { name: 'New York' },
- { name: 'Newark' },
- { name: 'Newark' },
- { name: 'Newark' },
- { name: 'Newport Beach' },
- { name: 'Newport News' },
- { name: 'Newton' },
- { name: 'Niagara Falls' },
- { name: 'Noblesville' },
- { name: 'Norfolk' },
- { name: 'Normal' },
- { name: 'Norman' },
- { name: 'North Charleston' },
- { name: 'North Las Vegas' },
- { name: 'North Lauderdale' },
- { name: 'North Little Rock' },
- { name: 'North Miami' },
- { name: 'North Miami Beach' },
- { name: 'North Port' },
- { name: 'North Richland Hills' },
- { name: 'Northglenn' },
- { name: 'Norwalk' },
- { name: 'Norwalk' },
- { name: 'Norwich' },
- { name: 'Novato' },
- { name: 'Novi' },
- { name: 'O\'Fallon' },
- { name: 'Oak Lawn' },
- { name: 'Oak Park' },
- { name: 'Oakland' },
- { name: 'Oakland Park' },
- { name: 'Oakley' },
- { name: 'Ocala' },
- { name: 'Oceanside' },
- { name: 'Ocoee' },
- { name: 'Odessa' },
- { name: 'Ogden' },
- { name: 'Oklahoma City' },
- { name: 'Olathe' },
- { name: 'Olympia' },
- { name: 'Omaha' },
- { name: 'Ontario' },
- { name: 'Orange' },
- { name: 'Orem' },
- { name: 'Orland Park' },
- { name: 'Orlando' },
- { name: 'Ormond Beach' },
- { name: 'Oro Valley' },
- { name: 'Oshkosh' },
- { name: 'Overland Park' },
- { name: 'Owensboro' },
- { name: 'Oxnard' },
- { name: 'Pacifica' },
- { name: 'Palatine' },
- { name: 'Palm Bay' },
- { name: 'Palm Beach Gardens' },
- { name: 'Palm Coast' },
- { name: 'Palm Desert' },
- { name: 'Palm Springs' },
- { name: 'Palmdale' },
- { name: 'Palo Alto' },
- { name: 'Panama City' },
- { name: 'Paramount' },
- { name: 'Park Ridge' },
- { name: 'Parker' },
- { name: 'Parma' },
- { name: 'Pasadena' },
- { name: 'Pasadena' },
- { name: 'Pasco' },
- { name: 'Passaic' },
- { name: 'Paterson' },
- { name: 'Pawtucket' },
- { name: 'Peabody' },
- { name: 'Peachtree Corners' },
- { name: 'Pearland' },
- { name: 'Pembroke Pines' },
- { name: 'Pensacola' },
- { name: 'Peoria' },
- { name: 'Peoria' },
- { name: 'Perris' },
- { name: 'Perth Amboy' },
- { name: 'Petaluma' },
- { name: 'Pflugerville' },
- { name: 'Pharr' },
- { name: 'Phenix City' },
- { name: 'Philadelphia' },
- { name: 'Phoenix' },
- { name: 'Pico Rivera' },
- { name: 'Pine Bluff' },
- { name: 'Pinellas Park' },
- { name: 'Pittsburg' },
- { name: 'Pittsburgh' },
- { name: 'Pittsfield' },
- { name: 'Placentia' },
- { name: 'Plainfield' },
- { name: 'Plainfield' },
- { name: 'Plano' },
- { name: 'Plantation' },
- { name: 'Pleasanton' },
- { name: 'Plymouth' },
- { name: 'Pocatello' },
- { name: 'Pomona' },
- { name: 'Pompano Beach' },
- { name: 'Pontiac' },
- { name: 'Port Arthur' },
- { name: 'Port Orange' },
- { name: 'Port St. Lucie' },
- { name: 'Portage' },
- { name: 'Porterville' },
- { name: 'Portland' },
- { name: 'Portland' },
- { name: 'Portsmouth' },
- { name: 'Poway' },
- { name: 'Prescott' },
- { name: 'Prescott Valley' },
- { name: 'Providence' },
- { name: 'Provo' },
- { name: 'Pueblo' },
- { name: 'Puyallup' },
- { name: 'Quincy' },
- { name: 'Quincy' },
- { name: 'Racine' },
- { name: 'Raleigh' },
- { name: 'Rancho Cordova' },
- { name: 'Rancho Cucamonga' },
- { name: 'Rancho Palos Verdes' },
- { name: 'Rancho Santa Margarita' },
- { name: 'Rapid City' },
- { name: 'Reading' },
- { name: 'Redding' },
- { name: 'Redlands' },
- { name: 'Redmond' },
- { name: 'Redondo Beach' },
- { name: 'Redwood City' },
- { name: 'Reno' },
- { name: 'Renton' },
- { name: 'Revere' },
- { name: 'Rialto' },
- { name: 'Richardson' },
- { name: 'Richland' },
- { name: 'Richmond' },
- { name: 'Richmond' },
- { name: 'Rio Rancho' },
- { name: 'Riverside' },
- { name: 'Riverton' },
- { name: 'Roanoke' },
- { name: 'Rochester' },
- { name: 'Rochester' },
- { name: 'Rochester Hills' },
- { name: 'Rock Hill' },
- { name: 'Rock Island' },
- { name: 'Rockford' },
- { name: 'Rocklin' },
- { name: 'Rockville' },
- { name: 'Rockwall' },
- { name: 'Rocky Mount' },
- { name: 'Rogers' },
- { name: 'Rohnert Park' },
- { name: 'Romeoville' },
- { name: 'Rosemead' },
- { name: 'Roseville' },
- { name: 'Roseville' },
- { name: 'Roswell' },
- { name: 'Roswell' },
- { name: 'Round Rock' },
- { name: 'Rowlett' },
- { name: 'Roy' },
- { name: 'Royal Oak' },
- { name: 'Sacramento' },
- { name: 'Saginaw' },
- { name: 'Salem' },
- { name: 'Salem' },
- { name: 'Salina' },
- { name: 'Salinas' },
- { name: 'Salt Lake City' },
- { name: 'Sammamish' },
- { name: 'San Angelo' },
- { name: 'San Antonio' },
- { name: 'San Bernardino' },
- { name: 'San Bruno' },
- { name: 'San Buenaventura (Ventura)' },
- { name: 'San Clemente' },
- { name: 'San Diego' },
- { name: 'San Francisco' },
- { name: 'San Gabriel' },
- { name: 'San Jacinto' },
- { name: 'San Jose' },
- { name: 'San Leandro' },
- { name: 'San Luis Obispo' },
- { name: 'San Marcos' },
- { name: 'San Marcos' },
- { name: 'San Mateo' },
- { name: 'San Rafael' },
- { name: 'San Ramon' },
- { name: 'Sandy' },
- { name: 'Sandy Springs' },
- { name: 'Sanford' },
- { name: 'Santa Ana' },
- { name: 'Santa Barbara' },
- { name: 'Santa Clara' },
- { name: 'Santa Clarita' },
- { name: 'Santa Cruz' },
- { name: 'Santa Fe' },
- { name: 'Santa Maria' },
- { name: 'Santa Monica' },
- { name: 'Santa Rosa' },
- { name: 'Santee' },
- { name: 'Sarasota' },
- { name: 'Savannah' },
- { name: 'Sayreville' },
- { name: 'Schaumburg' },
- { name: 'Schenectady' },
- { name: 'Scottsdale' },
- { name: 'Scranton' },
- { name: 'Seattle' },
- { name: 'Shakopee' },
- { name: 'Shawnee' },
- { name: 'Sheboygan' },
- { name: 'Shelton' },
- { name: 'Sherman' },
- { name: 'Shoreline' },
- { name: 'Shreveport' },
- { name: 'Sierra Vista' },
- { name: 'Simi Valley' },
- { name: 'Sioux City' },
- { name: 'Sioux Falls' },
- { name: 'Skokie' },
- { name: 'Smyrna' },
- { name: 'Smyrna' },
- { name: 'Somerville' },
- { name: 'South Bend' },
- { name: 'South Gate' },
- { name: 'South Jordan' },
- { name: 'South San Francisco' },
- { name: 'Southaven' },
- { name: 'Southfield' },
- { name: 'Spanish Fork' },
- { name: 'Sparks' },
- { name: 'Spartanburg' },
- { name: 'Spokane' },
- { name: 'Spokane Valley' },
- { name: 'Springdale' },
- { name: 'Springfield' },
- { name: 'Springfield' },
- { name: 'Springfield' },
- { name: 'Springfield' },
- { name: 'Springfield' },
- { name: 'St. Charles' },
- { name: 'St. Clair Shores' },
- { name: 'St. Cloud' },
- { name: 'St. Cloud' },
- { name: 'St. George' },
- { name: 'St. Joseph' },
- { name: 'St. Louis' },
- { name: 'St. Louis Park' },
- { name: 'St. Paul' },
- { name: 'St. Peters' },
- { name: 'St. Petersburg' },
- { name: 'Stamford' },
- { name: 'Stanton' },
- { name: 'State College' },
- { name: 'Sterling Heights' },
- { name: 'Stillwater' },
- { name: 'Stockton' },
- { name: 'Streamwood' },
- { name: 'Strongsville' },
- { name: 'Suffolk' },
- { name: 'Sugar Land' },
- { name: 'Summerville' },
- { name: 'Sumter' },
- { name: 'Sunnyvale' },
- { name: 'Sunrise' },
- { name: 'Surprise' },
- { name: 'Syracuse' },
- { name: 'Tacoma' },
- { name: 'Tallahassee' },
- { name: 'Tamarac' },
- { name: 'Tampa' },
- { name: 'Taunton' },
- { name: 'Taylor' },
- { name: 'Taylorsville' },
- { name: 'Temecula' },
- { name: 'Tempe' },
- { name: 'Temple' },
- { name: 'Terre Haute' },
- { name: 'Texarkana' },
- { name: 'Texas City' },
- { name: 'The Colony' },
- { name: 'Thornton' },
- { name: 'Thousand Oaks' },
- { name: 'Tigard' },
- { name: 'Tinley Park' },
- { name: 'Titusville' },
- { name: 'Toledo' },
- { name: 'Topeka' },
- { name: 'Torrance' },
- { name: 'Tracy' },
- { name: 'Trenton' },
- { name: 'Troy' },
- { name: 'Troy' },
- { name: 'Tucson' },
- { name: 'Tulare' },
- { name: 'Tulsa' },
- { name: 'Turlock' },
- { name: 'Tuscaloosa' },
- { name: 'Tustin' },
- { name: 'Twin Falls' },
- { name: 'Tyler' },
- { name: 'Union City' },
- { name: 'Union City' },
- { name: 'Upland' },
- { name: 'Urbana' },
- { name: 'Urbandale' },
- { name: 'Utica' },
- { name: 'Vacaville' },
- { name: 'Valdosta' },
- { name: 'Vallejo' },
- { name: 'Valley Stream' },
- { name: 'Vancouver' },
- { name: 'Victoria' },
- { name: 'Victorville' },
- { name: 'Vineland' },
- { name: 'Virginia Beach' },
- { name: 'Visalia' },
- { name: 'Vista' },
- { name: 'Waco' },
- { name: 'Walnut Creek' },
- { name: 'Waltham' },
- { name: 'Warner Robins' },
- { name: 'Warren' },
- { name: 'Warren' },
- { name: 'Warwick' },
- { name: 'Washington' },
- { name: 'Waterbury' },
- { name: 'Waterloo' },
- { name: 'Watsonville' },
- { name: 'Waukegan' },
- { name: 'Waukesha' },
- { name: 'Wausau' },
- { name: 'Wauwatosa' },
- { name: 'Wellington' },
- { name: 'Weslaco' },
- { name: 'West Allis' },
- { name: 'West Covina' },
- { name: 'West Des Moines' },
- { name: 'West Haven' },
- { name: 'West Jordan' },
- { name: 'West New York' },
- { name: 'West Palm Beach' },
- { name: 'West Sacramento' },
- { name: 'West Valley City' },
- { name: 'Westerville' },
- { name: 'Westfield' },
- { name: 'Westland' },
- { name: 'Westminster' },
- { name: 'Westminster' },
- { name: 'Weston' },
- { name: 'Weymouth Town' },
- { name: 'Wheaton' },
- { name: 'Wheeling' },
- { name: 'White Plains' },
- { name: 'Whittier' },
- { name: 'Wichita' },
- { name: 'Wichita Falls' },
- { name: 'Wilkes-Barre' },
- { name: 'Wilmington' },
- { name: 'Wilmington' },
- { name: 'Wilson' },
- { name: 'Winston-Salem' },
- { name: 'Winter Garden' },
- { name: 'Woburn' },
- { name: 'Woodbury' },
- { name: 'Woodland' },
- { name: 'Woonsocket' },
- { name: 'Worcester' },
- { name: 'Wylie' },
- { name: 'Wyoming' },
- { name: 'Yakima' },
- { name: 'Yonkers' },
- { name: 'Yorba Linda' },
- { name: 'York' },
- { name: 'Youngstown' },
- { name: 'Yuba City' },
- { name: 'Yucaipa' },
- { name: 'Yuma' }
-];
diff --git a/examples/src/data/contributors.js b/examples/src/data/contributors.js
deleted file mode 100644
index 883f7a1f3a..0000000000
--- a/examples/src/data/contributors.js
+++ /dev/null
@@ -1,11 +0,0 @@
-module.exports = [
- { github: 'jedwatson', name: 'Jed Watson' },
- { github: 'bruderstein', name: 'Dave Brotherstone' },
- { github: 'jossmac', name: 'Joss Mackison' },
- { github: 'jniechcial', name: 'Jakub Niechciał' },
- { github: 'craigdallimore', name: 'Craig Dallimore' },
- { github: 'julen', name: 'Julen Ruiz Aizpuru' },
- { github: 'dcousens', name: 'Daniel Cousens' },
- { github: 'jgautsch', name: 'Jon Gautsch' },
- { github: 'dmitry-smirnov', name: 'Dmitry Smirnov' },
-];
diff --git a/examples/src/data/states.js b/examples/src/data/states.js
deleted file mode 100644
index ec10689a56..0000000000
--- a/examples/src/data/states.js
+++ /dev/null
@@ -1,72 +0,0 @@
-exports.AU = [
- { value: 'australian-capital-territory', label: 'Australian Capital Territory', className: 'State-ACT' },
- { value: 'new-south-wales', label: 'New South Wales', className: 'State-NSW' },
- { value: 'victoria', label: 'Victoria', className: 'State-Vic' },
- { value: 'queensland', label: 'Queensland', className: 'State-Qld' },
- { value: 'western-australia', label: 'Western Australia', className: 'State-WA' },
- { value: 'south-australia', label: 'South Australia', className: 'State-SA' },
- { value: 'tasmania', label: 'Tasmania', className: 'State-Tas' },
- { value: 'northern-territory', label: 'Northern Territory', className: 'State-NT' },
-];
-
-exports.US = [
- { value: 'AL', label: 'Alabama', disabled: true },
- { value: 'AK', label: 'Alaska' },
- { value: 'AS', label: 'American Samoa' },
- { value: 'AZ', label: 'Arizona' },
- { value: 'AR', label: 'Arkansas' },
- { value: 'CA', label: 'California' },
- { value: 'CO', label: 'Colorado' },
- { value: 'CT', label: 'Connecticut' },
- { value: 'DE', label: 'Delaware' },
- { value: 'DC', label: 'District Of Columbia' },
- { value: 'FM', label: 'Federated States Of Micronesia' },
- { value: 'FL', label: 'Florida' },
- { value: 'GA', label: 'Georgia' },
- { value: 'GU', label: 'Guam' },
- { value: 'HI', label: 'Hawaii' },
- { value: 'ID', label: 'Idaho' },
- { value: 'IL', label: 'Illinois' },
- { value: 'IN', label: 'Indiana' },
- { value: 'IA', label: 'Iowa' },
- { value: 'KS', label: 'Kansas' },
- { value: 'KY', label: 'Kentucky' },
- { value: 'LA', label: 'Louisiana' },
- { value: 'ME', label: 'Maine' },
- { value: 'MH', label: 'Marshall Islands' },
- { value: 'MD', label: 'Maryland' },
- { value: 'MA', label: 'Massachusetts' },
- { value: 'MI', label: 'Michigan' },
- { value: 'MN', label: 'Minnesota' },
- { value: 'MS', label: 'Mississippi' },
- { value: 'MO', label: 'Missouri' },
- { value: 'MT', label: 'Montana' },
- { value: 'NE', label: 'Nebraska' },
- { value: 'NV', label: 'Nevada' },
- { value: 'NH', label: 'New Hampshire' },
- { value: 'NJ', label: 'New Jersey' },
- { value: 'NM', label: 'New Mexico' },
- { value: 'NY', label: 'New York' },
- { value: 'NC', label: 'North Carolina' },
- { value: 'ND', label: 'North Dakota' },
- { value: 'MP', label: 'Northern Mariana Islands' },
- { value: 'OH', label: 'Ohio' },
- { value: 'OK', label: 'Oklahoma' },
- { value: 'OR', label: 'Oregon' },
- { value: 'PW', label: 'Palau' },
- { value: 'PA', label: 'Pennsylvania' },
- { value: 'PR', label: 'Puerto Rico' },
- { value: 'RI', label: 'Rhode Island' },
- { value: 'SC', label: 'South Carolina' },
- { value: 'SD', label: 'South Dakota' },
- { value: 'TN', label: 'Tennessee' },
- { value: 'TX', label: 'Texas' },
- { value: 'UT', label: 'Utah' },
- { value: 'VT', label: 'Vermont' },
- { value: 'VI', label: 'Virgin Islands' },
- { value: 'VA', label: 'Virginia' },
- { value: 'WA', label: 'Washington' },
- { value: 'WV', label: 'West Virginia' },
- { value: 'WI', label: 'Wisconsin' },
- { value: 'WY', label: 'Wyoming' },
-];
diff --git a/examples/src/data/users.js b/examples/src/data/users.js
deleted file mode 100644
index c3aa626cd2..0000000000
--- a/examples/src/data/users.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = [
- { value: 'John Smith', label: 'John Smith', email: 'john@smith.com' },
- { value: 'Merry Jane', label: 'Merry Jane', email: 'merry@jane.com' },
- { value: 'Stan Hoper', label: 'Stan Hoper', email: 'stan@hoper.com' }
-];
diff --git a/examples/src/example.less b/examples/src/example.less
deleted file mode 100644
index 801c1fc5d1..0000000000
--- a/examples/src/example.less
+++ /dev/null
@@ -1,256 +0,0 @@
-//
-// Common Example Styles
-// ------------------------------
-
-
-
-
-// import select field styles
-
-@import "../../less/select.less";
-
-
-
-
-// Constants
-// ------------------------------
-
-// example site
-
-@heading-color: black;
-@text-color: #333;
-@link-color: #007eff;
-@gutter: 30px;
-
-
-
-
-// Base
-// ------------------------------
-
-body {
- color: @text-color;
- font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
- font-size: 14px;
- line-height: 1.4;
- margin: 0;
- padding: 0;
-}
-
-a {
- color: @link-color;
- text-decoration: none;
-
- &:hover {
- text-decoration: underline;
- }
-}
-
-.container {
- margin-left: auto;
- margin-right: auto;
- max-width: 400px;
- padding: 0 @gutter;
-}
-
-
-
-
-// Headings
-// ------------------------------
-
-h1, h2, h3, h4, h5, h6,
-.h1, .h2, .h3, .h4, .h5, .h6 {
- color: @heading-color;
- font-weight: 500;
- line-height: 1;
- margin-bottom: .66em;
- margin-top: 0;
-}
-
-h1, .h1 {
- font-size: 3em;
-}
-h2, .h2 {
- font-size: 2em;
- font-weight: 300;
-}
-h3, .h3 {
- font-size: 1.25em;
- // text-transform: uppercase;
-}
-h4, .h4 {
- font-size: 1em;
-}
-h5, .h5 {
- font-size: .85em;
-}
-h6, .h6 {
- font-size: .75em;
-}
-
-
-
-
-// Layout
-// ------------------------------
-
-// common
-
-.page-body,
-.page-footer,
-.page-header {
- padding: @gutter 0;
-}
-
-// header
-
-.page-header {
- background-color: @link-color;
- color: mix(white, @link-color, 75%);
-
- h1, h2, h3 {
- color: white;
- }
- p {
- font-size: 1.2em;
- margin: 0;
- }
- a {
- border-bottom: 1px solid fade(white, 30%);
- color: white;
- text-decoration: none;
-
- &:hover,
- &:focus {
- border-bottom-color: white;
- outline: none;
- text-decoration: none;
- }
- }
-}
-
-// subheader
-
-.page-subheader {
- background-color: mix(@link-color, white, 10%);
- line-height: 20px;
- padding: @gutter 0;
-}
-.page-subheader__button {
- float: right;
-}
-.page-subheader__link {
- border-bottom: 1px solid fade(@link-color, 30%);
- outline: none;
- text-decoration: none;
-
- &:hover,
- &:focus {
- border-bottom-color: @link-color;
- outline: none;
- text-decoration: none;
- }
-}
-
-// footer
-
-.page-footer {
- background-color: #fafafa;
- // border-top: 1px solid #eee;
- color: #999;
- padding: @gutter 0;
- text-align: center;
-
- a {
- color: black;
- }
-}
-
-// layout changes based on screen dimensions
-
-@media (min-width: 480px) {
- .page-body,
- .page-header {
- padding: (@gutter * 2) 0;
- }
- .page-header {
- font-size: 1.4em;
- }
- .page-subheader {
- font-size: 1.125em;
- line-height: 28px;
- }
-}
-
-
-
-
-// Form Styles
-// ------------------------------
-
-.checkbox-list {
- margin-top: .5em;
- overflow: hidden;
-}
-.checkbox-list > .checkbox {
- clear: left;
- float: left;
- margin-top: .5em;
-}
-.checkbox-control {
- margin-right: .5em;
- position: relative;
- top: -1px;
-}
-.checkbox-label {}
-
-
-
-
-// Switcher
-// ------------------------------
-
-.switcher {
- color: #999;
- cursor: default;
- font-size: 12px;
- margin: 10px 0;
- text-transform: uppercase;
-
- .link {
- color: @link-color;
- cursor: pointer;
- font-weight: bold;
- margin-left: 10px;
-
- &:hover {
- text-decoration: underline;
- }
- }
- .active {
- color: #666;
- font-weight: bold;
- margin-left: 10px;
- }
-}
-
-
-
-
-// Miscellaneous
-// ------------------------------
-
-.section {
- margin-bottom: 40px;
-}
-
-.hint {
- font-size: .85em;
- margin: 15px 0;
- color: #666;
-}
-
-.virtual-scroll {
- z-index: 1;
-}
diff --git a/examples/src/index.html b/examples/src/index.html
deleted file mode 100644
index 8f18a6249b..0000000000
--- a/examples/src/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
- React-Select Example
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/src/standalone.html b/examples/src/standalone.html
deleted file mode 100644
index fccd81ccb9..0000000000
--- a/examples/src/standalone.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
- React-Select Example
-
-
-
-
-
React Select
-
Standalone bulid
-
For usage without babel / browserify / webpack
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gulpfile.js b/gulpfile.js
deleted file mode 100644
index ad7049e3fa..0000000000
--- a/gulpfile.js
+++ /dev/null
@@ -1,39 +0,0 @@
-var gulp = require('gulp');
-var initGulpTasks = require('react-component-gulp-tasks');
-
-var taskConfig = {
-
- component: {
- name: 'Select',
- dependencies: [
- 'classnames',
- 'react-input-autosize',
- 'react',
- 'react-dom'
- ],
- less: {
- path: 'less',
- entry: 'default.less'
- }
- },
-
- example: {
- src: 'examples/src',
- dist: 'examples/dist',
- standalone: true,
- files: [
- 'index.html',
- 'standalone.html',
- '.gitignore'
- ],
- scripts: [
- 'app.js'
- ],
- less: [
- 'example.less'
- ]
- }
-
-};
-
-initGulpTasks(gulp, taskConfig);
diff --git a/less/control.less b/less/control.less
deleted file mode 100644
index 6a5ced741d..0000000000
--- a/less/control.less
+++ /dev/null
@@ -1,275 +0,0 @@
-//
-// Control
-// ------------------------------
-
-// Mixins
-
-// focused styles
-.Select-focus-state(@color) {
- border-color: @color;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px fade(@color, 10%);
-}
-// "classic" focused styles: maintain for legacy
-.Select-focus-state-classic() {
- border-color: @select-input-border-focus lighten(@select-input-border-focus, 5%) lighten(@select-input-border-focus, 5%);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade(@select-input-border-focus,50%);
-}
-
-// base
-
-.Select {
- position: relative;
-
- // preferred box model
- &,
- & div,
- & input,
- & span {
- .box-sizing(border-box);
- }
-
- // handle disabled state
- &.is-disabled > .Select-control {
- background-color: @select-input-bg-disabled;
- &:hover {
- box-shadow: none;
- }
- }
- &.is-disabled .Select-arrow-zone {
- cursor: default;
- pointer-events: none;
- opacity: 0.35;
- }
-}
-
-// base
-
-.Select-control {
- background-color: @select-input-bg;
- border-color: lighten(@select-input-border-color, 5%) @select-input-border-color darken(@select-input-border-color, 10%);
- border-radius: @select-input-border-radius;
- border: @select-input-border-width solid @select-input-border-color;
- color: @select-text-color;
- cursor: default;
- display: table;
- border-spacing: 0;
- border-collapse: separate;
- height: @select-input-height;
- outline: none;
- overflow: hidden;
- position: relative;
- width: 100%;
-
- &:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- }
-
- .Select-input:focus {
- outline: none;
- }
-}
-
-.is-searchable {
- &.is-open > .Select-control {
- cursor: text;
- }
-}
-
-.is-open > .Select-control {
- .border-bottom-radius( 0 );
- background: @select-input-bg;
- border-color: darken(@select-input-border-color, 10%) @select-input-border-color lighten(@select-input-border-color, 5%);
-
- // flip the arrow so its pointing up when the menu is open
- .Select-arrow {
- top: -2px;
- border-color: transparent transparent @select-arrow-color;
- border-width: 0 @select-arrow-width @select-arrow-width;
- }
-}
-
-.is-searchable {
- &.is-focused:not(.is-open) > .Select-control {
- cursor: text;
- }
-}
-
-.is-focused:not(.is-open) > .Select-control {
- .Select-focus-state(@select-input-border-focus);
-}
-
-// placeholder
-.Select-placeholder,
-.Select--single > .Select-control .Select-value {
- bottom: 0;
- color: @select-input-placeholder;
- left: 0;
- line-height: @select-input-internal-height;
- padding-left: @select-padding-horizontal;
- padding-right: @select-padding-horizontal;
- position: absolute;
- right: 0;
- top: 0;
-
- // crop text
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.has-value.Select--single > .Select-control .Select-value,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value {
- .Select-value-label {
- color: @select-text-color;
- }
- a.Select-value-label {
- cursor: pointer;
- text-decoration: none;
-
- &:hover,
- &:focus {
- color: @select-link-hover-color;
- outline: none;
- text-decoration: underline;
- }
- }
-}
-
-
-// the element users type in
-
-.Select-input {
- // inherits `display: inline-block` from "react-input-autosize"
- height: @select-input-internal-height;
- padding-left: @select-padding-horizontal;
- padding-right: @select-padding-horizontal;
- vertical-align: middle;
-
- > input {
- width: 100%;
- background: none transparent;
- border: 0 none;
- box-shadow: none;
- cursor: default;
- display: inline-block;
- font-family: inherit;
- font-size: inherit;
- // height: @select-input-internal-height;
- margin: 0;
- outline: none;
- // padding: 0;
- line-height: 14px; /* For IE 8 compatibility */
- padding: ((@select-input-internal-height - 14) / 2 - 2) 0 ((@select-input-internal-height - 14) / 2 + 2); /* For IE 8 compatibility */
- -webkit-appearance: none;
-
- .is-focused & {
- cursor: text;
- }
- }
-
-}
-
-// fake-hide the input when the control is pseudo-focused
-.has-value.is-pseudo-focused .Select-input {
- opacity: 0;
-}
-
-// fake input
-.Select-control:not(.is-searchable) > .Select-input {
- outline: none;
-}
-
-// loading indicator
-.Select-loading-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: @select-loading-size;
-}
-.Select-loading {
- .Select-spinner(@select-loading-size, @select-loading-color-bg, @select-loading-color);
- vertical-align: middle;
-}
-
-
-// the little cross that clears the field
-
-.Select-clear-zone {
- .animation( Select-animation-fadeIn 200ms );
- color: @select-clear-color;
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: @select-clear-width;
-
- &:hover {
- color: @select-clear-hover-color;
- }
-}
-.Select-clear {
- display: inline-block;
- font-size: @select-clear-size;
- line-height: 1;
-}
-.Select--multi .Select-clear-zone {
- width: @select-clear-width;
-}
-
-
-// arrow indicator
-
-.Select-arrow-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: (@select-arrow-width * 5);
- padding-right: @select-arrow-width;
-}
-
-.Select-arrow {
- border-color: @select-arrow-color transparent transparent;
- border-style: solid;
- border-width: @select-arrow-width @select-arrow-width (@select-arrow-width / 2);
- display: inline-block;
- height: 0;
- width: 0;
- position: relative;
-}
-.is-open .Select-arrow,
-.Select-arrow-zone:hover > .Select-arrow {
- border-top-color: @select-arrow-color-hover;
-}
-
-.Select--multi .Select-multi-value-wrapper {
- display: inline-block;
-}
-.Select .Select-aria-only {
- display: inline-block;
- height: 1px;
- width: 1px;
- margin: -1px;
- clip: rect(0,0,0,0);
- overflow: hidden;
- float: left;
-}
-
-// Animation
-// ------------------------------
-
-// fade in
-
-@-webkit-keyframes Select-animation-fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-@keyframes Select-animation-fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
diff --git a/less/default.less b/less/default.less
deleted file mode 100644
index 894e61b203..0000000000
--- a/less/default.less
+++ /dev/null
@@ -1 +0,0 @@
-@import "select.less";
diff --git a/less/menu.less b/less/menu.less
deleted file mode 100644
index 8b9fe457c0..0000000000
--- a/less/menu.less
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-// Select Menu
-// ------------------------------
-
-
-// wrapper around the menu
-
-.Select-menu-outer {
- // Unfortunately, having both border-radius and allows scrolling using overflow defined on the same
- // element forces the browser to repaint on scroll. However, if these definitions are split into an
- // outer and an inner element, the browser is able to optimize the scrolling behavior and does not
- // have to repaint on scroll.
- .border-bottom-radius( @select-input-border-radius );
- background-color: @select-input-bg;
- border: 1px solid @select-input-border-color;
- border-top-color: mix(@select-input-bg, @select-input-border-color, 50%);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- box-sizing: border-box;
- margin-top: -1px;
- max-height: @select-menu-max-height;
- position: absolute;
- top: 100%;
- width: 100%;
- z-index: @select-menu-zindex;
- -webkit-overflow-scrolling: touch;
-}
-
-
-// wrapper
-
-.Select-menu {
- max-height: (@select-menu-max-height - 2px);
- overflow-y: auto;
-}
-
-
-// options
-
-.Select-option {
- box-sizing: border-box;
- background-color: @select-option-bg;
- color: @select-option-color;
- cursor: pointer;
- display: block;
- padding: @select-padding-vertical @select-padding-horizontal;
-
- &:last-child {
- .border-bottom-radius( @select-input-border-radius );
- }
-
- &.is-selected {
- background-color: @select-option-selected-bg-fb; /* Fallback color for IE 8 */
- background-color: @select-option-selected-bg;
- color: @select-option-selected-color;
- }
-
- &.is-focused {
- background-color: @select-option-focused-bg-fb; /* Fallback color for IE 8 */
- background-color: @select-option-focused-bg;
- color: @select-option-focused-color;
- }
-
- &.is-disabled {
- color: @select-option-disabled-color;
- cursor: default;
- }
-
-}
-
-
-// no results
-
-.Select-noresults {
- box-sizing: border-box;
- color: @select-noresults-color;
- cursor: default;
- display: block;
- padding: @select-padding-vertical @select-padding-horizontal;
-}
diff --git a/less/mixins.less b/less/mixins.less
deleted file mode 100644
index b703f117ad..0000000000
--- a/less/mixins.less
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Mixins
-// ------------------------------
-
-
-// Utilities
-
-.size(@width; @height) {
- width: @width;
- height: @height;
-}
-.square(@size) {
- .size(@size; @size);
-}
-.border-top-radius(@radius) {
- border-top-right-radius: @radius;
- border-top-left-radius: @radius;
-}
-.border-right-radius(@radius) {
- border-bottom-right-radius: @radius;
- border-top-right-radius: @radius;
-}
-.border-bottom-radius(@radius) {
- border-bottom-right-radius: @radius;
- border-bottom-left-radius: @radius;
-}
-.border-left-radius(@radius) {
- border-bottom-left-radius: @radius;
- border-top-left-radius: @radius;
-}
-
-
-// Vendor Prefixes
-
-.animation(@animation) {
- -webkit-animation: @animation;
- -o-animation: @animation;
- animation: @animation;
-}
-.box-sizing(@boxmodel) {
- -webkit-box-sizing: @boxmodel;
- -moz-box-sizing: @boxmodel;
- box-sizing: @boxmodel;
-}
-.rotate(@degrees) {
- -webkit-transform: rotate(@degrees);
- -ms-transform: rotate(@degrees); // IE9 only
- -o-transform: rotate(@degrees);
- transform: rotate(@degrees);
-}
-.transform(@transform) {
- -webkit-transform: @transform;
- -moz-transform: @transform;
- -ms-transform: @transform;
- transform: @transform;
-}
diff --git a/less/multi.less b/less/multi.less
deleted file mode 100644
index ee5449fe4e..0000000000
--- a/less/multi.less
+++ /dev/null
@@ -1,103 +0,0 @@
-//
-// Multi-Select
-// ------------------------------
-
-
-// Base
-
-.Select--multi {
-
- // add margin to the input element
- .Select-input {
- vertical-align: middle;
- // border: 1px solid transparent;
- margin-left: @select-padding-horizontal;
- padding: 0;
- }
-
- // reduce margin once there is value
- &.has-value .Select-input {
- margin-left: @select-item-gutter;
- }
-
- // Items
- .Select-value {
- background-color: @select-item-bg-fb; /* Fallback color for IE 8 */
- background-color: @select-item-bg;
- border-radius: @select-item-border-radius;
- border: 1px solid @select-item-border-color-fb; /* Fallback color for IE 8 */
- border: 1px solid @select-item-border-color;
- color: @select-item-color;
- display: inline-block;
- font-size: @select-item-font-size;
- line-height: 1.4;
- margin-left: @select-item-gutter;
- margin-top: @select-item-gutter;
- vertical-align: top;
- }
-
- // common
- .Select-value-icon,
- .Select-value-label {
- display: inline-block;
- vertical-align: middle;
- }
-
- // label
- .Select-value-label {
- .border-right-radius( @select-item-border-radius );
- cursor: default;
- padding: @select-item-padding-vertical @select-item-padding-horizontal;
- }
- a.Select-value-label {
- color: @select-item-color;
- cursor: pointer;
- text-decoration: none;
-
- &:hover {
- text-decoration: underline;
- }
- }
-
- // icon
- .Select-value-icon {
- cursor: pointer;
- .border-left-radius( @select-item-border-radius );
- border-right: 1px solid @select-item-border-color-fb; /* Fallback color for IE 8 */
- border-right: 1px solid @select-item-border-color;
-
- // move the baseline up by 1px
- padding: (@select-item-padding-vertical - 1) @select-item-padding-horizontal (@select-item-padding-vertical + 1);
-
- &:hover,
- &:focus {
- background-color: @select-item-hover-bg-fb; /* Fallback color for IE 8 */
- background-color: @select-item-hover-bg;
- color: @select-item-hover-color;
- }
- &:active {
- background-color: @select-item-border-color-fb; /* Fallback color for IE 8 */
- background-color: @select-item-border-color;
- }
- }
-
-}
-
-.Select--multi.is-disabled {
- .Select-value {
- background-color: @select-item-disabled-bg;
- border: 1px solid @select-item-disabled-border-color;
- color: @select-item-disabled-color;
- }
- // icon
- .Select-value-icon {
- cursor: not-allowed;
- border-right: 1px solid @select-item-disabled-border-color;
-
- &:hover,
- &:focus,
- &:active {
- background-color: @select-item-disabled-bg;
- }
- }
-}
diff --git a/less/select.less b/less/select.less
deleted file mode 100644
index a1875c7b58..0000000000
--- a/less/select.less
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/JedWatson/react-select
-*/
-
-// Variables
-// ------------------------------
-
-// common
-@select-primary-color: #007eff;
-
-// control options
-@select-input-bg: #fff;
-@select-input-bg-disabled: #f9f9f9;
-@select-input-border-color: #ccc;
-@select-input-border-radius: 4px;
-@select-input-border-focus: @select-primary-color;
-@select-input-border-width: 1px;
-@select-input-height: 36px;
-@select-input-internal-height: (@select-input-height - (@select-input-border-width * 2));
-@select-input-placeholder: #aaa;
-@select-text-color: #333;
-@select-link-hover-color: @select-input-border-focus;
-
-@select-padding-vertical: 8px;
-@select-padding-horizontal: 10px;
-
-// menu options
-@select-menu-zindex: 1;
-@select-menu-max-height: 200px;
-
-@select-option-color: lighten(@select-text-color, 20%);
-@select-option-bg: @select-input-bg;
-@select-option-focused-color: @select-text-color;
-@select-option-focused-bg: fade(@select-primary-color, 8%);
-@select-option-focused-bg-fb: mix(@select-primary-color, @select-option-bg, 8%); // Fallback color for IE 8
-@select-option-selected-color: @select-text-color;
-@select-option-selected-bg: fade(@select-primary-color, 4%);
-@select-option-selected-bg-fb: mix(@select-primary-color, @select-option-bg, 4%); // Fallback color for IE 8
-@select-option-disabled-color: lighten(@select-text-color, 60%);
-
-@select-noresults-color: lighten(@select-text-color, 40%);
-
-// clear "x" button
-@select-clear-size: floor((@select-input-height / 2));
-@select-clear-color: #999;
-@select-clear-hover-color: #D0021B; // red
-@select-clear-width: (@select-input-internal-height / 2);
-
-// arrow indicator
-@select-arrow-color: #999;
-@select-arrow-color-hover: #666;
-@select-arrow-width: 5px;
-
-// loading indicator
-@select-loading-size: 16px;
-@select-loading-color: @select-text-color;
-@select-loading-color-bg: @select-input-border-color;
-
-// multi-select item
-@select-item-font-size: .9em;
-
-@select-item-bg: fade(@select-primary-color, 8%);
-@select-item-bg-fb: mix(@select-primary-color, @select-input-bg, 8%); // Fallback color for IE 8
-@select-item-color: @select-primary-color;
-@select-item-border-color: fade(@select-primary-color, 24%);
-@select-item-border-color-fb: mix(@select-primary-color, @select-input-bg, 24%); // Fallback color for IE 8
-@select-item-hover-color: darken(@select-item-color, 5%);
-@select-item-hover-bg: darken(@select-item-bg, 5%);
-@select-item-hover-bg-fb: mix(darken(@select-primary-color, 5%), @select-item-bg-fb, 8%); // Fallback color for IE 8
-@select-item-disabled-color: #333;
-@select-item-disabled-bg: #fcfcfc;
-@select-item-disabled-border-color: darken(@select-item-disabled-bg, 10%);
-
-@select-item-border-radius: 2px;
-@select-item-gutter: 5px;
-
-@select-item-padding-horizontal: 5px;
-@select-item-padding-vertical: 2px;
-
-// imports
-@import "control.less";
-@import "menu.less";
-@import "mixins.less";
-@import "multi.less";
-@import "spinner.less";
diff --git a/less/spinner.less b/less/spinner.less
deleted file mode 100644
index 7263396700..0000000000
--- a/less/spinner.less
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// Spinner
-// ------------------------------
-
-.Select-spinner(@size, @orbit, @satellite) {
- .animation( Select-animation-spin 400ms infinite linear );
- .square(@size);
- box-sizing: border-box;
- border-radius: 50%;
- border: floor((@size / 8)) solid @orbit;
- border-right-color: @satellite;
- display: inline-block;
- position: relative;
-
-}
-
-@keyframes Select-animation-spin {
- to { transform: rotate(1turn); }
-}
-@-webkit-keyframes Select-animation-spin {
- to { -webkit-transform: rotate(1turn); }
-}
diff --git a/lib/Async.js b/lib/Async.js
deleted file mode 100644
index bcc34b5197..0000000000
--- a/lib/Async.js
+++ /dev/null
@@ -1,265 +0,0 @@
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
-
-var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-var _utilsStripDiacritics = require('./utils/stripDiacritics');
-
-var _utilsStripDiacritics2 = _interopRequireDefault(_utilsStripDiacritics);
-
-var propTypes = {
- autoload: _react2['default'].PropTypes.bool.isRequired, // automatically call the `loadOptions` prop on-mount; defaults to true
- cache: _react2['default'].PropTypes.any, // object to use to cache results; set to null/false to disable caching
- children: _react2['default'].PropTypes.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element
- ignoreAccents: _react2['default'].PropTypes.bool, // strip diacritics when filtering; defaults to true
- ignoreCase: _react2['default'].PropTypes.bool, // perform case-insensitive filtering; defaults to true
- loadingPlaceholder: _react2['default'].PropTypes.oneOfType([// replaces the placeholder while options are loading
- _react2['default'].PropTypes.string, _react2['default'].PropTypes.node]),
- loadOptions: _react2['default'].PropTypes.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise
- options: _react.PropTypes.array.isRequired, // array of options
- placeholder: _react2['default'].PropTypes.oneOfType([// field placeholder, displayed when there's no value (shared with Select)
- _react2['default'].PropTypes.string, _react2['default'].PropTypes.node]),
- noResultsText: _react2['default'].PropTypes.oneOfType([// field noResultsText, displayed when no options come back from the server
- _react2['default'].PropTypes.string, _react2['default'].PropTypes.node]),
- onChange: _react2['default'].PropTypes.func, // onChange handler: function (newValue) {}
- searchPromptText: _react2['default'].PropTypes.oneOfType([// label to prompt for search input
- _react2['default'].PropTypes.string, _react2['default'].PropTypes.node]),
- onInputChange: _react2['default'].PropTypes.func, // optional for keeping track of what is being typed
- value: _react2['default'].PropTypes.any };
-
-// initial field value
-var defaultCache = {};
-
-var defaultProps = {
- autoload: true,
- cache: defaultCache,
- children: defaultChildren,
- ignoreAccents: true,
- ignoreCase: true,
- loadingPlaceholder: 'Loading...',
- options: [],
- searchPromptText: 'Type to search'
-};
-
-var Async = (function (_Component) {
- _inherits(Async, _Component);
-
- function Async(props, context) {
- _classCallCheck(this, Async);
-
- _get(Object.getPrototypeOf(Async.prototype), 'constructor', this).call(this, props, context);
-
- this._cache = props.cache === defaultCache ? {} : props.cache;
-
- this.state = {
- isLoading: false,
- options: props.options
- };
-
- this._onInputChange = this._onInputChange.bind(this);
- }
-
- _createClass(Async, [{
- key: 'componentDidMount',
- value: function componentDidMount() {
- var autoload = this.props.autoload;
-
- if (autoload) {
- this.loadOptions('');
- }
- }
- }, {
- key: 'componentWillUpdate',
- value: function componentWillUpdate(nextProps, nextState) {
- var _this = this;
-
- var propertiesToSync = ['options'];
- propertiesToSync.forEach(function (prop) {
- if (_this.props[prop] !== nextProps[prop]) {
- _this.setState(_defineProperty({}, prop, nextProps[prop]));
- }
- });
- }
- }, {
- key: 'clearOptions',
- value: function clearOptions() {
- this.setState({ options: [] });
- }
- }, {
- key: 'loadOptions',
- value: function loadOptions(inputValue) {
- var _this2 = this;
-
- var loadOptions = this.props.loadOptions;
-
- var cache = this._cache;
-
- if (cache && cache.hasOwnProperty(inputValue)) {
- this.setState({
- options: cache[inputValue]
- });
-
- return;
- }
-
- var callback = function callback(error, data) {
- if (callback === _this2._callback) {
- _this2._callback = null;
-
- var options = data && data.options || [];
-
- if (cache) {
- cache[inputValue] = options;
- }
-
- _this2.setState({
- isLoading: false,
- options: options
- });
- }
- };
-
- // Ignore all but the most recent request
- this._callback = callback;
-
- var promise = loadOptions(inputValue, callback);
- if (promise) {
- promise.then(function (data) {
- return callback(null, data);
- }, function (error) {
- return callback(error);
- });
- }
-
- if (this._callback && !this.state.isLoading) {
- this.setState({
- isLoading: true
- });
- }
-
- return inputValue;
- }
- }, {
- key: '_onInputChange',
- value: function _onInputChange(inputValue) {
- var _props = this.props;
- var ignoreAccents = _props.ignoreAccents;
- var ignoreCase = _props.ignoreCase;
- var onInputChange = _props.onInputChange;
-
- if (ignoreAccents) {
- inputValue = (0, _utilsStripDiacritics2['default'])(inputValue);
- }
-
- if (ignoreCase) {
- inputValue = inputValue.toLowerCase();
- }
-
- if (onInputChange) {
- onInputChange(inputValue);
- }
-
- return this.loadOptions(inputValue);
- }
- }, {
- key: 'inputValue',
- value: function inputValue() {
- if (this.select) {
- return this.select.state.inputValue;
- }
- return '';
- }
- }, {
- key: 'noResultsText',
- value: function noResultsText() {
- var _props2 = this.props;
- var loadingPlaceholder = _props2.loadingPlaceholder;
- var noResultsText = _props2.noResultsText;
- var searchPromptText = _props2.searchPromptText;
- var isLoading = this.state.isLoading;
-
- var inputValue = this.inputValue();
-
- if (isLoading) {
- return loadingPlaceholder;
- }
- if (inputValue && noResultsText) {
- return noResultsText;
- }
- return searchPromptText;
- }
- }, {
- key: 'focus',
- value: function focus() {
- this.select.focus();
- }
- }, {
- key: 'render',
- value: function render() {
- var _this3 = this;
-
- var _props3 = this.props;
- var children = _props3.children;
- var loadingPlaceholder = _props3.loadingPlaceholder;
- var placeholder = _props3.placeholder;
- var _state = this.state;
- var isLoading = _state.isLoading;
- var options = _state.options;
-
- var props = {
- noResultsText: this.noResultsText(),
- placeholder: isLoading ? loadingPlaceholder : placeholder,
- options: isLoading && loadingPlaceholder ? [] : options,
- ref: function ref(_ref) {
- return _this3.select = _ref;
- },
- onChange: function onChange(newValues) {
- if (_this3.props.multi && _this3.props.value && newValues.length > _this3.props.value.length) {
- _this3.clearOptions();
- }
- _this3.props.onChange(newValues);
- }
- };
-
- return children(_extends({}, this.props, props, {
- isLoading: isLoading,
- onInputChange: this._onInputChange
- }));
- }
- }]);
-
- return Async;
-})(_react.Component);
-
-exports['default'] = Async;
-
-Async.propTypes = propTypes;
-Async.defaultProps = defaultProps;
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/AsyncCreatable.js b/lib/AsyncCreatable.js
deleted file mode 100644
index 18491df46a..0000000000
--- a/lib/AsyncCreatable.js
+++ /dev/null
@@ -1,56 +0,0 @@
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-function reduce(obj) {
- var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
- return Object.keys(obj).reduce(function (props, key) {
- var value = obj[key];
- if (value !== undefined) props[key] = value;
- return props;
- }, props);
-}
-
-var AsyncCreatable = _react2['default'].createClass({
- displayName: 'AsyncCreatableSelect',
-
- render: function render() {
- var _this = this;
-
- return _react2['default'].createElement(
- _Select2['default'].Async,
- this.props,
- function (asyncProps) {
- return _react2['default'].createElement(
- _Select2['default'].Creatable,
- _this.props,
- function (creatableProps) {
- return _react2['default'].createElement(_Select2['default'], _extends({}, reduce(asyncProps, reduce(creatableProps, {})), {
- onInputChange: function (input) {
- creatableProps.onInputChange(input);
- return asyncProps.onInputChange(input);
- },
- ref: function (ref) {
- creatableProps.ref(ref);
- asyncProps.ref(ref);
- }
- }));
- }
- );
- }
- );
- }
-});
-
-module.exports = AsyncCreatable;
\ No newline at end of file
diff --git a/lib/Creatable.js b/lib/Creatable.js
deleted file mode 100644
index b5d0101115..0000000000
--- a/lib/Creatable.js
+++ /dev/null
@@ -1,316 +0,0 @@
-'use strict';
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _Select = require('./Select');
-
-var _Select2 = _interopRequireDefault(_Select);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var Creatable = _react2['default'].createClass({
- displayName: 'CreatableSelect',
-
- propTypes: {
- // Child function responsible for creating the inner Select component
- // This component can be used to compose HOCs (eg Creatable and Async)
- // (props: Object): PropTypes.element
- children: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.filterOptions
- filterOptions: _react2['default'].PropTypes.any,
-
- // Searches for any matching option within the set of options.
- // This function prevents duplicate options from being created.
- // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean
- isOptionUnique: _react2['default'].PropTypes.func,
-
- // Determines if the current input text represents a valid option.
- // ({ label: string }): boolean
- isValidNewOption: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.menuRenderer
- menuRenderer: _react2['default'].PropTypes.any,
-
- // Factory to create new option.
- // ({ label: string, labelKey: string, valueKey: string }): Object
- newOptionCreator: _react2['default'].PropTypes.func,
-
- // input change handler: function (inputValue) {}
- onInputChange: _react2['default'].PropTypes.func,
-
- // input keyDown handler: function (event) {}
- onInputKeyDown: _react2['default'].PropTypes.func,
-
- // new option click handler: function (option) {}
- onNewOptionClick: _react2['default'].PropTypes.func,
-
- // See Select.propTypes.options
- options: _react2['default'].PropTypes.array,
-
- // Creates prompt/placeholder option text.
- // (filterText: string): string
- promptTextCreator: _react2['default'].PropTypes.func,
-
- // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option.
- shouldKeyDownEventCreateNewOption: _react2['default'].PropTypes.func
- },
-
- // Default prop methods
- statics: {
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- },
-
- getDefaultProps: function getDefaultProps() {
- return {
- filterOptions: _utilsDefaultFilterOptions2['default'],
- isOptionUnique: isOptionUnique,
- isValidNewOption: isValidNewOption,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- newOptionCreator: newOptionCreator,
- promptTextCreator: promptTextCreator,
- shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption
- };
- },
-
- createNewOption: function createNewOption() {
- var _props = this.props;
- var isValidNewOption = _props.isValidNewOption;
- var newOptionCreator = _props.newOptionCreator;
- var onNewOptionClick = _props.onNewOptionClick;
- var _props$options = _props.options;
- var options = _props$options === undefined ? [] : _props$options;
- var shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption;
-
- if (isValidNewOption({ label: this.inputValue })) {
- var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey });
- var _isOptionUnique = this.isOptionUnique({ option: option });
-
- // Don't add the same option twice.
- if (_isOptionUnique) {
- if (onNewOptionClick) {
- onNewOptionClick(option);
- } else {
- options.unshift(option);
-
- this.select.selectValue(option);
- }
- }
- }
- },
-
- filterOptions: function filterOptions() {
- var _props2 = this.props;
- var filterOptions = _props2.filterOptions;
- var isValidNewOption = _props2.isValidNewOption;
- var options = _props2.options;
- var promptTextCreator = _props2.promptTextCreator;
-
- // TRICKY Check currently selected options as well.
- // Don't display a create-prompt for a value that's selected.
- // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array.
- var excludeOptions = arguments[2] || [];
-
- var filteredOptions = filterOptions.apply(undefined, arguments) || [];
-
- if (isValidNewOption({ label: this.inputValue })) {
- var _newOptionCreator = this.props.newOptionCreator;
-
- var option = _newOptionCreator({
- label: this.inputValue,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- // TRICKY Compare to all options (not just filtered options) in case option has already been selected).
- // For multi-selects, this would remove it from the filtered list.
- var _isOptionUnique2 = this.isOptionUnique({
- option: option,
- options: excludeOptions.concat(filteredOptions)
- });
-
- if (_isOptionUnique2) {
- var _prompt = promptTextCreator(this.inputValue);
-
- this._createPlaceholderOption = _newOptionCreator({
- label: _prompt,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- filteredOptions.unshift(this._createPlaceholderOption);
- }
- }
-
- return filteredOptions;
- },
-
- isOptionUnique: function isOptionUnique(_ref2) {
- var option = _ref2.option;
- var options = _ref2.options;
- var isOptionUnique = this.props.isOptionUnique;
-
- options = options || this.select.filterOptions();
-
- return isOptionUnique({
- labelKey: this.labelKey,
- option: option,
- options: options,
- valueKey: this.valueKey
- });
- },
-
- menuRenderer: function menuRenderer(params) {
- var menuRenderer = this.props.menuRenderer;
-
- return menuRenderer(_extends({}, params, {
- onSelect: this.onOptionSelect,
- selectValue: this.onOptionSelect
- }));
- },
-
- onInputChange: function onInputChange(input) {
- var onInputChange = this.props.onInputChange;
-
- if (onInputChange) {
- onInputChange(input);
- }
-
- // This value may be needed in between Select mounts (when this.select is null)
- this.inputValue = input;
- },
-
- onInputKeyDown: function onInputKeyDown(event) {
- var _props3 = this.props;
- var shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption;
- var onInputKeyDown = _props3.onInputKeyDown;
-
- var focusedOption = this.select.getFocusedOption();
-
- if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) {
- this.createNewOption();
-
- // Prevent decorated Select from doing anything additional with this keyDown event
- event.preventDefault();
- } else if (onInputKeyDown) {
- onInputKeyDown(event);
- }
- },
-
- onOptionSelect: function onOptionSelect(option, event) {
- if (option === this._createPlaceholderOption) {
- this.createNewOption();
- } else {
- this.select.selectValue(option);
- }
- },
-
- render: function render() {
- var _this = this;
-
- var _props4 = this.props;
- var newOptionCreator = _props4.newOptionCreator;
- var shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption;
-
- var restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']);
-
- var children = this.props.children;
-
- // We can't use destructuring default values to set the children,
- // because it won't apply work if `children` is null. A falsy check is
- // more reliable in real world use-cases.
- if (!children) {
- children = defaultChildren;
- }
-
- var props = _extends({}, restProps, {
- allowCreate: true,
- filterOptions: this.filterOptions,
- menuRenderer: this.menuRenderer,
- onInputChange: this.onInputChange,
- onInputKeyDown: this.onInputKeyDown,
- ref: function ref(_ref) {
- _this.select = _ref;
-
- // These values may be needed in between Select mounts (when this.select is null)
- if (_ref) {
- _this.labelKey = _ref.props.labelKey;
- _this.valueKey = _ref.props.valueKey;
- }
- }
- });
-
- return children(props);
- }
-});
-
-function defaultChildren(props) {
- return _react2['default'].createElement(_Select2['default'], props);
-};
-
-function isOptionUnique(_ref3) {
- var option = _ref3.option;
- var options = _ref3.options;
- var labelKey = _ref3.labelKey;
- var valueKey = _ref3.valueKey;
-
- return options.filter(function (existingOption) {
- return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey];
- }).length === 0;
-};
-
-function isValidNewOption(_ref4) {
- var label = _ref4.label;
-
- return !!label;
-};
-
-function newOptionCreator(_ref5) {
- var label = _ref5.label;
- var labelKey = _ref5.labelKey;
- var valueKey = _ref5.valueKey;
-
- var option = {};
- option[valueKey] = label;
- option[labelKey] = label;
- option.className = 'Select-create-option-placeholder';
- return option;
-};
-
-function promptTextCreator(label) {
- return 'Create option "' + label + '"';
-}
-
-function shouldKeyDownEventCreateNewOption(_ref6) {
- var keyCode = _ref6.keyCode;
-
- switch (keyCode) {
- case 9: // TAB
- case 13: // ENTER
- case 188:
- // COMMA
- return true;
- }
-
- return false;
-};
-
-module.exports = Creatable;
\ No newline at end of file
diff --git a/lib/Option.js b/lib/Option.js
deleted file mode 100644
index 5c8334ed7c..0000000000
--- a/lib/Option.js
+++ /dev/null
@@ -1,111 +0,0 @@
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Option = _react2['default'].createClass({
- displayName: 'Option',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- className: _react2['default'].PropTypes.string, // className (based on mouse position)
- instancePrefix: _react2['default'].PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
- isDisabled: _react2['default'].PropTypes.bool, // the option is disabled
- isFocused: _react2['default'].PropTypes.bool, // the option is focused
- isSelected: _react2['default'].PropTypes.bool, // the option is selected
- onFocus: _react2['default'].PropTypes.func, // method to handle mouseEnter on option element
- onSelect: _react2['default'].PropTypes.func, // method to handle click on option element
- onUnfocus: _react2['default'].PropTypes.func, // method to handle mouseLeave on option element
- option: _react2['default'].PropTypes.object.isRequired, // object that is base for that option
- optionIndex: _react2['default'].PropTypes.number },
- // index of the option, used to generate unique ids for aria
- blockEvent: function blockEvent(event) {
- event.preventDefault();
- event.stopPropagation();
- if (event.target.tagName !== 'A' || !('href' in event.target)) {
- return;
- }
- if (event.target.target) {
- window.open(event.target.href, event.target.target);
- } else {
- window.location.href = event.target.href;
- }
- },
-
- handleMouseDown: function handleMouseDown(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
-
- handleMouseEnter: function handleMouseEnter(event) {
- this.onFocus(event);
- },
-
- handleMouseMove: function handleMouseMove(event) {
- this.onFocus(event);
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- this.handleMouseDown(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- onFocus: function onFocus(event) {
- if (!this.props.isFocused) {
- this.props.onFocus(this.props.option, event);
- }
- },
- render: function render() {
- var _props = this.props;
- var option = _props.option;
- var instancePrefix = _props.instancePrefix;
- var optionIndex = _props.optionIndex;
-
- var className = (0, _classnames2['default'])(this.props.className, option.className);
-
- return option.disabled ? _react2['default'].createElement(
- 'div',
- { className: className,
- onMouseDown: this.blockEvent,
- onClick: this.blockEvent },
- this.props.children
- ) : _react2['default'].createElement(
- 'div',
- { className: className,
- style: option.style,
- role: 'option',
- onMouseDown: this.handleMouseDown,
- onMouseEnter: this.handleMouseEnter,
- onMouseMove: this.handleMouseMove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEnd,
- id: instancePrefix + '-option-' + optionIndex,
- title: option.title },
- this.props.children
- );
- }
-});
-
-module.exports = Option;
\ No newline at end of file
diff --git a/lib/Select.js b/lib/Select.js
deleted file mode 100644
index f3fb8bb8c8..0000000000
--- a/lib/Select.js
+++ /dev/null
@@ -1,1227 +0,0 @@
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/react-select
-*/
-
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _reactDom = require('react-dom');
-
-var _reactDom2 = _interopRequireDefault(_reactDom);
-
-var _reactInputAutosize = require('react-input-autosize');
-
-var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _utilsDefaultArrowRenderer = require('./utils/defaultArrowRenderer');
-
-var _utilsDefaultArrowRenderer2 = _interopRequireDefault(_utilsDefaultArrowRenderer);
-
-var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions');
-
-var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions);
-
-var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer');
-
-var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer);
-
-var _utilsDefaultClearRenderer = require('./utils/defaultClearRenderer');
-
-var _utilsDefaultClearRenderer2 = _interopRequireDefault(_utilsDefaultClearRenderer);
-
-var _Async = require('./Async');
-
-var _Async2 = _interopRequireDefault(_Async);
-
-var _AsyncCreatable = require('./AsyncCreatable');
-
-var _AsyncCreatable2 = _interopRequireDefault(_AsyncCreatable);
-
-var _Creatable = require('./Creatable');
-
-var _Creatable2 = _interopRequireDefault(_Creatable);
-
-var _Option = require('./Option');
-
-var _Option2 = _interopRequireDefault(_Option);
-
-var _Value = require('./Value');
-
-var _Value2 = _interopRequireDefault(_Value);
-
-function stringifyValue(value) {
- var valueType = typeof value;
- if (valueType === 'string') {
- return value;
- } else if (valueType === 'object') {
- return JSON.stringify(value);
- } else if (valueType === 'number' || valueType === 'boolean') {
- return String(value);
- } else {
- return '';
- }
-}
-
-var stringOrNode = _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.string, _react2['default'].PropTypes.node]);
-
-var instanceId = 1;
-
-var Select = _react2['default'].createClass({
-
- displayName: 'Select',
-
- propTypes: {
- addLabelText: _react2['default'].PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input
- 'aria-label': _react2['default'].PropTypes.string, // Aria label (for assistive tech)
- 'aria-labelledby': _react2['default'].PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
- arrowRenderer: _react2['default'].PropTypes.func, // Create drop-down caret element
- autoBlur: _react2['default'].PropTypes.bool, // automatically blur the component when an option is selected
- autofocus: _react2['default'].PropTypes.bool, // autofocus the component on mount
- autosize: _react2['default'].PropTypes.bool, // whether to enable autosizing or not
- backspaceRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- backspaceToRemoveMessage: _react2['default'].PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
- className: _react2['default'].PropTypes.string, // className for the outer element
- clearAllText: stringOrNode, // title for the "clear" control when multi: true
- clearRenderer: _react2['default'].PropTypes.func, // create clearable x element
- clearValueText: stringOrNode, // title for the "clear" control
- clearable: _react2['default'].PropTypes.bool, // should it be possible to reset value
- deleteRemoves: _react2['default'].PropTypes.bool, // whether backspace removes an item if there is no text input
- delimiter: _react2['default'].PropTypes.string, // delimiter to use to join multiple values for the hidden field value
- disabled: _react2['default'].PropTypes.bool, // whether the Select is disabled or not
- escapeClearsValue: _react2['default'].PropTypes.bool, // whether escape clears the value when the menu is closed
- filterOption: _react2['default'].PropTypes.func, // method to filter a single option (option, filterString)
- filterOptions: _react2['default'].PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
- ignoreAccents: _react2['default'].PropTypes.bool, // whether to strip diacritics when filtering
- ignoreCase: _react2['default'].PropTypes.bool, // whether to perform case-insensitive filtering
- inputProps: _react2['default'].PropTypes.object, // custom attributes for the Input
- inputRenderer: _react2['default'].PropTypes.func, // returns a custom input component
- instanceId: _react2['default'].PropTypes.string, // set the components instanceId
- isLoading: _react2['default'].PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded)
- joinValues: _react2['default'].PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
- labelKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- matchPos: _react2['default'].PropTypes.string, // (any|start) match the start or entire string when filtering
- matchProp: _react2['default'].PropTypes.string, // (any|label|value) which option property to filter on
- menuBuffer: _react2['default'].PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
- menuContainerStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu container
- menuRenderer: _react2['default'].PropTypes.func, // renders a custom menu with options
- menuStyle: _react2['default'].PropTypes.object, // optional style to apply to the menu
- multi: _react2['default'].PropTypes.bool, // multi-value input
- name: _react2['default'].PropTypes.string, // generates a hidden tag with this field name for html forms
- noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
- onBlur: _react2['default'].PropTypes.func, // onBlur handler: function (event) {}
- onBlurResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared on blur
- onChange: _react2['default'].PropTypes.func, // onChange handler: function (newValue) {}
- onClose: _react2['default'].PropTypes.func, // fires when the menu is closed
- onCloseResetsInput: _react2['default'].PropTypes.bool, // whether input is cleared when menu is closed through the arrow
- onFocus: _react2['default'].PropTypes.func, // onFocus handler: function (event) {}
- onInputChange: _react2['default'].PropTypes.func, // onInputChange handler: function (inputValue) {}
- onInputKeyDown: _react2['default'].PropTypes.func, // input keyDown handler: function (event) {}
- onMenuScrollToBottom: _react2['default'].PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
- onOpen: _react2['default'].PropTypes.func, // fires when the menu is opened
- onValueClick: _react2['default'].PropTypes.func, // onClick handler for value labels: function (value, event) {}
- openAfterFocus: _react2['default'].PropTypes.bool, // boolean to enable opening dropdown when focused
- openOnFocus: _react2['default'].PropTypes.bool, // always open options menu on focus
- optionClassName: _react2['default'].PropTypes.string, // additional class(es) to apply to the elements
- optionComponent: _react2['default'].PropTypes.func, // option component to render in dropdown
- optionRenderer: _react2['default'].PropTypes.func, // optionRenderer: function (option) {}
- options: _react2['default'].PropTypes.array, // array of options
- pageSize: _react2['default'].PropTypes.number, // number of entries to page when using page up/down keys
- placeholder: stringOrNode, // field placeholder, displayed when there's no value
- required: _react2['default'].PropTypes.bool, // applies HTML5 required attribute when needed
- resetValue: _react2['default'].PropTypes.any, // value to use when you clear the control
- scrollMenuIntoView: _react2['default'].PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
- searchable: _react2['default'].PropTypes.bool, // whether to enable searching feature or not
- simpleValue: _react2['default'].PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
- style: _react2['default'].PropTypes.object, // optional style to apply to the control
- tabIndex: _react2['default'].PropTypes.string, // optional tab index of the control
- tabSelectsValue: _react2['default'].PropTypes.bool, // whether to treat tabbing out while focused to be value selection
- value: _react2['default'].PropTypes.any, // initial field value
- valueComponent: _react2['default'].PropTypes.func, // value component to render
- valueKey: _react2['default'].PropTypes.string, // path of the label value in option objects
- valueRenderer: _react2['default'].PropTypes.func, // valueRenderer: function (option) {}
- wrapperStyle: _react2['default'].PropTypes.object },
-
- // optional style to apply to the component wrapper
- statics: { Async: _Async2['default'], AsyncCreatable: _AsyncCreatable2['default'], Creatable: _Creatable2['default'] },
-
- getDefaultProps: function getDefaultProps() {
- return {
- addLabelText: 'Add "{label}"?',
- arrowRenderer: _utilsDefaultArrowRenderer2['default'],
- autosize: true,
- backspaceRemoves: true,
- backspaceToRemoveMessage: 'Press backspace to remove {label}',
- clearable: true,
- clearAllText: 'Clear all',
- clearRenderer: _utilsDefaultClearRenderer2['default'],
- clearValueText: 'Clear value',
- deleteRemoves: true,
- delimiter: ',',
- disabled: false,
- escapeClearsValue: true,
- filterOptions: _utilsDefaultFilterOptions2['default'],
- ignoreAccents: true,
- ignoreCase: true,
- inputProps: {},
- isLoading: false,
- joinValues: false,
- labelKey: 'label',
- matchPos: 'any',
- matchProp: 'any',
- menuBuffer: 0,
- menuRenderer: _utilsDefaultMenuRenderer2['default'],
- multi: false,
- noResultsText: 'No results found',
- onBlurResetsInput: true,
- onCloseResetsInput: true,
- openAfterFocus: false,
- optionComponent: _Option2['default'],
- pageSize: 5,
- placeholder: 'Select...',
- required: false,
- scrollMenuIntoView: true,
- searchable: true,
- simpleValue: false,
- tabSelectsValue: true,
- valueComponent: _Value2['default'],
- valueKey: 'value'
- };
- },
-
- getInitialState: function getInitialState() {
- return {
- inputValue: '',
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- required: false
- };
- },
-
- componentWillMount: function componentWillMount() {
- this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
- var valueArray = this.getValueArray(this.props.value);
-
- if (this.props.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], this.props.multi)
- });
- }
- },
-
- componentDidMount: function componentDidMount() {
- if (this.props.autofocus) {
- this.focus();
- }
- },
-
- componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
- var valueArray = this.getValueArray(nextProps.value, nextProps);
-
- if (nextProps.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], nextProps.multi)
- });
- }
- },
-
- componentWillUpdate: function componentWillUpdate(nextProps, nextState) {
- if (nextState.isOpen !== this.state.isOpen) {
- this.toggleTouchOutsideEvent(nextState.isOpen);
- var handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose;
- handler && handler();
- }
- },
-
- componentDidUpdate: function componentDidUpdate(prevProps, prevState) {
- // focus to the selected option
- if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
- var focusedOptionNode = _reactDom2['default'].findDOMNode(this.focused);
- var menuNode = _reactDom2['default'].findDOMNode(this.menu);
- menuNode.scrollTop = focusedOptionNode.offsetTop;
- this.hasScrolledToOption = true;
- } else if (!this.state.isOpen) {
- this.hasScrolledToOption = false;
- }
-
- if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
- this._scrollToFocusedOptionOnUpdate = false;
- var focusedDOM = _reactDom2['default'].findDOMNode(this.focused);
- var menuDOM = _reactDom2['default'].findDOMNode(this.menu);
- var focusedRect = focusedDOM.getBoundingClientRect();
- var menuRect = menuDOM.getBoundingClientRect();
- if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) {
- menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight;
- }
- }
- if (this.props.scrollMenuIntoView && this.menuContainer) {
- var menuContainerRect = this.menuContainer.getBoundingClientRect();
- if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
- window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
- }
- }
- if (prevProps.disabled !== this.props.disabled) {
- this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
- this.closeMenu();
- }
- },
-
- componentWillUnmount: function componentWillUnmount() {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- },
-
- toggleTouchOutsideEvent: function toggleTouchOutsideEvent(enabled) {
- if (enabled) {
- if (!document.addEventListener && document.attachEvent) {
- document.attachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.addEventListener('touchstart', this.handleTouchOutside);
- }
- } else {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- }
- },
-
- handleTouchOutside: function handleTouchOutside(event) {
- // handle touch outside on ios to dismiss menu
- if (this.wrapper && !this.wrapper.contains(event.target)) {
- this.closeMenu();
- }
- },
-
- focus: function focus() {
- if (!this.input) return;
- this.input.focus();
-
- if (this.props.openAfterFocus) {
- this.setState({
- isOpen: true
- });
- }
- },
-
- blurInput: function blurInput() {
- if (!this.input) return;
- this.input.blur();
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- handleTouchEnd: function handleTouchEnd(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.handleMouseDown(event);
- },
-
- handleTouchEndClearValue: function handleTouchEndClearValue(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Clear the value
- this.clearValue(event);
- },
-
- handleMouseDown: function handleMouseDown(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
-
- if (event.target.tagName === 'INPUT') {
- return;
- }
-
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
-
- // for the non-searchable select, toggle the menu
- if (!this.props.searchable) {
- this.focus();
- return this.setState({
- isOpen: !this.state.isOpen
- });
- }
-
- if (this.state.isFocused) {
- // On iOS, we can get into a state where we think the input is focused but it isn't really,
- // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
- // Call focus() again here to be safe.
- this.focus();
-
- var input = this.input;
- if (typeof input.getInput === 'function') {
- // Get the actual DOM input if the ref is an component
- input = input.getInput();
- }
-
- // clears the value so that the cursor will be at the end of input when the component re-renders
- input.value = '';
-
- // if the input is focused, ensure the menu is open
- this.setState({
- isOpen: true,
- isPseudoFocused: false
- });
- } else {
- // otherwise, focus the input and open the menu
- this._openAfterFocus = this.props.openOnFocus;
- this.focus();
- }
- },
-
- handleMouseDownOnArrow: function handleMouseDownOnArrow(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- // If the menu isn't open, let the event bubble to the main handleMouseDown
- if (!this.state.isOpen) {
- return;
- }
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
- // close the menu
- this.closeMenu();
- },
-
- handleMouseDownOnMenu: function handleMouseDownOnMenu(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- this._openAfterFocus = true;
- this.focus();
- },
-
- closeMenu: function closeMenu() {
- if (this.props.onCloseResetsInput) {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: ''
- });
- } else {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: this.state.inputValue
- });
- }
- this.hasScrolledToOption = false;
- },
-
- handleInputFocus: function handleInputFocus(event) {
- if (this.props.disabled) return;
- var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
- if (this.props.onFocus) {
- this.props.onFocus(event);
- }
- this.setState({
- isFocused: true,
- isOpen: isOpen
- });
- this._openAfterFocus = false;
- },
-
- handleInputBlur: function handleInputBlur(event) {
- // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
- if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
- this.focus();
- return;
- }
-
- if (this.props.onBlur) {
- this.props.onBlur(event);
- }
- var onBlurredState = {
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false
- };
- if (this.props.onBlurResetsInput) {
- onBlurredState.inputValue = '';
- }
- this.setState(onBlurredState);
- },
-
- handleInputChange: function handleInputChange(event) {
- var newInputValue = event.target.value;
-
- if (this.state.inputValue !== event.target.value && this.props.onInputChange) {
- var nextState = this.props.onInputChange(newInputValue);
- // Note: != used deliberately here to catch undefined and null
- if (nextState != null && typeof nextState !== 'object') {
- newInputValue = '' + nextState;
- }
- }
-
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- inputValue: newInputValue
- });
- },
-
- handleKeyDown: function handleKeyDown(event) {
- if (this.props.disabled) return;
-
- if (typeof this.props.onInputKeyDown === 'function') {
- this.props.onInputKeyDown(event);
- if (event.defaultPrevented) {
- return;
- }
- }
-
- switch (event.keyCode) {
- case 8:
- // backspace
- if (!this.state.inputValue && this.props.backspaceRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- case 9:
- // tab
- if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
- return;
- }
- this.selectFocusedOption();
- return;
- case 13:
- // enter
- if (!this.state.isOpen) return;
- event.stopPropagation();
- this.selectFocusedOption();
- break;
- case 27:
- // escape
- if (this.state.isOpen) {
- this.closeMenu();
- event.stopPropagation();
- } else if (this.props.clearable && this.props.escapeClearsValue) {
- this.clearValue(event);
- event.stopPropagation();
- }
- break;
- case 38:
- // up
- this.focusPreviousOption();
- break;
- case 40:
- // down
- this.focusNextOption();
- break;
- case 33:
- // page up
- this.focusPageUpOption();
- break;
- case 34:
- // page down
- this.focusPageDownOption();
- break;
- case 35:
- // end key
- if (event.shiftKey) {
- return;
- }
- this.focusEndOption();
- break;
- case 36:
- // home key
- if (event.shiftKey) {
- return;
- }
- this.focusStartOption();
- break;
- case 46:
- // backspace
- if (!this.state.inputValue && this.props.deleteRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- default:
- return;
- }
- event.preventDefault();
- },
-
- handleValueClick: function handleValueClick(option, event) {
- if (!this.props.onValueClick) return;
- this.props.onValueClick(option, event);
- },
-
- handleMenuScroll: function handleMenuScroll(event) {
- if (!this.props.onMenuScrollToBottom) return;
- var target = event.target;
-
- if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) {
- this.props.onMenuScrollToBottom();
- }
- },
-
- handleRequired: function handleRequired(value, multi) {
- if (!value) return true;
- return multi ? value.length === 0 : Object.keys(value).length === 0;
- },
-
- getOptionLabel: function getOptionLabel(op) {
- return op[this.props.labelKey];
- },
-
- /**
- * Turns a value into an array from the given options
- * @param {String|Number|Array} value - the value of the select input
- * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
- * @returns {Array} the value of the select represented in an array
- */
- getValueArray: function getValueArray(value, nextProps) {
- var _this = this;
-
- /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
- var props = typeof nextProps === 'object' ? nextProps : this.props;
- if (props.multi) {
- if (typeof value === 'string') value = value.split(props.delimiter);
- if (!Array.isArray(value)) {
- if (value === null || value === undefined) return [];
- value = [value];
- }
- return value.map(function (value) {
- return _this.expandValue(value, props);
- }).filter(function (i) {
- return i;
- });
- }
- var expandedValue = this.expandValue(value, props);
- return expandedValue ? [expandedValue] : [];
- },
-
- /**
- * Retrieve a value from the given options and valueKey
- * @param {String|Number|Array} value - the selected value(s)
- * @param {Object} props - the Select component's props (or nextProps)
- */
- expandValue: function expandValue(value, props) {
- var valueType = typeof value;
- if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
- var options = props.options;
- var valueKey = props.valueKey;
-
- if (!options) return;
- for (var i = 0; i < options.length; i++) {
- if (options[i][valueKey] === value) return options[i];
- }
- },
-
- setValue: function setValue(value) {
- var _this2 = this;
-
- if (this.props.autoBlur) {
- this.blurInput();
- }
- if (!this.props.onChange) return;
- if (this.props.required) {
- var required = this.handleRequired(value, this.props.multi);
- this.setState({ required: required });
- }
- if (this.props.simpleValue && value) {
- value = this.props.multi ? value.map(function (i) {
- return i[_this2.props.valueKey];
- }).join(this.props.delimiter) : value[this.props.valueKey];
- }
- this.props.onChange(value);
- },
-
- selectValue: function selectValue(value) {
- var _this3 = this;
-
- //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise)
- this.hasScrolledToOption = false;
- if (this.props.multi) {
- this.setState({
- inputValue: '',
- focusedIndex: null
- }, function () {
- _this3.addValue(value);
- });
- } else {
- this.setState({
- isOpen: false,
- inputValue: '',
- isPseudoFocused: this.state.isFocused
- }, function () {
- _this3.setValue(value);
- });
- }
- },
-
- addValue: function addValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- var visibleOptions = this._visibleOptions.filter(function (val) {
- return !val.disabled;
- });
- var lastValueIndex = visibleOptions.indexOf(value);
- this.setValue(valueArray.concat(value));
- if (visibleOptions.length - 1 === lastValueIndex) {
- // the last option was selected; focus the second-last one
- this.focusOption(visibleOptions[lastValueIndex - 1]);
- } else if (visibleOptions.length > lastValueIndex) {
- // focus the option below the selected one
- this.focusOption(visibleOptions[lastValueIndex + 1]);
- }
- },
-
- popValue: function popValue() {
- var valueArray = this.getValueArray(this.props.value);
- if (!valueArray.length) return;
- if (valueArray[valueArray.length - 1].clearableValue === false) return;
- this.setValue(valueArray.slice(0, valueArray.length - 1));
- },
-
- removeValue: function removeValue(value) {
- var valueArray = this.getValueArray(this.props.value);
- this.setValue(valueArray.filter(function (i) {
- return i !== value;
- }));
- this.focus();
- },
-
- clearValue: function clearValue(event) {
- // if the event was triggered by a mousedown and not the primary
- // button, ignore it.
- if (event && event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
- this.setValue(this.getResetValue());
- this.setState({
- isOpen: false,
- inputValue: ''
- }, this.focus);
- },
-
- getResetValue: function getResetValue() {
- if (this.props.resetValue !== undefined) {
- return this.props.resetValue;
- } else if (this.props.multi) {
- return [];
- } else {
- return null;
- }
- },
-
- focusOption: function focusOption(option) {
- this.setState({
- focusedOption: option
- });
- },
-
- focusNextOption: function focusNextOption() {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption: function focusPreviousOption() {
- this.focusAdjacentOption('previous');
- },
-
- focusPageUpOption: function focusPageUpOption() {
- this.focusAdjacentOption('page_up');
- },
-
- focusPageDownOption: function focusPageDownOption() {
- this.focusAdjacentOption('page_down');
- },
-
- focusStartOption: function focusStartOption() {
- this.focusAdjacentOption('start');
- },
-
- focusEndOption: function focusEndOption() {
- this.focusAdjacentOption('end');
- },
-
- focusAdjacentOption: function focusAdjacentOption(dir) {
- var options = this._visibleOptions.map(function (option, index) {
- return { option: option, index: index };
- }).filter(function (option) {
- return !option.option.disabled;
- });
- this._scrollToFocusedOptionOnUpdate = true;
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: '',
- focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
- });
- return;
- }
- if (!options.length) return;
- var focusedIndex = -1;
- for (var i = 0; i < options.length; i++) {
- if (this._focusedOption === options[i].option) {
- focusedIndex = i;
- break;
- }
- }
- if (dir === 'next' && focusedIndex !== -1) {
- focusedIndex = (focusedIndex + 1) % options.length;
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedIndex = focusedIndex - 1;
- } else {
- focusedIndex = options.length - 1;
- }
- } else if (dir === 'start') {
- focusedIndex = 0;
- } else if (dir === 'end') {
- focusedIndex = options.length - 1;
- } else if (dir === 'page_up') {
- var potentialIndex = focusedIndex - this.props.pageSize;
- if (potentialIndex < 0) {
- focusedIndex = 0;
- } else {
- focusedIndex = potentialIndex;
- }
- } else if (dir === 'page_down') {
- var potentialIndex = focusedIndex + this.props.pageSize;
- if (potentialIndex > options.length - 1) {
- focusedIndex = options.length - 1;
- } else {
- focusedIndex = potentialIndex;
- }
- }
-
- if (focusedIndex === -1) {
- focusedIndex = 0;
- }
-
- this.setState({
- focusedIndex: options[focusedIndex].index,
- focusedOption: options[focusedIndex].option
- });
- },
-
- getFocusedOption: function getFocusedOption() {
- return this._focusedOption;
- },
-
- getInputValue: function getInputValue() {
- return this.state.inputValue;
- },
-
- selectFocusedOption: function selectFocusedOption() {
- if (this._focusedOption) {
- return this.selectValue(this._focusedOption);
- }
- },
-
- renderLoading: function renderLoading() {
- if (!this.props.isLoading) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-loading-zone', 'aria-hidden': 'true' },
- _react2['default'].createElement('span', { className: 'Select-loading' })
- );
- },
-
- renderValue: function renderValue(valueArray, isOpen) {
- var _this4 = this;
-
- var renderLabel = this.props.valueRenderer || this.getOptionLabel;
- var ValueComponent = this.props.valueComponent;
- if (!valueArray.length) {
- return !this.state.inputValue ? _react2['default'].createElement(
- 'div',
- { className: 'Select-placeholder' },
- this.props.placeholder
- ) : null;
- }
- var onClick = this.props.onValueClick ? this.handleValueClick : null;
- if (this.props.multi) {
- return valueArray.map(function (value, i) {
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: _this4._instancePrefix + '-value-' + i,
- instancePrefix: _this4._instancePrefix,
- disabled: _this4.props.disabled || value.clearableValue === false,
- key: 'value-' + i + '-' + value[_this4.props.valueKey],
- onClick: onClick,
- onRemove: _this4.removeValue,
- value: value
- },
- renderLabel(value, i),
- _react2['default'].createElement(
- 'span',
- { className: 'Select-aria-only' },
- ' '
- )
- );
- });
- } else if (!this.state.inputValue) {
- if (isOpen) onClick = null;
- return _react2['default'].createElement(
- ValueComponent,
- {
- id: this._instancePrefix + '-value-item',
- disabled: this.props.disabled,
- instancePrefix: this._instancePrefix,
- onClick: onClick,
- value: valueArray[0]
- },
- renderLabel(valueArray[0])
- );
- }
- },
-
- renderInput: function renderInput(valueArray, focusedOptionIndex) {
- var _classNames,
- _this5 = this;
-
- var className = (0, _classnames2['default'])('Select-input', this.props.inputProps.className);
- var isOpen = !!this.state.isOpen;
-
- var ariaOwns = (0, _classnames2['default'])((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames));
-
- // TODO: Check how this project includes Object.assign()
- var inputProps = _extends({}, this.props.inputProps, {
- role: 'combobox',
- 'aria-expanded': '' + isOpen,
- 'aria-owns': ariaOwns,
- 'aria-haspopup': '' + isOpen,
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- 'aria-labelledby': this.props['aria-labelledby'],
- 'aria-label': this.props['aria-label'],
- className: className,
- tabIndex: this.props.tabIndex,
- onBlur: this.handleInputBlur,
- onChange: this.handleInputChange,
- onFocus: this.handleInputFocus,
- ref: function ref(_ref) {
- return _this5.input = _ref;
- },
- required: this.state.required,
- value: this.state.inputValue
- });
-
- if (this.props.inputRenderer) {
- return this.props.inputRenderer(inputProps);
- }
-
- if (this.props.disabled || !this.props.searchable) {
- var _props$inputProps = this.props.inputProps;
- var inputClassName = _props$inputProps.inputClassName;
-
- var divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']);
-
- return _react2['default'].createElement('div', _extends({}, divProps, {
- role: 'combobox',
- 'aria-expanded': isOpen,
- 'aria-owns': isOpen ? this._instancePrefix + '-list' : this._instancePrefix + '-value',
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- className: className,
- tabIndex: this.props.tabIndex || 0,
- onBlur: this.handleInputBlur,
- onFocus: this.handleInputFocus,
- ref: function (ref) {
- return _this5.input = ref;
- },
- 'aria-readonly': '' + !!this.props.disabled,
- style: { border: 0, width: 1, display: 'inline-block' } }));
- }
-
- if (this.props.autosize) {
- return _react2['default'].createElement(_reactInputAutosize2['default'], _extends({}, inputProps, { minWidth: '5' }));
- }
- return _react2['default'].createElement(
- 'div',
- { className: className },
- _react2['default'].createElement('input', inputProps)
- );
- },
-
- renderClear: function renderClear() {
- if (!this.props.clearable || !this.props.value || this.props.value === 0 || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return;
- var clear = this.props.clearRenderer();
-
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText,
- onMouseDown: this.clearValue,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove,
- onTouchEnd: this.handleTouchEndClearValue
- },
- clear
- );
- },
-
- renderArrow: function renderArrow() {
- var onMouseDown = this.handleMouseDownOnArrow;
- var isOpen = this.state.isOpen;
- var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen });
-
- return _react2['default'].createElement(
- 'span',
- {
- className: 'Select-arrow-zone',
- onMouseDown: onMouseDown
- },
- arrow
- );
- },
-
- filterOptions: function filterOptions(excludeOptions) {
- var filterValue = this.state.inputValue;
- var options = this.props.options || [];
- if (this.props.filterOptions) {
- // Maintain backwards compatibility with boolean attribute
- var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _utilsDefaultFilterOptions2['default'];
-
- return filterOptions(options, filterValue, excludeOptions, {
- filterOption: this.props.filterOption,
- ignoreAccents: this.props.ignoreAccents,
- ignoreCase: this.props.ignoreCase,
- labelKey: this.props.labelKey,
- matchPos: this.props.matchPos,
- matchProp: this.props.matchProp,
- valueKey: this.props.valueKey
- });
- } else {
- return options;
- }
- },
-
- onOptionRef: function onOptionRef(ref, isFocused) {
- if (isFocused) {
- this.focused = ref;
- }
- },
-
- renderMenu: function renderMenu(options, valueArray, focusedOption) {
- if (options && options.length) {
- return this.props.menuRenderer({
- focusedOption: focusedOption,
- focusOption: this.focusOption,
- instancePrefix: this._instancePrefix,
- labelKey: this.props.labelKey,
- onFocus: this.focusOption,
- onSelect: this.selectValue,
- optionClassName: this.props.optionClassName,
- optionComponent: this.props.optionComponent,
- optionRenderer: this.props.optionRenderer || this.getOptionLabel,
- options: options,
- selectValue: this.selectValue,
- valueArray: valueArray,
- valueKey: this.props.valueKey,
- onOptionRef: this.onOptionRef
- });
- } else if (this.props.noResultsText) {
- return _react2['default'].createElement(
- 'div',
- { className: 'Select-noresults' },
- this.props.noResultsText
- );
- } else {
- return null;
- }
- },
-
- renderHiddenField: function renderHiddenField(valueArray) {
- var _this6 = this;
-
- if (!this.props.name) return;
- if (this.props.joinValues) {
- var value = valueArray.map(function (i) {
- return stringifyValue(i[_this6.props.valueKey]);
- }).join(this.props.delimiter);
- return _react2['default'].createElement('input', {
- type: 'hidden',
- ref: function (ref) {
- return _this6.value = ref;
- },
- name: this.props.name,
- value: value,
- disabled: this.props.disabled });
- }
- return valueArray.map(function (item, index) {
- return _react2['default'].createElement('input', { key: 'hidden.' + index,
- type: 'hidden',
- ref: 'value' + index,
- name: _this6.props.name,
- value: stringifyValue(item[_this6.props.valueKey]),
- disabled: _this6.props.disabled });
- });
- },
-
- getFocusableOptionIndex: function getFocusableOptionIndex(selectedOption) {
- var options = this._visibleOptions;
- if (!options.length) return null;
-
- var focusedOption = this.state.focusedOption || selectedOption;
- if (focusedOption && !focusedOption.disabled) {
- var focusedOptionIndex = options.indexOf(focusedOption);
- if (focusedOptionIndex !== -1) {
- return focusedOptionIndex;
- }
- }
-
- for (var i = 0; i < options.length; i++) {
- if (!options[i].disabled) return i;
- }
- return null;
- },
-
- renderOuter: function renderOuter(options, valueArray, focusedOption) {
- var _this7 = this;
-
- var menu = this.renderMenu(options, valueArray, focusedOption);
- if (!menu) {
- return null;
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menuContainer = ref;
- }, className: 'Select-menu-outer', style: this.props.menuContainerStyle },
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this7.menu = ref;
- }, role: 'listbox', className: 'Select-menu', id: this._instancePrefix + '-list',
- style: this.props.menuStyle,
- onScroll: this.handleMenuScroll,
- onMouseDown: this.handleMouseDownOnMenu },
- menu
- )
- );
- },
-
- render: function render() {
- var _this8 = this;
-
- var valueArray = this.getValueArray(this.props.value);
- var options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null);
- var isOpen = this.state.isOpen;
- if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
- var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
-
- var focusedOption = null;
- if (focusedOptionIndex !== null) {
- focusedOption = this._focusedOption = options[focusedOptionIndex];
- } else {
- focusedOption = this._focusedOption = null;
- }
- var className = (0, _classnames2['default'])('Select', this.props.className, {
- 'Select--multi': this.props.multi,
- 'Select--single': !this.props.multi,
- 'is-disabled': this.props.disabled,
- 'is-focused': this.state.isFocused,
- 'is-loading': this.props.isLoading,
- 'is-open': isOpen,
- 'is-pseudo-focused': this.state.isPseudoFocused,
- 'is-searchable': this.props.searchable,
- 'has-value': valueArray.length
- });
-
- var removeMessage = null;
- if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) {
- removeMessage = _react2['default'].createElement(
- 'span',
- { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' },
- this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])
- );
- }
-
- return _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.wrapper = ref;
- },
- className: className,
- style: this.props.wrapperStyle },
- this.renderHiddenField(valueArray),
- _react2['default'].createElement(
- 'div',
- { ref: function (ref) {
- return _this8.control = ref;
- },
- className: 'Select-control',
- style: this.props.style,
- onKeyDown: this.handleKeyDown,
- onMouseDown: this.handleMouseDown,
- onTouchEnd: this.handleTouchEnd,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove
- },
- _react2['default'].createElement(
- 'span',
- { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' },
- this.renderValue(valueArray, isOpen),
- this.renderInput(valueArray, focusedOptionIndex)
- ),
- removeMessage,
- this.renderLoading(),
- this.renderClear(),
- this.renderArrow()
- ),
- isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null
- );
- }
-
-});
-
-exports['default'] = Select;
-module.exports = exports['default'];
diff --git a/lib/Value.js b/lib/Value.js
deleted file mode 100644
index 5d578eac2d..0000000000
--- a/lib/Value.js
+++ /dev/null
@@ -1,106 +0,0 @@
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var Value = _react2['default'].createClass({
-
- displayName: 'Value',
-
- propTypes: {
- children: _react2['default'].PropTypes.node,
- disabled: _react2['default'].PropTypes.bool, // disabled prop passed to ReactSelect
- id: _react2['default'].PropTypes.string, // Unique id for the value - used for aria
- onClick: _react2['default'].PropTypes.func, // method to handle click on value label
- onRemove: _react2['default'].PropTypes.func, // method to handle removal of the value
- value: _react2['default'].PropTypes.object.isRequired },
-
- // the option object for this value
- handleMouseDown: function handleMouseDown(event) {
- if (event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- if (this.props.onClick) {
- event.stopPropagation();
- this.props.onClick(this.props.value, event);
- return;
- }
- if (this.props.value.href) {
- event.stopPropagation();
- }
- },
-
- onRemove: function onRemove(event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onRemove(this.props.value);
- },
-
- handleTouchEndRemove: function handleTouchEndRemove(event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.onRemove(event);
- },
-
- handleTouchMove: function handleTouchMove(event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart: function handleTouchStart(event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- renderRemoveIcon: function renderRemoveIcon() {
- if (this.props.disabled || !this.props.onRemove) return;
- return _react2['default'].createElement(
- 'span',
- { className: 'Select-value-icon',
- 'aria-hidden': 'true',
- onMouseDown: this.onRemove,
- onTouchEnd: this.handleTouchEndRemove,
- onTouchStart: this.handleTouchStart,
- onTouchMove: this.handleTouchMove },
- '×'
- );
- },
-
- renderLabel: function renderLabel() {
- var className = 'Select-value-label';
- return this.props.onClick || this.props.value.href ? _react2['default'].createElement(
- 'a',
- { className: className, href: this.props.value.href, target: this.props.value.target, onMouseDown: this.handleMouseDown, onTouchEnd: this.handleMouseDown },
- this.props.children
- ) : _react2['default'].createElement(
- 'span',
- { className: className, role: 'option', 'aria-selected': 'true', id: this.props.id },
- this.props.children
- );
- },
-
- render: function render() {
- return _react2['default'].createElement(
- 'div',
- { className: (0, _classnames2['default'])('Select-value', this.props.value.className),
- style: this.props.value.style,
- title: this.props.value.title
- },
- this.renderRemoveIcon(),
- this.renderLabel()
- );
- }
-
-});
-
-module.exports = Value;
\ No newline at end of file
diff --git a/lib/utils/defaultArrowRenderer.js b/lib/utils/defaultArrowRenderer.js
deleted file mode 100644
index 99115a3de9..0000000000
--- a/lib/utils/defaultArrowRenderer.js
+++ /dev/null
@@ -1,24 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports["default"] = arrowRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function arrowRenderer(_ref) {
- var onMouseDown = _ref.onMouseDown;
-
- return _react2["default"].createElement("span", {
- className: "Select-arrow",
- onMouseDown: onMouseDown
- });
-}
-
-;
-module.exports = exports["default"];
\ No newline at end of file
diff --git a/lib/utils/defaultClearRenderer.js b/lib/utils/defaultClearRenderer.js
deleted file mode 100644
index a529ecc22b..0000000000
--- a/lib/utils/defaultClearRenderer.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-Object.defineProperty(exports, '__esModule', {
- value: true
-});
-exports['default'] = clearRenderer;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function clearRenderer() {
- return _react2['default'].createElement('span', {
- className: 'Select-clear',
- dangerouslySetInnerHTML: { __html: '×' }
- });
-}
-
-;
-module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/utils/defaultFilterOptions.js b/lib/utils/defaultFilterOptions.js
deleted file mode 100644
index 19f054a746..0000000000
--- a/lib/utils/defaultFilterOptions.js
+++ /dev/null
@@ -1,42 +0,0 @@
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _stripDiacritics = require('./stripDiacritics');
-
-var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics);
-
-function filterOptions(options, filterValue, excludeOptions, props) {
- var _this = this;
-
- if (props.ignoreAccents) {
- filterValue = (0, _stripDiacritics2['default'])(filterValue);
- }
-
- if (props.ignoreCase) {
- filterValue = filterValue.toLowerCase();
- }
-
- if (excludeOptions) excludeOptions = excludeOptions.map(function (i) {
- return i[props.valueKey];
- });
-
- return options.filter(function (option) {
- if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false;
- if (props.filterOption) return props.filterOption.call(_this, option, filterValue);
- if (!filterValue) return true;
- var valueTest = String(option[props.valueKey]);
- var labelTest = String(option[props.labelKey]);
- if (props.ignoreAccents) {
- if (props.matchProp !== 'label') valueTest = (0, _stripDiacritics2['default'])(valueTest);
- if (props.matchProp !== 'value') labelTest = (0, _stripDiacritics2['default'])(labelTest);
- }
- if (props.ignoreCase) {
- if (props.matchProp !== 'label') valueTest = valueTest.toLowerCase();
- if (props.matchProp !== 'value') labelTest = labelTest.toLowerCase();
- }
- return props.matchPos === 'start' ? props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue || props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue : props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0 || props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0;
- });
-}
-
-module.exports = filterOptions;
\ No newline at end of file
diff --git a/lib/utils/defaultMenuRenderer.js b/lib/utils/defaultMenuRenderer.js
deleted file mode 100644
index f5877091d0..0000000000
--- a/lib/utils/defaultMenuRenderer.js
+++ /dev/null
@@ -1,61 +0,0 @@
-'use strict';
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-var _classnames = require('classnames');
-
-var _classnames2 = _interopRequireDefault(_classnames);
-
-var _react = require('react');
-
-var _react2 = _interopRequireDefault(_react);
-
-function menuRenderer(_ref) {
- var focusedOption = _ref.focusedOption;
- var instancePrefix = _ref.instancePrefix;
- var labelKey = _ref.labelKey;
- var onFocus = _ref.onFocus;
- var onSelect = _ref.onSelect;
- var optionClassName = _ref.optionClassName;
- var optionComponent = _ref.optionComponent;
- var optionRenderer = _ref.optionRenderer;
- var options = _ref.options;
- var valueArray = _ref.valueArray;
- var valueKey = _ref.valueKey;
- var onOptionRef = _ref.onOptionRef;
-
- var Option = optionComponent;
-
- return options.map(function (option, i) {
- var isSelected = valueArray && valueArray.indexOf(option) > -1;
- var isFocused = option === focusedOption;
- var optionClass = (0, _classnames2['default'])(optionClassName, {
- 'Select-option': true,
- 'is-selected': isSelected,
- 'is-focused': isFocused,
- 'is-disabled': option.disabled
- });
-
- return _react2['default'].createElement(
- Option,
- {
- className: optionClass,
- instancePrefix: instancePrefix,
- isDisabled: option.disabled,
- isFocused: isFocused,
- isSelected: isSelected,
- key: 'option-' + i + '-' + option[valueKey],
- onFocus: onFocus,
- onSelect: onSelect,
- option: option,
- optionIndex: i,
- ref: function (ref) {
- onOptionRef(ref, isFocused);
- }
- },
- optionRenderer(option, i)
- );
- });
-}
-
-module.exports = menuRenderer;
\ No newline at end of file
diff --git a/lib/utils/stripDiacritics.js b/lib/utils/stripDiacritics.js
deleted file mode 100644
index 2b46234737..0000000000
--- a/lib/utils/stripDiacritics.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use strict';
-
-var map = [{ 'base': 'A', 'letters': /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g }, { 'base': 'AA', 'letters': /[\uA732]/g }, { 'base': 'AE', 'letters': /[\u00C6\u01FC\u01E2]/g }, { 'base': 'AO', 'letters': /[\uA734]/g }, { 'base': 'AU', 'letters': /[\uA736]/g }, { 'base': 'AV', 'letters': /[\uA738\uA73A]/g }, { 'base': 'AY', 'letters': /[\uA73C]/g }, { 'base': 'B', 'letters': /[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g }, { 'base': 'C', 'letters': /[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g }, { 'base': 'D', 'letters': /[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g }, { 'base': 'DZ', 'letters': /[\u01F1\u01C4]/g }, { 'base': 'Dz', 'letters': /[\u01F2\u01C5]/g }, { 'base': 'E', 'letters': /[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g }, { 'base': 'F', 'letters': /[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g }, { 'base': 'G', 'letters': /[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g }, { 'base': 'H', 'letters': /[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g }, { 'base': 'I', 'letters': /[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g }, { 'base': 'J', 'letters': /[\u004A\u24BF\uFF2A\u0134\u0248]/g }, { 'base': 'K', 'letters': /[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g }, { 'base': 'L', 'letters': /[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g }, { 'base': 'LJ', 'letters': /[\u01C7]/g }, { 'base': 'Lj', 'letters': /[\u01C8]/g }, { 'base': 'M', 'letters': /[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g }, { 'base': 'N', 'letters': /[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g }, { 'base': 'NJ', 'letters': /[\u01CA]/g }, { 'base': 'Nj', 'letters': /[\u01CB]/g }, { 'base': 'O', 'letters': /[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g }, { 'base': 'OI', 'letters': /[\u01A2]/g }, { 'base': 'OO', 'letters': /[\uA74E]/g }, { 'base': 'OU', 'letters': /[\u0222]/g }, { 'base': 'P', 'letters': /[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g }, { 'base': 'Q', 'letters': /[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g }, { 'base': 'R', 'letters': /[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g }, { 'base': 'S', 'letters': /[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g }, { 'base': 'T', 'letters': /[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g }, { 'base': 'TZ', 'letters': /[\uA728]/g }, { 'base': 'U', 'letters': /[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g }, { 'base': 'V', 'letters': /[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g }, { 'base': 'VY', 'letters': /[\uA760]/g }, { 'base': 'W', 'letters': /[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g }, { 'base': 'X', 'letters': /[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g }, { 'base': 'Y', 'letters': /[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g }, { 'base': 'Z', 'letters': /[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g }, { 'base': 'a', 'letters': /[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g }, { 'base': 'aa', 'letters': /[\uA733]/g }, { 'base': 'ae', 'letters': /[\u00E6\u01FD\u01E3]/g }, { 'base': 'ao', 'letters': /[\uA735]/g }, { 'base': 'au', 'letters': /[\uA737]/g }, { 'base': 'av', 'letters': /[\uA739\uA73B]/g }, { 'base': 'ay', 'letters': /[\uA73D]/g }, { 'base': 'b', 'letters': /[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g }, { 'base': 'c', 'letters': /[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g }, { 'base': 'd', 'letters': /[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g }, { 'base': 'dz', 'letters': /[\u01F3\u01C6]/g }, { 'base': 'e', 'letters': /[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g }, { 'base': 'f', 'letters': /[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g }, { 'base': 'g', 'letters': /[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g }, { 'base': 'h', 'letters': /[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g }, { 'base': 'hv', 'letters': /[\u0195]/g }, { 'base': 'i', 'letters': /[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g }, { 'base': 'j', 'letters': /[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g }, { 'base': 'k', 'letters': /[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g }, { 'base': 'l', 'letters': /[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g }, { 'base': 'lj', 'letters': /[\u01C9]/g }, { 'base': 'm', 'letters': /[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g }, { 'base': 'n', 'letters': /[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g }, { 'base': 'nj', 'letters': /[\u01CC]/g }, { 'base': 'o', 'letters': /[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g }, { 'base': 'oi', 'letters': /[\u01A3]/g }, { 'base': 'ou', 'letters': /[\u0223]/g }, { 'base': 'oo', 'letters': /[\uA74F]/g }, { 'base': 'p', 'letters': /[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g }, { 'base': 'q', 'letters': /[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g }, { 'base': 'r', 'letters': /[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g }, { 'base': 's', 'letters': /[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g }, { 'base': 't', 'letters': /[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g }, { 'base': 'tz', 'letters': /[\uA729]/g }, { 'base': 'u', 'letters': /[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g }, { 'base': 'v', 'letters': /[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g }, { 'base': 'vy', 'letters': /[\uA761]/g }, { 'base': 'w', 'letters': /[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g }, { 'base': 'x', 'letters': /[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g }, { 'base': 'y', 'letters': /[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g }, { 'base': 'z', 'letters': /[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g }];
-
-module.exports = function stripDiacritics(str) {
- for (var i = 0; i < map.length; i++) {
- str = str.replace(map[i].letters, map[i].base);
- }
- return str;
-};
\ No newline at end of file
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 0000000000..c17ef2d629
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,6 @@
+[build]
+ command = "yarn build:docs"
+ publish = "docs/dist"
+
+[build.environment]
+ YARN_VERSION = "1.22.22"
diff --git a/package.json b/package.json
index 12151a0505..f09b73ef48 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,8 @@
{
- "name": "react-select",
- "version": "1.0.0-rc.3",
+ "name": "@react-select/monorepo",
+ "private": true,
+ "version": "1.0.0",
"description": "A Select control built with and for ReactJS",
- "main": "lib/Select.js",
- "style": "dist/react-select.min.css",
"author": "Jed Watson",
"license": "MIT",
"repository": {
@@ -11,61 +10,86 @@
"url": "https://github.com/JedWatson/react-select.git"
},
"dependencies": {
- "classnames": "^2.2.4",
- "react-input-autosize": "^1.1.0"
- },
- "devDependencies": {
- "babel": "^5.8.23",
- "babel-eslint": "^4.1.3",
- "chai": "^3.5.0",
- "coveralls": "^2.11.12",
- "eslint": "^1.10.3",
- "eslint-plugin-react": "^3.15.0",
- "gulp": "^3.9.1",
- "isomorphic-fetch": "^2.2.1",
- "istanbul": "^0.4.5",
- "jsdom": "^9.5.0",
- "mocha": "^3.0.2",
- "react": "^15.0",
- "react-addons-shallow-compare": "^15.0",
- "react-addons-test-utils": "^15.0",
- "react-component-gulp-tasks": "^0.7.7",
- "react-dom": "^15.0",
- "react-gravatar": "^2.4.5",
- "react-highlight-words": "^0.3.0",
- "react-virtualized": "^7.23.0",
- "react-virtualized-select": "^1.4.0",
- "sinon": "^1.17.5",
- "unexpected": "^10.17.0",
- "unexpected-dom": "^3.1.0",
- "unexpected-react": "^3.2.4",
- "unexpected-sinon": "^10.4.0"
- },
- "peerDependencies": {
- "react": "^0.14 || ^15.0.0-rc || ^15.0",
- "react-dom": "^0.14 || ^15.0.0-rc || ^15.0"
- },
- "browserify-shim": {
- "classnames": "global:classNames",
- "react": "global:React",
- "react-dom": "global:ReactDOM",
- "react-input-autosize": "global:AutosizeInput"
+ "@babel/core": "^7.19.6",
+ "@babel/plugin-proposal-class-properties": "^7.12.1",
+ "@babel/plugin-proposal-private-methods": "^7.13.0",
+ "@babel/plugin-transform-runtime": "^7.12.0",
+ "@babel/polyfill": "^7.12.1",
+ "@babel/preset-env": "^7.19.4",
+ "@babel/preset-react": "^7.12.1",
+ "@babel/preset-typescript": "^7.18.6",
+ "@babel/runtime": "^7.12.0",
+ "@changesets/cli": "^2.17.0",
+ "@changesets/get-github-info": "^0.5.0",
+ "@emotion/babel-plugin": "^11.10.2",
+ "@emotion/jest": "^11.1.0",
+ "@manypkg/cli": "^0.19.2",
+ "@preconstruct/cli": "^2.6.2",
+ "@testing-library/dom": "8.19.0",
+ "@testing-library/jest-dom": "5.1.1",
+ "@testing-library/react": "12.1.4",
+ "@testing-library/user-event": "^10.0.0",
+ "@types/copy-webpack-plugin": "^5.0.2",
+ "@types/html-webpack-plugin": "^3.2.4",
+ "@types/jest-in-case": "^1.0.6",
+ "@types/node": "^16.11.68",
+ "@types/pretty-proptypes": "^1.1.0",
+ "@types/react": "^16.14.60",
+ "@types/react-dom": "^16.9.10",
+ "@types/react-transition-group": "^4.4.0",
+ "@typescript-eslint/eslint-plugin": "^4.14.0",
+ "@typescript-eslint/parser": "^4.14.0",
+ "babel-core": "^7.0.0-bridge.0",
+ "babel-eslint": "^10.1.0",
+ "babel-jest": "^23.6.0",
+ "babel-loader": "^8.2.5",
+ "concurrently": "^7.5.0",
+ "copy-webpack-plugin": "^5.0.3",
+ "coveralls": "^3.1.1",
+ "cross-env": "^7.0.3",
+ "css-loader": "^0.28.7",
+ "cypress": "^5.0.0",
+ "dotenv": "^16.0.3",
+ "eslint": "^7.18.0",
+ "eslint-plugin-react": "^7.22.0",
+ "eslint-plugin-react-hooks": "^4.2.0",
+ "gh-pages": "^1.1.0",
+ "jest": "^25.1.0",
+ "jest-in-case": "^1.0.2",
+ "prettier": "^2.2.1",
+ "style-loader": "^0.23.1",
+ "typescript": "^4.1.3",
+ "user-agent-data-types": "^0.4.2"
},
"scripts": {
- "build": "gulp clean && NODE_ENV=production gulp build",
- "bump": "gulp bump",
- "bump:major": "gulp bump:major",
- "bump:minor": "gulp bump:minor",
- "cover": "istanbul cover _mocha -- -u exports --compilers js:babel/register -R spec",
- "coveralls": "NODE_ENV=test istanbul cover _mocha --report lcovonly -- -u exports --compilers js:babel/register -R spec && cat coverage/lcov.info | coveralls",
- "examples": "gulp dev:server",
- "lint": "eslint .",
- "publish:examples": "NODE_ENV=production gulp publish:examples",
- "release": "NODE_ENV=production gulp release",
- "start": "gulp dev",
- "test": "npm run lint && mocha --compilers js:babel/register",
- "watch": "gulp watch:lib"
+ "build": "preconstruct build",
+ "watch": "preconstruct watch",
+ "coveralls": "cat coverage/lcov.info | coveralls",
+ "prettify": "prettier --write .",
+ "prettier:check": "prettier --check .",
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "start": "cd docs && yarn start",
+ "start:test": "cd docs && yarn start:test",
+ "build:docs": "yarn --cwd=docs build:docs && yarn --cwd=storybook build && cp -r storybook/storybook-static docs/dist/storybook",
+ "fresh": "rm -rf node_modules && yarn install",
+ "test": "npm run test:jest && npm run test:cypress",
+ "test:jest": "jest --coverage",
+ "e2e": "concurrently --kill-others --success=first --names 'SERVER,E2E' 'yarn start:test' 'yarn test:cypress'",
+ "type-check": "tsc --build packages/react-select/tsconfig.json && tsc --build packages/react-select/src/__tests__/tsconfig.json && tsc --build docs/tsconfig.json && tsc --build cypress/tsconfig.json",
+ "precommit": "yarn run type-check",
+ "postinstall": "preconstruct dev && manypkg check",
+ "test:cypress": "yarn test:cypress:chrome && yarn test:cypress:firefox",
+ "test:cypress:chrome": "cypress run --browser chrome",
+ "test:cypress:firefox": "cypress run --browser firefox",
+ "test:cypress:watch": "node ./node_modules/.bin/cypress open",
+ "changeset": "changeset",
+ "version-packages": "changeset version",
+ "release": "yarn build && changeset publish"
},
+ "files": [
+ "dist",
+ "src"
+ ],
"keywords": [
"combobox",
"form",
@@ -75,5 +99,34 @@
"react-component",
"select",
"ui"
- ]
+ ],
+ "jest": {
+ "modulePathIgnorePatterns": [
+ "./node_modules"
+ ],
+ "testRegex": "src/*(/(__tests?__/)([^_].*/)*?[^_][^/]*?\\.(test|spec)?\\.(ts|js)x?)$",
+ "setupFilesAfterEnv": [
+ "./test-setup.js"
+ ],
+ "snapshotSerializers": [
+ "@emotion/jest/serializer"
+ ]
+ },
+ "workspaces": [
+ "packages/*",
+ "docs",
+ "storybook"
+ ],
+ "preconstruct": {
+ "packages": [
+ "packages/*",
+ "docs/generate-magical-types"
+ ],
+ "exports": {
+ "importConditionDefaultExport": "default"
+ }
+ },
+ "resolutions": {
+ "csstype": "^3.0.2"
+ }
}
diff --git a/packages/react-select/CHANGELOG.md b/packages/react-select/CHANGELOG.md
new file mode 100644
index 0000000000..393254bebd
--- /dev/null
+++ b/packages/react-select/CHANGELOG.md
@@ -0,0 +1,2017 @@
+# react-select
+
+## 5.10.2
+
+### Patch Changes
+
+- [`bf0c8615`](https://github.com/JedWatson/react-select/commit/bf0c8615f8574264883f984c0d2ff36ff9dcdcb7) [#6051](https://github.com/JedWatson/react-select/pull/6051) Thanks [@jnyholm-sc](https://github.com/jnyholm-sc)! - fix: hydration problem caused by isAppleDevice
+
+## 5.10.1
+
+### Patch Changes
+
+- [`c5706a0d`](https://github.com/JedWatson/react-select/commit/c5706a0d2b90f7a29bf12b760b048262ae8cc24c) [#6013](https://github.com/JedWatson/react-select/pull/6013) Thanks [@jonahShaf](https://github.com/jonahShaf)! - Distribute license file
+
+## 5.10.0
+
+### Minor Changes
+
+- [`6d28ed76`](https://github.com/JedWatson/react-select/commit/6d28ed762e5ef47543fc63ce7588db77455d1534) [#5993](https://github.com/JedWatson/react-select/pull/5993) Thanks [@onihani](https://github.com/onihani)! - Export the `FilterOptionOption` type
+
+## 5.9.0
+
+### Minor Changes
+
+- [`01206c33`](https://github.com/JedWatson/react-select/commit/01206c333c481b511e36521e5b568aebd4534b26) [#5984](https://github.com/JedWatson/react-select/pull/5984) Thanks [@Thris3n](https://github.com/Thris3n)! - Add React 19 to peer dependency range
+
+## 5.8.3
+
+### Patch Changes
+
+- [`111efad1`](https://github.com/JedWatson/react-select/commit/111efad170a11dbae96ae436251cd028e702eb72) [#5974](https://github.com/JedWatson/react-select/pull/5974) Thanks [@j2ghz](https://github.com/j2ghz)! - Fix types compatibility with React 19
+
+## 5.8.2
+
+### Patch Changes
+
+- [`781284a9`](https://github.com/JedWatson/react-select/commit/781284a97059b80c07eb77bc871540fe99304e8f) [#5771](https://github.com/JedWatson/react-select/pull/5771) Thanks [@tu4mo](https://github.com/tu4mo)! - Fix for calling non-cancellable scroll events
+
+## 5.8.1
+
+### Patch Changes
+
+- [`dd740ced`](https://github.com/JedWatson/react-select/commit/dd740cedb29c810a89da4445d4864cd7e63d3aaf) [#5960](https://github.com/JedWatson/react-select/pull/5960) Thanks [@leonaves](https://github.com/leonaves)! - No longer send pop-value action when multi-select is empty. This correctly resolves typings with that event, where removedValue cannot be undefined.
+
+## 5.8.0
+
+### Minor Changes
+
+- [`884f1c42`](https://github.com/JedWatson/react-select/commit/884f1c42549faad7cb210169223b427ad6f0c9fd) [#5758](https://github.com/JedWatson/react-select/pull/5758) Thanks [@Ke1sy](https://github.com/Ke1sy)! - 1. Added 'aria-activedescendant' for input and functionality to calculate it;
+
+ 2. Added role 'option' and 'aria-selected' for option;
+ 3. Added role 'listbox' for menu;
+ 4. Added tests for 'aria-activedescendant';
+ 5. Changes in aria-live region:
+
+ - the instructions how to use select will be announced only one time when user focuses the input for the first time.
+ - instructions for menu or selected value will be announced only once after focusing them.
+ - removed aria-live for focused option because currently with correct aria-attributes it will be announced by screenreader natively as well as the status of this option (active or disabled).
+ - separated ariaContext into ariaFocused, ariaResults, ariaGuidance to avoid announcing redundant information and higlight only current change.
+
+## 5.7.7
+
+### Patch Changes
+
+- [`224a8f0d`](https://github.com/JedWatson/react-select/commit/224a8f0d01a5b6200ff10280a0d7a9b613383032) [#5666](https://github.com/JedWatson/react-select/pull/5666) Thanks [@yhy-1](https://github.com/yhy-1)! - Add aria-disabled to select's control component.
+
+## 5.7.6
+
+### Patch Changes
+
+- [`f6315cd5`](https://github.com/JedWatson/react-select/commit/f6315cd5feddb2e9ea168bcad391b29990b53afb) [#5672](https://github.com/JedWatson/react-select/pull/5672) Thanks [@tu4mo](https://github.com/tu4mo)! - Fix for calling non-cancellable scroll events
+
+## 5.7.5
+
+### Patch Changes
+
+- [`9d1730ba`](https://github.com/JedWatson/react-select/commit/9d1730ba4f97a51d25c7e704acd1a4c2be8f7182) [#5347](https://github.com/JedWatson/react-select/pull/5347) Thanks [@aszmyd](https://github.com/aszmyd)! - Make scroll lock div work on a document context it belongs to
+
+## 5.7.4
+
+### Patch Changes
+
+- [`16414bb5`](https://github.com/JedWatson/react-select/commit/16414bb53295b362690d2b089d74182ddeabc1dd) [#5689](https://github.com/JedWatson/react-select/pull/5689) Thanks [@Rall3n](https://github.com/Rall3n)! - Resolve `defaultProps` deprecation warning for React v18+.
+
+## 5.7.3
+
+### Patch Changes
+
+- [`59513d00`](https://github.com/JedWatson/react-select/commit/59513d0035a20cf9c0575c4be52204de7f77d742) [#5626](https://github.com/JedWatson/react-select/pull/5626) Thanks [@emmatown](https://github.com/emmatown)! - Fix importing `react-select` in Node ESM
+
+## 5.7.2
+
+### Patch Changes
+
+- [`925cd4a2`](https://github.com/JedWatson/react-select/commit/925cd4a26097823187fb14cdae2561dd3c637e8c) [#5536](https://github.com/JedWatson/react-select/pull/5536) Thanks [@Rall3n](https://github.com/Rall3n)! - `required` prop accessibiltiy and functionality improvements
+
+## 5.7.1
+
+### Patch Changes
+
+- [`597143ee`](https://github.com/JedWatson/react-select/commit/597143ee3d5c27ce87e9b1508b068dc7c1323201) [#5559](https://github.com/JedWatson/react-select/pull/5559) Thanks [@gdiazdelaserna](https://github.com/gdiazdelaserna)! - Add `exports` field in package.json
+
+## 5.7.0
+
+### Minor Changes
+
+- [`0773095f`](https://github.com/JedWatson/react-select/commit/0773095f4990b636f64ae7d0ab593353a1e03b22) [#5457](https://github.com/JedWatson/react-select/pull/5457) Thanks [@nderkim](https://github.com/nderkim)! - Add classNames API and unstyled prop
+
+## 5.6.1
+
+### Patch Changes
+
+- [`cda16826`](https://github.com/JedWatson/react-select/commit/cda168262f777fd7be275d46063149c7d157fe55) [#5482](https://github.com/JedWatson/react-select/pull/5482) Thanks [@nderkim](https://github.com/nderkim)! - Fix unstable theme rerendering menu
+
+## 5.6.0
+
+### Minor Changes
+
+- [`c37e86d8`](https://github.com/JedWatson/react-select/commit/c37e86d8eaa3f6eba83696453a58d525cce6c7c6) [#4882](https://github.com/JedWatson/react-select/pull/4882) Thanks [@Rall3n](https://github.com/Rall3n)! - Add `required` prop
+
+## 5.5.9
+
+### Patch Changes
+
+- [`851ed2b8`](https://github.com/JedWatson/react-select/commit/851ed2b8b88d7230be2263a6c07c826bf507374d) [#5430](https://github.com/JedWatson/react-select/pull/5430) Thanks [@Rall3n](https://github.com/Rall3n)! - Fix focused option if `defaultMenuIsOpen` is set
+
+## 5.5.8
+
+### Patch Changes
+
+- [`1ad6de4e`](https://github.com/JedWatson/react-select/commit/1ad6de4ee75041129a657b92931a2965a1805c31) [#5084](https://github.com/JedWatson/react-select/pull/5084) Thanks [@kosciolek](https://github.com/kosciolek)! - When focusing a dropdown option, the numbers included in the aria live region take filtering into consideration.
+
+## 5.5.7
+
+### Patch Changes
+
+- [`0ca2d5ba`](https://github.com/JedWatson/react-select/commit/0ca2d5ba4aa42fb2a1bf033bcee660a293e39e50) [#5431](https://github.com/JedWatson/react-select/pull/5431) Thanks [@nderkim](https://github.com/nderkim)! - Change `class` components to `functional` components
+
+## 5.5.6
+
+### Patch Changes
+
+- [`92398939`](https://github.com/JedWatson/react-select/commit/9239893986c6aaaa7105d3f5a91022827e544b10) [#5409](https://github.com/JedWatson/react-select/pull/5409) Thanks [@lukebennett88](https://github.com/lukebennett88)! - Move files around to as to be compatible with version 2 of `@preconstruct/cli`
+
+## 5.5.5
+
+### Patch Changes
+
+- [`0dd38029`](https://github.com/JedWatson/react-select/commit/0dd3802977e525b4d8ea1eb083f8f13788016c28) [#5246](https://github.com/JedWatson/react-select/pull/5246) Thanks [@Rall3n](https://github.com/Rall3n)! - Fix re-focus of component in Firefox if being disabled while focused
+
+## 5.5.4
+
+### Patch Changes
+
+- [`ebb0a17a`](https://github.com/JedWatson/react-select/commit/ebb0a17a30b22cb7e7f7467ed8eda4256166e401) [#5404](https://github.com/JedWatson/react-select/pull/5404) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Use ResizeObserver to auto-update menu position if available
+
+## 5.5.3
+
+### Patch Changes
+
+- [`07656aaa`](https://github.com/JedWatson/react-select/commit/07656aaac7f636129f8d09e723df9fa6e5ff2841) [#5399](https://github.com/JedWatson/react-select/pull/5399) Thanks [@dependabot](https://github.com/apps/dependabot)! - Update memoize-one
+
+## 5.5.2
+
+### Patch Changes
+
+- [`00238f1a`](https://github.com/JedWatson/react-select/commit/00238f1a65ce9184b99edd6d3b3307f9b5c0c6c1) [#5376](https://github.com/JedWatson/react-select/pull/5376) Thanks [@lukebennett88](https://github.com/lukebennett88)! - Fix bug with animated multi-value select width being too wide
+
+## 5.5.1
+
+### Patch Changes
+
+- [`0f6ef093`](https://github.com/JedWatson/react-select/commit/0f6ef093282ca7356fb0e7ee7c706681a5a97901) [#5381](https://github.com/JedWatson/react-select/pull/5381) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Disable use of ResizeObserver for menu position auto-updating to avoid potential breaking changes.
+
+## 5.5.0
+
+### Minor Changes
+
+- [`598f9ee0`](https://github.com/JedWatson/react-select/commit/598f9ee0e641138820ae1b3d2a2121a1c21d3876) [#5256](https://github.com/JedWatson/react-select/pull/5256) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Auto-update menu position when using menu portalling
+
+## 5.4.0
+
+### Minor Changes
+
+- [`5d49f70a`](https://github.com/JedWatson/react-select/commit/5d49f70aeb9d6c2685b81b361e3dab3e2064292d) [#5249](https://github.com/JedWatson/react-select/pull/5249) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Export `formatOptionLabel` types (i.e., `FormatOptionLabelMeta` and `FormatOptionLabelContext`).
+
+## 5.3.2
+
+### Patch Changes
+
+- [`1f140e42`](https://github.com/JedWatson/react-select/commit/1f140e423707e9966254050e3234a65ee05977e9) [#5177](https://github.com/JedWatson/react-select/pull/5177) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fix view height used for menu positioning to be the scroll parent instead of the window
+
+## 5.3.1
+
+### Patch Changes
+
+- [`03bf7351`](https://github.com/JedWatson/react-select/commit/03bf735127fec6e47de8ae45e7cdc0a39c8b638b) [#5164](https://github.com/JedWatson/react-select/pull/5164) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Bump @emotion/react to ^11.8.1 to avoid `useInsertionEffect` bug
+
+## 5.3.0
+
+### Minor Changes
+
+- [`c7d8d4b3`](https://github.com/JedWatson/react-select/commit/c7d8d4b3ee01cee63b34adf4a895ef07ce2f3b03) [#5133](https://github.com/JedWatson/react-select/pull/5133) Thanks [@nil4](https://github.com/nil4)! - Update `peerDependencies` to include React 18
+
+### Patch Changes
+
+- [`0aaa9575`](https://github.com/JedWatson/react-select/commit/0aaa9575ed7e817841b9c9b494b4bd4dc2247b26) [#5134](https://github.com/JedWatson/react-select/pull/5134) Thanks [@rkulinski](https://github.com/rkulinski)! - Use defaultPrevented to skip duplicate event handler for clicking select.
+
+- [`87e14431`](https://github.com/JedWatson/react-select/commit/87e144319f485fba20b46bc71eb8162f88d19430) [#5131](https://github.com/JedWatson/react-select/pull/5131) Thanks [@pcorpet](https://github.com/pcorpet)! - Avoid referencing an ID that is not in the DOM
+
+- [`7184d538`](https://github.com/JedWatson/react-select/commit/7184d538f587c1dd5a4ca5ad6cc0745fbb8d3809) [#5082](https://github.com/JedWatson/react-select/pull/5082) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fix type inference for Async's loadOptions prop
+
+- [`bd4ee8ae`](https://github.com/JedWatson/react-select/commit/bd4ee8ae66e581e8be1679fa4b1838451e3f23b7) [#5057](https://github.com/JedWatson/react-select/pull/5057) Thanks [@Rall3n](https://github.com/Rall3n)! - Prevent transition props from being forwarded to ` ` element in `DummyInput` component
+
+## 5.2.2
+
+### Patch Changes
+
+- [`940a50b1`](https://github.com/JedWatson/react-select/commit/940a50b1a579b279b82c1efc5608a92eb422919e) [#4928](https://github.com/JedWatson/react-select/pull/4928) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fix usage with esModuleInterop disabled
+
+- [`54f9538e`](https://github.com/JedWatson/react-select/commit/54f9538e350bae4e11aa11311731cb95eb56d669) [#4941](https://github.com/JedWatson/react-select/pull/4941) Thanks [@prichey](https://github.com/prichey)! - Use React's AriaAttributes type directly rather than recreating
+
+- [`e97d45c0`](https://github.com/JedWatson/react-select/commit/e97d45c04bbc91e9e2ff9509f0d9c16fc4e4234e) [#4908](https://github.com/JedWatson/react-select/pull/4908) Thanks [@vjee](https://github.com/vjee)! - Make 3rd argument of CommonProps['setValue'] optional.
+
+## 5.2.1
+
+### Patch Changes
+
+- [`f172d7f9`](https://github.com/JedWatson/react-select/commit/f172d7f9c20b82db14e795d578ee4802475d2bdc) [#4886](https://github.com/JedWatson/react-select/pull/4886) Thanks [@Akridian](https://github.com/Akridian)! - Hooks for creation of custom Selects are now exported from main entry
+
+## 5.2.0
+
+### Minor Changes
+
+- [`6c7a3d1e`](https://github.com/JedWatson/react-select/commit/6c7a3d1e07b7d6a8f484a829e69b20eae5a92b91) [#4785](https://github.com/JedWatson/react-select/pull/4785) Thanks [@Rall3n](https://github.com/Rall3n)! - Add `prevInputValue` to action meta
+
+- [`b522ac65`](https://github.com/JedWatson/react-select/commit/b522ac658f85701ecf413436f3cf8d8d49117c82) [#4860](https://github.com/JedWatson/react-select/pull/4860) Thanks [@ebonow](https://github.com/ebonow)! - Fix animated MultiValue transitions when being removed and change method used to generate unique keys for Option components. Closes #4844 , closes #4602
+
+### Patch Changes
+
+- [`417e7217`](https://github.com/JedWatson/react-select/commit/417e721786af309ede9b35983a18df89363cd1c5) [#4842](https://github.com/JedWatson/react-select/pull/4842) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Remove src directory from published package
+
+- [`480ea85b`](https://github.com/JedWatson/react-select/commit/480ea85bed6f7c90c45d14884b4ec1105d92971a) [#4846](https://github.com/JedWatson/react-select/pull/4846) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Add missing index to MultiValue props type
+
+- [`b8e34472`](https://github.com/JedWatson/react-select/commit/b8e34472d352a87e9687027a5c3f4ed767984177) [#4854](https://github.com/JedWatson/react-select/pull/4854) Thanks [@mikunpham](https://github.com/mikunpham)! - Make input container css re-compute whenever input value changes due to a bug from `@emotion/react` in development env.
+
+## 5.1.0
+
+### Minor Changes
+
+- [8b38d49b](https://github.com/JedWatson/react-select/commit/8b38d49b4a779c653f70b502a61f7c64220fa44d) [#4807](https://github.com/JedWatson/react-select/pull/4807) Thanks [@hcharley](https://github.com/hcharley)! - Export AsyncCreatableProps from creatable entrypoint
+
+- [46eeda1a](https://github.com/JedWatson/react-select/commit/46eeda1a6829af168ae24b49a251d12e410706ab) [#4801](https://github.com/JedWatson/react-select/pull/4801) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Export more types from main entry point
+
+### Patch Changes
+
+- [fdd01e66](https://github.com/JedWatson/react-select/commit/fdd01e664400b684b83c2b1c629bd3c76b152236) [#4833](https://github.com/JedWatson/react-select/pull/4833) Thanks [@ebonow](https://github.com/ebonow)! - Value container display property should be grid when isMulti and has no value so the Placeholder component is positioned correctly with the Input
+
+- [0937604f](https://github.com/JedWatson/react-select/commit/0937604ffcec5d56dd4918ae728feee345e1c78c) [#4823](https://github.com/JedWatson/react-select/pull/4823) Thanks [@mikunpham](https://github.com/mikunpham)! - Fix the issue where input contents are moved to the left due to multiple space characters.
+
+- [ec80b577](https://github.com/JedWatson/react-select/commit/ec80b577665f2bd9b2cff9d7ca34723b6b65e5b8) [#4803](https://github.com/JedWatson/react-select/pull/4803) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Import CSSObject from @emotion/react instead of @emotion/serialize
+
+## 5.0.0
+
+### Major Changes
+
+- [ef87c3ac](https://github.com/JedWatson/react-select/commit/ef87c3ac7fd453800595eebebb85f1107f78d34c) [#4683](https://github.com/JedWatson/react-select/pull/4683) Thanks [@JedWatson](https://github.com/JedWatson)! - React-Select has been converted from Flow to TypeScript.
+
+ Other changes for v5 include usage of `forwardRef`, new hooks for `stateManager`, `async` and `creatable` components, and more reliable filtering implementation with new options in the creatable variant.
+
+### Patch Changes
+
+- [10225290](https://github.com/JedWatson/react-select/commit/10225290f9b1c9a722fc96fa4c74d91bfbeb7df8) [#4720](https://github.com/JedWatson/react-select/pull/4720) - Updated the layout for the singleValue input/placeholder/container so that it works better when used in flex layouts.
+
+- [53f1972b](https://github.com/JedWatson/react-select/commit/53f1972b2d76443a63df18eb538ccbf68787e362) [#4731](https://github.com/JedWatson/react-select/pull/4731) Thanks [@JedWatson](https://github.com/JedWatson)! - MultiValue key now includes a hyphen between the value and the index to prevent edge cases where you could get a duplicate key error
+
+- [b41f4ceb](https://github.com/JedWatson/react-select/commit/b41f4cebbcaa8714bcf36cf24357f580a74c6a16) [#4704](https://github.com/JedWatson/react-select/pull/4704) Thanks [@Rall3n](https://github.com/Rall3n)! - Fix findDOMNode deprecation by adding refs to transition components
+
+- [4b028829](https://github.com/JedWatson/react-select/commit/4b028829721bcd9014d70ee8dce1efbaf6373cd0) [#4634](https://github.com/JedWatson/react-select/pull/4634) - The readonly attribute has been removed from the DummyInput to improve accessibility
+
+- [7fcec537](https://github.com/JedWatson/react-select/commit/7fcec537e75b80b3084b64db76150cfef9d2ee2f) [#4697](https://github.com/JedWatson/react-select/pull/4697) - Add the role of combobox and the required ARIA attributes to the Input and DummyInput components to allow JAWS support and a better screen reader experience overall.
+
+- [ca2c0e5b](https://github.com/JedWatson/react-select/commit/ca2c0e5b18f0c862e7cb5956d0f56104ffa4255f) [#4756](https://github.com/JedWatson/react-select/pull/4756) Thanks [@fdcds](https://github.com/fdcds)! - Add `option` field to type of `CreateOptionActionMeta`
+
+- [9e82aadc](https://github.com/JedWatson/react-select/commit/9e82aadcd1931f730235d317a2299a681da8c373) [#4676](https://github.com/JedWatson/react-select/pull/4676) - The following improvements have been made for screen reader users:
+
+ - NVDA now announces the context text when initially focused
+ - Selected option/s (single and multi) are now announced when initially focused
+ - VoiceOver now announces the context text when re-focusing
+ - The clear action is now announced
+ - Placeholder text is now announced
+ - Mobile VoiceOver is now able to remove selected multi options
+
+- [638f5455](https://github.com/JedWatson/react-select/commit/638f545517d320fe70ca954511a71e96956abae3) [#4702](https://github.com/JedWatson/react-select/pull/4702) Thanks [@Methuselah96](https://github.com/Methuselah96)! - The Option generic is no longer required to extend the OptionBase type
+
+- [23cea0b5](https://github.com/JedWatson/react-select/commit/23cea0b513525bdf6282e3d03e66eff38da9e993) [#4782](https://github.com/JedWatson/react-select/pull/4782) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fix type of loadingMessage prop to allow it to return any ReactNode
+
+## 5.0.0-beta.1
+
+### Patch Changes
+
+- [10225290](https://github.com/JedWatson/react-select/commit/10225290f9b1c9a722fc96fa4c74d91bfbeb7df8) [#4720](https://github.com/JedWatson/react-select/pull/4720) - Updated the layout for the singleValue input/placeholder/container so that it works better when used in flex layouts.
+
+- [53f1972b](https://github.com/JedWatson/react-select/commit/53f1972b2d76443a63df18eb538ccbf68787e362) [#4731](https://github.com/JedWatson/react-select/pull/4731) Thanks [@JedWatson](https://github.com/JedWatson)! - MultiValue key now includes a hyphen between the value and the index to prevent edge cases where you could get a duplicate key error
+
+- [b41f4ceb](https://github.com/JedWatson/react-select/commit/b41f4cebbcaa8714bcf36cf24357f580a74c6a16) [#4704](https://github.com/JedWatson/react-select/pull/4704) Thanks [@Rall3n](https://github.com/Rall3n)! - Fix findDOMNode deprecation by adding refs to transition components
+
+- [7fcec537](https://github.com/JedWatson/react-select/commit/7fcec537e75b80b3084b64db76150cfef9d2ee2f) [#4697](https://github.com/JedWatson/react-select/pull/4697) - Add the role of combobox and the required ARIA attributes to the Input and DummyInput components to allow JAWS support and a better screen reader experience overall.
+
+- [9e82aadc](https://github.com/JedWatson/react-select/commit/9e82aadcd1931f730235d317a2299a681da8c373) [#4676](https://github.com/JedWatson/react-select/pull/4676) - The following improvements have been made for screen reader users:
+
+ - NVDA now announces the context text when initially focused
+ - Selected option/s (single and multi) are now announced when initially focused
+ - VoiceOver now announces the context text when re-focusing
+ - The clear action is now announced
+ - Placeholder text is now announced
+ - Mobile VoiceOver is now able to remove selected multi options
+
+- [638f5455](https://github.com/JedWatson/react-select/commit/638f545517d320fe70ca954511a71e96956abae3) [#4702](https://github.com/JedWatson/react-select/pull/4702) Thanks [@Methuselah96](https://github.com/Methuselah96)! - The Option generic is no longer required to extend the OptionBase type
+
+## 5.0.0-beta.0
+
+### Major Changes
+
+- [ef87c3ac](https://github.com/JedWatson/react-select/commit/ef87c3ac7fd453800595eebebb85f1107f78d34c) [#4489](https://github.com/JedWatson/react-select/pull/4489) Thanks [@Methuselah96](https://github.com/Methuselah96)! - React-Select has been converted from Flow to TypeScript.
+
+ Other changes for v5 include usage of `forwardRef`, new hooks for `stateManager`, `async` and `creatable` components, and more reliable filtering implementation with new options in the creatable variant.
+
+- [#4625](https://github.com/JedWatson/react-select/pull/4625) Thanks [@ebonow](https://github.com/ebonow)! - Remove dependency on AutoSizeInput
+ - BREAKING CHANGES:
+ - IE11 no longer works as it does not fully support CSS grid
+ - Renaming the .prefix\_\_input now targets the input and NOT the container. Unfortunate but overdue and perhaps opens the door to completely decoupling the input from needing a container if autosizing is not important.
+
+### Patch Changes
+
+- [4b028829](https://github.com/JedWatson/react-select/commit/4b028829721bcd9014d70ee8dce1efbaf6373cd0) [#4634](https://github.com/JedWatson/react-select/pull/4634) - The readonly attribute has been removed from the DummyInput to improve accessibility
+
+---
+
+## 4.3.1
+
+### Patch Changes
+
+- [2c915d10](https://github.com/JedWatson/react-select/commit/2c915d10b5ce7b7f48aa0903fa838f9c294c434d) [#4577](https://github.com/JedWatson/react-select/pull/4577) - Bump @emotion/cache to v11.4.0 which fixes an issue where different versions of Emotion running at the same time causes styles to disappear in production.
+
+## 4.3.0
+
+### Minor Changes
+
+- [035294f4](https://github.com/JedWatson/react-select/commit/035294f457921423c9237861f7c73584bdecbcc4) [#3360](https://github.com/JedWatson/react-select/pull/3360) Thanks [@JedWatson](https://github.com/JedWatson)! - Now pass the focusedOption to the MenuList Component as a prop
+
+### Patch Changes
+
+- [7a414a7c](https://github.com/JedWatson/react-select/commit/7a414a7c7a1f8e2902e43bd476e3db17a8dce049) [#3262](https://github.com/JedWatson/react-select/pull/3262) Thanks [@JedWatson](https://github.com/JedWatson)! - The Menu bottom is no longer scrolled into view when menuShouldScrollIntoView=false
+
+## 4.2.1
+
+### Patch Changes
+
+- [ca3c41bb](https://github.com/JedWatson/react-select/commit/ca3c41bb55e2666589bbbb69d1153357191d07a4) [#4478](https://github.com/JedWatson/react-select/pull/4478) Thanks [@ebonow](https://github.com/ebonow)! - Check passive events polyfill for the existence of window for SSR
+
+## 4.2.0
+
+### Minor Changes
+
+- [2ffed9c6](https://github.com/JedWatson/react-select/commit/2ffed9c6c40c9d5b81d7c8faf7bfc995976299ec) [#4444](https://github.com/JedWatson/react-select/pull/4444) Thanks [@Rall3n](https://github.com/Rall3n)! - Use accessor props to get value and label in `compareOption`
+
+- [2baf5a9d](https://github.com/JedWatson/react-select/commit/2baf5a9df2f4f56f9c9374fcb879cb5259a6d8d0) [#4414](https://github.com/JedWatson/react-select/pull/4414) Thanks [@ebonow](https://github.com/ebonow)! - Add ariaLiveMessages prop for internationalization and other customisations
+
+- [7cdb8a6b](https://github.com/JedWatson/react-select/commit/7cdb8a6b4d9de89a599b3aee8b6d90a44a931ea6) [#4391](https://github.com/JedWatson/react-select/pull/4391) Thanks [@ebonow](https://github.com/ebonow)! - Pass and sanitize CommonProps passed to Group and Input components
+
+### Patch Changes
+
+- [c955415c](https://github.com/JedWatson/react-select/commit/c955415cd3724489423dd8e84d6dab5ace24c984) [#4437](https://github.com/JedWatson/react-select/pull/4437) Thanks [@ebonow](https://github.com/ebonow)! - Set event listeners to be non-passive to remove Chrome console warnings
+
+- [3ca22b2f](https://github.com/JedWatson/react-select/commit/3ca22b2f49ad4f05f98ec8a565d74c483c0b98aa) [#3827](https://github.com/JedWatson/react-select/pull/3827) Thanks [@emmatown](https://github.com/emmatown)! - Memoize stripDiacritics in createFilter for the input with memoize-one so that stripDiacritics is not called for the same string as many times as there are options every time the input changes
+
+ Inspired by https://blog.johnnyreilly.com/2019/04/react-select-with-less-typing-lag.html
+
+- [dce3863f](https://github.com/JedWatson/react-select/commit/dce3863ff2ba8dfb50f505d81a2e70cf2d7a97e7) [#4423](https://github.com/JedWatson/react-select/pull/4423) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Remove browser alias fields in order to fix SSR apps
+
+- [ec7c0728](https://github.com/JedWatson/react-select/commit/ec7c0728c5bfe98a81ab557699147ae244f7a073) [#4443](https://github.com/JedWatson/react-select/pull/4443) Thanks [@ebonow](https://github.com/ebonow)! - Allow tabIndex prop Type to be number or string
+
+## 4.1.0
+
+### Minor Changes
+
+- [b5f9b0c5](https://github.com/JedWatson/react-select/commit/b5f9b0c59d7ac8559f88287ba73f0495b4c8eed2) [#4342](https://github.com/JedWatson/react-select/pull/4342) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Standardized innerProps and className props on customisable components
+
+- [19b76342](https://github.com/JedWatson/react-select/commit/19b763428d6df254f0b9662f18a698dd3c59d83b) [#3911](https://github.com/JedWatson/react-select/pull/3911) Thanks [@eugenet8k](https://github.com/eugenet8k)! - Add `removedValues` to `onChange` event meta when the action is `clear` (when the user clears the value in the Select)
+
+### Patch Changes
+
+- [f600d13f](https://github.com/JedWatson/react-select/commit/f600d13f5981c9e54e78247fdd82f62555373cff) [#4422](https://github.com/JedWatson/react-select/pull/4422) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fix finding focusable options for groups
+
+- [a016c878](https://github.com/JedWatson/react-select/commit/a016c87821d9289ef9c317c0c397d64a0824ce16) [#4420](https://github.com/JedWatson/react-select/pull/4420) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Bump dependency on @babel/runtime in order to fix compatibility issues with Webpack 5
+
+- [10b5f5a5](https://github.com/JedWatson/react-select/commit/10b5f5a5edc93becb6b46f22666305ec8c1b7de3) [#4404](https://github.com/JedWatson/react-select/pull/4404) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Remove unnecessary dependency on @emotion/css
+
+## 4.0.2
+
+### Patch Changes
+
+- [44f285b0](https://github.com/JedWatson/react-select/commit/44f285b0d4a50e16713b9aa3746d73d80dee2c91) [#4399](https://github.com/JedWatson/react-select/pull/4399) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fixed building focusable options from groups
+
+## 4.0.1
+
+### Patch Changes
+
+- [645feb3e](https://github.com/JedWatson/react-select/commit/645feb3e34776a5f181b32f603027df5ca709b7d) [#4396](https://github.com/JedWatson/react-select/pull/4396) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fixed keys for options within groups
+
+## 4.0.0
+
+### Major Changes
+
+- [02050675](https://github.com/JedWatson/react-select/commit/020506755728f607a77145e2a00458526596496f) [#4339](https://github.com/JedWatson/react-select/pull/4339) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Standardized value passed to onChange
+
+- [26b6325c](https://github.com/JedWatson/react-select/commit/26b6325c95113591e568451bc2296f98318a8dd9) [#4283](https://github.com/JedWatson/react-select/pull/4283) Thanks [@majgaard](https://github.com/majgaard)! - Upgrades Emotion dependency to v11.0.0
+
+ BREAKING CHANGE: The NonceProvider component now requires a `cacheKey` prop that corresponds to the `key` for the Emotion cache.
+
+- [b2488bb5](https://github.com/JedWatson/react-select/commit/b2488bb561ed08c822bc1a828d2d9fd957f25bdf) [#4313](https://github.com/JedWatson/react-select/pull/4313) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Removed usages of UNSAFE React methods
+
+### Patch Changes
+
+- [2d5496d5](https://github.com/JedWatson/react-select/commit/2d5496d52b6650b57352a0ea0dfcab383567f3ac) [#4388](https://github.com/JedWatson/react-select/pull/4388) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Removed memoization of buildMenuOptions
+
+## 3.2.0
+
+### Minor Changes
+
+- [c615e93d](https://github.com/JedWatson/react-select/commit/c615e93dbca15b9f9c6c3e6437744ca53703347f) [#4084](https://github.com/JedWatson/react-select/pull/4084) Thanks [@JedWatson](https://github.com/JedWatson)! - Changed the `cx` and `getValue` props that are passed to components into instance properties, which means they now pass a referential equality check on subsequent renders.
+
+ This is helpful, for example, when you're optimising the performance of rendering custom Option components - see [#3055](https://github.com/JedWatson/react-select/issues/3055)
+
+- [72f6036f](https://github.com/JedWatson/react-select/commit/72f6036fa6f425837c8c2326bf91dff7bd7f6147) [#4306](https://github.com/JedWatson/react-select/pull/4306) Thanks [@bladey](https://github.com/bladey)! - Remove duplicate prop createOptionPosition
+
+### Patch Changes
+
+- [ee638d46](https://github.com/JedWatson/react-select/commit/ee638d4615e789090ea860d2e1c9f4d95a829d50) [#4275](https://github.com/JedWatson/react-select/pull/4275) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Adds react ^17.0.0 to peer dependencies for React 17 support
+
+- [a0133f19](https://github.com/JedWatson/react-select/commit/a0133f19f45eb2dc9a2faebd74e18f44da7d509b) [#4154](https://github.com/JedWatson/react-select/pull/4154) Thanks [@brenshanny](https://github.com/brenshanny)! - Creatable: Fixed removing MultiValues that have identical values. See issue #4137 for details.
+
+- [d1e660c6](https://github.com/JedWatson/react-select/commit/d1e660c6b261d7fd60a85a6eca2ee9e3e0348ea2) [#4213](https://github.com/JedWatson/react-select/pull/4213) Thanks [@eythort](https://github.com/eythort)! - Added a guard to the `ScrollCaptor` component to check that `el` exists before calling `removeEventListener`, fixes intermittent errors
+
+- [a1e1db25](https://github.com/JedWatson/react-select/commit/a1e1db255aceda301d9705d0639e7ca0302bd079) [#4373](https://github.com/JedWatson/react-select/pull/4373) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Fixed value passed to onChange when clearing value
+
+- [2ad29d61](https://github.com/JedWatson/react-select/commit/2ad29d615bc769c3b3dc4177eb0007a267369748) [#4136](https://github.com/JedWatson/react-select/pull/4136) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Base aria-live message on tabSelectsValue prop
+
+- [ad890f27](https://github.com/JedWatson/react-select/commit/ad890f279300b6baaca55a642141999a79af8883) [#4326](https://github.com/JedWatson/react-select/pull/4326) Thanks [@Methuselah96](https://github.com/Methuselah96)! - Updated react-input-autosize to v3.0.0
+
+- [b28d9922](https://github.com/JedWatson/react-select/commit/b28d99222ab191db27482c6219f8c8b12ef753d8) [#3990](https://github.com/JedWatson/react-select/pull/3990) Thanks [@nikitaindik](https://github.com/nikitaindik)! - Fixed onCreateOption is not always called for Creatable
+
+- [24ba8702](https://github.com/JedWatson/react-select/commit/24ba8702b93885790ee919de8c01ea8f44d1c354) [#4289](https://github.com/JedWatson/react-select/pull/4289) Thanks [@slimklim](https://github.com/slimklim)! - Added `innerProps` prop to the built-in `MenuList` component to reduce the need for additional DOM nodes or forking internal code when passing additional props to the DOM element the MenuList component is rendering.
+
+ See issue [#4265](https://github.com/JedWatson/react-select/issues/4265) for an explanation.
+
+## 3.1.1
+
+### Patch Changes
+
+- [c8d74bd5](https://github.com/JedWatson/react-select/commit/c8d74bd5710b1db6736837fb4334a59e46614a27) [#3979](https://github.com/JedWatson/react-select/pull/3979) Thanks [@emmatown](https://github.com/emmatown)! - Fix repository field
+
+- [c8447f48](https://github.com/JedWatson/react-select/commit/c8447f480f8b9ca04386bee08e8d3a6fbb4f07c8) [#4034](https://github.com/JedWatson/react-select/pull/4034) Thanks [@sophiebits](https://github.com/sophiebits)! - Improve performance of option filtering when ignoreAccents is enabled (the default)
+
+- [7af1aafb](https://github.com/JedWatson/react-select/commit/7af1aafb2314db02544b7970784b868e97ec4824) [#4295](https://github.com/JedWatson/react-select/pull/4295) Thanks [@JedWatson](https://github.com/JedWatson)! - Fix menuplacement context
+
+- [32ad5c04](https://github.com/JedWatson/react-select/commit/32ad5c040bdd96cd1ca71010c2558842d684629c) [#3892](https://github.com/JedWatson/react-select/pull/3892) Thanks [@flexdinesh](https://github.com/flexdinesh)! - Fix react-select ignoring HTML5 "form" attribute
+
+- [6af14fbb](https://github.com/JedWatson/react-select/commit/6af14fbbc8ab42f2d17721732c9fe221d47c9e30) [#3897](https://github.com/JedWatson/react-select/pull/3897) Thanks [@lorisdev](https://github.com/lorisdev)! - Removes the call to `onMenuOpen` on every input change
+
+ If you were relying on this undesired behavior it may be a breaking change.
+ Please upgrade accordingly.
+
+- [0eb1ef96](https://github.com/JedWatson/react-select/commit/0eb1ef9625de907fddaf29516cec3bd93bf9c5f7) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixes touch issues in IE11
+
+- [ad608c8f](https://github.com/JedWatson/react-select/commit/ad608c8f1f445e70a082bae755dd30bda5b5f205) [#3928](https://github.com/JedWatson/react-select/pull/3928) Thanks [@dpordomingo](https://github.com/dpordomingo)! - Update MenuPlacer context usage in order to the new React Context API
+
+## 3.1.0
+
+### Minor Changes
+
+- [4cf6c43c](https://github.com/JedWatson/react-select/commit/4cf6c43cc17a01b043fb60b33cad355d433fdf8c) [#3690](https://github.com/JedWatson/react-select/pull/3690) Thanks [@JedWatson](https://github.com/JedWatson)! - Add `isLoading` prop support to the AsyncSelect component (see #3690)
+
+### Patch Changes
+
+- [83b48de4](https://github.com/JedWatson/react-select/commit/83b48de4a18263b361744fc5e89d9b9845b26e4f) [#3868](https://github.com/JedWatson/react-select/pull/3868) Thanks [@Tirzono](https://github.com/Tirzono)! - Fix for not focusing the selected value when the menu opens
+- [563b046a](https://github.com/JedWatson/react-select/commit/563b046a57a94c47950e62cedc4ce1c489f19f91) [#3794](https://github.com/JedWatson/react-select/pull/3794) Thanks [@emmatown](https://github.com/emmatown)! - Convert class components that don't have to be class components to function components to reduce bundle size
+- [c7e9c697](https://github.com/JedWatson/react-select/commit/c7e9c697dada15ce3ff9a767bf914ad890080433) [#3682](https://github.com/JedWatson/react-select/pull/3682) Thanks [@JedWatson](https://github.com/JedWatson)! - Allow the input component to be a `textarea` element
+- [3c7de0de](https://github.com/JedWatson/react-select/commit/3c7de0de52826fe74d303a01475c43fe88256156) [#3090](https://github.com/JedWatson/react-select/pull/3090) Thanks [@akiselev](https://github.com/akiselev)! - Add aria attributes to dummy input
+- [d2a820ef](https://github.com/JedWatson/react-select/commit/d2a820efc70835adf864169eebc76947783a15e2) [#3537](https://github.com/JedWatson/react-select/pull/3537) Thanks [@jdelStrother](https://github.com/jdelStrother)! - Fix Flow issues. Refer to the linked PR for more details on the specific issues.
+- [fc52085b](https://github.com/JedWatson/react-select/commit/fc52085b969b1b6f53adf29d52469db9560b828c) [#3662](https://github.com/JedWatson/react-select/pull/3662) Thanks [@eemeli](https://github.com/eemeli)! - Update react-transition-group to ^4.3.0
+- [edb18dd3](https://github.com/JedWatson/react-select/commit/edb18dd3d65b8fbc342bde9e805c5e3293ab6e37) [#3797](https://github.com/JedWatson/react-select/pull/3797) Thanks [@emmatown](https://github.com/emmatown)! - Enable Babel loose mode to improve bundle size
+
+## 3.0.8
+
+### Patch Changes
+
+- [a575a3c4](https://github.com/JedWatson/react-select/commit/a575a3c41798696620c77e8098c1150b4adda6cb) [#3727](https://github.com/JedWatson/react-select/pull/3727) Thanks [@tonytangau](https://github.com/tonytangau)! - Adding an `index` prop to `MultiValue` components
+- [916f0d2c](https://github.com/JedWatson/react-select/commit/916f0d2c651189bfeff2289d8d3cc597e06cb2ea) [#3644](https://github.com/JedWatson/react-select/pull/3644) Thanks [@TrySound](https://github.com/TrySound)! - Remove usage of `raf` package and replace with `window.requestAnimationFrame` because React already depends on `requestAnimationFrame`
+- [cba15309](https://github.com/JedWatson/react-select/commit/cba15309c4d7523ab6a785c8d5c0c7ec1048e22f) [#3676](https://github.com/JedWatson/react-select/pull/3676) Thanks [@wiesys](https://github.com/wiesys)! - Fix `loadingMessage` and `noOptionsMessage` properties in `Styles` flow type
+- [32f9475e](https://github.com/JedWatson/react-select/commit/32f9475e6d43a71000a3906da9e6d2d30710efd2) [#3790](https://github.com/JedWatson/react-select/pull/3790) Thanks [@JedWatson](https://github.com/JedWatson)! - Remove unnecessary dependency on `classnames` package
+- [1731175d](https://github.com/JedWatson/react-select/commit/1731175d790530b9dbfa787e3fffaff3fb0e44a0) [#3733](https://github.com/JedWatson/react-select/pull/3733) Thanks [@ddc67cd](https://github.com/ddc67cd)! - Pass `name` to `onChange` meta in `Creatable` to make it consistent with onChange in standard `Select`
+
+## 3.0.7
+
+### Patch Changes
+
+- [df864f2](https://github.com/JedWatson/react-select/commit/df864f2) - Include updated yarn.lock
+
+## 3.0.6
+
+### Patch Changes
+
+- [3e0a7a7](https://github.com/JedWatson/react-select/commit/3e0a7a7) - \* remove emotion 9 dep from mono repo (this wasn't being used anywhere)
+ - update dep on react-input-autosize to 2.2.2 (adds UNSAFE prefix to deprecated lifecycles) (resolves #3773)
+
+## 3.0.5
+
+### Patch Changes
+
+- [270cc01](https://github.com/JedWatson/react-select/commit/270cc01) [#3719](https://github.com/JedWatson/react-select/pulls/3719) Thanks [@jossmac](https://github.com/jossmac)! - Leverage currentColor for loading indicator dots -- makes styling easier, and more consistent, for consumers
+- [bab8af1](https://github.com/JedWatson/react-select/commit/bab8af1) - Update lifecycle methods with UNSAFE prefix
+
+## 3.0.4
+
+### Patch Changes
+
+- [cd8c3090](https://github.com/JedWatson/react-select/commit/cd8c3090) [#3586](https://github.com/JedWatson/react-select/pull/3586) Thanks [@emmatown](https://github.com/emmatown)! - Add base entrypoint back
+
+- [#3569](https://github.com/JedWatson/react-select/pull/3569) Thanks [@vadimka123](https://github.com/vadimka123) - Performance improvement: menu items are built when the menu opens, not in the constructor
+
+- [#3326](https://github.com/JedWatson/react-select/pull/3326) Thanks [@stevemao](https://github.com/stevemao) Fix for iOS focus management when clearing the select value
+
+- [#3532](https://github.com/JedWatson/react-select/pull/3532) Thanks [@alisonhall](https://github.com/alisonhall)! - Change aria-live assertive to polite
+
+## 3.0.3
+
+- Remove base entrypoint to fix rollup dependency resolution issue
+
+## 3.0.2
+
+- fix erroneous build
+
+## 3.0.1
+
+- [patch][](https://github.com/JedWatson/react-select/commit/):
+
+ - Add README.md file for npm
+
+## 3.0.0
+
+- [major][9ad152b](https://github.com/JedWatson/react-select/commit/9ad152b) [#3574](https://github.com/JedWatson/react-select/pulls/3574) Thanks [@gwyneplaine](https://github.com/gwyneplaine):
+ - Upgrade emotion dependency from 9.x to 10.x [#3321](https://github.com/JedWatson/react-select/pull/3321)
+ - Normalize Values [#3416](https://github.com/JedWatson/react-select/pull/3416)
+ - Separate entrypoints for Async, Creatable and makeAnimated [#3541](https://github.com/JedWatson/react-select/pull/3541)
+ - UMD builds deprecated
+ - required react peer-dependecy of 16.8
+
+## v2.4.4 / 2019-05-27
+
+### BugFixes
+
+- [#3540] Fixed active styles previously being applied to disabled options. Thanks [@risenforces](https://github.com/risenforces)
+- [#3563] Fixed IME composition bugs in non Chrome browsers. Thanks [@jwilander](https://github.com/jwilander)
+
+## v2.4.3 / 2019-03-17
+
+### Bugfixes
+
+- [#3492](https://github.com/JedWatson/react-select/pull/3492) Add labels to fields to make inspection. [@destructobeam](https://github.com/destructobeam)
+- [#3442](https://github.com/JedWatson/react-select/pull/3442) Ignore keydown events on `Enter` in IME. [@sat0yu](https://github.com/sat0yu).
+- [#3343](https://github.com/JedWatson/react-select/pull/3343) fix lint issues. [@JoshMcCullough](https://github.com/JoshMcCullough).
+- [#3498](https://github.com/JedWatson/react-select/pull/3498) Fix async type. [@mufasa71](https://github.com/mufasa71)
+- [#3436](https://github.com/JedWatson/react-select/pull/3436) Allow Node as placeholder [@eemeli](https://github.com/eemeli).
+
+## v2.4.2 / 2019-03-11
+
+### Bug fixes
+
+- [#3446](https://github.com/JedWatson/react-select/pull/3446) Fix bug with select input value not being selectable. Thanks [kangweichan](https://github.com/kangweichan).
+- [#3445](https://github.com/JedWatson/react-select/pull/3446) Fix accessibility bug. Disabled options are now focusable and announced by screen-readers but not selectable. Thanks [sarahbethfederman](https://github.com/sarahbethfederman).
+
+## Updates
+
+- Fixed typo in style docs. Thanks [thiagodebastos](https://github.com/thiagodebastos).
+- [#3460](https://github.com/JedWatson/react-select/pull/3460) Added description for actionTypes to docs. Thanks [mikekellyio](https://github.com/mikekellyio)
+
+## v2.4.1 / 2019-02-18
+
+### Bug fixes
+
+- [#3432](https://github.com/JedWatson/react-select/pull/3432) Fix bug with select menu's not working on mobile.
+
+## v2.4.0 / 2019-02-15
+
+### Bug fixes
+
+- [#3427](https://github.com/JedWatson/react-select/pull/3427) remove focusOption() invocation on ENTER press if the menu is not open.
+- [#3402](https://github.com/JedWatson/react-select/pull/3402) fix menu scroll being reset on focus of a select with an open menu in ie11. See [#3342](https://github.com/JedWatson/react-select/issues/3342) for details. Thanks [timothypage](https://github.com/timothypage)
+- [#3420](https://github.com/JedWatson/react-select/pull/3420) fixed select menu being opened on click, when openMenuOnClick is false. Thanks [caleb](https://github.com/caleb) and [rscotten](https://github.com/rscotten)
+- [#3419](https://github.com/JedWatson/react-select/pull/3419) fixed bug with ScrollCaptor operating on an undefined scrollTarget. Thanks [iulian-radu-at](https://github.com/iulian-radu-at)
+- [#3411](https://github.com/JedWatson/react-select/pull/3411) fix bug where Enter key press on select with a closed menu wouldn't propagate up. Resolves [#2217](https://github.com/JedWatson/react-select/issues/2217).
+- [#3407](https://github.com/JedWatson/react-select/pull/3407) remove unnecessary aria-roles from menu and options. This is now all handled by our aria-live implementation. Resolves [#3355](https://github.com/JedWatson/react-select/issues/3355). Thanks [sarahbethfederman](https://github.com/sarahbethfederman).
+- [#3393](https://github.com/JedWatson/react-select/pull/3393), fix aria live announcement text for removing a selected option. Thanks [msharkeyiii](https://github.com/msharkeyiii).
+- [#3350](https://github.com/JedWatson/react-select/pull/3350) Updated to 0.91 of flow. Updated types to pass stricter type checking, in later versions of flow. Thanks [DragonWW](https://github.com/DragorWW)
+
+### Updates
+
+- [#3370](https://github.com/JedWatson/react-select/pull/3370) Updated memoize-one dependency to 5.0.0. Thanks [adam187](https://github.com/adam187)
+- [#3366](https://github.com/JedWatson/react-select/pull/3366/files) Update build tooling, to leverage babel 7. Thanks [DragonWW](https://github.com/DragorWW)
+
+## v2.3.0 / 2019-01-18
+
+### Bug fixes
+
+- [#3315](https://github.com/JedWatson/react-select/pull/3315) add RAF call to Collapse component getRef() such that getBoundingClientRect() is invoked consistently.
+- [#3275](https://github.com/JedWatson/react-select/pull/3275/files) wrap String invocation around inputValue to avoid calling toLowerCase on invalid elements. thanks [tavareshenrique](https://github.com/tavareshenrique)
+- [#3357](https://github.com/JedWatson/react-select/pull/3357), fix loadOptions call in Async select to always pass in a string for the inputValue.
+- [#3346](https://github.com/JedWatson/react-select/pull/3346) Revert work done in CSP nonce PR [#3260](https://github.com/JedWatson/react-select/pull/3260) to unblock react-select usage in an SSR setting. Users who need nonce support still, please pin your version of react-select at 2.2.0. Nonce support will be re-added in 3.0.0 along with an upgrade to emotion 10; which includes nonce support without having to provide a custom emotion instance.
+
+### Features
+
+- [#3115](https://github.com/JedWatson/react-select/pull/3115) menu-is-open modifier added to control class when the menu is open. [@s20lee](https://github.com/s20lee)
+
+## v2.2.0 / 2018-12-28
+
+### Bug Fixes
+
+- [#3296](https://github.com/JedWatson/react-select/pull/3296) Fix for tab interactions when in composition mode with an IME. Thanks [yshr446](https://github.com/yshr446) for the PR.
+- [#3302](https://github.com/JedWatson/react-select/pull/3302) Fix to breaking android and mobile safari touch bug [#2755](https://github.com/JedWatson/react-select/issues/2755), by adding more conscientious checks to the onTouchStart and onTouchMove listeners. Thanks [xakep139](https://github.com/xakep139) for the PR.
+- [#3303](https://github.com/JedWatson/react-select/pull/3303) Input and GroupHeading components now get passed the selectProps prop, thanks [maxmarchuk](https://github.com/maxmarchuk) for the PR.
+- [#3260](https://github.com/JedWatson/react-select/pull/3260) As a result of the CSP nonce support feature, the emotion instance is now cached and passed down to all internal components, meaning that users looking to heavily customise their Select components can do so without externally importing emotion, and nonce instances are respected per select instance. Please see [this segment](https://react-select.com/styles#cx-and-custom-components) in the docs for a more detailed explanation.
+- [#3299](https://github.com/JedWatson/react-select/pull/3299) fix to assistive text on menu open.
+
+### Feature
+
+- [#3260](https://github.com/JedWatson/react-select/pull/3260) Add CSP nonce support to Select, thanks [Avaq](https://github.com/Avaq) and [Andarist](https://github.com/Andarist) for the heavy lifting.
+
+## v2.1.2 / 2018-11-22
+
+### Bug fixes
+
+- [#3161] Initialize state with `inputValue` when `defaultOptions` is true in AsyncSelect, resolves [#3160](https://github.com/JedWatson/react-select/issues/3160), thanks [@cutterbl](https://github.com/cutterbl)
+- [#3096] Placeholder component now also receives the isFocused state value as a prop. Thanks [@Nelrohd](https://github.com/Nelrohd)
+- [#3060] Fix bug where trying to set the cursor somewhere in an input value would close the menu. Thanks [@stijndeschuymer](https://github.com/stijndeschuymer)
+- [#3163] Fixed bug where isDisabled wasn't being reflected onto the DummyInput, which meant that disabled non searchable selects were still focusable. Thanks [@gm0t](https://github.com/gm0t)
+- [#3216] Fixes bug where clearing with backspace in a single select would result in an empty array, as opposed to the expected empty object. Thanks [@IanVS](https://github.com/IanVS)
+- [#3013] Fixes bug where the menu would close on trying to scroll using the scroll bar in IE11. Thanks [@rakid](https://github.com/rakid)
+
+### Misc
+
+- A big shoutout to everyone who helped contribute to the docs. In no particular order [@acrawford13](https://github.com/JedWatson/react-select/commits?author=acrawford13), [@kirillku](https://github.com/kirillku), [@ajaymathur](https://github.com/ajaymathur), [@mgalgs](https://github.com/mgalgs), [@cutterbl](https://github.com/cutterbl), [@JonathanWbn](https://github.com/JonathanWbn), [@mwood23](https://github.com/mwood23), [@stevemao](https://github.com/stevemao), [@jossmac](https://github.com/jossmac), and anyone else I've missed.
+- Thanks to [@IanVS](https://github.com/IanVS) for cleaning up our cypress tests.
+
+## v2.1.1 / 2018-10-24
+
+### Bug fixes
+
+- [#3132] Strip theme props from default Input and GroupHeading components, as they were polluting the DOM.
+- [#3131] Add support for the 'Delete' key in the internal onKeyDown method. Same functionality as 'Backspace'.
+- [#3100] Update flow-types and normalised default prop declarations in indicators. Thanks [iseredov](https://github.com/iseredov)
+
+### Updates
+
+- [#3083] Added sideEffects property to package.json to support tree-shaking in webpack 4.x. Thanks [SimenB](https://github.com/SimenB).
+- [#3078] Update jest dependency to 23.6.0. Thanks [papandreou](https://github.com/papandreou)
+- [#3065] Update babel-plugin-emotion to 9.2.10. Thanks [mtzhang](https://github.com/mtzhang)
+- [#3108] Update docs to include instructions for replicating the simple-value use case within react-select v2. Thanks [elboletaire](https://github.com/elboletaire)
+
+## v2.1.0 / 2018-10-03
+
+- [#2839] Added support for theming via theme prop. Thanks [akx](https://github.com/akx)
+- [#2874] Fixed flow-types of MultiValue components. Thanks [mike1808](https://github.com/mike1808)
+- [#2903] Fix missing form input when there isn't a selected value. Thanks [alvinsj](https://github.com/alvinsj)
+- [#2934] Reduced theme colors to a sane value set to make the exported theme more easy to consume and configure. Thanks [jossmac](https://github.com/jossmac)
+- [#2876] Added overflow hidden to valueContainer to stop overflowing text in the control. Thanks [mike1808](https://github.com/mike1808)
+- [#2975] Separated menu placement logic from menu primitive. Thanks [jossmac](https://github.com/jossmac).
+
+## v2.0.0 / 2018-07-23
+
+- async select now accepts a filterOptions function as a prop [#2822](https://github.com/JedWatson/react-select/pull/2822)
+- [BREAKING] react-select now exports react-select.esm.js from dist instead of react-select.es.js [#2641](https://github.com/JedWatson/react-select/pull/2641)
+- [BREAKING] innerRef assignments in custom components must now be made from the root of the prop object, as opposed to reaching into innerProps. This is part of the work to normalize the behaviour circa custom components. [#2824](https://github.com/JedWatson/react-select/pull/2824)
+- className and classNamePrefix deprecation warning and backward compatibility removed. className now only affects the select container, classNamePrefix prefixes all internal components. [#2820](https://github.com/JedWatson/react-select/pull/2820)
+- Added `closeMenuOnScroll` prop, which can either be a `boolean` or a `function`, if set to `true` the select menu will close on scroll of the document/body. If a function is supplied, it must take the following shape `(event: ScrollEvent) => boolean`, the boolean value will be used to resolve whether the menu should be closed or stay open. [#2809](https://github.com/JedWatson/react-select/pull/2809), thanks [Vynlar](https://github.com/Vynlar) for this.
+- Added fix to support IME inputs. [#2767](https://github.com/JedWatson/react-select/pull/2767), thanks [shamabe](https://github.com/shamabe)
+- Removed primitives, and normalise multi-value components to be in line with existing component customisation patterns. [#2821](https://github.com/JedWatson/react-select/pull/2821)
+- Normalised isOptionDisabled to be inline with its sibling prop isOptionSelected. [#2821](https://github.com/JedWatson/react-select/pull/2695) Thanks [SimeonC](https://github.com/SimeonC)
+- [#2814](https://github.com/JedWatson/react-select/pull/2814) Added memoization to custom components within Select.js as well as in the exported makeAnimated factory method. Thanks to [Alex Reardon's](https://github.com/alexreardon) [memoize-one](https://github.com/alexreardon/memoize-one)
+- [#2652](https://github.com/JedWatson/react-select/pull/2652), Async Select now re-evaluates defaultOptions on componentWillReceiveProps. Thanks [jesstelford](https://github.com/jesstelford)
+
+## v2.0.0-beta.7 / 2018-07-03
+
+- Removed old aria-attributes in Option, MenuList and other components in favor of an aria-live-region implementation. `screenReaderStatus` prop is still at the moment untouched, and `aria-labelledby` and `aria-label` props are still available and retain their functionality. See [#2581](https://github.com/JedWatson/react-select/pull/2581).
+- Internal ref `input` is now `inputRef` for consistency.
+- Internal ref `menuRef` is now `menuListRef` for consistency.
+- Fixed bug with MultiValueRemove interaction not working in mobile [#2762](https://github.com/JedWatson/react-select/pull/2762), thanks [chuckbergeron](https://github.com/chuckbergeron).
+- Added makeAnimated function export, that takes passed in components and wraps them in higher order components that expose animated functionality. [#2724](https://github.com/JedWatson/react-select/pull/2724)
+- Added functionality to not render the menu if `noOptionsMessage` or `loadingMessage` are set to null. [#2754](https://github.com/JedWatson/react-select/pull/2754)
+- Fixed bug with mobile menu being blocked when `menuShouldBlockScroll` is true.
+ [#2756](https://github.com/JedWatson/react-select/pull/2756)
+- Enabled hideSelectedOptions functionality for single-select as well. Changed logic so that if isMulti is true and hideSelectedOptions is not defined, we will hide selected options by default. Explicitly setting hideSelectedOptions will override this behaviour. https://github.com/JedWatson/react-select/pull/2753
+- Updates to flow types, thanks [mike1808](https://github.com/mike1808), [himerus](https://github.com/himerus),
+ [teamable-software](https://github.com/teamable-software) and
+- Bumped internal flow-bin dependency to 0.72.0, [#2646](https://github.com/JedWatson/react-select/pull/2646) thanks [lunij](https://github.com/lunij)
+- Fixed [#2701](https://github.com/JedWatson/react-select/issues/2701), use of un-polyfilled array.includes() in Select.js, this has now been subbed out for a IE compatible implementation.
+- [#2733](https://github.com/JedWatson/react-select/issues/2733), fixed classname bug to do with prefixing classes with modifiers.
+- [#2723](https://github.com/JedWatson/react-select/issues/2732), fixed emotion compilation bug blocking loadingDot rendering.
+- [#2749](https://github.com/JedWatson/react-select/pull/2749) fixed typo in docs. thanks [JuhQ](https://github.com/juhq)
+- [#2717](https://github.com/JedWatson/react-select/pull/2717) added selected value to onChange to accommodate multi-select, thanks [SimeonC](https://github.com/simeonc)
+
+## v2.0.0-beta.6 / 2018-05-23
+
+- Fixed bug with `css` attribute being wrongly applied to a DOM element in SingleValue. Thanks [guigs](http://github.com/guigs)
+- Added `removedValue` to the `actionMeta` of the `remove-value` action that's passed into the `onChange` prop.
+- Reverted previous change of `innerRef` in `innerProps` of custom Components to `ref`. The property is now once again named `innerRef`. This is mostly to resolve issues with styled-components not passing `ref` down to wrapped dom elements, however this is also a safer pattern to apply as it requires users providing their own custom components to explicitly associate the passed down ref with the requisite dom element.
+- selectValue now filters items based on the getOptionValue method. Thanks (inv8der)[http://github.com/inv8der]
+- Added `createOptionPosition` to creatable select to allow users to specify where the createOption element appears in the menu.
+- Added touch handling logic to detect user intent to scroll the page when interacting with the select control.
+
+## v2.0.0-beta.5 / 2018-05-18
+
+- Added `controlShouldRenderValue` prop, defaults to true. Setting it to false disables rendering values in the control. Thanks[Joss Mackison](http://github.com/jossmac)
+
+## v2.0.0-beta.4 / 2018-05-15
+
+- Fixed bug where transition props were being spread onto the DummyInput causing react warnings in the console. Thanks [Mike Gardner](https://github.com/MikeLimeRocket)
+
+## v2.0.0-beta.3 / 2018-05-14
+
+**Note**: There is an important change in this release to the behaviour of `className`.
+
+Previously, `className` would control the class names applied to internal components
+as well as the containing element. Now, the `className` prop only controls the class
+name of the containing element, and the new prop `classNamePrefix` controls classes
+applies to internal components.
+
+Until 2.0.0 final is released, we have added backwards compatibility and a deprecation
+warning to cover this change.
+
+- Added `classNamePrefix` prop, which now controls the class names applied to internal components
+- Refactored cx internal implementation to reduce specificity of css-in-jss base styles.
+- `maxValueHeight` prop removed
+- Added `--is-disabled` className modifier to Option component, thanks [eemeli](https://github.com/eemeli)
+- Fixed various IE11 issues, see [#2583](https://github.com/JedWatson/react-select/issues/2583)
+- Added multi-value keyboard navigation using left and right arrows.
+- Simplified flow distribution, thanks [falconmick](https://github.com/falconmick)
+- Added fix to ensure focus is on the Input when the menu opens
+
+## v2.0.0-beta.2 / 2018-04-25
+
+- Switched from glam to [emotion](https://emotion.sh) for css-in-js
+- Input colour can now be changed
+- Use of React 16 Fragment removed, 2.0.0 should work with React 15
+- SSR support improved
+- Indicator icons are now exported
+
+## v2.0.0-beta.1 / 2018-04-20
+
+- Added `tabIndex` prop
+- Added `classNames` prop
+- Added upgrade guide from v1 --> v2
+- Fixed bug with overflowing long values in the control
+- Fixed ie11 bug to do with absolutely positioned children in flex parent.
+- Documentation ie11, styling and copy improvements
+
+## v2.0.0-alpha.11 / 2018-04-12
+
+Minor fix since last alpha:
+
+- Fixed a flow type issue that was causing issues for consumers
+
+## v2.0.0-alpha.10 / 2018-04-10
+
+Minor fix since last alpha:
+
+- Fixed an issue with `dist/react-select.es.js` where `babelHelpers` weren't defined
+
+## v2.0.0-alpha.9 / 2018-04-10
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Added `openMenuOnClick` and `openMenuOnFocus` props
+- Significant test coverage and documentation improvements
+- Added `onMenuScrollToTop` and `onMenuScrollToBottom` event props
+- `scrollMenuIntoView` prop renamed `menuShouldScrollIntoView`
+- `onKeyDown` now based on event.key not event.keyCode
+- Component ids no longer have double separators
+- Fixed a Firefox bug with `position: absolute` and `display: flex`
+- Added support for fixed position menu and scroll blocking
+- Fixed issue with transition group props being passed to child components
+- Fixed issue with portalled menu display when `menuPlacement="top"`
+
+## v2.0.0-alpha.8 / 2018-02-20
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Made `focus` and `blur` methods work consistently when composing HOCs
+- Added `menuPortalTarget` prop which portals the menu, with a `MenuPortal` component and `menuPortal` style key
+- Allow the `MultiValueRemove` component children to be changed
+- Lots of new tests, updates to documentation and examples
+
+## v2.0.0-alpha.7 / 2018-02-14
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Significantly improved touch and mobile support
+- New positioning behaviour for the Menu
+- Added `scrollMenuIntoView` prop, which does exactly what you'd expect
+- Added action meta to the `onInputChange` event handler arguments
+- `Creatable` Component Added
+- `AsyncCreatable` Component Added
+- Fixed an issue with the layout that would trigger a Firefox repaint bug
+- Improved behaviour when the `isDisabled` prop value is changed
+- The `IndicatorSeparator` isn't rendered when there is no `DropdownIndicator`
+- Converted `StateManager` to a higher order component
+- New website, docs, and more tests! (still WIP)
+- Examples can now be launched in CodeSandbox, thanks to [Ben Conolly](https://github.com/noviny)
+
+## v2.0.0-alpha.6 / 2018-02-14
+
+Ongoing rewrite. Major changes since last alpha:
+
+- `menuIsOpen`, `inputValue` and `value` are now controllable props that default to internal state
+- Fixed missing loading indicator
+- Added "open in code sandbox" to all examples
+- Switched menu rendering from li to div tags for better screen reader usability
+- Removed unused primitives and simplified indicator components
+- Improved accessibility of groups and options, cleaned up Group implementation
+- Fixed some input alignment issues
+- Added right-to-left support with `isRtl` prop
+- Support blocking page scroll at menu boundaries with `captureMenuScroll` prop
+- Added automatic menu flipping at window boundaries with `menuPlacement` and `menuShouldFlip` props
+- Added `isSearchable` prop to support simple (not searchable) select inputs
+- Added `pageSize` prop
+
+## v2.0.0-alpha.5 / 2018-02-07
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Fixed an issue where animated values would show ellipsis while leaving
+- Long single values are now also correctly truncated
+
+## v2.0.0-alpha.4 / 2018-02-06
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Added support for Promises in the Async component
+- Added `setValue` method on the Select class
+- More consistent use of `innerProps` for internal components
+- Internal components are now provided a consistent set of props and API
+- Improved handling of keyboard and mouse interaction for options in the menu
+- Default filtering behaviour now has parity with v1
+- New `createFilter` method lets you customise the filter options
+- Some unnecessary components have been removed for better performance
+- Long values are now truncated
+
+## v2.0.0-alpha.3 / 2018-02-02
+
+Ongoing rewrite. Major changes since last alpha:
+
+- Added `getOptionValue`, `getOptionLabel` and `formatOptionLabel` props
+- Added `isOptionSelected` and `isOptionDisabled` props
+- Added `name` and `delimiter` props to support hidden html inputs for forms
+- Added `loadingMessage`, `noOptionsMessage` and `screenReaderStatus` props so messages can be customised
+- Customisable components are now passed `innerProps` for simpler implementation
+- Cleaned up internal Components and made sure they can all be styled
+- Implemented customisable filtering function with support for case and diacritics
+- Fixed various css bugs and vendor prefixing issues
+- Accessibility improvements
+
+## v2.0.0-alpha.2 / 2018-01-25
+
+Ongoing rewrite. Major changes since last alpha:
+
+- `Async` component added
+- `styles` prop added to Select component
+- `isLoading` prop to Select component and new indicator added
+- Support added for disabled options
+- Internal components cleaned up
+- Cypress tests added
+- CSS class names added to default components
+- Accessibility improvements
+
+## v2.0.0-alpha.1 / 2018-01-12
+
+Complete rewrite, docs and upgrade notes on changes from v1 to come later.
+
+## v1.2.1 / 2018-01-13
+
+- Fixed blocking the Del key when deleteRemoves is false, thanks [Nachtigall, Jens (init)](https://github.com/jnachtigall) - [see PR](https://github.com/JedWatson/react-select/pull/2291)
+- Fixed inline-block rendering for arrowRenderer without autosize, thanks [Harry Kao](https://github.com/harrykao) - [see PR](https://github.com/JedWatson/react-select/pull/2276)
+- Fixed dropdown menu positioning issues in IE 11, thanks [jharris4](https://github.com/jharris4) - [see PR](https://github.com/JedWatson/react-select/pull/2273)
+- Added missing rule to the `scss` stylesheet, thanks [Jordan Whitfield](https://github.com/mantissa7) - [see PR](https://github.com/JedWatson/react-select/pull/2280)
+ > > > > > > > master
+
+## v1.2.0 / 2018-01-08
+
+- Source cleanup, thanks to [Yuri S](https://github.com/yuri-sakharov) and
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2262)
+- Switched from babel-preset-es2015 to babel-preset-env, thanks
+ [Rambabu Yadlapalli](https://github.com/RamYadlapalli) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2254)
+- Fixed focused option. Issue #2237, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2245)
+- Fix onSelectResetsInput bug from keyboard navigation, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2259)
+- Fixed all warnings on running tests, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2231)
+- Added missing tests for Option.js and refactored Option-test.js., thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2249)
+- Added missing tests for Async.js, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2250)
+- Fixed console error in GitHub users example, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2244)
+- Fixed readme example. Issue #2235, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2246)
+- Regression fix for single select with onSelectResetsInput=false, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2226)
+- Pass placeholder prop to ValueComponent, thanks
+ [Aravind Srivatsan](https://github.com/aravindsrivats) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2225)
+- Refactored handleKeyDown switch, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2228)
+- onSelectResetsInput regression fixed, thanks
+ [Jed Watson](https://github.com/dehamilton) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2215)
+- Don't open drop down menu when clear values, thanks
+ [Jed Watson](https://github.com/Chopinsky) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2198)
+- Clear input value on receiving props with another value., thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2183)
+- Fix/is option unique crash, thanks [Jacob Zuo](https://github.com/Chopinsky) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2185)
+- Use react-input-autosize v2.1.2 for guard against undefined window, thanks
+ [DStyleZ](https://github.com/sximba) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2187)
+- Fix issue #2182, thanks [Kurt Hoyt](https://github.com/kurtinatlanta) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2213)
+- Documenting behavior of onBlurResetsInput in the readme., thanks
+ [hobbsl](https://github.com/levininja) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2212)
+- Use onSelectResetsInput for single select, thanks
+ [lachiet](https://github.com/lachiet) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2205)
+- Fix state value in README example, thanks
+ [Srishan Bhattarai](https://github.com/srishanbhattarai) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2192)
+- document breaking change of removing getInputValue, thanks
+ [Turadg Aleahmad](https://github.com/turadg) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2195)
+- Fixed search for invalid label and/or value, thanks
+ [Yuri S](https://github.com/yuri-sakharov) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2179)
+
+## v1.1.0 / 2017-11-28
+
+- added; more props are passed to the Option component: `focusOption`,
+ `inputValue`, `selectValue`, `removeValue`
+- added; the `inputValue` is passed as the third argument to the
+ `optionRenderer`
+- fixed; issues opening the menu correctly for multiselect when
+ `autosize={false}`
+- fixed; removed `event.stopPropagation()` from Select's `clearValue` and
+ `onClick` handlers, thanks [Thomas Burke](https://github.com/etburke)
+- fixed; `handleMouseDownOnArrow` when `openOnClick={false}`, thanks
+ [elias ghali](https://github.com/elghali)
+- fixed; conditional scrolling into view of focused option, thanks
+ [Michael Lewis](https://github.com/mtlewis)
+
+## v1.0.1 / 2017-11-24
+
+- reintroduced source files for scss and less stylesheets into the npm package
+
+## v1.0.0 / 2017-11-23
+
+- breaking; removed `getInputValue` function -
+ [see PR](https://github.com/JedWatson/react-select/pull/2108)
+- reverted spacebar-selects-option behaviour for searchable selects, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2163)
+- fixed behaviour where async doesn't handle onInputChange returning a value,
+ thanks [Anton](https://github.com/tehbi4) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2133)
+- fixed Creatable bug where the first enter keypress is ignored when
+ `promptTextCreator` returns only the label, thanks
+ [George Karagkiaouris](https://github.com/karaggeorge) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2140)
+- Utility functions are now exported from the es6 build, thanks
+ [Deiru](https://github.com/Deiru2k) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2154)
+- Update aria-only class to have absolute positioning, thanks
+ [Jacob Hilker](https://github.com/JHilker) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1243)
+- gives possibility to use ref property for Creatable, thanks
+ [blacktemplar](https://github.com/blacktemplar) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1646)
+- Adds lint and test pre-commit hooks, thanks
+ [carymcpoland](https://github.com/mcpolandc) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2077)
+- Disable some browser-specific behaviours that break the input, thanks
+ [Jed Watson](https://github.com/JedWatson) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2101)
+- onOpen: run after dom has rendered, thanks
+ [Karl-Aksel Puulmann](https://github.com/macobo) -
+ [see PR](https://github.com/JedWatson/react-select/pull/#1756)
+- fix not clearing when given invalid values, from #1756, thanks
+ [Mário][https://github.com/ticklemynausea] -
+ [see PR](https://github.com/JedWatson/react-select/pull/2100)
+- Exports Option Component, thanks
+ [Erkelens, Jan Paul](https://github.com/jperkelens) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2097)
+- Fix/numeric multi select, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2086)
+- removeSelected prop (round 2), for optionally keeping selected values in
+ dropdown, thanks [Jed Watson](https://github.com/banderson) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1891)
+- pass removeValue() and always pass valueArray, thanks
+ [kcliu](https://github.com/kcliu) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1850)
+- Accessibility Enhancements - Aria tags, Space/Enter keys, thanks
+ [sushmabadam](https://github.com/sushmabadam) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1428)
+- added rtl support, thanks [Dekel](https://github.com/dekelb) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1613)
+- Add inputValue to menuRenderer, thanks
+ [headcanon](https://github.com/chronick) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1732)
+- fix typo in handleKeyDown method, thanks
+ [jasonchangxo](https://github.com/jasonchangxo) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2088)
+- Fix/numeric multi select, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2086)
+- expose children in AsyncCreatable.js, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2084)
+- replace trim fn loop with regex, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2085)
+- Trim search text from beginning and the end. (fixes #1861), thanks
+ [Serkan Ozer](https://github.com/serkanozer) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1862)
+- Add variable for focused input background, thanks
+ [Aron Strandberg](https://github.com/aronstrandberg) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1998)
+- Added id in the input select, thanks
+ [thecreazy](https://github.com/thecreazy) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2027)
+- adding a nvmrc file and adding coverage to eslintignore, thanks
+ [Dave Birch](https://github.com/uxtx) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1137)
+- Updated the comment for the deleteRemoves option., thanks
+ [Abul Dider](https://github.com/dider7) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2078)
+- implemented optional rendering of arrow, thanks
+ [rolandjohann](https://github.com/rolandjohann) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1761)
+- Skip rendering arrow wrapper when custom arrow renderer returns falsy value,
+ thanks [Mike Lewis](https://github.com/mtlewis) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2055)
+- do not show clear button if value is an empty string, thanks
+ [Marie Godon](https://github.com/mariegodon) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2074)
+- Set isLoading to false if cache hit, thanks
+ [timhwang21](https://github.com/timhwang21) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2042)
+- Add aria-labels to Options, thanks
+ [jasonchangxo](https://github.com/jasonchangxo) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2036)
+- Adds source links to each example, thanks
+ [Damon Bauer](https://github.com/damonbauer) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2051)
+- Issue #2056: onInputChange should return modified value, thanks
+ [Caleb Scholze](https://github.com/cscholze) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2057)
+- Remove option `addLabelText` from README and propTypes, thanks
+ [Jannes Jeising](https://github.com/jjeising) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2040)
+- GitHub has a capital H, thanks
+ [David Baumgold](https://github.com/singingwolfboy) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2053)
+- refactor componentWillUnmount(), thanks
+ [riophae](https://github.com/riophae) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2064)
+- Slim down NPM package, thanks [Valentin Agachi](https://github.com/avaly) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2062)
+- Update contributing doc, thanks [Gregg Brewster](https://github.com/greggb) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2059)
+- strip proptypes in production build (fixes #1882), thanks
+ [Jochen Berger](https://github.com/jochenberger) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2003)
+- Support Webpack 2, Webpack 3, rollup., thanks
+ [Matthew Schnee](https://github.com/mschnee) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2020)
+- Add missing semicolon, thanks
+ [jochenberger](https://github.com/jochenberger) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2018)
+- autofocus --> autoFocus, thanks
+ [Charles Lee](https://github.com/gwyneplaine) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2002)
+- Async> cache async response regardless of req order, thanks
+ [Timothy Hwang](https://github.com/timhwang21) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2012)
+- Make this work in preact., thanks [liaoxuezhi](https://github.com/2betop) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2013)
+- Correct release candidate version on README, thanks
+ [Damon Aw](https://github.com/daemonsy) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2017)
+- Fix test name, thanks [jochenberger](https://github.com/jochenberger) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2005)
+- Fixing css states to be scoped with Select selector, closes #1951., thanks
+ [Adam Girton](https://github.com/agirton) -
+ [see PR](https://github.com/JedWatson/react-select/pull/2000)
+- fix typo, thanks [jochenberger](https://github.com/jochenberger) -
+ [see PR](https://github.com/JedWatson/react-select/pull/1999)
+
+## v1.0.0-rc.10 / 2017-09-13
+
+- changed; `openAfterFocus` prop has been renamed to `openOnClick`, and now
+ defaults to `true`
+- fixed; React.PropTypes deprecation warning, thanks
+ [Jeremy Liberman](https://github.com/MrLeebo)
+- improved; scrolling behaviour when navigating the menu with the keyboard,
+ thanks [boatkorachal](https://github.com/boatkorachal)
+- fixed; error with the `Async` cache when you type `"hasOwnProperty"`, thanks
+ [SuhushinAS](https://github.com/SuhushinAS)
+
+## v1.0.0-rc.9 / 2017-09-13
+
+- fixed; clearable padding style, thanks
+ [Minori Miyauchi](https://github.com/mmiyauchi)
+- fixed; removed use of `Object.assign`, fixes IE compatibility
+- added; new `closeOnSelect` prop (defaults to `true`) that controls whether the
+ menu is closed when an option is selected, thanks to
+ [Michael Elgar](https://github.com/melgar) for the original idea
+- changed; by default, the menu for multi-selects now closes when an option is
+ selected
+- changed; `Async` component no longer always clears options when one is
+ selected (although the menu is now closed by default). Use
+ `closeOnSelect={false} onSelectResetsInput={false}` to leave the menu open.
+- fixed; `Async` component always called `onChange` even when it wasn't provided
+- fixed; input lag for the `Async` component when results are returned from
+ cache
+- fixed; required was not being updated without an onChange handler
+- fixed; peer dependencies for `prop-types`, thanks
+ [Michaël De Boey](https://github.com/MichaelDeBoey)
+- fixed; internal optimisations, thanks
+ [Kieran Boyle](https://github.com/dysfunc)
+- added; `Value` component is now exported, thanks
+ [Prof Gra](https://github.com/Grahack)
+- fixed; callback fired after `Async` component unmounts, thanks
+ [Andrew Russell](https://github.com/DeadHeadRussell)
+- fixed; wrapping on Firefox in SCSS files, thanks
+ [Michael Williamson](https://github.com/mwilliamson)
+
+## v1.0.0-rc.8 / 2017-09-12
+
+- fixed; `onMenuScrollToBottom` does not work in chrome 58.0, thanks
+ [Simon Hartcher](https://github.com/deevus)
+- fixed; missing es6 module build for `js:next` entrypoint
+- updated; `react-input-autosize@2.0.0` including several fixes for react-select
+ (see
+ [changes](https://github.com/JedWatson/react-input-autosize/blob/master/HISTORY.md))
+
+## v1.0.0-rc.7 / 2017-09-11
+
+- fixed; issue with `lib` build preventing use in ES2015 environments
+
+## v1.0.0-rc.6 / 2017-09-10
+
+- fixed; changing `required` prop from `true` to `false` now works as expected,
+ thanks [George Karagkiaouris](https://github.com/karaggeorge)
+- added; new prop `onSelectResetsInput` controls whether the input value is
+ cleared when options are selected, thanks
+ [David Roeca](https://github.com/davidroeca) and
+ [Alexander Nosov](https://github.com/nosovsh)
+- fixed; tabindex parent bug fix for Edge, thanks
+ [George Payne](https://github.com/George-A-Payne)
+- fixed; update selectize link in README.md, thanks
+ [kerumen](https://github.com/kerumen)
+- added; standard issue template, thanks [agirton](https://github.com/agirton)
+- added; new build process using rollup and webpack. Removed grunt. thanks
+ [gwyneplaine](https://github.com/gwyneplaine)
+- fixed; updated contributor docs with the correct node version reference
+ [gwyneplaine](https://github.com/gwyneplaine)
+- fixed; missing method binds in Option, thanks
+ [agirton](https://github.com/agirton)
+- fixed; converted components to use es6 classes, thanks
+ [jochenberger](https://github.com/jochenberger)
+- fixed; console.log example in usage docs, thanks
+ [rohmanhm](https://github.com/rohmanhm)
+- fixed; hide create option after closing menu, thanks
+ [andreme](https://github.com/andreme)
+- fixed; remove circular reference, thanks [agirton](https://github.com/agirton)
+- fixed; readme typo, thanks [ieldanr](https:/github.com/ieldanr)
+- fixed; add missing function binds in Option component, thanks
+ [agirton](https://github.com/agirton) and
+ [blacktemplar](https://github.com/blacktemplar)
+- fixed; re-added fix to
+ [#1580](https://github.com/JedWatson/react-select/issues/1580), thanks
+ [agirton](https://github.com/agirton)
+- fixed; avoid mutating user inputs when ignoring case/accents, thanks
+ [not-an-aardvark](https://github.com/not-an-aardvark)
+- fixed; issues synchronising options props in `Async`, thanks
+ [cbergmiller](https://github.com/cbergmiller)
+- fixed; backspace handling for non-multi select controls, thanks
+ [Jeremy Liberman](https://github.com/MrLeebo)
+
+## v1.0.0-rc.5 / 2017-05-25
+
+- fixed; Allow `falsey` values to be clearable, thanks
+ [Simon Gaestel](https://github.com/sgaestel)
+- fixed; issue where Firefox would crash due to incorrect use of `aria-owns`
+ attribute, thanks [Max Hubenthal](https://github.com/mhubenthal)
+- fixed; regression where options not using the value key couldn't be focused,
+ thanks [Benjamin Piouffle](https://github.com/Betree)
+
+## v1.0.0-rc.4 / 2017-05-14
+
+- fixed; no more warning when using React 15.5, thanks
+ [Adam Girton](https://github.com/agirton)
+- fixed; issue comparing objects in `getFocusableOptionIndex`, thanks
+ [rndm2](https://github.com/rndm2)
+- fixed; missing .focus() method in `Creatable`, thanks
+ [Anton Alexandrenok](https://github.com/the-spyke)
+- added; support for `aria-describedby` attribute, thanks
+ [Eric Lee](https://github.com/ericj17)
+- added; `.is-clearable` className when clearable is true, thanks
+ [Dan Diaz](https://github.com/dan-diaz)
+
+## v1.0.0-rc.3 / 2017-02-01
+
+- added; `arrowRenderer` prop, thanks [Brian Vaughn](https://github.com/bvaughn)
+- added; child-function support to `Async` and `Creatable` components so that
+ they can compose each other (or future HOCs), thanks
+ [Brian Vaughn](https://github.com/bvaughn)
+- added; `asyncCreatable` HOC that combines `Async` and `Creatable` so they can
+ be used together, thanks [Brian Vaughn](https://github.com/bvaughn)
+- added; undocumented arguments for `menuRenderer`, thanks
+ [Julian Krispel-Samsel](https://github.com/juliankrispel)
+- fixed; Do not focus and open menu when disabled, thanks
+ [nhducit](https://github.com/nhducit)
+- fixed; Scrolling with arrow-keys is not working correctly, thanks
+ [Damian Pieczynski](https://github.com/piecyk)
+- added; "select all text" functionality `Shift+Home|Del`, thanks
+ [Damian Pieczynski](https://github.com/piecyk)
+- added; support for `boolean` values, thanks
+ [Aaron Hardy](https://github.com/Aaronius)
+- fixed; Remove duplicated `promptTextCreator` field from readme, thanks
+ [Jih-Chi Lee](https://github.com/jihchi)
+- fixed; Adding back ref that was removed in rc2, thanks
+ [Martin Jujou](https://github.com/jooj123)
+- fixed; `Creatable` component doesn't allow input key down handling, thanks
+ [Ivan Leonenko](https://github.com/IvanLeonenko)
+- added; Allow react nodes to be passed as loadingPlaceholder, thanks
+ [Daniel Heath](https://github.com/DanielHeath)
+- fixed; IE8 compatibility issues, thanks
+ [Kirill Mesnyankin](https://github.com/strayiker)
+- improved; Allow users to specify noResultsText, thanks
+ [Daniel Heath](https://github.com/DanielHeath)
+- added; Only remove options if a loading placeholder is available, thanks
+ [Daniel Heath](https://github.com/DanielHeath)
+- fixed; firefox display items in two rows due to reflow, thanks
+ [Daniel Heath](https://github.com/DanielHeath)
+- fixed; `Creatable` readme typo, thanks [Ben](https://github.com/rockingskier)
+- fixed; explain way to implement `allowCreate` functionality with `Creatable`
+ to readme, thanks [mayerwin](https://github.com/mayerwin)
+- added; delete key removes an item when there is no input, thanks
+ [forum-is](https://github.com/forum-is)
+- added; `onNewOptionClick` handler for `Creatable`, thanks
+ [Lee Siong Chan](https://github.com/leesiongchan)
+- fixed; `onInputChange` consistent for `Creatable`, thanks
+ [Lee Siong Chan](https://github.com/leesiongchan)
+- fixed; `menuRenderer` is treated consistently between `Creatable` and
+ `Select`, thanks [Brian Vaughn](https://github.com/bvaughn)
+- fixed; `asyncCreatable` options parsing will not parse undefined values into
+ props, thanks [Romain Dardour](https://github.com/unity)
+- added; pass `inputProps` to `inputRenderer`, thanks
+ [Alec Winograd](https://github.com/awinograd)
+- fixed; no exception when clearing an Async field that is not set to multi,
+ thanks [Patrik Stutz](https://github.com/VanCoding)
+- added; allow rendering a custom clear component, thanks
+ [Conor Hastings](https://github.com/conorhastings)
+- fixed; document `ignoreAccents`, thanks
+ [Domenico Matteo](https://github.com/dmatteo)
+- fixed; arrowing up or down in `Select` with 0 options does not throw type
+ error, thanks [Alex Howard](https://github.com/thezanke)
+- fixed; `Creatable` handles null children prop, thanks
+ [Jack Coulter](https://github.com/jscinoz)
+- added; provide `isOpen` to arrowRenderer, thanks
+ [Kuan](https://github.com/khankuan)
+- fixed; re-added the `focus()` method on `Select.Async`, thanks,
+ [Maarten Claes](https://github.com/mcls)
+- fixed; focus the next available option after a selection, not the top option,
+ thanks [Nicolas Raynaud](https://github.com/nraynaud)
+
+Note there has also been a breaking change to the props for the `Async`
+component: both `minimumInput` and `searchingText` have been removed. See #1226
+for more details. Apologies for doing this in an RC release, but we had to trade
+off between resolving some important bugs and breaking the API, and figured it
+was better to do this before declaring 1.0.0 stable.
+
+## v1.0.0-rc.1 / 2016-09-04
+
+- fixed; reset value to `[]` when `multi=true`, thanks
+ [Michael Williamson](https://github.com/mwilliamson)
+- added; pass index to `renderLabel` method, thanks
+ [nhducit](https://github.com/nhducit)
+- fixed; uncontrolled to controlled component warning in React 15.3
+- fixed; props cleanup, thanks
+ [Forbes Lindesay](https://github.com/ForbesLindesay)
+- fixed; issue where a value of the number `0` would be assumed to be no value,
+ thanks [Hanwen Cheng](https://github.com/hanwencheng)
+- fixed; internal refs converted to callbacks instead of strings, thanks
+ [Johnny Nguyen](https://github.com/gojohnnygo)
+- added; optional `instanceId` prop for server-side rendering, thanks
+ [Jevin Anderson](https://github.com/JevinAnderson)
+- added; `onCloseResetsInput` prop, thanks
+ [Frankie](https://github.com/frankievx)
+- added; `Creatable` component, replaces pre-1.0 `allowCreate` prop, thanks
+ [Brian Vaughn](https://github.com/bvaughn)
+
+## v1.0.0-beta14 / 2016-07-17
+
+- fixed; `react-input-autosize` has been updated to `1.1.0`, which includes
+ fixes for the new warnings that React 15.2 logs
+- fixed; "Unknown prop `inputClassName` on tag" warning, thanks
+ [Max Stoiber](https://github.com/mxstbr)
+- fixed; Removed unnecessary `onUnfocus`, thanks
+ [Johnny Nguyen](https://github.com/gojohnnygo)
+- added; Support for react components in `searchPromptText`, thanks
+ [Matt](https://github.com/hellaeon)
+- fixed; focus bug on iOS, thanks
+ [Tony deCatanzaro](https://github.com/tonydecat)
+- fixed; Async bugs with Promises, thanks
+ [Vladimir](https://github.com/VladimirPal) and
+ [Ian Firkin](https://github.com/lobsteropteryx)
+- fixed; `searchingText` bug, thanks
+ [Tony deCatanzaro](https://github.com/tonydecat)
+- improved; More antive-like input behaviour, thanks
+ [Johnny Nguyen](https://github.com/gojohnnygo)
+- fixed; Added missing unit (px) to `minWidth` attribute, thanks
+ [Ian Witherow](https://github.com/ianwitherow)
+- added; Support for assistive technologies, thanks
+ [Dave Brotherstone](https://github.com/bruderstein)
+- fixed; React error if `onChange` callback causes a root component to unmount,
+ thanks [Nathan Norton](https://github.com/Xesued)
+- fixed; Open menu is now closed if `disabled` becomes true, thanks
+ [Jason Moon](https://github.com/jsnmoon)
+- fixed; Prevent `getFocusableOptionIndex` from returning a disabled option,
+ thanks [Brian Powers](https://github.com/brianspowers)
+- added; Home, End, Page Up/Down support, thanks
+ [Jason Kadrmas](https://github.com/blackjk3)
+- fixed; Don't render `backspaceToRemoveMessage` if `backspaceRemoves` is set to
+ false, thanks [Ryan Zec](https://github.com/ryanzec)
+- fixed; Issue with an outline appearing on the auto sized input, thanks
+ [Ryan Zec](https://github.com/ryanzec)
+- fixed; Events don't propagate when `esc` is pressed, thanks
+ [Yoshihide Jimbo](https://github.com/jmblog)
+- fixed; Update `required` prop based on nextProps on update, thanks
+ [Matt Shwery](https://github.com/mshwery)
+- fixed; On focus check whether input ref is a real input or an input component,
+ thanks [Peter Brant](https://github.com/pbrant) and
+ [Greg Poole](https://github.com/gpoole)
+
+Also a big thanks to [Brian Vaughn](https://github.com/bvaughn) for his help
+triaging issues for this release!
+
+## v1.0.0-beta13 / 2016-05-30
+
+- added; `inputRenderer` prop, allows you to override the input component,
+ thanks [Sean Burke](https://github.com/leftmostcat)
+- added; `openOnFocus` prop, causes the menu to always open when the select
+ control is focused, thanks
+ [HuysentruytRuben](https://github.com/HuysentruytRuben)
+- added; `react-virtualised-select` HOC example, thanks
+ [Brian Vaughn](https://github.com/bvaughn)
+- added; `tabSelectsValue` prop can be set to false to prevent selection of
+ focused option when tab is pressed, thanks
+ [Byron Anderson](https://github.com/byronanderson)
+- added; ability to override `resetValue` when clearing the control, thanks
+ [Alexander Luberg](https://github.com/LubergAlexander)
+- added; input can be updated with `onInputChange`, thanks
+ [Brett DeWoody](https://github.com/brettdewoody)
+- added; Styles for .is-selected class, thanks
+ [Danny Herran](https://github.com/dherran)
+- fixed; `noResultsText` prop type is now `stringOrNode` for Async component,
+ thanks [Michael Groeneman](https://github.com/mgroeneman)
+- fixed; `onInputChange` is wrapped by Async component, thanks
+ [Eric O'Connell](https://github.com/drd)
+- fixed; `scrollMenuIntoView` behaviour in IE10, thanks
+ [Ivan Jager](https://github.com/aij)
+- fixed; isEqualNode replaced with strict equality check, thanks
+ [Alexandre Balhier](https://github.com/abalhier)
+- fixed; issue with value object not being passed to `handleRequired`, thanks
+ [Andrew Hite](https://github.com/andyhite)
+- fixed; the menu-outer container is no longer rendered when it does not contain
+ anything, thanks [Kuan](https://github.com/khankuan)
+- improved; better support for IE8 in styles, thanks
+ [Rockallite Wulf](https://github.com/rockallite)
+
+## v1.0.0-beta12 / 2016-04-02
+
+- added; `menuRenderer` method and example for efficiently rendering thousands
+ of options, thanks [Brian Vaughn](https://github.com/bvaughn)
+- added; `optionClassName` prop, thanks [Max Tyler](https://github.com/iam4x)
+
+## v1.0.0-beta11 / 2016-03-09
+
+- updated dependencies to allow use with React 15.x
+- changed; multiple selected values are now submitted using multiple inputs,
+ thanks [Trinh Hoang Nhu](https://github.com/james4388)
+- added; `joinValues` prop to revert the above change and submit multiple values
+ in a single field with the delimiter
+
+## v1.0.0-beta10 / 2016-02-23
+
+- fixed build issues with v1.0.0-beta9
+
+## v1.0.0-beta9 / 2016-02-12
+
+- added; onBlurResetsInput prop, thanks
+ [Sly Bridges](https://github.com/slybridges)
+- changed; Enter selects and retains focus, Tab selects and shifts focus, thanks
+ [RDX](https://github.com/rdsubhas)
+- fixed; Hide noResultsText when value is falsy, thanks
+ [Fernando Alex Helwanger](https://github.com/fhelwanger)
+- added; `required` prop, adds HTML5 required attribute, thanks
+ [Domenico Matteo](https://github.com/dmatteo)
+- fixed; Touch drag behaviour, thanks
+ [Pavel Tarnopolsky](https://github.com/Paveltarno)
+- added; `onOpen` and `onClose` event props, thanks
+ [Jacob Page](https://github.com/DullReferenceException)
+- fixed; Pressing Enter on open Select should stop propagation, thanks
+ [Jeremy Liberman](https://github.com/MrLeebo)
+- fixed; Missing handleMouseDownOnMenu, thanks
+ [Jeremy Liberman](https://github.com/MrLeebo)
+- added; Ensures the selected option is immediately visible when the menu is
+ open, thanks [Martin Jujou](https://github.com/jooj123)
+- added; `autoBlur` prop, blurs the input when a value is selected, thanks
+ [Pavel Tarnopolsky](https://github.com/Paveltarno)
+- fixed; Several isFocused checks weren't working properly
+
+## v1.0.0-beta8 / 2015-12-20
+
+- fixed; input focus bug when toggling `disabled` prop, thanks
+ [Davide Curletti](https://github.com/dcurletti)
+- fixed; `focus()` is now exposed on the `Async` component, thanks
+ [AugustinLF](https://github.com/AugustinLF)
+
+## v1.0.0-beta7 / 2015-12-15
+
+- You can now use React elements for placeholders and the text props, thanks
+ [kromit](https://github.com/kromit) and
+ [Alyssa Biasi](https://github.com/alyssaBiasi)
+- Fixed a problem where the border doesn't show when the element is inside a
+ table, thanks [Rodrigo Boratto](https://github.com/rwrz)
+- New prop `scrollMenuIntoView` scrolls the viewport to display the menu, thanks
+ [Alexander Zaharakis](https://github.com/azaharakis)
+- New LESS / SCSS variable `select-option-bg` lets you control the menu option
+ background color, thanks [Evan Goldenberg](https://github.com/Naveg)
+- Fixed an error in the blur handler on IE when the menu is not visible, thanks
+ [Gaston Sanchez](https://github.com/gaastonsr)
+- Added support for a `clearableValue` option property in `multi` mode, thanks
+ [Sly Bridges](https://github.com/slybridges)
+
+## v1.0.0-beta6 / 2015-11-29
+
+- Test suite complete and passing, with a couple of minor fixes thanks to
+ @bruderstein
+
+## v1.0.0-beta5 / 2015-11-08
+
+- Fixes issues relating to serializing simple values into the hidden field
+
+## v1.0.0-beta4 / 2015-11-08
+
+- New default styles that match [Elemental UI](http://elemental-ui.com) and look
+ right at home in the new [KeystoneJS Admin UI](http://keystonejs.com)
+
+We're potentially going to ship some theme stylesheets in the future, shout out
+on GitHub if this interests you.
+
+## v1.0.0-beta3 / 2015-11-08
+
+- The selected value populated in the hidden field has been fixed (was `"[object Object]"` before)
+- Added new `autofocus` prop
+- Fixed duplicate key error for options and values with duplicate `value`
+ properties
+- SCSS variables now have `!default` so you can override them
+
+## v1.0.0-beta2 / 2015-11-06
+
+Changed since beta 1:
+
+- Async options cache works again
+- New style props for custom styling the component without modifying css
+ classes: `style` `wrapperStyle` `menuStyle` `menuContainerStyle`
+- The menu opens and closes correctly when `searchable={false}`, there is still
+ some work to do on this use-case
+
+## v1.0.0-beta1 / 2015-11-06
+
+This is a complete rewrite. Major changes include:
+
+- Everything is simpler (I'm nearly done and the source code is only 60% of the
+ size of the last version)
+- No more timeouts or weird handlers, the restructuring has let me make
+ everything more straight-forward
+- The options array is no longer preprocessed into state, just retrieved from
+ props
+- The values array is now initialised in the Options array during render, and
+ not stored in state, which along with the change to options makes the
+ component more reliable and fixes issues with props not updating correctly
+- The component no longer stores its own value in state (ever) - it needs to be
+ passed as a prop and handled with `onChange`.
+- Complex values are now enabled by default (so you're passed the option object,
+ not its value); you can enable the legacy mode with a prop
+- The Value and Option components have been cleaned up as well for consistency
+- The hidden `
` field is now optional and the component is better suited
+ to use in a rich React.js app than it was
+- You can disable options filtering to do the filtering externally with
+ `onInputChange`
+- Accents on characters can now be ignored
+- The `asyncOptions` prop has been replaced by a new wrapper component:
+ `Select.Async`
+
+Note that "Tag mode" (creating options on the fly) isn't reimplemented yet.
+
+A full guide to the breaking changes and new features will be written up soon.
+In the meantime please see the new examples.
+
+## v0.9.1 / 2015-11-01
+
+- added; new Contributors example w/ async options loading and custom value /
+ label keys
+- fixed; several issues with custom `valueKey` and `labelKey` props
+- fixed; autoload now loads options with no search input
+
+## v0.9.0 / 2015-10-29
+
+- added; SCSS stylesheets!
+- improved; Options rendering should be more performant
+- breaking change; Custom `Option` components now need to pass their `option`
+ prop to event handlers; see
+ [this commit](https://github.com/JedWatson/react-select/commit/89af12a80a972794222b193a767f44234bbe9817)
+ for an example of the required change.
+
+## v0.8.4 / 2015-10-27
+
+- fixed; LESS math operations now work with --strict-math=on, thanks
+ [Vincent Fretin](https://github.com/vincentfretin)
+
+## v0.8.3 / 2015-10-27
+
+- fixed; IE issue where clicking the scrollbar would close the menu, thanks
+ [Pete Nykänen](https://github.com/petetnt)
+
+## v0.8.2 / 2015-10-22
+
+- added; Promise support for `loadAsyncOptions`, thanks
+ [Domenico Matteo](https://github.com/dmatteo)
+
+## v0.8.1 / 2015-10-20
+
+- fixed; `loadAsyncOptions` raises TypeError in setup, see #439 for details,
+ thanks [Pancham Mehrunkar](https://github.com/pancham348)
+
+## v0.8.0 / 2015-10-19
+
+This release contains significant DOM structure and CSS improvements by
+@jossmac, including:
+
+- no more `position: absolute` for inner controls
+- `display: table` is used for layout, which works in IE8 and above, and
+ [all other modern browsers](http://caniuse.com/#feat=css-table)
+- less "magic numbers" used for layout, should fix various browser-specific
+ alignment issues
+- clear "x" control now animates in
+- clearer `.Select--multi` className replaces `.Select.is-multi`
+- new height & theme variables
+- "dropdown" indicator chevron is no longer displayed for multi-select controls
+
+There are no functional changes, but if you've forked the LESS / CSS to create
+your own theme you'll want to pay close attention to PR #527 when upgrading to
+this version.
+
+## v0.7.0 / 2015-10-10
+
+React Select is updated for React 0.14. If you're still using React 0.13, please
+continue to use `react-select@0.6.x`. There are no functional differences
+between v0.7.0 and v0.6.12.
+
+Additionally, our tests now require Node.js 4.x. If you are developing
+`react-select`, please make sure you are running the latest version of node.
+
+Thanks to @bruderstein, @dmatteo and @hull for their help getting these updates
+shipped!
+
+## v0.6.12 / 2015-10-02
+
+- added; `labelKey` and `valueKey` props, so you can now use different keys in
+ `option` objects for the label and value
+- fixed; additional `isMounted()` checks in timeouts
+- fixed; componentDidUpdate timeout is reset correctly, see #208 and #434,
+ thanks [Petr Gladkikh](https://github.com/PetrGlad)
+- fixed; mousedown event on scrollbar in menu no longer hides it, thanks
+ [Yishai Burt](https://github.com/burtyish)
+
+## v0.6.11 / 2015-09-28
+
+- added; `isLoading` prop, allows indication of async options loading in
+ situations where more control is required, thanks
+ [Jon Gautsch](https://github.com/jgautsch)
+
+## v0.6.10 / 2015-09-24
+
+- fixed; a build issue with the previous release that prevented the stylesheet
+ being generated / included
+- fixed; a LESS syntax issue, thanks [Bob Cardenas](https://github.com/bcardi)
+
+## v0.6.9 / 2015-09-19
+
+- added; `style` key for package.json, thanks
+ [Stephen Wan](https://github.com/stephen)
+- added; `onInputChange` handler that returns the current input value, thanks
+ [Tom Leslie](https://github.com/lomteslie)
+- fixed; simplifying handleKey function & preventDefault behaviour, thanks
+ [davidpene](https://github.com/davidpene)
+- fixed; Display spinner while auto-loading initial data, thanks
+ [Ben Jenkinson](https://github.com/BenJenkinson)
+- fixed; better support for touch events, thanks
+ [Montlouis-Calixte Stéphane](https://github.com/bulby97)
+- fixed; prevent value splitting on non-multi-value select, thanks
+ [Alan R. Soares](https://github.com/alanrsoares)
+
+## v0.6.8 / 2015-09-16
+
+- fixed; broader range of allowed prereleases for React 0.14, including rc1
+- fixed; preventing backspace from navigating back in the browser history,
+ thanks [davidpene](https://github.com/davidpene)
+
+## v0.6.7 / 2015-08-28
+
+- fixed; missing styles for `.Select-search-prompt` and `.Select-searching`
+ issues, thanks [Jaak Erisalu](https://github.com/jaakerisalu) and
+ [davidpene](https://github.com/davidpene)
+
+## v0.6.6 / 2015-08-26
+
+- fixed; issue in Chrome where clicking the scrollbar would close the menu,
+ thanks [Vladimir Matsola](https://github.com/vomchik)
+
+## v0.6.5 / 2015-08-24
+
+- fixed; completely ignores clicks on disabled items, unless the target of the
+ click is a link, thanks [Ben Stahl](https://github.com/bhstahl)
+
+## v0.6.4 / 2015-08-24
+
+This release includes a huge improvement to the examples / website thanks to
+@jossmac. Also:
+
+- added; support for React 0.14 beta3
+- fixed; disabled options after searching, thanks @bruderstein
+- added; support for "Searching..." text (w/ prop) while loading async results,
+ thanks @bruderstein and @johnomalley
+- added; `className`, `style` and `title` keys are now supported in option
+ properties, thanks @bruderstein
+
+## v0.6.3 / 2015-08-18
+
+Otherwise known as "the real 0.6.2" this includes the updated build for the last
+version; sorry about that!
+
+## v0.6.2 / 2015-08-13
+
+- changed; if the `searchable` prop is `false`, the menu is opened _or closed_
+ on click, more like a standard Select input. thanks
+ [MaaikeB](https://github.com/MaaikeB)
+
+## v0.6.1 / 2015-08-09
+
+- added; Support for options with numeric values, thanks
+ [Dave Brotherstone](https://github.com/bruderstein)
+- changed; Disabled options now appear in the search results , thanks
+ [Dave Brotherstone](https://github.com/bruderstein)
+- fixed; asyncOptions are reloaded on componentWillReceiveProps when the value
+ has changed, thanks [Francis Cote](https://github.com/drfeelgoud)
+- added; `cacheAsyncResults` prop (default `true`) now controls whether the
+ internal cache is used for `asyncOptions`
+
+## v0.6.0 / 2015-08-05
+
+- improved; option, value and single value have been split out into their own
+ components, and can be customised with props. see
+ [#328](https://github.com/JedWatson/react-select/pull/328) for more details.
+- improved; Near-complete test coverage thanks to the awesome work of
+ [Dave Brotherstone](https://github.com/bruderstein)
+- improved; Support all alpha/beta/rc's of React 0.14.0, thanks
+ [Sébastien Lorber](https://github.com/slorber)
+- fixed; Close multi-select menu when tabbing away, thanks
+ [Ben Alpert](https://github.com/spicyj)
+- fixed; Bug where Select shows the value instead of the label (reapplying fix)
+- fixed; `valueRenderer` now works when `multi={false}`, thanks
+ [Chris Portela](https://github.com/0xCMP)
+- added; New property `backspaceRemoves` (default `true`), allows the default
+ behaviour of removing values with backspace when `multi={true}`, thanks
+ [Leo Lehikoinen](https://github.com/lehikol2)
+
+## v0.5.6 / 2015-07-27
+
+- fixed; Allow entering of commas when allowCreate is on but multi is off,
+ thanks [Angelo DiNardi](https://github.com/adinardi)
+- fixed; Times (clear) character is now rendered from string unicode character
+ for consistent output, thanks [Nibbles](https://github.com/Siliconrob)
+- fixed; allowCreate bug, thanks [goodzsq](https://github.com/goodzsq)
+- fixed; changes to props.placeholder weren't being reflected correctly, thanks
+ [alesn](https://github.com/alesn)
+- fixed; error when escape is pressedn where `clearValue` was not passed the
+ event, thanks [Mikhail Kotelnikov](https://github.com/mkotelnikov)
+- added; More tests, thanks [Dave Brotherstone](https://github.com/bruderstein)
+
+## v0.5.5 / 2015-07-12
+
+- fixed; replaced usage of `component.getDOMNode()` with
+ `React.findDOMNode(component)` for compatibility with React 0.14
+
+## v0.5.4 / 2015-07-06
+
+- fixed; regression in 0.5.3 that broke componentWillMount, sorry everyone!
+- added; `addLabelText` prop for customising the "add {label}?" text when in
+ tags mode, thanks [Fenn](https://github.com/Fenntasy)
+
+## v0.5.3 / 2015-07-05
+
+- fixed; autoload issues, thanks [Maxime Tyler](https://github.com/iam4x)
+- fixed; style incompatibilities with Foundation framework, thanks
+ [Timothy Kempf](https://github.com/Fauntleroy)
+
+## v0.5.2 / 2015-06-28
+
+- fixed; bug where Select shows the value instead of the label, thanks
+ [Stephen Demjanenko](https://github.com/sdemjanenko)
+- added; 'is-selected' classname is added to the selected option, thanks
+ [Alexey Volodkin](https://github.com/miraks)
+- fixed; async options are now loaded with the initial value, thanks
+ [Pokai Chang](https://github.com/Neson)
+- fixed; `react-input-autosize` now correctly escapes ampersands (&), not
+ actually a fix in react-select but worth noting here because it would have
+ been causing a problem in `react-select` as well.
+
+## v0.5.1 / 2015-06-21
+
+- added; custom option and value rendering capability, thanks
+ [Brian Reavis](https://github.com/brianreavis)
+- fixed; collapsing issue when single-select or empty multi-select fields are
+ disabled
+- fixed; issue where an empty value would be left after clearing all values in a
+ multi-select field
+
+## v0.5.0 / 2015-06-20
+
+- fixed; `esc` key incorrectly created empty options, thanks
+ [rgrzelak](https://github.com/rgrzelak)
+- adeed; New feature to allow option creation ("tags mode"), enable with
+ `allowCreate` prop, thanks [Florent Vilmart](https://github.com/flovilmart)
+ and [Brian Reavis](https://github.com/brianreavis)
+- fixed; IE8 compatibility fallback for `addEventListener/removeEventListener`,
+ which don't exist in IE8, thanks
+ [Stefan Billiet](https://github.com/StefanBilliet)
+- fixed; Undefined values when using asyncOptions, thanks
+ [bannaN](https://github.com/bannaN)
+- fixed; Prevent add the last focused value when the drop down menu is closed /
+ Pushing enter without dropdown open adds a value, thanks
+ [Giuseppe](https://github.com/giuse88)
+- fixed; Callback context is undefined, thanks
+ [Giuseppe](https://github.com/giuse88)
+- fixed; Issue with event being swallowed on Enter `keydown`, thanks
+ [Kevin Burke](https://github.com/kembuco)
+- added; Support for case-insensitive filtering when `matchPos="start"`, thanks
+ [wesrage](https://github.com/wesrage)
+- added; Support for customisable background color, thanks
+ [John Morales](https://github.com/JohnMorales)
+- fixed; Updated ESLint and cleared up warnings, thanks
+ [Alexander Shemetovsky](https://github.com/AlexKVal)
+- fixed; Close dropdown when clicking on select, thanks
+ [Nik Butenko](https://github.com/nkbt)
+- added; Tests, and mocha test framework, thanks
+ [Craig Dallimore](https://github.com/craigdallimore)
+- fixed; You can now start the example server and watch for changes with `npm start`
+
+## v0.4.9 / 2015-05-11
+
+- fixed; focus was being grabbed by the select when `autoload` and
+ `asyncOptions` were set
+- added; `focus` method on the component
+- added; support for disabled options, thanks
+ [Pasha Palangpour](https://github.com/pashap)
+- improved; more closures, less binds, for better performance, thanks
+ [Daniel Cousens](https://github.com/dcousens)
+
+## v0.4.8 / 2015-05-02
+
+- fixed; restored `dist/default.css`
+- fixed; standalone example works again
+- fixed; clarified dependency documentation and added dependencies for Bower
+- fixed; Scoping issues in `_bindCloseMenuIfClickedOutside`, thanks
+ [bannaN](https://github.com/bannaN)
+- fixed; Doesn't try to set focus afterupdate if component is disabled, thanks
+ [bannaN](https://github.com/bannaN)
+
+## v0.4.7 / 2015-04-21
+
+- improved; lodash is no longer a dependency, thanks
+ [Daniel Lo Nigro](https://github.com/Daniel15)
+
+## v0.4.6 / 2015-04-06
+
+- updated; dependencies, build process and input-autosize component
+
+## v0.4.5 / 2015-03-28
+
+- fixed; issue with long options overlapping arrow and clear icons, thanks
+ [Rohit Kalkur](https://github.com/rovolution)
+
+## v0.4.4 / 2015-03-26
+
+- fixed; error handling click events when the menu is closed, thanks
+ [Ilya Petrov](https://github.com/muromec)
+- fixed; issue where options will not be filtered in certain conditions, thanks
+ [G. Kay Lee](https://github.com/gsklee)
+
+## v0.4.3 / 2015-03-25
+
+- added tests and updated dependencies
+
+## v0.4.2 / 2015-03-23
+
+- added; ESLint and contributing guide
+- fixed; incorrect `classnames` variable assignment in window scope
+- fixed; all ESLint errors and warnings (except invalid JSX undefined/unused
+ vars due to ESLint bug)
+- fixed; first option is now focused correctly, thanks
+ [Eivind Siqveland Larsen](https://github.com/esiqveland)
+
+## v0.4.1 / 2015-03-20
+
+- fixed; IE11 issue: clicking on scrollbar within menu no longer closes menu,
+ thanks [Rohit Kalkur](https://github.com/rovolution)
+
+## v0.4.0 / 2015-03-12
+
+- updated; compatible with React 0.13
+
+## v0.3.5 / 2015-03-09
+
+- improved; less/no repaint on scroll for performance wins, thanks
+ [jsmunich](https://github.com/jsmunich)
+- added; `onBlur` and `onFocus` event handlers, thanks
+ [Jonas Budelmann](https://github.com/cloudkite)
+- added; support for `inputProps` prop, passed to the `
` component,
+ thanks [Yann Plantevin](https://github.com/YannPl)
+- changed; now using
+ [react-component-gulp-tasks](https://github.com/JedWatson/react-component-gulp-tasks)
+ for build
+- fixed; issue w/ remote callbacks overriding cached options, thanks
+ [Corey McMahon](https://github.com/coreymcmahon)
+- fixed; if not `this.props.multi`, menu doesn't need handleMouseDown, thanks
+ [wenbing](https://github.com/wenbing)
+
+## v0.3.4 / 2015-02-23
+
+- fixed; issues with the underscore/lodash dependency change, thanks
+ [Aaron Powell](https://github.com/aaronpowell)
+
+## v0.3.3 / 2015-02-22
+
+- added; `disabled` prop, thanks [Danny Shaw](https://github.com/dannyshaw)
+- added; `searchable` prop - set to `false` to disable the search box, thanks
+ [Julen Ruiz Aizpuru](https://github.com/julen)
+- added; `onOptionLabelClick` prop - see
+ [#66](https://github.com/JedWatson/react-select/pull/66) for docs, thanks
+ [Dmitry Smirnov](https://github.com/dmitry-smirnov)
+- fixed; `text-overflow: ellipsis;` typo, thanks
+ [Andru Vallance](https://github.com/andru)
+
+## v0.3.2 / 2015-01-30
+
+- fixed; issue adding undefined values to multiselect, thanks
+ [Tejas Dinkar](https://github.com/gja)
+
+## v0.3.1 / 2015-01-20
+
+- fixed; missing `var` statement
+
+## v0.3.0 / 2015-01-20
+
+- added; node compatible build now available in `/lib`
+
+## v0.2.14 / 2015-01-07
+
+- added; `searchPromptText` property that is displayed when `asyncOptions` is
+ set and there are (a) no options loaded, and (b) no input entered to search
+ on, thanks [Anton Fedchenko](https://github.com/kompot)
+- added; `clearable` property (defaults to `true`) to control whether the
+ "clear" control is available, thanks
+ [Anton Fedchenko](https://github.com/kompot)
+
+## v0.2.13 / 2015-01-05
+
+- fixed; height issues in Safari, thanks
+ [Joss Mackison](https://github.com/jossmac)
+- added; Option to specify "Clear value" label as prop for i18n
+
+## v0.2.12 / 2015-01-04
+
+- fixed; UI now responds to touch events, and works on mobile devices! thanks
+ [Fraser Xu](https://github.com/fraserxu)
+
+## v0.2.11 / 2015-01-04
+
+- fixed; Options in the dropdown now scroll into view when they are focused,
+ thanks [Adam](https://github.com/fmovlex)
+- improved; Example dist is now excluded from the npm package
+
+## v0.2.10 / 2015-01-01
+
+- fixed; More specific mixin name to avoid conflicts (css)
+- fixed; Example CSS now correctly rebuilds on changes in development
+- fixed; Values are now expanded correctly when options change (see #28)
+- added; Option to specify "No results found" label as prop for i18n, thanks
+ [Julen Ruiz Aizpuru](https://github.com/julen)
+
+## v0.2.9 / 2014-12-09
+
+- added; `filterOption` and `filterOptions` props for more control over
+ filtering
+
+## v0.2.8 / 2014-12-08
+
+- added; `matchPos` option to control whether to match the `start` or `any`
+ position in the string when filtering options (default: `any`)
+- added; `matchProp` option to control whether to match the `value`, `label` or
+ `any` property of each option when filtering (default: `any`)
+
+## v0.2.7 / 2014-12-01
+
+- fixed; screen-readers will now read "clear value" instead of "times" for the
+ clear button
+- fixed; non-left-click mousedown events aren't blocked by the control
+
+## v0.2.6 / 2014-11-30
+
+- improved; better comparison of changes to [options] in `willReceiveProps`
+- fixed; now focuses the first option correctly when in multiselect mode
+- fixed; fixed focused option behaviour on value change
+- fixed; when filtering, there is always a focused option (#19)
+- changed; using ^ in package.json to compare dependencies
+
+## v0.2.5 / 2014-11-20
+
+- fixed; compatibility with case-sensitive file systems
+
+## v0.2.4 / 2014-11-20
+
+- fixed; package.json pointed at the right file
+
+## v0.2.3 / 2014-11-17
+
+- fixed; Updating state correctly when props change
+- improved; Build tasks and docs
+- added; Working standalone build
+- added; Minified dist version
+- added; Published to Bower
+
+## v0.2.2 / 2014-11-15
+
+- fixed; backspace event being incorrectly cancelled
+
+## v0.2.1 / 2014-11-15
+
+- fixed; issue where backspace incorrectly clears the value (#14)
+
+## v0.2.0 / 2014-11-15
+
+- changed; Major rewrite to improve focus handling and internal state management
+- added; Support for `multi` prop, enable multiselect mode
+
+## v0.1.1 / 2014-11-03
+
+- added; Support for `onChange` event
+- added; `propTypes` are defined by the `Select` component now
+- added; `className` property, sets the `className` on the outer `div` element
+- fixed; Removed deprecated `React.DOM.x` calls
+
+## v0.1.0 / 2014-11-01
+
+- updated; React to 0.12.0
+
+## v0.0.6 / 2014-10-14
+
+- fixed; Error keeping value when using Async Options
diff --git a/packages/react-select/LICENSE b/packages/react-select/LICENSE
new file mode 100644
index 0000000000..841ac571fa
--- /dev/null
+++ b/packages/react-select/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2022 Jed Watson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/react-select/README.md b/packages/react-select/README.md
new file mode 100644
index 0000000000..8a01c67c06
--- /dev/null
+++ b/packages/react-select/README.md
@@ -0,0 +1,168 @@
+[](https://www.npmjs.com/package/react-select)
+[](https://circleci.com/gh/JedWatson/react-select/tree/master)
+[](https://coveralls.io/github/JedWatson/react-select?branch=master)
+[](http://thinkmill.com.au/?utm_source=github&utm_medium=badge&utm_campaign=react-select)
+
+# React-Select
+
+The Select control for [React](https://reactjs.com). Initially built for use in [KeystoneJS](http://www.keystonejs.com).
+
+See [react-select.com](https://www.react-select.com) for live demos and comprehensive docs.
+
+React Select is funded by [Thinkmill](https://www.thinkmill.com.au) and [Atlassian](https://atlaskit.atlassian.com). It represents a whole new approach to developing powerful React.js components that _just work_ out of the box, while being extremely customisable.
+
+For the story behind this component, watch Jed's talk at React Conf 2019 - [building React Select](https://youtu.be/yS0jUnmBujE)
+
+Features include:
+
+- Flexible approach to data, with customisable functions
+- Extensible styling API with [emotion](https://emotion.sh)
+- Component Injection API for complete control over the UI behaviour
+- Controllable state props and modular architecture
+- Long-requested features like option groups, portal support, animation, and more
+
+## Using an older version?
+
+- [v3, v4, and v5 upgrade guide](https://react-select.com/upgrade)
+- [v2 upgrade guide](https://react-select.com/upgrade-to-v2)
+- React Select v1 documentation and examples are available at [v1.react-select.com](https://v1.react-select.com)
+
+# Installation and usage
+
+The easiest way to use react-select is to install it from npm and build it into your app with Webpack.
+
+```
+yarn add react-select
+```
+
+Then use it in your app:
+
+#### With React Component
+
+```js
+import React from 'react';
+import Select from 'react-select';
+
+const options = [
+ { value: 'chocolate', label: 'Chocolate' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'vanilla', label: 'Vanilla' },
+];
+
+class App extends React.Component {
+ state = {
+ selectedOption: null,
+ };
+ handleChange = (selectedOption) => {
+ this.setState({ selectedOption }, () =>
+ console.log(`Option selected:`, this.state.selectedOption)
+ );
+ };
+ render() {
+ const { selectedOption } = this.state;
+
+ return (
+
+ );
+ }
+}
+```
+
+#### With React Hooks
+
+```js
+import React, { useState } from 'react';
+import Select from 'react-select';
+
+const options = [
+ { value: 'chocolate', label: 'Chocolate' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'vanilla', label: 'Vanilla' },
+];
+
+export default function App() {
+ const [selectedOption, setSelectedOption] = useState(null);
+
+ return (
+
+
+
+ );
+}
+```
+
+## Props
+
+Common props you may want to specify include:
+
+- `autoFocus` - focus the control when it mounts
+- `className` - apply a className to the control
+- `classNamePrefix` - apply classNames to inner elements with the given prefix
+- `isDisabled` - disable the control
+- `isMulti` - allow the user to select multiple values
+- `isSearchable` - allow the user to search for matching options
+- `name` - generate an HTML input with this name, containing the current value
+- `onChange` - subscribe to change events
+- `options` - specify the options the user can select from
+- `placeholder` - change the text displayed when no option is selected
+- `noOptionsMessage` - ({ inputValue: string }) => string | null - Text to display when there are no options
+- `value` - control the current value
+
+See the [props documentation](https://www.react-select.com/props) for complete documentation on the props react-select supports.
+
+## Controllable Props
+
+You can control the following props by providing values for them. If you don't, react-select will manage them for you.
+
+- `value` / `onChange` - specify the current value of the control
+- `menuIsOpen` / `onMenuOpen` / `onMenuClose` - control whether the menu is open
+- `inputValue` / `onInputChange` - control the value of the search input (changing this will update the available options)
+
+If you don't provide these props, you can set the initial value of the state they control:
+
+- `defaultValue` - set the initial value of the control
+- `defaultMenuIsOpen` - set the initial open value of the menu
+- `defaultInputValue` - set the initial value of the search input
+
+## Methods
+
+React-select exposes two public methods:
+
+- `focus()` - focus the control programmatically
+- `blur()` - blur the control programmatically
+
+## Customisation
+
+Check the docs for more information on:
+
+- [Customising the styles](https://www.react-select.com/styles)
+- [Using custom components](https://www.react-select.com/components)
+- [Using the built-in animated components](https://www.react-select.com/home#animated-components)
+- [Creating an async select](https://www.react-select.com/async)
+- [Allowing users to create new options](https://www.react-select.com/creatable)
+- [Advanced use-cases](https://www.react-select.com/advanced)
+- [TypeScript guide](https://www.react-select.com/typescript)
+
+## TypeScript
+
+The v5 release represents a rewrite from JavaScript to TypeScript. The types for v4 and earlier releases are available at [@types](https://www.npmjs.com/package/@types/react-select). See the [TypeScript guide](https://www.react-select.com/typescript) for how to use the types starting with v5.
+
+# Thanks
+
+Thank you to everyone who has contributed to this project. It's been a wild ride.
+
+If you like React Select, you should [follow me on twitter](https://twitter.com/jedwatson)!
+
+Shout out to [Joss Mackison](https://github.com/jossmac), [Charles Lee](https://github.com/gwyneplaine), [Ben Conolly](https://github.com/Noviny), [Tom Walker](https://github.com/bladey), [Nathan Bierema](https://github.com/Methuselah96), [Eric Bonow](https://github.com/ebonow), [Emma Hamilton](https://github.com/emmatown), [Dave Brotherstone](https://github.com/bruderstein), [Brian Vaughn](https://github.com/bvaughn), and the [Atlassian Design System](https://atlassian.design) team who along with many other contributors have made this possible ❤️
+
+## License
+
+MIT Licensed. Copyright (c) Jed Watson 2022.
diff --git a/packages/react-select/animated/package.json b/packages/react-select/animated/package.json
new file mode 100644
index 0000000000..480f66dd01
--- /dev/null
+++ b/packages/react-select/animated/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "dist/react-select-animated.cjs.js",
+ "module": "dist/react-select-animated.esm.js",
+ "types": "dist/react-select-animated.cjs.d.ts"
+}
diff --git a/packages/react-select/async-creatable/package.json b/packages/react-select/async-creatable/package.json
new file mode 100644
index 0000000000..0a3bddde09
--- /dev/null
+++ b/packages/react-select/async-creatable/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "dist/react-select-async-creatable.cjs.js",
+ "module": "dist/react-select-async-creatable.esm.js",
+ "types": "dist/react-select-async-creatable.cjs.d.ts"
+}
diff --git a/packages/react-select/async/package.json b/packages/react-select/async/package.json
new file mode 100644
index 0000000000..b58d5d1e27
--- /dev/null
+++ b/packages/react-select/async/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "dist/react-select-async.cjs.js",
+ "module": "dist/react-select-async.esm.js",
+ "types": "dist/react-select-async.cjs.d.ts"
+}
diff --git a/packages/react-select/base/package.json b/packages/react-select/base/package.json
new file mode 100644
index 0000000000..957568d890
--- /dev/null
+++ b/packages/react-select/base/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "dist/react-select-base.cjs.js",
+ "module": "dist/react-select-base.esm.js",
+ "types": "dist/react-select-base.cjs.d.ts"
+}
diff --git a/packages/react-select/creatable/package.json b/packages/react-select/creatable/package.json
new file mode 100644
index 0000000000..347a42cf5c
--- /dev/null
+++ b/packages/react-select/creatable/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "dist/react-select-creatable.cjs.js",
+ "module": "dist/react-select-creatable.esm.js",
+ "types": "dist/react-select-creatable.cjs.d.ts"
+}
diff --git a/packages/react-select/package.json b/packages/react-select/package.json
new file mode 100644
index 0000000000..901e9768c3
--- /dev/null
+++ b/packages/react-select/package.json
@@ -0,0 +1,96 @@
+{
+ "name": "react-select",
+ "version": "5.10.2",
+ "description": "A Select control built with and for ReactJS",
+ "main": "dist/react-select.cjs.js",
+ "module": "dist/react-select.esm.js",
+ "types": "dist/react-select.cjs.d.ts",
+ "sideEffects": false,
+ "author": "Jed Watson",
+ "license": "MIT",
+ "repository": "https://github.com/JedWatson/react-select/tree/master/packages/react-select",
+ "dependencies": {
+ "@babel/runtime": "^7.12.0",
+ "@emotion/cache": "^11.4.0",
+ "@emotion/react": "^11.8.1",
+ "@floating-ui/dom": "^1.0.1",
+ "@types/react-transition-group": "^4.4.0",
+ "memoize-one": "^6.0.0",
+ "prop-types": "^15.6.0",
+ "react-transition-group": "^4.3.0",
+ "use-isomorphic-layout-effect": "^1.2.0"
+ },
+ "devDependencies": {
+ "@types/jest-in-case": "^1.0.6",
+ "enzyme": "^3.8.0",
+ "enzyme-to-json": "^3.3.0",
+ "jest-in-case": "^1.0.2",
+ "react": "^16.13.0",
+ "react-dom": "^16.13.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "files": [
+ "dist",
+ "base",
+ "animated",
+ "async",
+ "creatable",
+ "async-creatable"
+ ],
+ "keywords": [
+ "combobox",
+ "form",
+ "input",
+ "multiselect",
+ "react",
+ "react-component",
+ "select",
+ "ui"
+ ],
+ "preconstruct": {
+ "entrypoints": [
+ "index.ts",
+ "base/index.ts",
+ "animated/index.ts",
+ "async/index.ts",
+ "creatable/index.ts",
+ "async-creatable/index.ts"
+ ]
+ },
+ "exports": {
+ ".": {
+ "module": "./dist/react-select.esm.js",
+ "import": "./dist/react-select.cjs.mjs",
+ "default": "./dist/react-select.cjs.js"
+ },
+ "./base": {
+ "module": "./base/dist/react-select-base.esm.js",
+ "import": "./base/dist/react-select-base.cjs.mjs",
+ "default": "./base/dist/react-select-base.cjs.js"
+ },
+ "./async": {
+ "module": "./async/dist/react-select-async.esm.js",
+ "import": "./async/dist/react-select-async.cjs.mjs",
+ "default": "./async/dist/react-select-async.cjs.js"
+ },
+ "./animated": {
+ "module": "./animated/dist/react-select-animated.esm.js",
+ "import": "./animated/dist/react-select-animated.cjs.mjs",
+ "default": "./animated/dist/react-select-animated.cjs.js"
+ },
+ "./creatable": {
+ "module": "./creatable/dist/react-select-creatable.esm.js",
+ "import": "./creatable/dist/react-select-creatable.cjs.mjs",
+ "default": "./creatable/dist/react-select-creatable.cjs.js"
+ },
+ "./async-creatable": {
+ "module": "./async-creatable/dist/react-select-async-creatable.esm.js",
+ "import": "./async-creatable/dist/react-select-async-creatable.cjs.mjs",
+ "default": "./async-creatable/dist/react-select-async-creatable.cjs.js"
+ },
+ "./package.json": "./package.json"
+ }
+}
diff --git a/packages/react-select/src/Async.tsx b/packages/react-select/src/Async.tsx
new file mode 100644
index 0000000000..35a1de7055
--- /dev/null
+++ b/packages/react-select/src/Async.tsx
@@ -0,0 +1,40 @@
+import * as React from 'react';
+import {
+ forwardRef,
+ MutableRefObject,
+ ReactElement,
+ RefAttributes,
+} from 'react';
+import Select from './Select';
+import { GroupBase } from './types';
+import useStateManager from './useStateManager';
+import useAsync from './useAsync';
+import type { AsyncProps } from './useAsync';
+export type { AsyncProps };
+
+type AsyncSelect = <
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase
= GroupBase
+>(
+ props: AsyncProps &
+ RefAttributes>
+) => ReactElement;
+
+const AsyncSelect = forwardRef(
+ >(
+ props: AsyncProps ,
+ ref:
+ | ((instance: Select | null) => void)
+ | MutableRefObject | null>
+ | null
+ ) => {
+ const stateManagedProps = useAsync(props);
+ const selectProps = useStateManager(stateManagedProps);
+
+ return ;
+ }
+) as AsyncSelect;
+
+export { useAsync };
+export default AsyncSelect;
diff --git a/packages/react-select/src/AsyncCreatable.tsx b/packages/react-select/src/AsyncCreatable.tsx
new file mode 100644
index 0000000000..e2b0d700cb
--- /dev/null
+++ b/packages/react-select/src/AsyncCreatable.tsx
@@ -0,0 +1,47 @@
+import * as React from 'react';
+import {
+ forwardRef,
+ MutableRefObject,
+ ReactElement,
+ RefAttributes,
+} from 'react';
+import Select from './Select';
+import { GroupBase } from './types';
+import useAsync, { AsyncAdditionalProps } from './useAsync';
+import useStateManager, { StateManagerProps } from './useStateManager';
+import useCreatable, { CreatableAdditionalProps } from './useCreatable';
+
+export type AsyncCreatableProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = StateManagerProps &
+ CreatableAdditionalProps &
+ AsyncAdditionalProps ;
+
+type AsyncCreatableSelect = <
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+>(
+ props: AsyncCreatableProps &
+ RefAttributes>
+) => ReactElement;
+
+const AsyncCreatableSelect = forwardRef(
+ >(
+ props: AsyncCreatableProps ,
+ ref:
+ | ((instance: Select | null) => void)
+ | MutableRefObject | null>
+ | null
+ ) => {
+ const stateManagerProps = useAsync(props);
+ const creatableProps = useStateManager(stateManagerProps);
+ const selectProps = useCreatable(creatableProps);
+
+ return ;
+ }
+) as AsyncCreatableSelect;
+
+export default AsyncCreatableSelect;
diff --git a/packages/react-select/src/Creatable.tsx b/packages/react-select/src/Creatable.tsx
new file mode 100644
index 0000000000..52d616a011
--- /dev/null
+++ b/packages/react-select/src/Creatable.tsx
@@ -0,0 +1,45 @@
+import * as React from 'react';
+import {
+ forwardRef,
+ MutableRefObject,
+ ReactElement,
+ RefAttributes,
+} from 'react';
+import Select from './Select';
+import { GroupBase } from './types';
+import useStateManager, { StateManagerProps } from './useStateManager';
+import useCreatable, { CreatableAdditionalProps } from './useCreatable';
+
+export type CreatableProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = StateManagerProps &
+ CreatableAdditionalProps ;
+
+type CreatableSelect = <
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+>(
+ props: CreatableProps &
+ RefAttributes>
+) => ReactElement;
+
+const CreatableSelect = forwardRef(
+ >(
+ props: CreatableProps ,
+ ref:
+ | ((instance: Select | null) => void)
+ | MutableRefObject | null>
+ | null
+ ) => {
+ const creatableProps = useStateManager(props);
+ const selectProps = useCreatable(creatableProps);
+
+ return ;
+ }
+) as CreatableSelect;
+
+export { useCreatable };
+export default CreatableSelect;
diff --git a/packages/react-select/src/NonceProvider.tsx b/packages/react-select/src/NonceProvider.tsx
new file mode 100644
index 0000000000..5e91a85e49
--- /dev/null
+++ b/packages/react-select/src/NonceProvider.tsx
@@ -0,0 +1,19 @@
+import * as React from 'react';
+import { useMemo } from 'react';
+import { ReactNode } from 'react';
+import { CacheProvider } from '@emotion/react';
+import createCache from '@emotion/cache';
+
+interface NonceProviderProps {
+ nonce: string;
+ children: ReactNode;
+ cacheKey: string;
+}
+
+export default ({ nonce, children, cacheKey }: NonceProviderProps) => {
+ const emotionCache = useMemo(
+ () => createCache({ key: cacheKey, nonce }),
+ [cacheKey, nonce]
+ );
+ return {children} ;
+};
diff --git a/packages/react-select/src/Select.tsx b/packages/react-select/src/Select.tsx
new file mode 100644
index 0000000000..146d084e20
--- /dev/null
+++ b/packages/react-select/src/Select.tsx
@@ -0,0 +1,2254 @@
+import * as React from 'react';
+import {
+ AriaAttributes,
+ Component,
+ FocusEventHandler,
+ FormEventHandler,
+ JSX,
+ KeyboardEventHandler,
+ MouseEventHandler,
+ ReactNode,
+ RefCallback,
+ TouchEventHandler,
+} from 'react';
+import { MenuPlacer } from './components/Menu';
+import LiveRegion from './components/LiveRegion';
+
+import { createFilter, FilterOptionOption } from './filters';
+import { DummyInput, ScrollManager, RequiredInput } from './internal/index';
+import { AriaLiveMessages, AriaSelection } from './accessibility/index';
+import { isAppleDevice } from './accessibility/helpers';
+
+import {
+ classNames,
+ cleanValue,
+ isTouchCapable,
+ isMobileDevice,
+ noop,
+ scrollIntoView,
+ isDocumentElement,
+ notNullish,
+ valueTernary,
+ multiValueAsValue,
+ singleValueAsValue,
+} from './utils';
+
+import {
+ formatGroupLabel as formatGroupLabelBuiltin,
+ getOptionLabel as getOptionLabelBuiltin,
+ getOptionValue as getOptionValueBuiltin,
+ isOptionDisabled as isOptionDisabledBuiltin,
+} from './builtins';
+
+import { defaultComponents, SelectComponentsConfig } from './components/index';
+
+import {
+ ClassNamesConfig,
+ defaultStyles,
+ StylesConfig,
+ StylesProps,
+} from './styles';
+import { defaultTheme, ThemeConfig } from './theme';
+
+import {
+ ActionMeta,
+ FocusDirection,
+ GetOptionLabel,
+ GetOptionValue,
+ GroupBase,
+ InputActionMeta,
+ MenuPlacement,
+ MenuPosition,
+ OnChangeValue,
+ Options,
+ OptionsOrGroups,
+ PropsValue,
+ SetValueAction,
+} from './types';
+
+export type FormatOptionLabelContext = 'menu' | 'value';
+export interface FormatOptionLabelMeta {
+ context: FormatOptionLabelContext;
+ inputValue: string;
+ selectValue: Options ;
+}
+
+export interface Props<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ /** HTML ID of an element containing an error message related to the input**/
+ 'aria-errormessage'?: AriaAttributes['aria-errormessage'];
+ /** Indicate if the value entered in the field is invalid **/
+ 'aria-invalid'?: AriaAttributes['aria-invalid'];
+ /** Aria label (for assistive tech) */
+ 'aria-label'?: AriaAttributes['aria-label'];
+ /** HTML ID of an element that should be used as the label (for assistive tech) */
+ 'aria-labelledby'?: AriaAttributes['aria-labelledby'];
+ /** Used to set the priority with which screen reader should treat updates to live regions. The possible settings are: off, polite (default) or assertive */
+ 'aria-live'?: AriaAttributes['aria-live'];
+ /** Customise the messages used by the aria-live component */
+ ariaLiveMessages?: AriaLiveMessages ;
+ /** Focus the control when it is mounted */
+ autoFocus?: boolean;
+ /** Remove the currently focused option when the user presses backspace when Select isClearable or isMulti */
+ backspaceRemovesValue: boolean;
+ /** Remove focus from the input when the user selects an option (handy for dismissing the keyboard on touch devices) */
+ blurInputOnSelect: boolean;
+ /** When the user reaches the top/bottom of the menu, prevent scroll on the scroll-parent */
+ captureMenuScroll: boolean;
+ /** Sets a className attribute on the outer component */
+ className?: string;
+ /**
+ * If provided, all inner components will be given a prefixed className attribute.
+ *
+ * This is useful when styling via CSS classes instead of the Styles API approach.
+ */
+ classNamePrefix?: string | null;
+ /**
+ * Provide classNames based on state for each inner component
+ */
+ classNames: ClassNamesConfig ;
+ /** Close the select menu when the user selects an option */
+ closeMenuOnSelect: boolean;
+ /**
+ * If `true`, close the select menu when the user scrolls the document/body.
+ *
+ * If a function, takes a standard javascript `ScrollEvent` you return a boolean:
+ *
+ * `true` => The menu closes
+ *
+ * `false` => The menu stays open
+ *
+ * This is useful when you have a scrollable modal and want to portal the menu out,
+ * but want to avoid graphical issues.
+ */
+ closeMenuOnScroll: boolean | ((event: Event) => boolean);
+ /**
+ * This complex object includes all the compositional components that are used
+ * in `react-select`. If you wish to overwrite a component, pass in an object
+ * with the appropriate namespace.
+ *
+ * If you only wish to restyle a component, we recommend using the `styles` prop
+ * instead. For a list of the components that can be passed in, and the shape
+ * that will be passed to them, see [the components docs](/components)
+ */
+ components: SelectComponentsConfig ;
+ /** Whether the value of the select, e.g. SingleValue, should be displayed in the control. */
+ controlShouldRenderValue: boolean;
+ /** Delimiter used to join multiple values into a single HTML Input value */
+ delimiter?: string;
+ /** Clear all values when the user presses escape AND the menu is closed */
+ escapeClearsValue: boolean;
+ /** Custom method to filter whether an option should be displayed in the menu */
+ filterOption:
+ | ((option: FilterOptionOption , inputValue: string) => boolean)
+ | null;
+ /**
+ * Formats group labels in the menu as React components
+ *
+ * An example can be found in the [Replacing builtins](/advanced#replacing-builtins) documentation.
+ */
+ formatGroupLabel: (group: Group) => ReactNode;
+ /** Formats option labels in the menu and control as React components */
+ formatOptionLabel?: (
+ data: Option,
+ formatOptionLabelMeta: FormatOptionLabelMeta
+ ) => ReactNode;
+ /**
+ * Resolves option data to a string to be displayed as the label by components
+ *
+ * Note: Failure to resolve to a string type can interfere with filtering and
+ * screen reader support.
+ */
+ getOptionLabel: GetOptionLabel ;
+ /** Resolves option data to a string to compare options and specify value attributes */
+ getOptionValue: GetOptionValue ;
+ /** Hide the selected option from the menu */
+ hideSelectedOptions?: boolean;
+ /** The id to set on the SelectContainer component. */
+ id?: string;
+ /** The value of the search input */
+ inputValue: string;
+ /** The id of the search input */
+ inputId?: string;
+ /** Define an id prefix for the select components e.g. {your-id}-value */
+ instanceId?: number | string;
+ /** Is the select value clearable */
+ isClearable?: boolean;
+ /** Is the select disabled */
+ isDisabled: boolean;
+ /** Is the select in a state of loading (async) */
+ isLoading: boolean;
+ /**
+ * Override the built-in logic to detect whether an option is disabled
+ *
+ * An example can be found in the [Replacing builtins](/advanced#replacing-builtins) documentation.
+ */
+ isOptionDisabled: (option: Option, selectValue: Options ) => boolean;
+ /** Override the built-in logic to detect whether an option is selected */
+ isOptionSelected?: (option: Option, selectValue: Options ) => boolean;
+ /** Support multiple selected options */
+ isMulti: IsMulti;
+ /** Is the select direction right-to-left */
+ isRtl: boolean;
+ /** Whether to enable search functionality */
+ isSearchable: boolean;
+ /** Async: Text to display when loading options */
+ loadingMessage: (obj: { inputValue: string }) => ReactNode;
+ /** Minimum height of the menu before flipping */
+ minMenuHeight: number;
+ /** Maximum height of the menu before scrolling */
+ maxMenuHeight: number;
+ /** Whether the menu is open */
+ menuIsOpen: boolean;
+ /**
+ * Default placement of the menu in relation to the control. 'auto' will flip
+ * when there isn't enough space below the control.
+ */
+ menuPlacement: MenuPlacement;
+ /** The CSS position value of the menu, when "fixed" extra layout management is required */
+ menuPosition: MenuPosition;
+ /**
+ * Whether the menu should use a portal, and where it should attach
+ *
+ * An example can be found in the [Portaling](/advanced#portaling) documentation
+ */
+ menuPortalTarget?: HTMLElement | null;
+ /** Whether to block scroll events when the menu is open */
+ menuShouldBlockScroll: boolean;
+ /** Whether the menu should be scrolled into view when it opens */
+ menuShouldScrollIntoView: boolean;
+ /** Name of the HTML Input (optional - without this, no input will be rendered) */
+ name?: string;
+ /** Text to display when there are no options */
+ noOptionsMessage: (obj: { inputValue: string }) => ReactNode;
+ /** Handle blur events on the control */
+ onBlur?: FocusEventHandler;
+ /** Handle change events on the select */
+ onChange: (
+ newValue: OnChangeValue,
+ actionMeta: ActionMeta
+ ) => void;
+ /** Handle focus events on the control */
+ onFocus?: FocusEventHandler;
+ /** Handle change events on the input */
+ onInputChange: (newValue: string, actionMeta: InputActionMeta) => void;
+ /** Handle key down events on the select */
+ onKeyDown?: KeyboardEventHandler;
+ /** Handle the menu opening */
+ onMenuOpen: () => void;
+ /** Handle the menu closing */
+ onMenuClose: () => void;
+ /** Fired when the user scrolls to the top of the menu */
+ onMenuScrollToTop?: (event: WheelEvent | TouchEvent) => void;
+ /** Fired when the user scrolls to the bottom of the menu */
+ onMenuScrollToBottom?: (event: WheelEvent | TouchEvent) => void;
+ /** Allows control of whether the menu is opened when the Select is focused */
+ openMenuOnFocus: boolean;
+ /** Allows control of whether the menu is opened when the Select is clicked */
+ openMenuOnClick: boolean;
+ /** Array of options that populate the select menu */
+ options: OptionsOrGroups;
+ /** Number of options to jump in menu when page{up|down} keys are used */
+ pageSize: number;
+ /** Placeholder for the select value */
+ placeholder: ReactNode;
+ /** Status to relay to screen readers */
+ screenReaderStatus: (obj: { count: number }) => string;
+ /**
+ * Style modifier methods
+ *
+ * A basic example can be found at the bottom of the [Replacing builtins](/advanced#replacing-builtins) documentation.
+ */
+ styles: StylesConfig ;
+ /** Theme modifier method */
+ theme?: ThemeConfig;
+ /** Sets the tabIndex attribute on the input */
+ tabIndex: number;
+ /** Select the currently focused option when the user presses tab */
+ tabSelectsValue: boolean;
+ /** Remove all non-essential styles */
+ unstyled: boolean;
+ /** The value of the select; reflected by the selected option */
+ value: PropsValue ;
+ /** Sets the form attribute on the input */
+ form?: string;
+ /** Marks the value-holding input as required for form validation */
+ required?: boolean;
+}
+
+export const defaultProps = {
+ 'aria-live': 'polite',
+ backspaceRemovesValue: true,
+ blurInputOnSelect: isTouchCapable(),
+ captureMenuScroll: !isTouchCapable(),
+ classNames: {},
+ closeMenuOnSelect: true,
+ closeMenuOnScroll: false,
+ components: {},
+ controlShouldRenderValue: true,
+ escapeClearsValue: false,
+ filterOption: createFilter(),
+ formatGroupLabel: formatGroupLabelBuiltin,
+ getOptionLabel: getOptionLabelBuiltin,
+ getOptionValue: getOptionValueBuiltin,
+ isDisabled: false,
+ isLoading: false,
+ isMulti: false,
+ isRtl: false,
+ isSearchable: true,
+ isOptionDisabled: isOptionDisabledBuiltin,
+ loadingMessage: () => 'Loading...',
+ maxMenuHeight: 300,
+ minMenuHeight: 140,
+ menuIsOpen: false,
+ menuPlacement: 'bottom',
+ menuPosition: 'absolute',
+ menuShouldBlockScroll: false,
+ menuShouldScrollIntoView: !isMobileDevice(),
+ noOptionsMessage: () => 'No options',
+ openMenuOnFocus: false,
+ openMenuOnClick: true,
+ options: [],
+ pageSize: 5,
+ placeholder: 'Select...',
+ screenReaderStatus: ({ count }: { count: number }) =>
+ `${count} result${count !== 1 ? 's' : ''} available`,
+ styles: {},
+ tabIndex: 0,
+ tabSelectsValue: true,
+ unstyled: false,
+};
+
+interface State<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ ariaSelection: AriaSelection | null;
+ inputIsHidden: boolean;
+ isFocused: boolean;
+ focusedOption: Option | null;
+ focusedOptionId: string | null;
+ focusableOptionsWithIds: FocusableOptionWithId [];
+ focusedValue: Option | null;
+ selectValue: Options ;
+ clearFocusValueOnUpdate: boolean;
+ prevWasFocused: boolean;
+ inputIsHiddenAfterUpdate: boolean | null | undefined;
+ prevProps: Props | void;
+ instancePrefix: string;
+ isAppleDevice: boolean;
+}
+
+interface CategorizedOption {
+ type: 'option';
+ data: Option;
+ isDisabled: boolean;
+ isSelected: boolean;
+ label: string;
+ value: string;
+ index: number;
+}
+
+interface FocusableOptionWithId {
+ data: Option;
+ id: string;
+}
+
+interface CategorizedGroup > {
+ type: 'group';
+ data: Group;
+ options: readonly CategorizedOption [];
+ index: number;
+}
+
+type CategorizedGroupOrOption > =
+ | CategorizedGroup
+ | CategorizedOption ;
+
+function toCategorizedOption<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ option: Option,
+ selectValue: Options ,
+ index: number
+): CategorizedOption {
+ const isDisabled = isOptionDisabled(props, option, selectValue);
+ const isSelected = isOptionSelected(props, option, selectValue);
+ const label = getOptionLabel(props, option);
+ const value = getOptionValue(props, option);
+
+ return {
+ type: 'option',
+ data: option,
+ isDisabled,
+ isSelected,
+ label,
+ value,
+ index,
+ };
+}
+
+function buildCategorizedOptions<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ selectValue: Options
+): CategorizedGroupOrOption [] {
+ return props.options
+ .map((groupOrOption, groupOrOptionIndex) => {
+ if ('options' in groupOrOption) {
+ const categorizedOptions = groupOrOption.options
+ .map((option, optionIndex) =>
+ toCategorizedOption(props, option, selectValue, optionIndex)
+ )
+ .filter((categorizedOption) => isFocusable(props, categorizedOption));
+ return categorizedOptions.length > 0
+ ? {
+ type: 'group' as const,
+ data: groupOrOption,
+ options: categorizedOptions,
+ index: groupOrOptionIndex,
+ }
+ : undefined;
+ }
+ const categorizedOption = toCategorizedOption(
+ props,
+ groupOrOption,
+ selectValue,
+ groupOrOptionIndex
+ );
+ return isFocusable(props, categorizedOption)
+ ? categorizedOption
+ : undefined;
+ })
+ .filter(notNullish);
+}
+
+function buildFocusableOptionsFromCategorizedOptions<
+ Option,
+ Group extends GroupBase
+>(categorizedOptions: readonly CategorizedGroupOrOption []) {
+ return categorizedOptions.reduce (
+ (optionsAccumulator, categorizedOption) => {
+ if (categorizedOption.type === 'group') {
+ optionsAccumulator.push(
+ ...categorizedOption.options.map((option) => option.data)
+ );
+ } else {
+ optionsAccumulator.push(categorizedOption.data);
+ }
+ return optionsAccumulator;
+ },
+ []
+ );
+}
+
+function buildFocusableOptionsWithIds >(
+ categorizedOptions: readonly CategorizedGroupOrOption [],
+ optionId: string
+) {
+ return categorizedOptions.reduce[]>(
+ (optionsAccumulator, categorizedOption) => {
+ if (categorizedOption.type === 'group') {
+ optionsAccumulator.push(
+ ...categorizedOption.options.map((option) => ({
+ data: option.data,
+ id: `${optionId}-${categorizedOption.index}-${option.index}`,
+ }))
+ );
+ } else {
+ optionsAccumulator.push({
+ data: categorizedOption.data,
+ id: `${optionId}-${categorizedOption.index}`,
+ });
+ }
+ return optionsAccumulator;
+ },
+ []
+ );
+}
+
+function buildFocusableOptions<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(props: Props , selectValue: Options ) {
+ return buildFocusableOptionsFromCategorizedOptions(
+ buildCategorizedOptions(props, selectValue)
+ );
+}
+
+function isFocusable<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ categorizedOption: CategorizedOption
+) {
+ const { inputValue = '' } = props;
+ const { data, isSelected, label, value } = categorizedOption;
+
+ return (
+ (!shouldHideSelectedOptions(props) || !isSelected) &&
+ filterOption(props, { label, value, data }, inputValue)
+ );
+}
+
+function getNextFocusedValue<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(state: State , nextSelectValue: Options ) {
+ const { focusedValue, selectValue: lastSelectValue } = state;
+ const lastFocusedIndex = lastSelectValue.indexOf(focusedValue!);
+ if (lastFocusedIndex > -1) {
+ const nextFocusedIndex = nextSelectValue.indexOf(focusedValue!);
+ if (nextFocusedIndex > -1) {
+ // the focused value is still in the selectValue, return it
+ return focusedValue;
+ } else if (lastFocusedIndex < nextSelectValue.length) {
+ // the focusedValue is not present in the next selectValue array by
+ // reference, so return the new value at the same index
+ return nextSelectValue[lastFocusedIndex];
+ }
+ }
+ return null;
+}
+
+function getNextFocusedOption<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(state: State , options: Options ) {
+ const { focusedOption: lastFocusedOption } = state;
+ return lastFocusedOption && options.indexOf(lastFocusedOption) > -1
+ ? lastFocusedOption
+ : options[0];
+}
+
+const getFocusedOptionId = (
+ focusableOptionsWithIds: FocusableOptionWithId [],
+ focusedOption: Option
+) => {
+ const focusedOptionId = focusableOptionsWithIds.find(
+ (option) => option.data === focusedOption
+ )?.id;
+ return focusedOptionId || null;
+};
+
+const getOptionLabel = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ data: Option
+): string => {
+ return props.getOptionLabel(data);
+};
+const getOptionValue = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ data: Option
+): string => {
+ return props.getOptionValue(data);
+};
+
+function isOptionDisabled<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ option: Option,
+ selectValue: Options
+): boolean {
+ return typeof props.isOptionDisabled === 'function'
+ ? props.isOptionDisabled(option, selectValue)
+ : false;
+}
+function isOptionSelected<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ option: Option,
+ selectValue: Options
+): boolean {
+ if (selectValue.indexOf(option) > -1) return true;
+ if (typeof props.isOptionSelected === 'function') {
+ return props.isOptionSelected(option, selectValue);
+ }
+ const candidate = getOptionValue(props, option);
+ return selectValue.some((i) => getOptionValue(props, i) === candidate);
+}
+function filterOption<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props ,
+ option: FilterOptionOption ,
+ inputValue: string
+) {
+ return props.filterOption ? props.filterOption(option, inputValue) : true;
+}
+
+const shouldHideSelectedOptions = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props
+) => {
+ const { hideSelectedOptions, isMulti } = props;
+ if (hideSelectedOptions === undefined) return isMulti;
+ return hideSelectedOptions;
+};
+
+let instanceId = 1;
+
+export default class Select<
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+> extends Component<
+ Props ,
+ State
+> {
+ static defaultProps = defaultProps;
+ state: State = {
+ ariaSelection: null,
+ focusedOption: null,
+ focusedOptionId: null,
+ focusableOptionsWithIds: [],
+ focusedValue: null,
+ inputIsHidden: false,
+ isFocused: false,
+ selectValue: [],
+ clearFocusValueOnUpdate: false,
+ prevWasFocused: false,
+ inputIsHiddenAfterUpdate: undefined,
+ prevProps: undefined,
+ instancePrefix: '',
+ isAppleDevice: false,
+ };
+
+ // Misc. Instance Properties
+ // ------------------------------
+
+ blockOptionHover = false;
+ isComposing = false;
+ commonProps: any; // TODO
+ initialTouchX = 0;
+ initialTouchY = 0;
+ openAfterFocus = false;
+ scrollToFocusedOptionOnUpdate = false;
+ userIsDragging?: boolean;
+
+ // Refs
+ // ------------------------------
+
+ controlRef: HTMLDivElement | null = null;
+ getControlRef: RefCallback = (ref) => {
+ this.controlRef = ref;
+ };
+ focusedOptionRef: HTMLDivElement | null = null;
+ getFocusedOptionRef: RefCallback = (ref) => {
+ this.focusedOptionRef = ref;
+ };
+ menuListRef: HTMLDivElement | null = null;
+ getMenuListRef: RefCallback = (ref) => {
+ this.menuListRef = ref;
+ };
+ inputRef: HTMLInputElement | null = null;
+ getInputRef: RefCallback = (ref) => {
+ this.inputRef = ref;
+ };
+
+ // Lifecycle
+ // ------------------------------
+
+ constructor(props: Props) {
+ super(props);
+ this.state.instancePrefix =
+ 'react-select-' + (this.props.instanceId || ++instanceId);
+ this.state.selectValue = cleanValue(props.value);
+ // Set focusedOption if menuIsOpen is set on init (e.g. defaultMenuIsOpen)
+ if (props.menuIsOpen && this.state.selectValue.length) {
+ const focusableOptionsWithIds: FocusableOptionWithId [] =
+ this.getFocusableOptionsWithIds();
+ const focusableOptions = this.buildFocusableOptions();
+ const optionIndex = focusableOptions.indexOf(this.state.selectValue[0]);
+ this.state.focusableOptionsWithIds = focusableOptionsWithIds;
+ this.state.focusedOption = focusableOptions[optionIndex];
+ this.state.focusedOptionId = getFocusedOptionId(
+ focusableOptionsWithIds,
+ focusableOptions[optionIndex]
+ );
+ }
+ }
+
+ static getDerivedStateFromProps(
+ props: Props>,
+ state: State>
+ ) {
+ const {
+ prevProps,
+ clearFocusValueOnUpdate,
+ inputIsHiddenAfterUpdate,
+ ariaSelection,
+ isFocused,
+ prevWasFocused,
+ instancePrefix,
+ } = state;
+ const { options, value, menuIsOpen, inputValue, isMulti } = props;
+ const selectValue = cleanValue(value);
+ let newMenuOptionsState = {};
+ if (
+ prevProps &&
+ (value !== prevProps.value ||
+ options !== prevProps.options ||
+ menuIsOpen !== prevProps.menuIsOpen ||
+ inputValue !== prevProps.inputValue)
+ ) {
+ const focusableOptions = menuIsOpen
+ ? buildFocusableOptions(props, selectValue)
+ : [];
+
+ const focusableOptionsWithIds = menuIsOpen
+ ? buildFocusableOptionsWithIds(
+ buildCategorizedOptions(props, selectValue),
+ `${instancePrefix}-option`
+ )
+ : [];
+
+ const focusedValue = clearFocusValueOnUpdate
+ ? getNextFocusedValue(state, selectValue)
+ : null;
+ const focusedOption = getNextFocusedOption(state, focusableOptions);
+ const focusedOptionId = getFocusedOptionId(
+ focusableOptionsWithIds,
+ focusedOption
+ );
+
+ newMenuOptionsState = {
+ selectValue,
+ focusedOption,
+ focusedOptionId,
+ focusableOptionsWithIds,
+ focusedValue,
+ clearFocusValueOnUpdate: false,
+ };
+ }
+ // some updates should toggle the state of the input visibility
+ const newInputIsHiddenState =
+ inputIsHiddenAfterUpdate != null && props !== prevProps
+ ? {
+ inputIsHidden: inputIsHiddenAfterUpdate,
+ inputIsHiddenAfterUpdate: undefined,
+ }
+ : {};
+
+ let newAriaSelection = ariaSelection;
+
+ let hasKeptFocus = isFocused && prevWasFocused;
+
+ if (isFocused && !hasKeptFocus) {
+ // If `value` or `defaultValue` props are not empty then announce them
+ // when the Select is initially focused
+ newAriaSelection = {
+ value: valueTernary(isMulti, selectValue, selectValue[0] || null),
+ options: selectValue,
+ action: 'initial-input-focus',
+ };
+
+ hasKeptFocus = !prevWasFocused;
+ }
+
+ // If the 'initial-input-focus' action has been set already
+ // then reset the ariaSelection to null
+ if (ariaSelection?.action === 'initial-input-focus') {
+ newAriaSelection = null;
+ }
+
+ return {
+ ...newMenuOptionsState,
+ ...newInputIsHiddenState,
+ prevProps: props,
+ ariaSelection: newAriaSelection,
+ prevWasFocused: hasKeptFocus,
+ };
+ }
+ componentDidMount() {
+ this.startListeningComposition();
+ this.startListeningToTouch();
+
+ if (this.props.closeMenuOnScroll && document && document.addEventListener) {
+ // Listen to all scroll events, and filter them out inside of 'onScroll'
+ document.addEventListener('scroll', this.onScroll, true);
+ }
+
+ if (this.props.autoFocus) {
+ this.focusInput();
+ }
+
+ // Scroll focusedOption into view if menuIsOpen is set on mount (e.g. defaultMenuIsOpen)
+ if (
+ this.props.menuIsOpen &&
+ this.state.focusedOption &&
+ this.menuListRef &&
+ this.focusedOptionRef
+ ) {
+ scrollIntoView(this.menuListRef, this.focusedOptionRef);
+ }
+ if (isAppleDevice()) {
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ isAppleDevice: true });
+ }
+ }
+ componentDidUpdate(prevProps: Props) {
+ const { isDisabled, menuIsOpen } = this.props;
+ const { isFocused } = this.state;
+
+ if (
+ // ensure focus is restored correctly when the control becomes enabled
+ (isFocused && !isDisabled && prevProps.isDisabled) ||
+ // ensure focus is on the Input when the menu opens
+ (isFocused && menuIsOpen && !prevProps.menuIsOpen)
+ ) {
+ this.focusInput();
+ }
+
+ if (isFocused && isDisabled && !prevProps.isDisabled) {
+ // ensure select state gets blurred in case Select is programmatically disabled while focused
+ // eslint-disable-next-line react/no-did-update-set-state
+ this.setState({ isFocused: false }, this.onMenuClose);
+ } else if (
+ !isFocused &&
+ !isDisabled &&
+ prevProps.isDisabled &&
+ this.inputRef === document.activeElement
+ ) {
+ // ensure select state gets focused in case Select is programatically re-enabled while focused (Firefox)
+ // eslint-disable-next-line react/no-did-update-set-state
+ this.setState({ isFocused: true });
+ }
+
+ // scroll the focused option into view if necessary
+ if (
+ this.menuListRef &&
+ this.focusedOptionRef &&
+ this.scrollToFocusedOptionOnUpdate
+ ) {
+ scrollIntoView(this.menuListRef, this.focusedOptionRef);
+ this.scrollToFocusedOptionOnUpdate = false;
+ }
+ }
+ componentWillUnmount() {
+ this.stopListeningComposition();
+ this.stopListeningToTouch();
+ document.removeEventListener('scroll', this.onScroll, true);
+ }
+
+ // ==============================
+ // Consumer Handlers
+ // ==============================
+
+ onMenuOpen() {
+ this.props.onMenuOpen();
+ }
+ onMenuClose() {
+ this.onInputChange('', {
+ action: 'menu-close',
+ prevInputValue: this.props.inputValue,
+ });
+
+ this.props.onMenuClose();
+ }
+ onInputChange(newValue: string, actionMeta: InputActionMeta) {
+ this.props.onInputChange(newValue, actionMeta);
+ }
+
+ // ==============================
+ // Methods
+ // ==============================
+
+ focusInput() {
+ if (!this.inputRef) return;
+ this.inputRef.focus();
+ }
+ blurInput() {
+ if (!this.inputRef) return;
+ this.inputRef.blur();
+ }
+
+ // aliased for consumers
+ focus = this.focusInput;
+ blur = this.blurInput;
+
+ openMenu(focusOption: 'first' | 'last') {
+ const { selectValue, isFocused } = this.state;
+ const focusableOptions = this.buildFocusableOptions();
+ let openAtIndex = focusOption === 'first' ? 0 : focusableOptions.length - 1;
+
+ if (!this.props.isMulti) {
+ const selectedIndex = focusableOptions.indexOf(selectValue[0]);
+ if (selectedIndex > -1) {
+ openAtIndex = selectedIndex;
+ }
+ }
+
+ // only scroll if the menu isn't already open
+ this.scrollToFocusedOptionOnUpdate = !(isFocused && this.menuListRef);
+
+ this.setState(
+ {
+ inputIsHiddenAfterUpdate: false,
+ focusedValue: null,
+ focusedOption: focusableOptions[openAtIndex],
+ focusedOptionId: this.getFocusedOptionId(focusableOptions[openAtIndex]),
+ },
+ () => this.onMenuOpen()
+ );
+ }
+
+ focusValue(direction: 'previous' | 'next') {
+ const { selectValue, focusedValue } = this.state;
+
+ // Only multiselects support value focusing
+ if (!this.props.isMulti) return;
+
+ this.setState({
+ focusedOption: null,
+ });
+
+ let focusedIndex = selectValue.indexOf(focusedValue!);
+ if (!focusedValue) {
+ focusedIndex = -1;
+ }
+
+ const lastIndex = selectValue.length - 1;
+ let nextFocus = -1;
+ if (!selectValue.length) return;
+
+ switch (direction) {
+ case 'previous':
+ if (focusedIndex === 0) {
+ // don't cycle from the start to the end
+ nextFocus = 0;
+ } else if (focusedIndex === -1) {
+ // if nothing is focused, focus the last value first
+ nextFocus = lastIndex;
+ } else {
+ nextFocus = focusedIndex - 1;
+ }
+ break;
+ case 'next':
+ if (focusedIndex > -1 && focusedIndex < lastIndex) {
+ nextFocus = focusedIndex + 1;
+ }
+ break;
+ }
+ this.setState({
+ inputIsHidden: nextFocus !== -1,
+ focusedValue: selectValue[nextFocus],
+ });
+ }
+
+ focusOption(direction: FocusDirection = 'first') {
+ const { pageSize } = this.props;
+ const { focusedOption } = this.state;
+ const options = this.getFocusableOptions();
+
+ if (!options.length) return;
+ let nextFocus = 0; // handles 'first'
+ let focusedIndex = options.indexOf(focusedOption!);
+ if (!focusedOption) {
+ focusedIndex = -1;
+ }
+
+ if (direction === 'up') {
+ nextFocus = focusedIndex > 0 ? focusedIndex - 1 : options.length - 1;
+ } else if (direction === 'down') {
+ nextFocus = (focusedIndex + 1) % options.length;
+ } else if (direction === 'pageup') {
+ nextFocus = focusedIndex - pageSize;
+ if (nextFocus < 0) nextFocus = 0;
+ } else if (direction === 'pagedown') {
+ nextFocus = focusedIndex + pageSize;
+ if (nextFocus > options.length - 1) nextFocus = options.length - 1;
+ } else if (direction === 'last') {
+ nextFocus = options.length - 1;
+ }
+ this.scrollToFocusedOptionOnUpdate = true;
+ this.setState({
+ focusedOption: options[nextFocus],
+ focusedValue: null,
+ focusedOptionId: this.getFocusedOptionId(options[nextFocus]),
+ });
+ }
+ onChange = (
+ newValue: OnChangeValue ,
+ actionMeta: ActionMeta
+ ) => {
+ const { onChange, name } = this.props;
+ actionMeta.name = name;
+
+ this.ariaOnChange(newValue, actionMeta);
+ onChange(newValue, actionMeta);
+ };
+ setValue = (
+ newValue: OnChangeValue ,
+ action: SetValueAction,
+ option?: Option
+ ) => {
+ const { closeMenuOnSelect, isMulti, inputValue } = this.props;
+ this.onInputChange('', { action: 'set-value', prevInputValue: inputValue });
+ if (closeMenuOnSelect) {
+ this.setState({
+ inputIsHiddenAfterUpdate: !isMulti,
+ });
+ this.onMenuClose();
+ }
+ // when the select value should change, we should reset focusedValue
+ this.setState({ clearFocusValueOnUpdate: true });
+ this.onChange(newValue, { action, option });
+ };
+ selectOption = (newValue: Option) => {
+ const { blurInputOnSelect, isMulti, name } = this.props;
+ const { selectValue } = this.state;
+ const deselected = isMulti && this.isOptionSelected(newValue, selectValue);
+ const isDisabled = this.isOptionDisabled(newValue, selectValue);
+
+ if (deselected) {
+ const candidate = this.getOptionValue(newValue);
+ this.setValue(
+ multiValueAsValue(
+ selectValue.filter((i) => this.getOptionValue(i) !== candidate)
+ ),
+ 'deselect-option',
+ newValue
+ );
+ } else if (!isDisabled) {
+ // Select option if option is not disabled
+ if (isMulti) {
+ this.setValue(
+ multiValueAsValue([...selectValue, newValue]),
+ 'select-option',
+ newValue
+ );
+ } else {
+ this.setValue(singleValueAsValue(newValue), 'select-option');
+ }
+ } else {
+ this.ariaOnChange(singleValueAsValue(newValue), {
+ action: 'select-option',
+ option: newValue,
+ name,
+ });
+ return;
+ }
+
+ if (blurInputOnSelect) {
+ this.blurInput();
+ }
+ };
+ removeValue = (removedValue: Option) => {
+ const { isMulti } = this.props;
+ const { selectValue } = this.state;
+ const candidate = this.getOptionValue(removedValue);
+ const newValueArray = selectValue.filter(
+ (i) => this.getOptionValue(i) !== candidate
+ );
+ const newValue = valueTernary(
+ isMulti,
+ newValueArray,
+ newValueArray[0] || null
+ );
+
+ this.onChange(newValue, { action: 'remove-value', removedValue });
+ this.focusInput();
+ };
+ clearValue = () => {
+ const { selectValue } = this.state;
+ this.onChange(valueTernary(this.props.isMulti, [], null), {
+ action: 'clear',
+ removedValues: selectValue,
+ });
+ };
+ popValue = () => {
+ const { isMulti } = this.props;
+ const { selectValue } = this.state;
+ const lastSelectedValue = selectValue[selectValue.length - 1];
+ const newValueArray = selectValue.slice(0, selectValue.length - 1);
+ const newValue = valueTernary(
+ isMulti,
+ newValueArray,
+ newValueArray[0] || null
+ );
+
+ if (lastSelectedValue) {
+ this.onChange(newValue, {
+ action: 'pop-value',
+ removedValue: lastSelectedValue,
+ });
+ }
+ };
+
+ // ==============================
+ // Getters
+ // ==============================
+
+ getTheme() {
+ // Use the default theme if there are no customisations.
+ if (!this.props.theme) {
+ return defaultTheme;
+ }
+ // If the theme prop is a function, assume the function
+ // knows how to merge the passed-in default theme with
+ // its own modifications.
+ if (typeof this.props.theme === 'function') {
+ return this.props.theme(defaultTheme);
+ }
+ // Otherwise, if a plain theme object was passed in,
+ // overlay it with the default theme.
+ return {
+ ...defaultTheme,
+ ...this.props.theme,
+ };
+ }
+
+ getFocusedOptionId = (focusedOption: Option) => {
+ return getFocusedOptionId(
+ this.state.focusableOptionsWithIds,
+ focusedOption
+ );
+ };
+
+ getFocusableOptionsWithIds = () => {
+ return buildFocusableOptionsWithIds(
+ buildCategorizedOptions(this.props, this.state.selectValue),
+ this.getElementId('option')
+ );
+ };
+
+ getValue = () => this.state.selectValue;
+
+ cx = (...args: any) => classNames(this.props.classNamePrefix, ...args);
+
+ getCommonProps() {
+ const {
+ clearValue,
+ cx,
+ getStyles,
+ getClassNames,
+ getValue,
+ selectOption,
+ setValue,
+ props,
+ } = this;
+ const { isMulti, isRtl, options } = props;
+ const hasValue = this.hasValue();
+
+ return {
+ clearValue,
+ cx,
+ getStyles,
+ getClassNames,
+ getValue,
+ hasValue,
+ isMulti,
+ isRtl,
+ options,
+ selectOption,
+ selectProps: props,
+ setValue,
+ theme: this.getTheme(),
+ };
+ }
+
+ getOptionLabel = (data: Option): string => {
+ return getOptionLabel(this.props, data);
+ };
+ getOptionValue = (data: Option): string => {
+ return getOptionValue(this.props, data);
+ };
+ getStyles = >(
+ key: Key,
+ props: StylesProps[Key]
+ ) => {
+ const { unstyled } = this.props;
+ const base = defaultStyles[key](props as any, unstyled);
+ base.boxSizing = 'border-box';
+ const custom = this.props.styles[key];
+ return custom ? custom(base, props as any) : base;
+ };
+ getClassNames = >(
+ key: Key,
+ props: StylesProps[Key]
+ ) => this.props.classNames[key]?.(props as any);
+ getElementId = (
+ element:
+ | 'group'
+ | 'input'
+ | 'listbox'
+ | 'option'
+ | 'placeholder'
+ | 'live-region'
+ ) => {
+ return `${this.state.instancePrefix}-${element}`;
+ };
+
+ getComponents = () => {
+ return defaultComponents(this.props);
+ };
+
+ buildCategorizedOptions = () =>
+ buildCategorizedOptions(this.props, this.state.selectValue);
+ getCategorizedOptions = () =>
+ this.props.menuIsOpen ? this.buildCategorizedOptions() : [];
+ buildFocusableOptions = () =>
+ buildFocusableOptionsFromCategorizedOptions(this.buildCategorizedOptions());
+ getFocusableOptions = () =>
+ this.props.menuIsOpen ? this.buildFocusableOptions() : [];
+
+ // ==============================
+ // Helpers
+ // ==============================
+
+ ariaOnChange = (
+ value: OnChangeValue ,
+ actionMeta: ActionMeta
+ ) => {
+ this.setState({ ariaSelection: { value, ...actionMeta } });
+ };
+
+ hasValue() {
+ const { selectValue } = this.state;
+ return selectValue.length > 0;
+ }
+ hasOptions() {
+ return !!this.getFocusableOptions().length;
+ }
+ isClearable(): boolean {
+ const { isClearable, isMulti } = this.props;
+
+ // single select, by default, IS NOT clearable
+ // multi select, by default, IS clearable
+ if (isClearable === undefined) return isMulti;
+
+ return isClearable;
+ }
+ isOptionDisabled(option: Option, selectValue: Options ): boolean {
+ return isOptionDisabled(this.props, option, selectValue);
+ }
+ isOptionSelected(option: Option, selectValue: Options ): boolean {
+ return isOptionSelected(this.props, option, selectValue);
+ }
+ filterOption(option: FilterOptionOption , inputValue: string) {
+ return filterOption(this.props, option, inputValue);
+ }
+ formatOptionLabel(
+ data: Option,
+ context: FormatOptionLabelContext
+ ): ReactNode {
+ if (typeof this.props.formatOptionLabel === 'function') {
+ const { inputValue } = this.props;
+ const { selectValue } = this.state;
+ return this.props.formatOptionLabel(data, {
+ context,
+ inputValue,
+ selectValue,
+ });
+ } else {
+ return this.getOptionLabel(data);
+ }
+ }
+ formatGroupLabel(data: Group) {
+ return this.props.formatGroupLabel(data);
+ }
+
+ // ==============================
+ // Mouse Handlers
+ // ==============================
+
+ onMenuMouseDown: MouseEventHandler = (event) => {
+ if (event.button !== 0) {
+ return;
+ }
+ event.stopPropagation();
+ event.preventDefault();
+ this.focusInput();
+ };
+ onMenuMouseMove: MouseEventHandler = (event) => {
+ this.blockOptionHover = false;
+ };
+ onControlMouseDown = (
+ event: React.MouseEvent | React.TouchEvent
+ ) => {
+ // Event captured by dropdown indicator
+ if (event.defaultPrevented) {
+ return;
+ }
+ const { openMenuOnClick } = this.props;
+ if (!this.state.isFocused) {
+ if (openMenuOnClick) {
+ this.openAfterFocus = true;
+ }
+ this.focusInput();
+ } else if (!this.props.menuIsOpen) {
+ if (openMenuOnClick) {
+ this.openMenu('first');
+ }
+ } else {
+ if (
+ (event.target as HTMLElement).tagName !== 'INPUT' &&
+ (event.target as HTMLElement).tagName !== 'TEXTAREA'
+ ) {
+ this.onMenuClose();
+ }
+ }
+ if (
+ (event.target as HTMLElement).tagName !== 'INPUT' &&
+ (event.target as HTMLElement).tagName !== 'TEXTAREA'
+ ) {
+ event.preventDefault();
+ }
+ };
+ onDropdownIndicatorMouseDown = (
+ event: React.MouseEvent | React.TouchEvent
+ ) => {
+ // ignore mouse events that weren't triggered by the primary button
+ if (
+ event &&
+ event.type === 'mousedown' &&
+ (event as React.MouseEvent).button !== 0
+ ) {
+ return;
+ }
+ if (this.props.isDisabled) return;
+ const { isMulti, menuIsOpen } = this.props;
+ this.focusInput();
+ if (menuIsOpen) {
+ this.setState({ inputIsHiddenAfterUpdate: !isMulti });
+ this.onMenuClose();
+ } else {
+ this.openMenu('first');
+ }
+ event.preventDefault();
+ };
+ onClearIndicatorMouseDown = (
+ event: React.MouseEvent | React.TouchEvent
+ ) => {
+ // ignore mouse events that weren't triggered by the primary button
+ if (
+ event &&
+ event.type === 'mousedown' &&
+ (event as React.MouseEvent).button !== 0
+ ) {
+ return;
+ }
+ this.clearValue();
+ event.preventDefault();
+ this.openAfterFocus = false;
+ if (event.type === 'touchend') {
+ this.focusInput();
+ } else {
+ setTimeout(() => this.focusInput());
+ }
+ };
+ onScroll = (event: Event) => {
+ if (typeof this.props.closeMenuOnScroll === 'boolean') {
+ if (
+ event.target instanceof HTMLElement &&
+ isDocumentElement(event.target)
+ ) {
+ this.props.onMenuClose();
+ }
+ } else if (typeof this.props.closeMenuOnScroll === 'function') {
+ if (this.props.closeMenuOnScroll(event)) {
+ this.props.onMenuClose();
+ }
+ }
+ };
+
+ // ==============================
+ // Composition Handlers
+ // ==============================
+
+ startListeningComposition() {
+ if (document && document.addEventListener) {
+ document.addEventListener(
+ 'compositionstart',
+ this.onCompositionStart,
+ false
+ );
+ document.addEventListener('compositionend', this.onCompositionEnd, false);
+ }
+ }
+ stopListeningComposition() {
+ if (document && document.removeEventListener) {
+ document.removeEventListener('compositionstart', this.onCompositionStart);
+ document.removeEventListener('compositionend', this.onCompositionEnd);
+ }
+ }
+ onCompositionStart = () => {
+ this.isComposing = true;
+ };
+ onCompositionEnd = () => {
+ this.isComposing = false;
+ };
+
+ // ==============================
+ // Touch Handlers
+ // ==============================
+
+ startListeningToTouch() {
+ if (document && document.addEventListener) {
+ document.addEventListener('touchstart', this.onTouchStart, false);
+ document.addEventListener('touchmove', this.onTouchMove, false);
+ document.addEventListener('touchend', this.onTouchEnd, false);
+ }
+ }
+ stopListeningToTouch() {
+ if (document && document.removeEventListener) {
+ document.removeEventListener('touchstart', this.onTouchStart);
+ document.removeEventListener('touchmove', this.onTouchMove);
+ document.removeEventListener('touchend', this.onTouchEnd);
+ }
+ }
+ onTouchStart = ({ touches }: TouchEvent) => {
+ const touch = touches && touches.item(0);
+ if (!touch) {
+ return;
+ }
+
+ this.initialTouchX = touch.clientX;
+ this.initialTouchY = touch.clientY;
+ this.userIsDragging = false;
+ };
+ onTouchMove = ({ touches }: TouchEvent) => {
+ const touch = touches && touches.item(0);
+ if (!touch) {
+ return;
+ }
+
+ const deltaX = Math.abs(touch.clientX - this.initialTouchX);
+ const deltaY = Math.abs(touch.clientY - this.initialTouchY);
+ const moveThreshold = 5;
+
+ this.userIsDragging = deltaX > moveThreshold || deltaY > moveThreshold;
+ };
+ onTouchEnd = (event: TouchEvent) => {
+ if (this.userIsDragging) return;
+
+ // close the menu if the user taps outside
+ // we're checking on event.target here instead of event.currentTarget, because we want to assert information
+ // on events on child elements, not the document (which we've attached this handler to).
+ if (
+ this.controlRef &&
+ !this.controlRef.contains(event.target as Node) &&
+ this.menuListRef &&
+ !this.menuListRef.contains(event.target as Node)
+ ) {
+ this.blurInput();
+ }
+
+ // reset move vars
+ this.initialTouchX = 0;
+ this.initialTouchY = 0;
+ };
+ onControlTouchEnd: TouchEventHandler = (event) => {
+ if (this.userIsDragging) return;
+ this.onControlMouseDown(event);
+ };
+ onClearIndicatorTouchEnd: TouchEventHandler = (event) => {
+ if (this.userIsDragging) return;
+
+ this.onClearIndicatorMouseDown(event);
+ };
+ onDropdownIndicatorTouchEnd: TouchEventHandler = (event) => {
+ if (this.userIsDragging) return;
+
+ this.onDropdownIndicatorMouseDown(event);
+ };
+
+ // ==============================
+ // Focus Handlers
+ // ==============================
+
+ handleInputChange: FormEventHandler = (event) => {
+ const { inputValue: prevInputValue } = this.props;
+ const inputValue = event.currentTarget.value;
+ this.setState({ inputIsHiddenAfterUpdate: false });
+ this.onInputChange(inputValue, { action: 'input-change', prevInputValue });
+ if (!this.props.menuIsOpen) {
+ this.onMenuOpen();
+ }
+ };
+ onInputFocus: FocusEventHandler = (event) => {
+ if (this.props.onFocus) {
+ this.props.onFocus(event);
+ }
+ this.setState({
+ inputIsHiddenAfterUpdate: false,
+ isFocused: true,
+ });
+ if (this.openAfterFocus || this.props.openMenuOnFocus) {
+ this.openMenu('first');
+ }
+ this.openAfterFocus = false;
+ };
+ onInputBlur: FocusEventHandler = (event) => {
+ const { inputValue: prevInputValue } = this.props;
+ if (this.menuListRef && this.menuListRef.contains(document.activeElement)) {
+ this.inputRef!.focus();
+ return;
+ }
+ if (this.props.onBlur) {
+ this.props.onBlur(event);
+ }
+ this.onInputChange('', { action: 'input-blur', prevInputValue });
+ this.onMenuClose();
+ this.setState({
+ focusedValue: null,
+ isFocused: false,
+ });
+ };
+ onOptionHover = (focusedOption: Option) => {
+ if (this.blockOptionHover || this.state.focusedOption === focusedOption) {
+ return;
+ }
+ const options = this.getFocusableOptions();
+ const focusedOptionIndex = options.indexOf(focusedOption!);
+ this.setState({
+ focusedOption,
+ focusedOptionId:
+ focusedOptionIndex > -1 ? this.getFocusedOptionId(focusedOption) : null,
+ });
+ };
+ shouldHideSelectedOptions = () => {
+ return shouldHideSelectedOptions(this.props);
+ };
+
+ // If the hidden input gets focus through form submit,
+ // redirect focus to focusable input.
+ onValueInputFocus: FocusEventHandler = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.focus();
+ };
+
+ // ==============================
+ // Keyboard Handlers
+ // ==============================
+
+ onKeyDown: KeyboardEventHandler = (event) => {
+ const {
+ isMulti,
+ backspaceRemovesValue,
+ escapeClearsValue,
+ inputValue,
+ isClearable,
+ isDisabled,
+ menuIsOpen,
+ onKeyDown,
+ tabSelectsValue,
+ openMenuOnFocus,
+ } = this.props;
+ const { focusedOption, focusedValue, selectValue } = this.state;
+
+ if (isDisabled) return;
+
+ if (typeof onKeyDown === 'function') {
+ onKeyDown(event);
+ if (event.defaultPrevented) {
+ return;
+ }
+ }
+
+ // Block option hover events when the user has just pressed a key
+ this.blockOptionHover = true;
+ switch (event.key) {
+ case 'ArrowLeft':
+ if (!isMulti || inputValue) return;
+ this.focusValue('previous');
+ break;
+ case 'ArrowRight':
+ if (!isMulti || inputValue) return;
+ this.focusValue('next');
+ break;
+ case 'Delete':
+ case 'Backspace':
+ if (inputValue) return;
+ if (focusedValue) {
+ this.removeValue(focusedValue);
+ } else {
+ if (!backspaceRemovesValue) return;
+ if (isMulti) {
+ this.popValue();
+ } else if (isClearable) {
+ this.clearValue();
+ }
+ }
+ break;
+ case 'Tab':
+ if (this.isComposing) return;
+
+ if (
+ event.shiftKey ||
+ !menuIsOpen ||
+ !tabSelectsValue ||
+ !focusedOption ||
+ // don't capture the event if the menu opens on focus and the focused
+ // option is already selected; it breaks the flow of navigation
+ (openMenuOnFocus && this.isOptionSelected(focusedOption, selectValue))
+ ) {
+ return;
+ }
+ this.selectOption(focusedOption);
+ break;
+ case 'Enter':
+ if (event.keyCode === 229) {
+ // ignore the keydown event from an Input Method Editor(IME)
+ // ref. https://www.w3.org/TR/uievents/#determine-keydown-keyup-keyCode
+ break;
+ }
+ if (menuIsOpen) {
+ if (!focusedOption) return;
+ if (this.isComposing) return;
+ this.selectOption(focusedOption);
+ break;
+ }
+ return;
+ case 'Escape':
+ if (menuIsOpen) {
+ this.setState({
+ inputIsHiddenAfterUpdate: false,
+ });
+ this.onInputChange('', {
+ action: 'menu-close',
+ prevInputValue: inputValue,
+ });
+ this.onMenuClose();
+ } else if (isClearable && escapeClearsValue) {
+ this.clearValue();
+ }
+ break;
+ case ' ': // space
+ if (inputValue) {
+ return;
+ }
+ if (!menuIsOpen) {
+ this.openMenu('first');
+ break;
+ }
+ if (!focusedOption) return;
+ this.selectOption(focusedOption);
+ break;
+ case 'ArrowUp':
+ if (menuIsOpen) {
+ this.focusOption('up');
+ } else {
+ this.openMenu('last');
+ }
+ break;
+ case 'ArrowDown':
+ if (menuIsOpen) {
+ this.focusOption('down');
+ } else {
+ this.openMenu('first');
+ }
+ break;
+ case 'PageUp':
+ if (!menuIsOpen) return;
+ this.focusOption('pageup');
+ break;
+ case 'PageDown':
+ if (!menuIsOpen) return;
+ this.focusOption('pagedown');
+ break;
+ case 'Home':
+ if (!menuIsOpen) return;
+ this.focusOption('first');
+ break;
+ case 'End':
+ if (!menuIsOpen) return;
+ this.focusOption('last');
+ break;
+ default:
+ return;
+ }
+ event.preventDefault();
+ };
+
+ // ==============================
+ // Renderers
+ // ==============================
+ renderInput() {
+ const {
+ isDisabled,
+ isSearchable,
+ inputId,
+ inputValue,
+ tabIndex,
+ form,
+ menuIsOpen,
+ required,
+ } = this.props;
+ const { Input } = this.getComponents();
+ const { inputIsHidden, ariaSelection } = this.state;
+ const { commonProps } = this;
+
+ const id = inputId || this.getElementId('input');
+
+ // aria attributes makes the JSX "noisy", separated for clarity
+ const ariaAttributes = {
+ 'aria-autocomplete': 'list' as const,
+ 'aria-expanded': menuIsOpen,
+ 'aria-haspopup': true,
+ 'aria-errormessage': this.props['aria-errormessage'],
+ 'aria-invalid': this.props['aria-invalid'],
+ 'aria-label': this.props['aria-label'],
+ 'aria-labelledby': this.props['aria-labelledby'],
+ 'aria-required': required,
+ role: 'combobox',
+ 'aria-activedescendant': this.state.isAppleDevice
+ ? undefined
+ : this.state.focusedOptionId || '',
+
+ ...(menuIsOpen && {
+ 'aria-controls': this.getElementId('listbox'),
+ }),
+ ...(!isSearchable && {
+ 'aria-readonly': true,
+ }),
+ ...(this.hasValue()
+ ? ariaSelection?.action === 'initial-input-focus' && {
+ 'aria-describedby': this.getElementId('live-region'),
+ }
+ : {
+ 'aria-describedby': this.getElementId('placeholder'),
+ }),
+ };
+
+ if (!isSearchable) {
+ // use a dummy input to maintain focus/blur functionality
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+ }
+ renderPlaceholderOrValue() {
+ const {
+ MultiValue,
+ MultiValueContainer,
+ MultiValueLabel,
+ MultiValueRemove,
+ SingleValue,
+ Placeholder,
+ } = this.getComponents();
+ const { commonProps } = this;
+ const {
+ controlShouldRenderValue,
+ isDisabled,
+ isMulti,
+ inputValue,
+ placeholder,
+ } = this.props;
+ const { selectValue, focusedValue, isFocused } = this.state;
+
+ if (!this.hasValue() || !controlShouldRenderValue) {
+ return inputValue ? null : (
+
+ {placeholder}
+
+ );
+ }
+
+ if (isMulti) {
+ return selectValue.map((opt, index) => {
+ const isOptionFocused = opt === focusedValue;
+ const key = `${this.getOptionLabel(opt)}-${this.getOptionValue(opt)}`;
+
+ return (
+ this.removeValue(opt),
+ onTouchEnd: () => this.removeValue(opt),
+ onMouseDown: (e) => {
+ e.preventDefault();
+ },
+ }}
+ data={opt}
+ >
+ {this.formatOptionLabel(opt, 'value')}
+
+ );
+ });
+ }
+
+ if (inputValue) {
+ return null;
+ }
+
+ const singleValue = selectValue[0];
+ return (
+
+ {this.formatOptionLabel(singleValue, 'value')}
+
+ );
+ }
+ renderClearIndicator() {
+ const { ClearIndicator } = this.getComponents();
+ const { commonProps } = this;
+ const { isDisabled, isLoading } = this.props;
+ const { isFocused } = this.state;
+
+ if (
+ !this.isClearable() ||
+ !ClearIndicator ||
+ isDisabled ||
+ !this.hasValue() ||
+ isLoading
+ ) {
+ return null;
+ }
+
+ const innerProps = {
+ onMouseDown: this.onClearIndicatorMouseDown,
+ onTouchEnd: this.onClearIndicatorTouchEnd,
+ 'aria-hidden': 'true',
+ };
+
+ return (
+
+ );
+ }
+ renderLoadingIndicator() {
+ const { LoadingIndicator } = this.getComponents();
+ const { commonProps } = this;
+ const { isDisabled, isLoading } = this.props;
+ const { isFocused } = this.state;
+
+ if (!LoadingIndicator || !isLoading) return null;
+
+ const innerProps = { 'aria-hidden': 'true' };
+ return (
+
+ );
+ }
+ renderIndicatorSeparator() {
+ const { DropdownIndicator, IndicatorSeparator } = this.getComponents();
+
+ // separator doesn't make sense without the dropdown indicator
+ if (!DropdownIndicator || !IndicatorSeparator) return null;
+
+ const { commonProps } = this;
+ const { isDisabled } = this.props;
+ const { isFocused } = this.state;
+
+ return (
+
+ );
+ }
+ renderDropdownIndicator() {
+ const { DropdownIndicator } = this.getComponents();
+ if (!DropdownIndicator) return null;
+ const { commonProps } = this;
+ const { isDisabled } = this.props;
+ const { isFocused } = this.state;
+
+ const innerProps = {
+ onMouseDown: this.onDropdownIndicatorMouseDown,
+ onTouchEnd: this.onDropdownIndicatorTouchEnd,
+ 'aria-hidden': 'true',
+ };
+
+ return (
+
+ );
+ }
+ renderMenu() {
+ const {
+ Group,
+ GroupHeading,
+ Menu,
+ MenuList,
+ MenuPortal,
+ LoadingMessage,
+ NoOptionsMessage,
+ Option,
+ } = this.getComponents();
+ const { commonProps } = this;
+ const { focusedOption } = this.state;
+ const {
+ captureMenuScroll,
+ inputValue,
+ isLoading,
+ loadingMessage,
+ minMenuHeight,
+ maxMenuHeight,
+ menuIsOpen,
+ menuPlacement,
+ menuPosition,
+ menuPortalTarget,
+ menuShouldBlockScroll,
+ menuShouldScrollIntoView,
+ noOptionsMessage,
+ onMenuScrollToTop,
+ onMenuScrollToBottom,
+ } = this.props;
+
+ if (!menuIsOpen) return null;
+
+ // TODO: Internal Option Type here
+ const render = (props: CategorizedOption, id: string) => {
+ const { type, data, isDisabled, isSelected, label, value } = props;
+ const isFocused = focusedOption === data;
+ const onHover = isDisabled ? undefined : () => this.onOptionHover(data);
+ const onSelect = isDisabled ? undefined : () => this.selectOption(data);
+ const optionId = `${this.getElementId('option')}-${id}`;
+ const innerProps = {
+ id: optionId,
+ onClick: onSelect,
+ onMouseMove: onHover,
+ onMouseOver: onHover,
+ tabIndex: -1,
+ role: 'option',
+ 'aria-selected': this.state.isAppleDevice ? undefined : isSelected, // is not supported on Apple devices
+ };
+
+ return (
+
+ {this.formatOptionLabel(props.data, 'menu')}
+
+ );
+ };
+
+ let menuUI: ReactNode;
+
+ if (this.hasOptions()) {
+ menuUI = this.getCategorizedOptions().map((item) => {
+ if (item.type === 'group') {
+ const { data, options, index: groupIndex } = item;
+ const groupId = `${this.getElementId('group')}-${groupIndex}`;
+ const headingId = `${groupId}-heading`;
+
+ return (
+
+ {item.options.map((option) =>
+ render(option, `${groupIndex}-${option.index}`)
+ )}
+
+ );
+ } else if (item.type === 'option') {
+ return render(item, `${item.index}`);
+ }
+ });
+ } else if (isLoading) {
+ const message = loadingMessage({ inputValue });
+ if (message === null) return null;
+ menuUI = {message} ;
+ } else {
+ const message = noOptionsMessage({ inputValue });
+ if (message === null) return null;
+ menuUI = {message} ;
+ }
+ const menuPlacementProps = {
+ minMenuHeight,
+ maxMenuHeight,
+ menuPlacement,
+ menuPosition,
+ menuShouldScrollIntoView,
+ };
+
+ const menuElement = (
+
+ {({ ref, placerProps: { placement, maxHeight } }) => (
+
+
+ {(scrollTargetRef) => (
+ {
+ this.getMenuListRef(instance);
+ scrollTargetRef(instance);
+ }}
+ innerProps={{
+ role: 'listbox',
+ 'aria-multiselectable': commonProps.isMulti,
+ id: this.getElementId('listbox'),
+ }}
+ isLoading={isLoading}
+ maxHeight={maxHeight}
+ focusedOption={focusedOption}
+ >
+ {menuUI}
+
+ )}
+
+
+ )}
+
+ );
+
+ // positioning behaviour is almost identical for portalled and fixed,
+ // so we use the same component. the actual portalling logic is forked
+ // within the component based on `menuPosition`
+ return menuPortalTarget || menuPosition === 'fixed' ? (
+
+ {menuElement}
+
+ ) : (
+ menuElement
+ );
+ }
+ renderFormField() {
+ const { delimiter, isDisabled, isMulti, name, required } = this.props;
+ const { selectValue } = this.state;
+
+ if (required && !this.hasValue() && !isDisabled) {
+ return ;
+ }
+
+ if (!name || isDisabled) return;
+
+ if (isMulti) {
+ if (delimiter) {
+ const value = selectValue
+ .map((opt) => this.getOptionValue(opt))
+ .join(delimiter);
+ return ;
+ } else {
+ const input =
+ selectValue.length > 0 ? (
+ selectValue.map((opt, i) => (
+
+ ))
+ ) : (
+
+ );
+
+ return {input}
;
+ }
+ } else {
+ const value = selectValue[0] ? this.getOptionValue(selectValue[0]) : '';
+ return ;
+ }
+ }
+
+ renderLiveRegion() {
+ const { commonProps } = this;
+ const {
+ ariaSelection,
+ focusedOption,
+ focusedValue,
+ isFocused,
+ selectValue,
+ } = this.state;
+
+ const focusableOptions = this.getFocusableOptions();
+
+ return (
+
+ );
+ }
+
+ render() {
+ const { Control, IndicatorsContainer, SelectContainer, ValueContainer } =
+ this.getComponents();
+
+ const { className, id, isDisabled, menuIsOpen } = this.props;
+ const { isFocused } = this.state;
+ const commonProps = (this.commonProps = this.getCommonProps());
+
+ return (
+
+ {this.renderLiveRegion()}
+
+
+ {this.renderPlaceholderOrValue()}
+ {this.renderInput()}
+
+
+ {this.renderClearIndicator()}
+ {this.renderLoadingIndicator()}
+ {this.renderIndicatorSeparator()}
+ {this.renderDropdownIndicator()}
+
+
+ {this.renderMenu()}
+ {this.renderFormField()}
+
+ );
+ }
+}
+
+export type PublicBaseSelectProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = JSX.LibraryManagedAttributes>;
diff --git a/packages/react-select/src/__tests__/Async.test.tsx b/packages/react-select/src/__tests__/Async.test.tsx
new file mode 100644
index 0000000000..ec35c8b676
--- /dev/null
+++ b/packages/react-select/src/__tests__/Async.test.tsx
@@ -0,0 +1,241 @@
+import React from 'react';
+import cases from 'jest-in-case';
+import { render, fireEvent, waitFor, act } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+import Async from '../Async';
+import { Option, OPTIONS } from './constants';
+
+test('defaults - snapshot', () => {
+ const { container } = render( );
+ expect(container).toMatchSnapshot();
+});
+
+/**
+ * loadOptions with promise is not resolved and it renders loading options
+ * confirmed by logging in component that loadOptions is resolved and options are available
+ * but still loading options is rendered
+ */
+cases(
+ 'load option prop with defaultOptions true',
+ async ({ props, expectOptionLength }) => {
+ const { container } = render(
+
+ );
+
+ await waitFor(() => {
+ expect(container.querySelectorAll('.react-select__option').length).toBe(
+ expectOptionLength
+ );
+ });
+ },
+ {
+ 'with callback > should resolve options': {
+ props: {
+ defaultOptions: true,
+ loadOptions: (
+ inputValue: string,
+ callBack: (options: readonly Option[]) => void
+ ) => callBack([OPTIONS[0]]),
+ },
+ expectOptionLength: 1,
+ },
+ 'with promise > should resolve options': {
+ props: {
+ defaultOptions: true,
+ loadOptions: () => Promise.resolve([OPTIONS[0]]),
+ },
+ expectOptionLength: 1,
+ },
+ }
+);
+
+test('load options prop with defaultOptions true and inputValue prop', () => {
+ const loadOptionsSpy = jest.fn((value) => value);
+ const searchString = 'hello world';
+ render(
+
+ );
+ expect(loadOptionsSpy).toHaveReturnedWith(searchString);
+});
+
+/**
+ * loadOptions with promise is not resolved and it renders loading options
+ * confirmed by logging in component that loadOptions is resolved and options are available
+ * but still loading options is rendered
+ */
+cases(
+ 'load options props with no default options',
+ async ({ props, expectloadOptionsLength }) => {
+ let { container } = render(
+
+ );
+ let input = container.querySelector('input.react-select__input');
+ userEvent.type(input!, 'a');
+ await waitFor(() => {
+ expect(container.querySelectorAll('.react-select__option').length).toBe(
+ expectloadOptionsLength
+ );
+ });
+ },
+ {
+ 'with callback > should resolve the options': {
+ props: {
+ loadOptions: (
+ inputValue: string,
+ callBack: (options: readonly Option[]) => void
+ ) => callBack(OPTIONS),
+ },
+ expectloadOptionsLength: 17,
+ },
+ 'with promise > should resolve the options': {
+ props: {
+ loadOptions: () => Promise.resolve(OPTIONS),
+ },
+ expectloadOptionsLength: 17,
+ },
+ }
+);
+
+test('to not call loadOptions again for same value when cacheOptions is true', () => {
+ let loadOptionsSpy = jest.fn((_, callback) => callback([]));
+ let { container } = render(
+
+ );
+ let input = container.querySelector('input.react-select__input');
+
+ fireEvent.input(input!, {
+ target: {
+ value: 'foo',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ fireEvent.input(input!, {
+ target: {
+ value: 'bar',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ fireEvent.input(input!, {
+ target: {
+ value: 'foo',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ expect(loadOptionsSpy).toHaveBeenCalledTimes(2);
+});
+
+test('to create new cache for each instance', async () => {
+ let loadOptionsOne = jest.fn();
+ let { container: containerOne } = render(
+
+ );
+ userEvent.type(containerOne.querySelector('input.react-select__input')!, 'a');
+
+ let loadOptionsTwo = jest.fn();
+ let { container: containerTwo } = render(
+
+ );
+
+ userEvent.type(containerTwo.querySelector('input.react-select__input')!, 'a');
+
+ expect(loadOptionsOne).toHaveBeenCalled();
+ expect(loadOptionsTwo).toHaveBeenCalled();
+});
+
+test('in case of callbacks display the most recently-requested loaded options (if results are returned out of order)', () => {
+ let callbacks: ((options: readonly Option[]) => void)[] = [];
+ const loadOptions = (
+ inputValue: string,
+ callback: (options: readonly Option[]) => void
+ ) => {
+ callbacks.push(callback);
+ };
+ let { container } = render(
+
+ );
+
+ let input = container.querySelector('input.react-select__input');
+ fireEvent.input(input!, {
+ target: {
+ value: 'foo',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ fireEvent.input(input!, {
+ target: {
+ value: 'bar',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ expect(container.querySelector('.react-select__option')).toBeFalsy();
+ act(() => {
+ callbacks[1]([{ value: 'bar', label: 'bar' }]);
+ });
+ act(() => {
+ callbacks[0]([{ value: 'foo', label: 'foo' }]);
+ });
+ expect(container.querySelector('.react-select__option')!.textContent).toBe(
+ 'bar'
+ );
+});
+
+// QUESTION: we currently do not do this, do we want to?
+test.skip('in case of callbacks should handle an error by setting options to an empty array', () => {
+ const loadOptions = (
+ inputValue: string,
+ callback: (options: readonly Option[]) => void
+ ) => {
+ // @ts-ignore
+ callback(new Error('error'));
+ };
+ let { container } = render(
+
+ );
+ let input = container.querySelector('input.react-select__input');
+ fireEvent.input(input!, {
+ target: {
+ value: 'foo',
+ },
+ bubbles: true,
+ cancelable: true,
+ });
+ expect(container.querySelectorAll('.react-select__option').length).toBe(0);
+});
diff --git a/packages/react-select/src/__tests__/AsyncCreatable.test.tsx b/packages/react-select/src/__tests__/AsyncCreatable.test.tsx
new file mode 100644
index 0000000000..d855717bd7
--- /dev/null
+++ b/packages/react-select/src/__tests__/AsyncCreatable.test.tsx
@@ -0,0 +1,70 @@
+import React from 'react';
+
+import AsyncCreatable from '../AsyncCreatable';
+import { Option, OPTIONS } from './constants';
+import { render, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+test('defaults - snapshot', () => {
+ const { container } = render( );
+ expect(container).toMatchSnapshot();
+});
+
+test('creates an inner Select', () => {
+ const { container } = render(
+
+ );
+ expect(container.querySelector('.react-select')).toBeInTheDocument();
+});
+
+test('render decorated select with props passed', () => {
+ const { container } = render(
+
+ );
+ expect(container.querySelector('.foo')).toBeInTheDocument();
+});
+
+test('to show the create option in menu', () => {
+ let { container, rerender } = render(
+
+ );
+ let input = container.querySelector('input.react-select__input');
+ rerender(
+
+ );
+ userEvent.type(input!, 'a');
+ expect(container.querySelector('.react-select__option')!.textContent).toBe(
+ 'Create "a"'
+ );
+});
+
+test('to show loading and then create option in menu', async () => {
+ let loadOptionsSpy = jest.fn(
+ (inputValue: string, callback: (options: readonly Option[]) => void) => {
+ setTimeout(() => callback(OPTIONS), 200);
+ }
+ );
+ let { container } = render(
+
+ );
+ let input = container.querySelector('input.react-select__input');
+ userEvent.type(input!, 'a');
+
+ // to show a loading message while loading options
+ expect(container.querySelector('.react-select__menu')!.textContent).toBe(
+ 'Loading...'
+ );
+ await waitFor(() => {
+ // show create options once options are loaded
+ let options = container.querySelectorAll('.react-select__option');
+ expect(options[options.length - 1].textContent).toBe('Create "a"');
+ });
+});
diff --git a/packages/react-select/src/__tests__/Creatable.test.tsx b/packages/react-select/src/__tests__/Creatable.test.tsx
new file mode 100644
index 0000000000..9cd01a741a
--- /dev/null
+++ b/packages/react-select/src/__tests__/Creatable.test.tsx
@@ -0,0 +1,347 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import cases from 'jest-in-case';
+
+import Creatable from '../Creatable';
+import { Option, OPTIONS } from './constants';
+
+interface BasicProps {
+ readonly className: string;
+ readonly classNamePrefix: string;
+ readonly onChange: () => void;
+ readonly onInputChange: () => void;
+ readonly onMenuClose: () => void;
+ readonly onMenuOpen: () => void;
+ readonly name: string;
+ readonly options: readonly Option[];
+}
+
+const BASIC_PROPS: BasicProps = {
+ className: 'react-select',
+ classNamePrefix: 'react-select',
+ onChange: jest.fn(),
+ onInputChange: jest.fn(),
+ onMenuClose: jest.fn(),
+ onMenuOpen: jest.fn(),
+ name: 'test-input-name',
+ options: OPTIONS,
+};
+
+test('defaults - snapshot', () => {
+ const { container } = render( );
+ expect(container).toMatchSnapshot();
+});
+
+interface Props extends Partial {
+ readonly isMulti?: boolean;
+}
+
+interface Opts {
+ readonly props?: Props;
+}
+
+cases(
+ 'filtered option is an exact match for an existing option',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+ const { container, rerender } = render( );
+ rerender( );
+ expect(
+ container.querySelector('.react-select__menu')!.textContent
+ ).not.toEqual(expect.stringContaining('create'));
+ },
+ {
+ 'single select > should not show "create..." prompt"': {},
+ 'multi select > should not show "create..." prompt"': {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+cases(
+ 'filterOptions returns invalid value ( null )',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+ let filterOptionSpy = jest.fn().mockReturnValue(null);
+
+ const { container, rerender } = render(
+
+ );
+ rerender(
+
+ );
+
+ expect(
+ container.querySelector('.react-select__menu-notice--no-options')!
+ .textContent
+ ).toEqual(expect.stringContaining('No options'));
+ },
+ {
+ 'single select > should not show "create..." prompt"': {},
+ 'multi select > should not show "create..." prompt"': {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+cases(
+ 'inputValue does not match any option after filter',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+
+ const { container, rerender } = render( );
+ rerender(
+
+ );
+
+ expect(container.querySelector('.react-select__menu')!.textContent).toBe(
+ 'Create "option not is list"'
+ );
+ },
+ {
+ 'single select > should show a placeholder "create..." prompt': {},
+ 'multi select > should show a placeholder "create..." prompt': {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+cases(
+ 'isValidNewOption() prop',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+ let isValidNewOption = jest.fn((options) => options === 'new Option');
+
+ const { container, rerender } = render(
+
+ );
+
+ rerender(
+
+ );
+
+ expect(container.querySelector('.react-select__menu')!.textContent).toEqual(
+ 'Create "new Option"'
+ );
+
+ expect(
+ container.querySelector('.react-select__menu-notice--no-options')
+ ).toBeFalsy();
+
+ rerender(
+
+ );
+ expect(
+ container.querySelector('.react-select__menu')!.textContent
+ ).not.toEqual('Create "invalid new Option"');
+
+ expect(
+ container.querySelector('.react-select__menu-notice--no-options')
+ ).toBeTruthy();
+ },
+ {
+ 'single select > should show "create..." prompt only if isValidNewOption returns thruthy value':
+ {},
+ 'multi select > should show "create..." prompt only if isValidNewOption returns thruthy value':
+ {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+cases(
+ 'close by hitting escape with search text present',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+ const { container, rerender } = render( );
+ rerender( );
+ fireEvent.keyDown(container, { keyCode: 27, key: 'Escape' });
+ expect(container.querySelector('input')!.textContent).toEqual('');
+ },
+ {
+ 'single select > should remove the search text': {},
+ 'multi select > should remove the search text': {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+test('should remove the new option after closing on blur', () => {
+ const { container, rerender } = render(
+
+ );
+ rerender( );
+ fireEvent.blur(container);
+ expect(container.querySelector('input')!.textContent).toEqual('');
+});
+
+cases(
+ 'getNewOptionData() prop',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+ let getNewOptionDataSpy = jest.fn((label) => ({
+ label: `custom text ${label}`,
+ value: label,
+ }));
+ const { container, rerender } = render(
+
+ );
+ rerender(
+
+ );
+
+ expect(container.querySelector('.react-select__menu')!.textContent).toEqual(
+ 'custom text new Option'
+ );
+ },
+ {
+ 'single select > should create option as per label returned from getNewOptionData':
+ {},
+ 'multi select > should create option as per label returned from getNewOptionData':
+ {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+cases(
+ 'formatCreateLabel() prop',
+ ({ props = { options: OPTIONS } }) => {
+ props = { ...BASIC_PROPS, ...props };
+ let formatCreateLabelSpy = jest.fn((label) => `custom label "${label}"`);
+ const { container, rerender } = render(
+
+ );
+
+ rerender(
+
+ );
+ expect(container.querySelector('.react-select__menu')!.textContent).toEqual(
+ 'custom label "new Option"'
+ );
+ },
+ {
+ 'single select > should show label of custom option as per text returned from formatCreateLabel':
+ {},
+ 'multi select > should show label of custom option as per text returned from formatCreateLabel':
+ {
+ props: {
+ isMulti: true,
+ options: OPTIONS,
+ },
+ },
+ }
+);
+
+interface CustomOption {
+ readonly key: string;
+ readonly title: string;
+}
+
+const CUSTOM_OPTIONS: readonly CustomOption[] = [
+ { key: 'testa', title: 'Test A' },
+ { key: 'testb', title: 'Test B' },
+ { key: 'testc', title: 'Test C' },
+ { key: 'testd', title: 'Test D' },
+];
+
+interface CustomOptsProps extends Partial> {
+ isMulti?: boolean;
+ options: readonly CustomOption[];
+}
+
+interface CustomOpts {
+ props: CustomOptsProps;
+}
+
+cases(
+ 'compareOption() method',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props };
+
+ const getOptionLabel = ({ title }: CustomOption) => title;
+ const getOptionValue = ({ key }: CustomOption) => key;
+
+ const { container, rerender } = render(
+
+ );
+
+ rerender(
+
+ );
+ expect(container.querySelector('.react-select__menu')!.textContent).toEqual(
+ 'Test C'
+ );
+ },
+ {
+ 'single select > should handle options with custom structure': {
+ props: {
+ options: CUSTOM_OPTIONS,
+ },
+ },
+ 'multi select > should handle options with custom structure': {
+ props: {
+ isMulti: true,
+ options: CUSTOM_OPTIONS,
+ },
+ },
+ }
+);
diff --git a/packages/react-select/src/__tests__/Select.test.tsx b/packages/react-select/src/__tests__/Select.test.tsx
new file mode 100644
index 0000000000..0313149095
--- /dev/null
+++ b/packages/react-select/src/__tests__/Select.test.tsx
@@ -0,0 +1,3397 @@
+import React, { KeyboardEvent } from 'react';
+import { render, fireEvent, EventType } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import cases from 'jest-in-case';
+
+import {
+ OPTIONS,
+ OPTIONS_ACCENTED,
+ OPTIONS_NUMBER_VALUE,
+ OPTIONS_GROUPED,
+ OPTIONS_BOOLEAN_VALUE,
+ OPTIONS_DISABLED,
+ Option,
+ GroupedOption,
+ OptionNumberValue,
+ OptionBooleanValue,
+} from './constants';
+import Select, { FormatOptionLabelMeta } from '../Select';
+import { FilterOptionOption } from '../filters';
+
+import { matchers } from '@emotion/jest';
+import { AriaLiveMessages } from '../accessibility';
+import { noop } from '../utils';
+import { GroupBase } from '../types';
+
+expect.extend(matchers);
+
+interface BasicProps {
+ readonly className: string;
+ readonly classNamePrefix: string;
+ readonly onChange: () => void;
+ readonly onInputChange: () => void;
+ readonly onMenuClose: () => void;
+ readonly onMenuOpen: () => void;
+ readonly name: string;
+ readonly options: readonly Option[];
+ readonly inputValue: string;
+ readonly value: null;
+}
+
+const BASIC_PROPS: BasicProps = {
+ className: 'react-select',
+ classNamePrefix: 'react-select',
+ onChange: jest.fn(),
+ onInputChange: jest.fn(),
+ onMenuClose: jest.fn(),
+ onMenuOpen: jest.fn(),
+ name: 'test-input-name',
+ options: OPTIONS,
+ inputValue: '',
+ value: null,
+};
+
+test('snapshot - defaults', () => {
+ const { container } = render(
+
+ );
+ expect(container).toMatchSnapshot();
+});
+
+test('instanceId prop > to have instanceId as id prefix for the select components', () => {
+ let { container } = render(
+
+ );
+ expect(container.querySelector('input')!.id).toContain('custom-id');
+ container.querySelectorAll('div.react-select__option').forEach((opt) => {
+ expect(opt.id).toContain('custom-id');
+ });
+});
+
+test('hidden input field is not present if name is not passes', () => {
+ let { container } = render(
+
+ );
+ expect(container.querySelector('input[type="hidden"]')).toBeNull();
+});
+
+test('hidden input field is present if name passes', () => {
+ let { container } = render(
+
+ );
+ expect(container.querySelector('input[type="hidden"]')).toBeTruthy();
+});
+
+test('single select > passing multiple values > should select the first value', () => {
+ const props = { ...BASIC_PROPS, value: [OPTIONS[0], OPTIONS[4]] };
+ let { container } = render( );
+
+ expect(container.querySelector('.react-select__control')!.textContent).toBe(
+ '0'
+ );
+});
+
+test('isRtl boolean prop sets direction: rtl on container', () => {
+ let { container } = render(
+
+ );
+ expect(container.firstChild).toHaveStyleRule('direction', 'rtl');
+});
+
+test('isOptionSelected() prop > single select > mark value as isSelected if isOptionSelected returns true for the option', () => {
+ // Select all but option with label '1'
+ let isOptionSelected = jest.fn((option) => option.label !== '1');
+ let { container } = render(
+
+ );
+ let options = container.querySelectorAll('.react-select__option');
+
+ // Option label 0 to be selected
+ expect(options[0].classList).toContain('react-select__option--is-selected');
+ // Option label 1 to be not selected
+ expect(options[1].classList).not.toContain(
+ 'react-select__option--is-selected'
+ );
+});
+
+test('isOptionSelected() prop > multi select > to not show the selected options in Menu for multiSelect', () => {
+ // Select all but option with label '1'
+ let isOptionSelected = jest.fn((option) => option.label !== '1');
+ let { container } = render(
+
+ );
+
+ expect(container.querySelectorAll('.react-select__option')).toHaveLength(1);
+ expect(container.querySelector('.react-select__option')!.textContent).toBe(
+ '1'
+ );
+});
+
+cases(
+ 'formatOptionLabel',
+ ({ props, valueComponentSelector, expectedOptions }) => {
+ let { container } = render( );
+ let value = container.querySelector(valueComponentSelector);
+ expect(value!.textContent).toBe(expectedOptions);
+ },
+ {
+ 'single select > should format label of options according to text returned by formatOptionLabel':
+ {
+ props: {
+ ...BASIC_PROPS,
+ formatOptionLabel: (
+ { label, value }: Option,
+ { context }: FormatOptionLabelMeta
+ ) => `${label} ${value} ${context}`,
+ value: OPTIONS[0],
+ },
+ valueComponentSelector: '.react-select__single-value',
+ expectedOptions: '0 zero value',
+ },
+ 'multi select > should format label of options according to text returned by formatOptionLabel':
+ {
+ props: {
+ ...BASIC_PROPS,
+ formatOptionLabel: (
+ { label, value }: Option,
+ { context }: FormatOptionLabelMeta
+ ) => `${label} ${value} ${context}`,
+ isMulti: true,
+ value: OPTIONS[0],
+ },
+ valueComponentSelector: '.react-select__multi-value',
+ expectedOptions: '0 zero value',
+ },
+ }
+);
+
+cases(
+ 'name prop',
+ ({ expectedName, props }) => {
+ let { container } = render( );
+ let input = container.querySelector('input[type=hidden]');
+
+ expect(input!.name).toBe(expectedName);
+ },
+ {
+ 'single select > should assign the given name': {
+ props: { ...BASIC_PROPS, name: 'form-field-single-select' },
+ expectedName: 'form-field-single-select',
+ },
+ 'multi select > should assign the given name': {
+ props: {
+ ...BASIC_PROPS,
+ name: 'form-field-multi-select',
+ isMulti: true,
+ value: OPTIONS[2],
+ },
+ expectedName: 'form-field-multi-select',
+ },
+ }
+);
+
+cases(
+ 'menuIsOpen prop',
+ ({ props = BASIC_PROPS }) => {
+ let { container, rerender } = render( );
+ expect(container.querySelector('.react-select__menu')).toBeFalsy();
+
+ rerender( );
+ expect(container.querySelector('.react-select__menu')).toBeTruthy();
+
+ rerender( );
+ expect(container.querySelector('.react-select__menu')).toBeFalsy();
+ },
+ {
+ 'single select > should show menu if menuIsOpen is true and hide menu if menuIsOpen prop is false':
+ {},
+ 'multi select > should show menu if menuIsOpen is true and hide menu if menuIsOpen prop is false':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'filterOption() prop - default filter behavior',
+ ({ props, searchString, expectResultsLength }) => {
+ let { container, rerender } = render( );
+ rerender( );
+ expect(container.querySelectorAll('.react-select__option')).toHaveLength(
+ expectResultsLength
+ );
+ },
+ {
+ 'single select > should match accented char': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS_ACCENTED,
+ },
+ searchString: 'ecole', // should match "école"
+ expectResultsLength: 1,
+ },
+ 'single select > should ignore accented char in query': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS_ACCENTED,
+ },
+ searchString: 'schoöl', // should match "school"
+ expectResultsLength: 1,
+ },
+ }
+);
+
+cases(
+ 'filterOption() prop - should filter only if function returns truthy for value',
+ ({ props, searchString, expectResultsLength }) => {
+ let { container, rerender } = render( );
+ rerender( );
+ expect(container.querySelectorAll('.react-select__option')).toHaveLength(
+ expectResultsLength
+ );
+ },
+ {
+ 'single select > should filter all options as per searchString': {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption, search: string) =>
+ value.value.indexOf(search) > -1,
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ searchString: 'o',
+ expectResultsLength: 5,
+ },
+ 'multi select > should filter all options other that options in value of select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption , search: string) =>
+ value.value.indexOf(search) > -1,
+ isMulti: true,
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ searchString: 'o',
+ expectResultsLength: 4,
+ },
+ }
+);
+
+cases(
+ 'filterOption prop is null',
+ ({ props, searchString, expectResultsLength }) => {
+ let { container, rerender } = render( );
+ rerender( );
+ expect(container.querySelectorAll('.react-select__option')).toHaveLength(
+ expectResultsLength
+ );
+ },
+ {
+ 'single select > should show all the options': {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: null,
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ searchString: 'o',
+ expectResultsLength: 17,
+ },
+ 'multi select > should show all the options other than selected options': {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: null,
+ isMulti: true,
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ searchString: 'o',
+ expectResultsLength: 16,
+ },
+ }
+);
+
+cases(
+ 'no option found on search based on filterOption prop',
+ ({ props, searchString }) => {
+ let { getByText, rerender } = render( );
+ rerender( );
+ expect(getByText('No options').className).toContain(
+ 'menu-notice--no-options'
+ );
+ },
+ {
+ 'single Select > should show NoOptionsMessage': {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption , search: string) =>
+ value.value.indexOf(search) > -1,
+ menuIsOpen: true,
+ },
+ searchString: 'some text not in options',
+ },
+ 'multi select > should show NoOptionsMessage': {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption , search: string) =>
+ value.value.indexOf(search) > -1,
+ menuIsOpen: true,
+ },
+ searchString: 'some text not in options',
+ },
+ }
+);
+
+cases(
+ 'noOptionsMessage() function prop',
+ ({ props, expectNoOptionsMessage, searchString }) => {
+ let { getByText, rerender } = render( );
+ rerender( );
+ expect(getByText(expectNoOptionsMessage).className).toContain(
+ 'menu-notice--no-options'
+ );
+ },
+ {
+ 'single Select > should show NoOptionsMessage returned from noOptionsMessage function prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption , search: string) =>
+ value.value.indexOf(search) > -1,
+ menuIsOpen: true,
+ noOptionsMessage: () =>
+ 'this is custom no option message for single select',
+ },
+ expectNoOptionsMessage:
+ 'this is custom no option message for single select',
+ searchString: 'some text not in options',
+ },
+ 'multi select > should show NoOptionsMessage returned from noOptionsMessage function prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ filterOption: (value: FilterOptionOption , search: string) =>
+ value.value.indexOf(search) > -1,
+ menuIsOpen: true,
+ noOptionsMessage: () =>
+ 'this is custom no option message for multi select',
+ },
+ expectNoOptionsMessage:
+ 'this is custom no option message for multi select',
+ searchString: 'some text not in options',
+ },
+ }
+);
+
+cases(
+ 'value prop',
+ ({ props, expectedValue }) => {
+ let value;
+ render(
+
+ {...props}
+ components={{
+ Control: ({ getValue }) => {
+ value = getValue();
+ return null;
+ },
+ }}
+ />
+ );
+ expect(value).toEqual(expectedValue);
+ },
+ {
+ 'single select > should set it as initial value': {
+ props: {
+ ...BASIC_PROPS,
+ value: OPTIONS[2],
+ },
+ expectedValue: [{ label: '2', value: 'two' }],
+ },
+ 'single select > with option values as number > should set it as initial value':
+ {
+ props: {
+ ...BASIC_PROPS,
+ value: OPTIONS_NUMBER_VALUE[2],
+ },
+ expectedValue: [{ label: '2', value: 2 }],
+ },
+ 'multi select > should set it as initial value': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ value: OPTIONS[1],
+ },
+ expectedValue: [{ label: '1', value: 'one' }],
+ },
+ 'multi select > with option values as number > should set it as initial value':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ value: OPTIONS_NUMBER_VALUE[1],
+ },
+ expectedValue: [{ label: '1', value: 1 }],
+ },
+ }
+);
+
+cases(
+ 'update the value prop',
+ ({
+ props = { ...BASIC_PROPS, value: OPTIONS[1] },
+ updateValueTo,
+ expectedInitialValue,
+ expectedUpdatedValue,
+ }) => {
+ let { container, rerender } = render(
+ {...props} />
+ );
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toEqual(expectedInitialValue);
+
+ rerender(
+
+ {...props}
+ value={updateValueTo}
+ />
+ );
+
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toEqual(expectedUpdatedValue);
+ },
+ {
+ 'single select > should update the value when prop is updated': {
+ updateValueTo: OPTIONS[3],
+ expectedInitialValue: 'one',
+ expectedUpdatedValue: 'three',
+ },
+ 'single select > value of options is number > should update the value when prop is updated':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS_NUMBER_VALUE,
+ value: OPTIONS_NUMBER_VALUE[2],
+ },
+ updateValueTo: OPTIONS_NUMBER_VALUE[3],
+ expectedInitialValue: '2',
+ expectedUpdatedValue: '3',
+ },
+ 'multi select > should update the value when prop is updated': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ value: OPTIONS[1],
+ },
+ updateValueTo: OPTIONS[3],
+ expectedInitialValue: 'one',
+ expectedUpdatedValue: 'three',
+ },
+ 'multi select > value of options is number > should update the value when prop is updated':
+ {
+ props: {
+ ...BASIC_PROPS,
+ delimiter: ',',
+ isMulti: true,
+ options: OPTIONS_NUMBER_VALUE,
+ value: OPTIONS_NUMBER_VALUE[2],
+ },
+ updateValueTo: [OPTIONS_NUMBER_VALUE[3], OPTIONS_NUMBER_VALUE[2]],
+ expectedInitialValue: '2',
+ expectedUpdatedValue: '3,2',
+ },
+ }
+);
+
+cases(
+ 'calls onChange on selecting an option',
+ ({
+ props = { ...BASIC_PROPS, menuIsOpen: true },
+ event: [eventName, eventOptions],
+ expectedSelectedOption,
+ optionsSelected,
+ focusedOption,
+ expectedActionMetaOption,
+ }) => {
+ let onChangeSpy = jest.fn();
+ props = { ...props, onChange: onChangeSpy };
+ let { container } = render(
+
+ {...props}
+ />
+ );
+
+ if (focusedOption) {
+ focusOption(container, focusedOption, props.options);
+ }
+
+ let selectOption = [
+ ...container.querySelectorAll('div.react-select__option'),
+ ].find((n) => n.textContent === optionsSelected.label);
+
+ fireEvent[eventName](selectOption!, eventOptions);
+ expect(onChangeSpy).toHaveBeenCalledWith(expectedSelectedOption, {
+ action: 'select-option',
+ option: expectedActionMetaOption,
+ name: BASIC_PROPS.name,
+ });
+ },
+ {
+ 'single select > option is clicked > should call onChange() prop with selected option':
+ {
+ event: ['click' as const] as const,
+ optionsSelected: { label: '2', value: 'two' },
+ expectedSelectedOption: { label: '2', value: 'two' },
+ },
+ 'single select > option with number value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS_NUMBER_VALUE,
+ },
+ event: ['click' as const] as const,
+ optionsSelected: { label: '0', value: 0 },
+ expectedSelectedOption: { label: '0', value: 0 },
+ },
+ 'single select > option with boolean value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS_BOOLEAN_VALUE,
+ },
+ event: ['click' as const] as const,
+ optionsSelected: { label: 'true', value: true },
+ expectedSelectedOption: { label: 'true', value: true },
+ },
+ 'single select > tab key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ event: ['keyDown' as const, { keyCode: 9, key: 'Tab' }] as const,
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: { label: '1', value: 'one' },
+ },
+ 'single select > enter key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ event: ['keyDown' as const, { keyCode: 13, key: 'Enter' }] as const,
+ optionsSelected: { label: '3', value: 'three' },
+ focusedOption: { label: '3', value: 'three' },
+ expectedSelectedOption: { label: '3', value: 'three' },
+ },
+ 'single select > space key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ event: ['keyDown' as const, { keyCode: 32, key: ' ' }] as const,
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: { label: '1', value: 'one' },
+ },
+ 'multi select > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ event: ['click' as const] as const,
+ optionsSelected: { label: '2', value: 'two' },
+ expectedSelectedOption: [{ label: '2', value: 'two' }],
+ expectedActionMetaOption: { label: '2', value: 'two' },
+ },
+ 'multi select > option with number value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS_NUMBER_VALUE,
+ },
+ event: ['click' as const] as const,
+ optionsSelected: { label: '0', value: 0 },
+ expectedSelectedOption: [{ label: '0', value: 0 }],
+ expectedActionMetaOption: { label: '0', value: 0 },
+ },
+ 'multi select > option with boolean value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS_BOOLEAN_VALUE,
+ },
+ event: ['click' as const] as const,
+ optionsSelected: { label: 'true', value: true },
+ expectedSelectedOption: [{ label: 'true', value: true }],
+ expectedActionMetaOption: { label: 'true', value: true },
+ },
+ 'multi select > tab key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ event: ['keyDown' as const, { keyCode: 9, key: 'Tab' }] as const,
+ menuIsOpen: true,
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: [{ label: '1', value: 'one' }],
+ expectedActionMetaOption: { label: '1', value: 'one' },
+ },
+ 'multi select > enter key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ event: ['keyDown' as const, { keyCode: 13, key: 'Enter' }] as const,
+ optionsSelected: { label: '3', value: 'three' },
+ focusedOption: { label: '3', value: 'three' },
+ expectedSelectedOption: [{ label: '3', value: 'three' }],
+ expectedActionMetaOption: { label: '3', value: 'three' },
+ },
+ 'multi select > space key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ event: ['keyDown' as const, { keyCode: 32, key: ' ' }] as const,
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: [{ label: '1', value: 'one' }],
+ expectedActionMetaOption: { label: '1', value: 'one' },
+ },
+ }
+);
+
+interface CallsOnChangeOnDeselectOptsProps
+ extends Omit {
+ readonly options: readonly (
+ | Option
+ | OptionNumberValue
+ | OptionBooleanValue
+ )[];
+ readonly value:
+ | readonly Option[]
+ | readonly OptionNumberValue[]
+ | readonly OptionBooleanValue[]
+ | Option;
+ readonly menuIsOpen?: boolean;
+ readonly hideSelectedOptions?: boolean;
+ readonly isMulti?: boolean;
+}
+
+interface CallsOnOnDeselectChangeOpts {
+ readonly props: CallsOnChangeOnDeselectOptsProps;
+ readonly event: readonly [EventType] | readonly [EventType, {}];
+ readonly menuIsOpen?: boolean;
+ readonly optionsSelected: Option | OptionNumberValue | OptionBooleanValue;
+ readonly focusedOption?: Option | OptionNumberValue | OptionBooleanValue;
+ readonly expectedSelectedOption:
+ | readonly Option[]
+ | readonly OptionNumberValue[]
+ | readonly OptionBooleanValue[];
+ readonly expectedMetaOption: Option | OptionNumberValue | OptionBooleanValue;
+}
+
+cases(
+ 'calls onChange on de-selecting an option in multi select',
+ ({
+ props,
+ event: [eventName, eventOptions],
+ expectedSelectedOption,
+ expectedMetaOption,
+ optionsSelected,
+ focusedOption,
+ }) => {
+ let onChangeSpy = jest.fn();
+ props = {
+ ...props,
+ onChange: onChangeSpy,
+ menuIsOpen: true,
+ hideSelectedOptions: false,
+ isMulti: true,
+ };
+ let { container } = render(
+
+ {...props}
+ />
+ );
+
+ let selectOption = [
+ ...container.querySelectorAll('div.react-select__option'),
+ ].find((n) => n.textContent === optionsSelected.label);
+ if (focusedOption) {
+ focusOption(container, focusedOption, props.options);
+ }
+ fireEvent[eventName](selectOption!, eventOptions);
+ expect(onChangeSpy).toHaveBeenCalledWith(expectedSelectedOption, {
+ action: 'deselect-option',
+ option: expectedMetaOption,
+ name: BASIC_PROPS.name,
+ });
+ },
+ {
+ 'option is clicked > should call onChange() prop with correct selected options and meta':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS,
+ value: [{ label: '2', value: 'two' }],
+ },
+ event: ['click'],
+ optionsSelected: { label: '2', value: 'two' },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: '2', value: 'two' },
+ },
+ 'option with number value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS_NUMBER_VALUE,
+ value: [{ label: '0', value: 0 }],
+ },
+ event: ['click'],
+ optionsSelected: { label: '0', value: 0 },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: '0', value: 0 },
+ },
+ 'option with boolean value > option is clicked > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS_BOOLEAN_VALUE,
+ value: [{ label: 'true', value: true }],
+ },
+ event: ['click'],
+ optionsSelected: { label: 'true', value: true },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: 'true', value: true },
+ },
+ 'tab key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS,
+ value: [{ label: '1', value: 'one' }],
+ },
+ event: ['keyDown', { keyCode: 9, key: 'Tab' }],
+ menuIsOpen: true,
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: '1', value: 'one' },
+ },
+ 'enter key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS,
+ value: { label: '3', value: 'three' },
+ },
+ event: ['keyDown', { keyCode: 13, key: 'Enter' }],
+ optionsSelected: { label: '3', value: 'three' },
+ focusedOption: { label: '3', value: 'three' },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: '3', value: 'three' },
+ },
+ 'space key is pressed while focusing option > should call onChange() prop with selected option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS,
+ value: [{ label: '1', value: 'one' }],
+ },
+ event: ['keyDown', { keyCode: 32, key: ' ' }],
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ expectedSelectedOption: [],
+ expectedMetaOption: { label: '1', value: 'one' },
+ },
+ }
+);
+
+function focusOption(
+ container: HTMLElement,
+ option: Option | OptionNumberValue | OptionBooleanValue,
+ options: readonly (Option | OptionNumberValue | OptionBooleanValue)[]
+) {
+ let indexOfSelectedOption = options.findIndex(
+ (o) => o.value === option.value
+ );
+
+ for (let i = -1; i < indexOfSelectedOption; i++) {
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+ }
+ expect(
+ container.querySelector('.react-select__option--is-focused')!.textContent
+ ).toEqual(option.label);
+}
+
+cases(
+ 'hitting escape on select option',
+ ({
+ props,
+ event: [eventName, eventOptions],
+ focusedOption,
+ optionsSelected,
+ }) => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+
+ let selectOption = [
+ ...container.querySelectorAll('div.react-select__option'),
+ ].find((n) => n.textContent === optionsSelected.label);
+ focusOption(container, focusedOption, props.options);
+
+ fireEvent[eventName](selectOption!, eventOptions);
+ expect(onChangeSpy).not.toHaveBeenCalled();
+ },
+ {
+ 'single select > should not call onChange prop': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ },
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ event: ['keyDown' as const, { keyCode: 27 }] as const,
+ },
+ 'multi select > should not call onChange prop': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ },
+ optionsSelected: { label: '1', value: 'one' },
+ focusedOption: { label: '1', value: 'one' },
+ event: ['keyDown' as const, { keyCode: 27 }] as const,
+ },
+ }
+);
+
+cases(
+ 'click to open select',
+ ({ props = BASIC_PROPS, expectedToFocus }) => {
+ let { container, rerender } = render(
+ {
+ rerender( );
+ }}
+ />
+ );
+
+ fireEvent.mouseDown(
+ container.querySelector('.react-select__dropdown-indicator')!,
+ { button: 0 }
+ );
+ expect(
+ container.querySelector('.react-select__option--is-focused')!.textContent
+ ).toEqual(expectedToFocus.label);
+ },
+ {
+ 'single select > should focus the first option': {
+ expectedToFocus: { label: '0', value: 'zero' },
+ },
+ 'multi select > should focus the first option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ expectedToFocus: { label: '0', value: 'zero' },
+ },
+ }
+);
+
+test('clicking when focused does not open select when openMenuOnClick=false', () => {
+ let spy = jest.fn();
+ let { container } = render(
+
+ );
+
+ // this will get updated on input click, though click on input is not bubbling up to control component
+ userEvent.click(container.querySelector('input.react-select__input')!);
+ expect(spy).not.toHaveBeenCalled();
+});
+
+cases(
+ 'focus on options > keyboard interaction with Menu',
+ ({ props, selectedOption, nextFocusOption, keyEvent = [] }) => {
+ let { container } = render( );
+
+ let indexOfSelectedOption = props.options.indexOf(selectedOption);
+
+ for (let i = -1; i < indexOfSelectedOption; i++) {
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+ }
+
+ expect(
+ container.querySelector('.react-select__option--is-focused')!.textContent
+ ).toEqual(selectedOption.label);
+
+ for (let event of keyEvent) {
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, event);
+ }
+
+ expect(
+ container.querySelector('.react-select__option--is-focused')!.textContent
+ ).toEqual(nextFocusOption.label);
+ },
+ {
+ 'single select > ArrowDown key on first option should focus second option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ },
+ keyEvent: [{ keyCode: 40, key: 'ArrowDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[1],
+ },
+ 'single select > ArrowDown key on last option should focus first option': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 40, key: 'ArrowDown' }],
+ selectedOption: OPTIONS[OPTIONS.length - 1],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'single select > ArrowUp key on first option should focus last option': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 38, key: 'ArrowUp' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ 'single select > ArrowUp key on last option should focus second last option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 38, key: 'ArrowUp' }],
+ selectedOption: OPTIONS[OPTIONS.length - 1],
+ nextFocusOption: OPTIONS[OPTIONS.length - 2],
+ },
+ 'single select > disabled options should be focusable': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS_DISABLED,
+ },
+ keyEvent: [{ keyCode: 40, key: 'ArrowDown' }],
+ selectedOption: OPTIONS_DISABLED[0],
+ nextFocusOption: OPTIONS_DISABLED[1],
+ },
+ 'single select > PageDown key takes us to next page with default page size of 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[5],
+ },
+ 'single select > PageDown key takes us to next page with custom pageSize 7':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ pageSize: 7,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[7],
+ },
+ 'single select > PageDown key takes to the last option is options below is less then page size':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[OPTIONS.length - 3],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ 'single select > PageUp key takes us to previous page with default page size of 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[6],
+ nextFocusOption: OPTIONS[1],
+ },
+ 'single select > PageUp key takes us to previous page with custom pageSize of 7':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ pageSize: 7,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[9],
+ nextFocusOption: OPTIONS[2],
+ },
+ 'single select > PageUp key takes us to first option - (previous options < pageSize)':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[1],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'single select > Home key takes up to the first option': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 36, key: 'Home' }],
+ selectedOption: OPTIONS[OPTIONS.length - 3],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'single select > End key takes down to the last option': {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 35, key: 'End' }],
+ selectedOption: OPTIONS[2],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ 'multi select > ArrowDown key on first option should focus second option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 40, key: 'ArrowDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[1],
+ },
+ 'multi select > ArrowDown key on last option should focus first option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 40, key: 'ArrowDown' }],
+ selectedOption: OPTIONS[OPTIONS.length - 1],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'multi select > ArrowUp key on first option should focus last option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 38, key: 'ArrowUp' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ 'multi select > ArrowUp key on last option should focus second last option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 38, key: 'ArrowUp' }],
+ selectedOption: OPTIONS[OPTIONS.length - 1],
+ nextFocusOption: OPTIONS[OPTIONS.length - 2],
+ },
+ 'multi select > PageDown key takes us to next page with default page size of 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[5],
+ },
+ 'multi select > PageDown key takes us to next page with custom pageSize of 8':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ pageSize: 8,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[0],
+ nextFocusOption: OPTIONS[8],
+ },
+ 'multi select > PageDown key takes to the last option is options below is less then page size':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 34, key: 'PageDown' }],
+ selectedOption: OPTIONS[OPTIONS.length - 3],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ 'multi select > PageUp key takes us to previous page with default page size of 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[6],
+ nextFocusOption: OPTIONS[1],
+ },
+ 'multi select > PageUp key takes us to previous page with default page size of 9':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ pageSize: 9,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[10],
+ nextFocusOption: OPTIONS[1],
+ },
+ 'multi select > PageUp key takes us to first option - previous options < pageSize':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 33, key: 'PageUp' }],
+ selectedOption: OPTIONS[1],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'multi select > Home key takes up to the first option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 36, key: 'Home' }],
+ selectedOption: OPTIONS[OPTIONS.length - 3],
+ nextFocusOption: OPTIONS[0],
+ },
+ 'multi select > End key takes down to the last option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ options: OPTIONS,
+ },
+ keyEvent: [{ keyCode: 35, key: 'End' }],
+ selectedOption: OPTIONS[2],
+ nextFocusOption: OPTIONS[OPTIONS.length - 1],
+ },
+ }
+);
+
+// TODO: Cover more scenario
+cases(
+ 'hitting escape with inputValue in select',
+ ({ props }) => {
+ let spy = jest.fn();
+ let { container } = render(
+
+ );
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(spy).toHaveBeenCalledWith('', {
+ action: 'menu-close',
+ prevInputValue: 'test',
+ });
+ },
+ {
+ 'single select > should call onInputChange prop with empty string as inputValue':
+ {
+ props: {
+ ...BASIC_PROPS,
+ inputValue: 'test',
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ },
+ 'multi select > should call onInputChange prop with empty string as inputValue':
+ {
+ props: {
+ ...BASIC_PROPS,
+ inputValue: 'test',
+ isMulti: true,
+ menuIsOpen: true,
+ value: OPTIONS[0],
+ },
+ },
+ }
+);
+
+cases(
+ 'Clicking dropdown indicator on select with closed menu with primary button on mouse',
+ ({ props = BASIC_PROPS }) => {
+ let onMenuOpenSpy = jest.fn();
+ props = { ...props, onMenuOpen: onMenuOpenSpy };
+ let { container } = render( );
+ // Menu is closed
+ expect(
+ container.querySelector('.react-select__menu')
+ ).not.toBeInTheDocument();
+ fireEvent.mouseDown(
+ container.querySelector('div.react-select__dropdown-indicator')!,
+ { button: 0 }
+ );
+ expect(onMenuOpenSpy).toHaveBeenCalled();
+ },
+ {
+ 'single select > should call onMenuOpen prop when select is opened and onMenuClose prop when select is closed':
+ {},
+ 'multi select > should call onMenuOpen prop when select is opened and onMenuClose prop when select is closed':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'Clicking dropdown indicator on select with open menu with primary button on mouse',
+ ({ props = BASIC_PROPS }) => {
+ let onMenuCloseSpy = jest.fn();
+ props = { ...props, onMenuClose: onMenuCloseSpy };
+ let { container } = render( );
+ // Menu is open
+ expect(container.querySelector('.react-select__menu')).toBeInTheDocument();
+ fireEvent.mouseDown(
+ container.querySelector('div.react-select__dropdown-indicator')!,
+ { button: 0 }
+ );
+ expect(onMenuCloseSpy).toHaveBeenCalled();
+ },
+ {
+ 'single select > should call onMenuOpen prop when select is opened and onMenuClose prop when select is closed':
+ {},
+ 'multi select > should call onMenuOpen prop when select is opened and onMenuClose prop when select is closed':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+interface ClickingEnterOptsProps extends BasicProps {
+ readonly menuIsOpen?: boolean;
+}
+
+interface ClickingEnterOpts {
+ readonly props: ClickingEnterOptsProps;
+ readonly expectedValue: boolean;
+}
+
+cases(
+ 'Clicking Enter on a focused select',
+ ({ props, expectedValue }) => {
+ let event!: KeyboardEvent;
+ let { container } = render(
+ {
+ event = _event;
+ event.persist();
+ }}
+ >
+
+
+ );
+ if (props.menuIsOpen) {
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+ }
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ key: 'Enter',
+ keyCode: 13,
+ });
+ expect(event.defaultPrevented).toBe(expectedValue);
+ },
+ {
+ 'while menuIsOpen && focusedOption && !isComposing > should invoke event.preventDefault':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ },
+ expectedValue: true,
+ },
+ 'while !menuIsOpen > should not invoke event.preventDefault': {
+ props: {
+ ...BASIC_PROPS,
+ },
+ expectedValue: false,
+ },
+ }
+);
+
+// QUESTION: Is this test right? I tried right clicking on the dropdown indicator in a browser and the select opened but this test says it shouldn't?
+cases(
+ 'clicking on select using secondary button on mouse',
+ ({ props = BASIC_PROPS }) => {
+ let onMenuOpenSpy = jest.fn();
+ let onMenuCloseSpy = jest.fn();
+ let { container, rerender } = render(
+
+ );
+ let downButton = container.querySelector(
+ 'div.react-select__dropdown-indicator'
+ );
+
+ // does not open menu if menu is closed
+ fireEvent.mouseDown(downButton!, { button: 1 });
+ expect(onMenuOpenSpy).not.toHaveBeenCalled();
+
+ // does not close menu if menu is opened
+ rerender(
+
+ );
+ fireEvent.mouseDown(downButton!, { button: 1 });
+ expect(onMenuCloseSpy).not.toHaveBeenCalled();
+ },
+ {
+ 'single select > secondary click is ignored > should not call onMenuOpen and onMenuClose prop':
+ {
+ skip: true,
+ },
+ 'multi select > secondary click is ignored > should not call onMenuOpen and onMenuClose prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ skip: true,
+ },
+ }
+);
+
+interface RequiredOnInputOpts {
+ readonly props?: BasicProps;
+ readonly isMulti?: boolean;
+}
+
+cases(
+ 'required on input is not there by default',
+ ({ props = BASIC_PROPS }) => {
+ let { container } = render( );
+ let input = container.querySelector(
+ 'input.react-select__input'
+ );
+ expect(input!.required).toBe(false);
+ },
+ {
+ 'single select > should not have required attribute': {},
+ 'multi select > should not have required attribute': { isMulti: true },
+ }
+);
+
+cases(
+ 'value of hidden input control',
+ ({ props, expectedValue }) => {
+ let { container } = render(
+
+ {...props}
+ />
+ );
+ let hiddenInput = container.querySelector(
+ 'input[type="hidden"]'
+ );
+ expect(hiddenInput!.value).toEqual(expectedValue);
+ },
+ {
+ 'single select > should set value of input as value prop': {
+ props: {
+ ...BASIC_PROPS,
+ value: OPTIONS[3],
+ },
+ expectedValue: 'three',
+ },
+ 'single select > options with number values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS_NUMBER_VALUE,
+ value: OPTIONS_NUMBER_VALUE[3],
+ },
+ expectedValue: '3',
+ },
+ 'single select > options with boolean values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ options: OPTIONS_BOOLEAN_VALUE,
+ value: OPTIONS_BOOLEAN_VALUE[1],
+ },
+ expectedValue: 'false',
+ },
+ 'multi select > should set value of input as value prop': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ value: OPTIONS[3],
+ },
+ expectedValue: 'three',
+ },
+ 'multi select > with delimiter prop > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ delimiter: ', ',
+ isMulti: true,
+ value: [OPTIONS[3], OPTIONS[5]],
+ },
+ expectedValue: 'three, five',
+ },
+ 'multi select > options with number values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ options: OPTIONS_NUMBER_VALUE,
+ value: OPTIONS_NUMBER_VALUE[3],
+ },
+ expectedValue: '3',
+ },
+ 'multi select > with delimiter prop > options with number values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ delimiter: ', ',
+ isMulti: true,
+ options: OPTIONS_NUMBER_VALUE,
+ value: [OPTIONS_NUMBER_VALUE[3], OPTIONS_NUMBER_VALUE[1]],
+ },
+ expectedValue: '3, 1',
+ },
+ 'multi select > options with boolean values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ options: OPTIONS_BOOLEAN_VALUE,
+ value: OPTIONS_BOOLEAN_VALUE[1],
+ },
+ expectedValue: 'false',
+ },
+ 'multi select > with delimiter prop > options with boolean values > should set value of input as value prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ delimiter: ', ',
+ isMulti: true,
+ options: OPTIONS_BOOLEAN_VALUE,
+ value: [OPTIONS_BOOLEAN_VALUE[1], OPTIONS_BOOLEAN_VALUE[0]],
+ },
+ expectedValue: 'false, true',
+ },
+ }
+);
+
+cases(
+ 'isOptionDisabled() prop',
+ ({ props, expectedEnabledOption, expectedDisabledOption }) => {
+ let { container } = render( );
+
+ const enabledOptionsValues = [
+ ...container.querySelectorAll('.react-select__option'),
+ ]
+ .filter((n) => !n.classList.contains('react-select__option--is-disabled'))
+ .map((option) => option.textContent);
+
+ enabledOptionsValues.forEach((option) => {
+ expect(expectedDisabledOption.indexOf(option!)).toBe(-1);
+ });
+
+ const disabledOptionsValues = [
+ ...container.querySelectorAll('.react-select__option'),
+ ]
+ .filter((n) => n.classList.contains('react-select__option--is-disabled'))
+ .map((option) => option.textContent);
+
+ disabledOptionsValues.forEach((option) => {
+ expect(expectedEnabledOption.indexOf(option!)).toBe(-1);
+ });
+ },
+ {
+ 'single select > should add isDisabled as true prop only to options that are disabled':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ isOptionDisabled: (option: Option) =>
+ ['zero', 'two', 'five', 'ten'].indexOf(option.value) > -1,
+ },
+ expectedEnabledOption: ['1', '3', '11'],
+ expectedDisabledOption: ['0', '2', '5'],
+ },
+ 'multi select > should add isDisabled as true prop only to options that are disabled':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ isOptionDisabled: (option: Option) =>
+ ['zero', 'two', 'five', 'ten'].indexOf(option.value) > -1,
+ },
+ expectedEnabledOption: ['1', '3', '11'],
+ expectedDisabledOption: ['0', '2', '5'],
+ },
+ }
+);
+
+cases(
+ 'isDisabled prop',
+ ({ props }) => {
+ let { container } = render( );
+
+ let control = container.querySelector('.react-select__control');
+ expect(
+ control!.classList.contains('react-select__control--is-disabled')
+ ).toBeTruthy();
+
+ let input = container.querySelector(
+ '.react-select__control input'
+ );
+ expect(input!.disabled).toBeTruthy();
+ },
+ {
+ 'single select > should add isDisabled prop to select components': {
+ props: {
+ ...BASIC_PROPS,
+ isDisabled: true,
+ },
+ },
+ 'multi select > should add isDisabled prop to select components': {
+ props: {
+ ...BASIC_PROPS,
+ isDisabled: true,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+test('hitting Enter on option should not call onChange if the event comes from IME', () => {
+ let spy = jest.fn();
+ let { container } = render(
+
+ );
+
+ let selectOption = container.querySelector('div.react-select__option');
+ let menu = container.querySelector('.react-select__menu');
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+
+ fireEvent.keyDown(selectOption!, { keyCode: 229, key: 'Enter' });
+
+ expect(spy).not.toHaveBeenCalled();
+});
+
+test('hitting tab on option should not call onChange if tabSelectsValue is false', () => {
+ let spy = jest.fn();
+ let { container } = render(
+
+ );
+
+ let selectOption = container.querySelector('div.react-select__option');
+ let menu = container.querySelector('.react-select__menu');
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+
+ fireEvent.keyDown(selectOption!, { keyCode: 9, key: 'Tab' });
+ expect(spy).not.toHaveBeenCalled();
+});
+
+test('multi select > to not show selected value in options', () => {
+ let onInputChangeSpy = jest.fn();
+ let onMenuCloseSpy = jest.fn();
+ let { container, rerender } = render(
+
+ );
+
+ let availableOptions = [
+ ...container.querySelectorAll('.react-select__option'),
+ ].map((option) => option.textContent);
+ expect(availableOptions.indexOf('0') > -1).toBeTruthy();
+
+ rerender(
+
+ );
+
+ // Re-open Menu
+ fireEvent.mouseDown(
+ container.querySelector('div.react-select__dropdown-indicator')!,
+ {
+ button: 0,
+ }
+ );
+ availableOptions = [
+ ...container.querySelectorAll('.react-select__option'),
+ ].map((option) => option.textContent);
+
+ expect(availableOptions.indexOf('0') > -1).toBeFalsy();
+});
+
+test('multi select > to not hide the selected options from the menu if hideSelectedOptions is false', () => {
+ let { container } = render(
+
+ );
+ let firstOption = container.querySelectorAll('.react-select__option')[0];
+ let secondoption = container.querySelectorAll('.react-select__option')[1];
+ expect(firstOption.textContent).toBe('0');
+ expect(secondoption.textContent).toBe('1');
+
+ userEvent.click(firstOption);
+
+ expect(firstOption.textContent).toBe('0');
+ expect(secondoption.textContent).toBe('1');
+});
+
+test('multi select > call onChange with all values but last selected value and remove event on hitting backspace', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ expect(container.querySelector('.react-select__control')!.textContent).toBe(
+ '012'
+ );
+
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).toHaveBeenCalledWith(
+ [
+ { label: '0', value: 'zero' },
+ { label: '1', value: 'one' },
+ ],
+ {
+ action: 'pop-value',
+ removedValue: { label: '2', value: 'two' },
+ name: BASIC_PROPS.name,
+ }
+ );
+});
+
+test('should not call onChange on hitting backspace when backspaceRemovesValue is false', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('should not call onChange on hitting backspace even when backspaceRemovesValue is true if isClearable is false', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('should call onChange with `null` on hitting backspace when backspaceRemovesValue is true and isMulti is false', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).toHaveBeenCalledWith(null, {
+ action: 'clear',
+ name: 'test-input-name',
+ removedValues: [],
+ });
+});
+
+test('should call onChange with an array on hitting backspace when backspaceRemovesValue is true and isMulti is true', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).toHaveBeenCalledWith([], {
+ action: 'pop-value',
+ name: 'test-input-name',
+ removedValue: OPTIONS[0],
+ });
+});
+
+test('should call not call onChange on hitting backspace when backspaceRemovesValue is true and isMulti is true and there are no values', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 8,
+ key: 'Backspace',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('multi select > clicking on X next to option will call onChange with all options other that the clicked option', () => {
+ let onChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ // there are 3 values in select
+ expect(container.querySelectorAll('.react-select__multi-value').length).toBe(
+ 3
+ );
+
+ const selectValueElement = [
+ ...container.querySelectorAll('.react-select__multi-value'),
+ ].find((multiValue) => multiValue.textContent === '4');
+ userEvent.click(
+ selectValueElement!.querySelector('div.react-select__multi-value__remove')!
+ );
+
+ expect(onChangeSpy).toHaveBeenCalledWith(
+ [
+ { label: '0', value: 'zero' },
+ { label: '2', value: 'two' },
+ ],
+ {
+ action: 'remove-value',
+ removedValue: { label: '4', value: 'four' },
+ name: BASIC_PROPS.name,
+ }
+ );
+});
+
+cases(
+ 'accessibility > aria-activedescendant for basic options',
+ (props: BasicProps) => {
+ const renderProps = {
+ ...props,
+ instanceId: 1000,
+ value: BASIC_PROPS.options[2],
+ menuIsOpen: true,
+ hideSelectedOptions: false,
+ };
+
+ const { container, rerender } = render( );
+
+ // aria-activedescendant should be set if menu is open initially and selected options are not hidden
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-2');
+
+ // aria-activedescendant is updated during keyboard navigation
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-3');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 38,
+ key: 'ArrowUp',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-2');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 36,
+ key: 'Home',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 35,
+ key: 'End',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-16');
+
+ rerender( );
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('');
+
+ // searching should update activedescendant
+ rerender( );
+
+ const setInputValue = (val: string) => {
+ rerender( );
+ };
+
+ setInputValue('four');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-4');
+
+ setInputValue('fourt');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-14');
+
+ setInputValue('fourt1');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('');
+ },
+ {
+ 'single select > should update aria-activedescendant as per focused option':
+ {
+ ...BASIC_PROPS,
+ },
+ 'multi select > should update aria-activedescendant as per focused option':
+ {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ }
+);
+
+cases(
+ 'accessibility > aria-activedescendant for grouped options',
+ (props: BasicProps) => {
+ const renderProps = {
+ ...props,
+ instanceId: 1000,
+ options: OPTIONS_GROUPED,
+ value: OPTIONS_GROUPED[0].options[2],
+ menuIsOpen: true,
+ hideSelectedOptions: false,
+ };
+
+ let { container, rerender } = render(
+
+ {...renderProps}
+ />
+ );
+
+ // aria-activedescendant should be set if menu is open initially and selected options are not hidden
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-2');
+
+ // aria-activedescendant is updated during keyboard navigation
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-3');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 38,
+ key: 'ArrowUp',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-2');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 36,
+ key: 'Home',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-0');
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 35,
+ key: 'End',
+ });
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-1-1');
+
+ rerender( );
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('');
+
+ // searching should update activedescendant
+ rerender( );
+
+ const setInputValue = (val: string) => {
+ rerender( );
+ };
+
+ setInputValue('1');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-1');
+
+ setInputValue('10');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('react-select-1000-option-0-10');
+
+ setInputValue('102');
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('');
+ },
+ {
+ 'single select > should update aria-activedescendant as per focused option':
+ {
+ ...BASIC_PROPS,
+ },
+ 'multi select > should update aria-activedescendant as per focused option':
+ {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ }
+);
+
+test('accessibility > aria-activedescendant should not exist if hideSelectedOptions=true', () => {
+ const { container } = render(
+
+ );
+
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-activedescendant')
+ ).toBe('');
+});
+
+cases(
+ 'accessibility > passes through aria-labelledby prop',
+ ({ props = { ...BASIC_PROPS, 'aria-labelledby': 'testing' } }) => {
+ let { container } = render( );
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-labelledby')
+ ).toBe('testing');
+ },
+ {
+ 'single select > should pass aria-labelledby prop down to input': {},
+ 'multi select > should pass aria-labelledby prop down to input': {
+ props: {
+ ...BASIC_PROPS,
+ 'aria-labelledby': 'testing',
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'accessibility > passes through aria-errormessage prop',
+ ({ props = { ...BASIC_PROPS, 'aria-errormessage': 'error-message' } }) => {
+ let { container } = render( );
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-errormessage')
+ ).toBe('error-message');
+ },
+ {
+ 'single select > should pass aria-errormessage prop down to input': {},
+ 'multi select > should pass aria-errormessage prop down to input': {
+ props: {
+ ...BASIC_PROPS,
+ 'aria-errormessage': 'error-message',
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'accessibility > passes through aria-invalid prop',
+ ({ props = { ...BASIC_PROPS, 'aria-invalid': true } }) => {
+ let { container } = render( );
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-invalid')
+ ).toBe('true');
+ },
+ {
+ 'single select > should pass aria-invalid prop down to input': {},
+ 'multi select > should pass aria-invalid prop down to input': {
+ props: {
+ ...BASIC_PROPS,
+ 'aria-invalid': true,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'accessibility > passes through aria-label prop',
+ ({ props = { ...BASIC_PROPS, 'aria-label': 'testing' } }) => {
+ let { container } = render( );
+ expect(
+ container
+ .querySelector('input.react-select__input')!
+ .getAttribute('aria-label')
+ ).toBe('testing');
+ },
+ {
+ 'single select > should pass aria-labelledby prop down to input': {},
+ 'multi select > should pass aria-labelledby prop down to input': {
+ props: {
+ ...BASIC_PROPS,
+ 'aria-label': 'testing',
+ isMulti: true,
+ },
+ },
+ }
+);
+
+test('accessibility > to show the number of options available in A11yText when the menu is Open', () => {
+ let { container, rerender } = render(
+
+ );
+
+ let setInputValue = (val: string) => {
+ rerender( );
+ };
+
+ const liveRegionResultsId = '#aria-results';
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ /17 results available/
+ );
+
+ setInputValue('0');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ /2 results available/
+ );
+
+ setInputValue('10');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ /1 result available/
+ );
+
+ setInputValue('100');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ /0 results available/
+ );
+});
+
+test('accessibility > interacting with disabled options shows correct A11yText', () => {
+ let { container } = render(
+
+ );
+ const liveRegionEventId = '#aria-selection';
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ // navigate to disabled option
+ let menu = container.querySelector('.react-select__menu');
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+ fireEvent.keyDown(menu!, { keyCode: 40, key: 'ArrowDown' });
+
+ // attempt to select disabled option
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+
+ expect(container.querySelector(liveRegionEventId)!.textContent).toMatch(
+ 'option 1 is disabled. Select another option.'
+ );
+});
+
+test('accessibility > interacting with multi values options shows correct A11yText', () => {
+ let renderProps = {
+ ...BASIC_PROPS,
+ options: OPTIONS_DISABLED,
+ isMulti: true,
+ value: [OPTIONS_DISABLED[0], OPTIONS_DISABLED[1]],
+ hideSelectedOptions: false,
+ };
+
+ let { container, rerender } = render( );
+
+ let openMenu = () => {
+ rerender( );
+ };
+
+ const liveRegionGuidanceId = '#aria-guidance';
+ const liveRegionFocusedId = '#aria-focused';
+ let input = container.querySelector('.react-select__value-container input')!;
+
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ expect(container.querySelector(liveRegionGuidanceId)!.textContent).toMatch(
+ 'Select is focused ,type to refine list, press Down to open the menu, press left to focus selected values'
+ );
+
+ fireEvent.keyDown(input, { keyCode: 37, key: 'ArrowLeft' });
+ expect(container.querySelector(liveRegionFocusedId)!.textContent).toMatch(
+ 'value 1 focused, 2 of 2.'
+ );
+ expect(container.querySelector(liveRegionGuidanceId)!.textContent).toMatch(
+ 'Use left and right to toggle between focused values, press Backspace to remove the currently focused value'
+ );
+
+ fireEvent.keyDown(input, { keyCode: 37, key: 'ArrowLeft' });
+ expect(container.querySelector(liveRegionFocusedId)!.textContent).toMatch(
+ 'value 0 focused, 1 of 2.'
+ );
+ expect(container.querySelector(liveRegionGuidanceId)!.textContent).toMatch(
+ 'Use left and right to toggle between focused values, press Backspace to remove the currently focused value'
+ );
+
+ openMenu();
+
+ // user will be notified if option is disabled by screen reader because of correct aria-attributes, so this message will be announce only once after menu opens
+ expect(container.querySelector(liveRegionGuidanceId)!.textContent).toMatch(
+ 'Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.'
+ );
+});
+
+test('accessibility > screenReaderStatus function prop > to pass custom text to A11yText', () => {
+ const screenReaderStatus = ({ count }: { count: number }) =>
+ `There are ${count} options available`;
+
+ const liveRegionResultsId = '#aria-results';
+ let { container, rerender } = render(
+
+ );
+
+ let setInputValue = (val: string) => {
+ rerender(
+
+ );
+ };
+
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ 'There are 17 options available'
+ );
+
+ setInputValue('0');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ 'There are 2 options available'
+ );
+
+ setInputValue('10');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ 'There are 1 options available'
+ );
+
+ setInputValue('100');
+ expect(container.querySelector(liveRegionResultsId)!.textContent).toMatch(
+ 'There are 0 options available'
+ );
+});
+
+test('accessibility > A11yTexts can be provided through ariaLiveMessages prop', () => {
+ const ariaLiveMessages: AriaLiveMessages> =
+ {
+ onChange: (props) => {
+ const { action, isDisabled, label } = props;
+ if (action === 'select-option' && !isDisabled) {
+ return `CUSTOM: option ${label} is selected.`;
+ }
+ return '';
+ },
+ };
+
+ let { container } = render(
+
+ );
+ const liveRegionEventId = '#aria-selection';
+
+ expect(container.querySelector(liveRegionEventId)!).toBeNull();
+
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ let menu = container.querySelector('.react-select__menu')!;
+ fireEvent.keyDown(menu, { keyCode: 40, key: 'ArrowDown' });
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+
+ expect(container.querySelector(liveRegionEventId)!.textContent).toMatch(
+ 'CUSTOM: option 0 is selected.'
+ );
+});
+
+test('accessibility > announces already selected values when focused', () => {
+ let { container } = render(
+
+ );
+ const liveRegionSelectionId = '#aria-selection';
+ const liveRegionContextId = '#aria-guidance';
+
+ // the live region should not be mounted yet
+ expect(container.querySelector(liveRegionSelectionId)!).toBeNull();
+
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+
+ expect(container.querySelector(liveRegionContextId)!.textContent).toMatch(
+ 'Select is focused ,type to refine list, press Down to open the menu, '
+ );
+ expect(container.querySelector(liveRegionSelectionId)!.textContent).toMatch(
+ 'option 0, selected.'
+ );
+});
+
+test('accessibility > announces cleared values', () => {
+ let { container } = render(
+
+ );
+ const liveRegionSelectionId = '#aria-selection';
+ /**
+ * announce deselected value
+ */
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+ fireEvent.mouseDown(
+ container.querySelector('.react-select__clear-indicator')!
+ );
+ expect(container.querySelector(liveRegionSelectionId)!.textContent).toMatch(
+ 'All selected options have been cleared.'
+ );
+});
+
+test('closeMenuOnSelect prop > when passed as false it should not call onMenuClose on selecting option', () => {
+ let onMenuCloseSpy = jest.fn();
+ let { container } = render(
+
+ );
+ userEvent.click(container.querySelector('div.react-select__option')!);
+ expect(onMenuCloseSpy).not.toHaveBeenCalled();
+});
+
+cases(
+ 'autoFocus',
+ ({ props = { ...BASIC_PROPS, autoFocus: true } }) => {
+ let { container } = render( );
+ expect(container.querySelector('input.react-select__input')).toBe(
+ document.activeElement
+ );
+ },
+ {
+ 'single select > should focus select on mount': {},
+ 'multi select > should focus select on mount': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ autoFocus: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'onFocus prop with autoFocus',
+ ({ props = { ...BASIC_PROPS, autoFocus: true } }) => {
+ let onFocusSpy = jest.fn();
+ let { container } = render( );
+ expect(container.querySelector('input.react-select__input')).toBe(
+ document.activeElement
+ );
+ expect(onFocusSpy).toHaveBeenCalledTimes(1);
+ },
+ {
+ 'single select > should call auto focus only once when select is autoFocus':
+ {
+ props: {
+ ...BASIC_PROPS,
+ autoFocus: true,
+ },
+ },
+ 'multi select > should call auto focus only once when select is autoFocus':
+ {
+ props: {
+ ...BASIC_PROPS,
+ autoFocus: true,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'onFocus prop is called on on focus of input',
+ ({ props = { ...BASIC_PROPS } }) => {
+ let onFocusSpy = jest.fn();
+ let { container } = render( );
+ fireEvent.focus(container.querySelector('input.react-select__input')!);
+ expect(onFocusSpy).toHaveBeenCalledTimes(1);
+ },
+ {
+ 'single select > should call onFocus handler on focus on input': {},
+ 'multi select > should call onFocus handler on focus on input': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+cases(
+ 'onBlur prop',
+ ({ props = { ...BASIC_PROPS } }) => {
+ let onBlurSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.blur(container.querySelector('input.react-select__input')!);
+ expect(onBlurSpy).toHaveBeenCalledTimes(1);
+ },
+ {
+ 'single select > should call onBlur handler on blur on input': {},
+ 'multi select > should call onBlur handler on blur on input': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+test('onInputChange() function prop to be called on blur', () => {
+ let onInputChangeSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.blur(container.querySelector('input.react-select__input')!);
+ // Once by blur and other time by menu-close
+ expect(onInputChangeSpy).toHaveBeenCalledTimes(2);
+});
+
+test('onMenuClose() function prop to be called on blur', () => {
+ let onMenuCloseSpy = jest.fn();
+ let { container } = render(
+
+ );
+ fireEvent.blur(container.querySelector('input.react-select__input')!);
+ expect(onMenuCloseSpy).toHaveBeenCalledTimes(1);
+});
+
+cases(
+ 'placeholder',
+ ({ props, expectPlaceholder = 'Select...' }) => {
+ let { container } = render( );
+ expect(container.querySelector('.react-select__control')!.textContent).toBe(
+ expectPlaceholder
+ );
+ },
+ {
+ 'single select > should display default placeholder "Select..."': {
+ props: BASIC_PROPS,
+ },
+ 'single select > should display provided string placeholder': {
+ props: {
+ ...BASIC_PROPS,
+ placeholder: 'single Select...',
+ },
+ expectPlaceholder: 'single Select...',
+ },
+ 'single select > should display provided node placeholder': {
+ props: {
+ ...BASIC_PROPS,
+ placeholder: single Select... ,
+ },
+ expectPlaceholder: 'single Select...',
+ },
+ 'multi select > should display default placeholder "Select..."': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ 'multi select > should display provided placeholder': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ placeholder: 'multi Select...',
+ },
+ expectPlaceholder: 'multi Select...',
+ },
+ }
+);
+
+cases(
+ 'display placeholder once value is removed',
+ ({ props }) => {
+ let { container, rerender } = render( );
+ expect(
+ container.querySelector('.react-select__placeholder')
+ ).not.toBeInTheDocument();
+ rerender( );
+ expect(
+ container.querySelector('.react-select__placeholder')
+ ).toBeInTheDocument();
+ },
+ {
+ 'single select > should display placeholder once the value is removed from select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ value: OPTIONS[0],
+ },
+ },
+ 'multi select > should display placeholder once the value is removed from select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ value: OPTIONS[0],
+ },
+ },
+ }
+);
+
+test('sets inputMode="none" when isSearchable is false', () => {
+ let { container } = render(
+
+ );
+ let input = container.querySelector(
+ '.react-select__value-container input'
+ );
+ expect(input!.inputMode).toBe('none');
+ expect(
+ window.getComputedStyle(input!).getPropertyValue('caret-color')
+ ).toEqual('transparent');
+});
+
+cases(
+ 'clicking on disabled option',
+ ({ props = BASIC_PROPS, optionsSelected }) => {
+ let onChangeSpy = jest.fn();
+ props = { ...props, onChange: onChangeSpy };
+ let { container } = render( );
+ let selectOption = [
+ ...container.querySelectorAll('div.react-select__option'),
+ ].find((n) => n.textContent === optionsSelected);
+ userEvent.click(selectOption!);
+ expect(onChangeSpy).not.toHaveBeenCalled();
+ },
+ {
+ 'single select > should not select the disabled option': {
+ props: {
+ ...BASIC_PROPS,
+ options: [
+ { label: 'option 1', value: 'opt1' },
+ { label: 'option 2', value: 'opt2', isDisabled: true },
+ ],
+ },
+ optionsSelected: 'option 2',
+ },
+ 'multi select > should not select the disabled option': {
+ props: {
+ ...BASIC_PROPS,
+ options: [
+ { label: 'option 1', value: 'opt1' },
+ { label: 'option 2', value: 'opt2', isDisabled: true },
+ ],
+ },
+ optionsSelected: 'option 2',
+ },
+ }
+);
+
+cases(
+ 'pressing enter on disabled option',
+ ({ props = BASIC_PROPS, optionsSelected }) => {
+ let onChangeSpy = jest.fn();
+ props = { ...props, onChange: onChangeSpy };
+ let { container } = render( );
+ let selectOption = [
+ ...container.querySelectorAll('div.react-select__option'),
+ ].find((n) => n.textContent === optionsSelected);
+ fireEvent.keyDown(selectOption!, { keyCode: 13, key: 'Enter' });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+ },
+ {
+ 'single select > should not select the disabled option': {
+ props: {
+ ...BASIC_PROPS,
+ options: [
+ { label: 'option 1', value: 'opt1' },
+ { label: 'option 2', value: 'opt2', isDisabled: true },
+ ],
+ },
+ optionsSelected: 'option 2',
+ },
+ 'multi select > should not select the disabled option': {
+ props: {
+ ...BASIC_PROPS,
+ options: [
+ { label: 'option 1', value: 'opt1' },
+ { label: 'option 2', value: 'opt2', isDisabled: true },
+ ],
+ },
+ optionsSelected: 'option 2',
+ },
+ }
+);
+
+test('does not select anything when a disabled option is the only item in the list after a search', () => {
+ let onChangeSpy = jest.fn();
+ const options = [
+ { label: 'opt', value: 'opt1', isDisabled: true },
+ ...OPTIONS,
+ ];
+ const props = { ...BASIC_PROPS, onChange: onChangeSpy, options };
+ let { container, rerender } = render(
+
+ );
+ rerender( );
+
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+
+ expect(onChangeSpy).not.toHaveBeenCalled();
+ // Menu is still open
+ expect(container.querySelector('.react-select__option')!.textContent).toBe(
+ 'opt'
+ );
+});
+
+test('render custom Input Component', () => {
+ const InputComponent = () =>
;
+ let { container } = render(
+
+ );
+
+ expect(
+ container.querySelector('input.react-select__input')
+ ).not.toBeInTheDocument();
+ expect(container.querySelector('.my-input-component')).toBeInTheDocument();
+});
+
+test('render custom Menu Component', () => {
+ const MenuComponent = () =>
;
+ let { container } = render(
+
+ );
+
+ expect(
+ container.querySelector('.react-select__menu')
+ ).not.toBeInTheDocument();
+ expect(container.querySelector('.my-menu-component')).toBeInTheDocument();
+});
+
+test('render custom Option Component', () => {
+ const OptionComponent = () =>
;
+ let { container } = render(
+
+ );
+
+ expect(
+ container.querySelector('.react-select__option')
+ ).not.toBeInTheDocument();
+ expect(container.querySelector('.my-option-component')).toBeInTheDocument();
+});
+
+cases(
+ 'isClearable is false',
+ ({ props = BASIC_PROPS }) => {
+ let { container } = render( );
+ expect(
+ container.querySelector('react-select__clear-indicator')
+ ).not.toBeInTheDocument();
+ },
+ {
+ 'single select > should not show the X (clear) button': {
+ props: {
+ ...BASIC_PROPS,
+ isClearable: false,
+ value: OPTIONS[0],
+ },
+ },
+ 'multi select > should not show X (clear) button': {
+ ...BASIC_PROPS,
+ isMulti: true,
+ isClearable: false,
+ value: [OPTIONS[0]],
+ },
+ }
+);
+
+test('clear select by clicking on clear button > should not call onMenuOpen', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy };
+ let { container } = render(
+
+ );
+
+ expect(container.querySelectorAll('.react-select__multi-value').length).toBe(
+ 1
+ );
+ fireEvent.mouseDown(
+ container.querySelector('.react-select__clear-indicator')!,
+ { button: 0 }
+ );
+ expect(onChangeSpy).toBeCalledWith([], {
+ action: 'clear',
+ name: BASIC_PROPS.name,
+ removedValues: [{ label: '0', value: 'zero' }],
+ });
+});
+
+test('clearing select using clear button to not call onMenuOpen or onMenuClose', () => {
+ let onMenuCloseSpy = jest.fn();
+ let onMenuOpenSpy = jest.fn();
+ let props = {
+ ...BASIC_PROPS,
+ onMenuClose: onMenuCloseSpy,
+ onMenuOpen: onMenuOpenSpy,
+ };
+ let { container } = render(
+
+ );
+ expect(container.querySelectorAll('.react-select__multi-value').length).toBe(
+ 1
+ );
+ fireEvent.mouseDown(
+ container.querySelector('.react-select__clear-indicator')!,
+ { button: 0 }
+ );
+ expect(onMenuOpenSpy).not.toHaveBeenCalled();
+ expect(onMenuCloseSpy).not.toHaveBeenCalled();
+});
+
+test('multi select > calls onChange when option is selected and isSearchable is false', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy };
+ let { container } = render(
+
+ );
+ userEvent.click(container.querySelector('.react-select__option')!);
+ const selectedOption = { label: '0', value: 'zero' };
+ expect(onChangeSpy).toHaveBeenCalledWith([selectedOption], {
+ action: 'select-option',
+ option: selectedOption,
+ name: BASIC_PROPS.name,
+ });
+});
+
+test('getOptionLabel() prop > to format the option label', () => {
+ const getOptionLabel = (option: Option) =>
+ `This a custom option ${option.label} label`;
+ const { container } = render(
+
+ );
+ expect(container.querySelector('.react-select__option')!.textContent).toBe(
+ 'This a custom option 0 label'
+ );
+});
+
+test('formatGroupLabel function prop > to format Group label', () => {
+ const formatGroupLabel = (group: Group) =>
+ `This is custom ${group.label} header`;
+ interface GroupOption {
+ readonly value: number;
+ readonly label: string;
+ }
+ interface Group {
+ readonly label: string;
+ readonly options: readonly GroupOption[];
+ }
+ const options = [
+ {
+ label: 'group 1',
+ options: [
+ { value: 1, label: '1' },
+ { value: 2, label: '2' },
+ ],
+ },
+ ];
+ const { container } = render(
+
+ classNamePrefix="react-select"
+ options={options}
+ menuIsOpen
+ formatGroupLabel={formatGroupLabel}
+ onChange={noop}
+ onInputChange={noop}
+ onMenuOpen={noop}
+ onMenuClose={noop}
+ inputValue=""
+ value={null}
+ />
+ );
+ expect(
+ container.querySelector('.react-select__group-heading')!.textContent
+ ).toBe('This is custom group 1 header');
+});
+
+test('to only render groups with at least one match when filtering', () => {
+ const options = [
+ {
+ label: 'group 1',
+ options: [
+ { value: 1, label: '1' },
+ { value: 2, label: '2' },
+ ],
+ },
+ {
+ label: 'group 2',
+ options: [
+ { value: 3, label: '3' },
+ { value: 4, label: '4' },
+ ],
+ },
+ ];
+ const { container } = render(
+
+ );
+
+ expect(container.querySelectorAll('.react-select__group').length).toBe(1);
+ expect(
+ container
+ .querySelector('.react-select__group')!
+ .querySelectorAll('.react-select__option').length
+ ).toBe(1);
+});
+
+test('not render any groups when there is not a single match when filtering', () => {
+ const options = [
+ {
+ label: 'group 1',
+ options: [
+ { value: 1, label: '1' },
+ { value: 2, label: '2' },
+ ],
+ },
+ {
+ label: 'group 2',
+ options: [
+ { value: 3, label: '3' },
+ { value: 4, label: '4' },
+ ],
+ },
+ ];
+ const { container } = render(
+
+ );
+
+ expect(container.querySelectorAll('.react-select__group').length).toBe(0);
+});
+
+test('multi select > have default value delimiter seperated', () => {
+ let { container } = render(
+
+ );
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('zero;one');
+});
+
+test('multi select > with multi character delimiter', () => {
+ let { container } = render(
+
+ );
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('zero===&===one');
+});
+
+test('hitting spacebar should select option if isSearchable is false', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy };
+ let { container } = render( );
+ // focus the first option
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 32,
+ key: ' ',
+ });
+ expect(onChangeSpy).toHaveBeenCalledWith(
+ { label: '0', value: 'zero' },
+ { action: 'select-option', name: BASIC_PROPS.name }
+ );
+});
+
+test('hitting escape does not call onChange if menu is Open', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy };
+ let { container } = render(
+
+ );
+
+ // focus the first option
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 40,
+ key: 'ArrowDown',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('multi select > removes the selected option from the menu options when isSearchable is false', () => {
+ let { container, rerender } = render(
+
+ );
+ expect(container.querySelectorAll('.react-select__option').length).toBe(17);
+ rerender(
+
+ );
+ // expect '0' to not be options
+ container.querySelectorAll('.react-select__option').forEach((option) => {
+ expect(option.textContent).not.toBe('0');
+ });
+ expect(container.querySelectorAll('.react-select__option').length).toBe(16);
+});
+
+test('hitting ArrowUp key on closed select should focus last element', () => {
+ let { container } = render( );
+
+ fireEvent.keyDown(container.querySelector('.react-select__control')!, {
+ keyCode: 38,
+ key: 'ArrowUp',
+ });
+
+ expect(
+ container.querySelector('.react-select__option--is-focused')!.textContent
+ ).toEqual('16');
+});
+
+test('close menu on hitting escape and clear input value if menu is open even if escapeClearsValue and isClearable are true', () => {
+ let onMenuCloseSpy = jest.fn();
+ let onInputChangeSpy = jest.fn();
+ let props = {
+ ...BASIC_PROPS,
+ onInputChange: onInputChangeSpy,
+ onMenuClose: onMenuCloseSpy,
+ value: OPTIONS[0],
+ };
+ let { container } = render(
+
+ );
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(
+ container.querySelector('.react-select__single-value')!.textContent
+ ).toEqual('0');
+
+ expect(onMenuCloseSpy).toHaveBeenCalled();
+ // once by onMenuClose and other is direct
+ expect(onInputChangeSpy).toHaveBeenCalledTimes(2);
+ expect(onInputChangeSpy).toHaveBeenCalledWith('', {
+ action: 'menu-close',
+ prevInputValue: '',
+ });
+ expect(onInputChangeSpy).toHaveBeenLastCalledWith('', {
+ action: 'menu-close',
+ prevInputValue: '',
+ });
+});
+
+test('to not clear value when hitting escape if escapeClearsValue is false (default) and isClearable is false', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy, value: OPTIONS[0] };
+ let { container } = render(
+
+ );
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('to not clear value when hitting escape if escapeClearsValue is true and isClearable is false', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy, value: OPTIONS[0] };
+ let { container } = render(
+
+ );
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('to not clear value when hitting escape if escapeClearsValue is false (default) and isClearable is true', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy, value: OPTIONS[0] };
+ let { container } = render( );
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('to clear value when hitting escape if escapeClearsValue and isClearable are true', () => {
+ let onInputChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onInputChangeSpy, value: OPTIONS[0] };
+ let { container } = render(
+
+ );
+
+ fireEvent.keyDown(container.querySelector('.react-select')!, {
+ keyCode: 27,
+ key: 'Escape',
+ });
+ expect(onInputChangeSpy).toHaveBeenCalledWith(null, {
+ action: 'clear',
+ name: BASIC_PROPS.name,
+ removedValues: [{ label: '0', value: 'zero' }],
+ });
+});
+
+test('hitting spacebar should not select option if isSearchable is true (default)', () => {
+ let onChangeSpy = jest.fn();
+ let props = { ...BASIC_PROPS, onChange: onChangeSpy };
+ let { container } = render( );
+ // Open Menu
+ fireEvent.keyDown(container, { keyCode: 32, key: ' ' });
+ expect(onChangeSpy).not.toHaveBeenCalled();
+});
+
+test('renders with custom theme', () => {
+ const primary = 'rgb(255, 164, 83)';
+ const { container } = render(
+ ({
+ ...theme,
+ borderRadius: 180,
+ colors: {
+ ...theme.colors,
+ primary,
+ },
+ })}
+ />
+ );
+ const menu = container.querySelector('.react-select__menu');
+ expect(
+ window.getComputedStyle(menu!).getPropertyValue('border-radius')
+ ).toEqual('180px');
+ const firstOption = container.querySelector('.react-select__option');
+ expect(
+ window.getComputedStyle(firstOption!).getPropertyValue('background-color')
+ ).toEqual(primary);
+});
+
+cases(
+ '`required` prop',
+ ({ props = BASIC_PROPS }) => {
+ const components = (value: Option | null | undefined = null) => (
+
+ );
+
+ const { container, rerender } = render(components());
+
+ expect(
+ container.querySelector('#formTest')?.checkValidity()
+ ).toEqual(false);
+ rerender(components(props.options[0]));
+ expect(
+ container.querySelector('#formTest')?.checkValidity()
+ ).toEqual(true);
+ },
+ {
+ 'single select > should validate with value': {
+ props: {
+ ...BASIC_PROPS,
+ },
+ },
+ 'single select (isSearchable is false) > should validate with value': {
+ props: {
+ ...BASIC_PROPS,
+ isSearchable: false,
+ },
+ },
+ 'multi select > should validate with value': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
diff --git a/packages/react-select/src/__tests__/StateManaged.test.tsx b/packages/react-select/src/__tests__/StateManaged.test.tsx
new file mode 100644
index 0000000000..5cd67ccb16
--- /dev/null
+++ b/packages/react-select/src/__tests__/StateManaged.test.tsx
@@ -0,0 +1,497 @@
+import React from 'react';
+import { render, fireEvent, EventType } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+import cases from 'jest-in-case';
+
+import { Option, OPTIONS } from './constants';
+import Select from '../';
+
+function openMenu(container: HTMLElement) {
+ expect(
+ container.querySelector('.react-select__menu')
+ ).not.toBeInTheDocument();
+
+ toggleMenuOpen(container);
+
+ expect(container.querySelector('.react-select__menu')).toBeInTheDocument();
+}
+
+function toggleMenuOpen(container: HTMLElement) {
+ fireEvent.mouseDown(
+ container.querySelector('.react-select__dropdown-indicator')!,
+ { button: 0 }
+ );
+}
+
+function closeMenu(container: HTMLElement) {
+ expect(container.querySelector('.react-select__menu')).toBeInTheDocument();
+ toggleMenuOpen(container);
+ expect(
+ container.querySelector('.react-select__menu')
+ ).not.toBeInTheDocument();
+}
+
+interface BasicProps {
+ readonly className: string;
+ readonly classNamePrefix: string;
+ readonly onChange: () => void;
+ readonly onInputChange: () => void;
+ readonly onMenuClose: () => void;
+ readonly onMenuOpen: () => void;
+ readonly name: string;
+ readonly options: readonly Option[];
+}
+
+const BASIC_PROPS: BasicProps = {
+ className: 'react-select',
+ classNamePrefix: 'react-select',
+ onChange: jest.fn(),
+ onInputChange: jest.fn(),
+ onMenuClose: jest.fn(),
+ onMenuOpen: jest.fn(),
+ name: 'test-input-name',
+ options: OPTIONS,
+};
+
+test('defaults > snapshot', () => {
+ const { container } = render( );
+ expect(container).toMatchSnapshot();
+});
+
+test('passes down the className prop', () => {
+ const { container } = render( );
+ expect(container.querySelector('.react-select')).toBeTruthy();
+});
+
+cases(
+ 'click on dropdown indicator',
+ ({ props }) => {
+ let { container } = render( );
+ // Menu not open by default
+ expect(
+ container.querySelector('.react-select__menu')
+ ).not.toBeInTheDocument();
+ openMenu(container);
+ closeMenu(container);
+ },
+ {
+ 'single select > should toggle Menu': { props: BASIC_PROPS },
+ 'multi select > should toggle Menu': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ },
+ }
+);
+
+test('If menuIsOpen prop is passed Menu should not close on clicking Dropdown Indicator', () => {
+ const { container } = render( );
+ expect(container.querySelector('.react-select__menu')).toBeTruthy();
+
+ toggleMenuOpen(container);
+ expect(container.querySelector('.react-select__menu')).toBeTruthy();
+});
+
+test('defaultMenuIsOpen prop > should open by menu default and clicking on Dropdown Indicator should toggle menu', () => {
+ const { container } = render( );
+ expect(container.querySelector('.react-select__menu')).toBeTruthy();
+
+ toggleMenuOpen(container);
+ expect(container.querySelector('.react-select__menu')).toBeFalsy();
+});
+
+test('Menu is controllable by menuIsOpen prop', () => {
+ const menuClass = `.${BASIC_PROPS.classNamePrefix}__menu`;
+ const { container, rerender } = render( );
+ expect(container.querySelector(menuClass)).toBeFalsy();
+
+ rerender( );
+ expect(container.querySelector(menuClass)).toBeTruthy();
+
+ rerender( );
+ expect(container.querySelector(menuClass)).toBeFalsy();
+});
+
+interface MenuToOpenByDefaultOptsProps extends Partial {
+ readonly isMulti?: boolean;
+ readonly menuIsOpen?: boolean;
+}
+
+interface MenuToOpenByDefaultOpts {
+ readonly props?: MenuToOpenByDefaultOptsProps;
+}
+
+cases(
+ 'Menu to open by default if menuIsOpen prop is true',
+ ({ props }) => {
+ props = { ...BASIC_PROPS, ...props, menuIsOpen: true };
+ const menuClass = `.${BASIC_PROPS.classNamePrefix}__menu`;
+ const { container } = render( );
+ expect(container.querySelector(menuClass)).toBeTruthy();
+
+ userEvent.click(
+ container.querySelector('div.react-select__dropdown-indicator')!
+ );
+
+ expect(container.querySelector(menuClass)).toBeTruthy();
+ },
+ {
+ 'single select > should keep Menu open by default if true is passed for menuIsOpen prop':
+ {},
+ 'multi select > should keep Menu open by default if true is passed for menuIsOpen prop':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ menuIsOpen: true,
+ },
+ },
+ }
+);
+
+test('multi select > selecting multiple values', () => {
+ let { container } = render( );
+ openMenu(container);
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+ expect(container.querySelector('.react-select__control')!.textContent).toBe(
+ '0'
+ );
+
+ openMenu(container);
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+ expect(container.querySelector('.react-select__control')!.textContent).toBe(
+ '01'
+ );
+});
+
+test('defaultInputValue prop > should update the inputValue on change of input if defaultInputValue prop is provided', () => {
+ const props = { ...BASIC_PROPS, defaultInputValue: '0' };
+ let { container } = render( );
+ let input = container.querySelector(
+ '.react-select__control input'
+ );
+
+ expect(input!.value).toBe('0');
+ userEvent.type(input!, 'A');
+ expect(input!.value).toBe('0A');
+});
+
+test('inputValue prop > should not update the inputValue when on change of input if inputValue prop is provided', () => {
+ const props = { ...BASIC_PROPS, inputValue: '0' };
+ let { container } = render( );
+ let input = container.querySelector(
+ '.react-select__control input'
+ );
+ expect(input!.value).toBe('0');
+ userEvent.type(input!, 'A');
+ expect(input!.value).toBe('0');
+});
+
+test('defaultValue prop > should update the value on selecting option', () => {
+ const props = { ...BASIC_PROPS, defaultValue: [OPTIONS[0]] };
+ let { container } = render( );
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('zero');
+ userEvent.click(container.querySelectorAll('div.react-select__option')[1]);
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('one');
+});
+
+test('value prop > should not update the value on selecting option', () => {
+ const props = { ...BASIC_PROPS, value: [OPTIONS[0]] };
+ let { container } = render( );
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('zero');
+ userEvent.click(container.querySelectorAll('div.react-select__option')[1]);
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe('zero');
+});
+
+cases(
+ 'Integration tests > selecting an option > mouse interaction',
+ ({
+ props = { ...BASIC_PROPS },
+ event: [eventName, eventArgs],
+ selectOption,
+ expectSelectedOption,
+ }) => {
+ let { container, getByText } = render( );
+ let toSelectOption = getByText(selectOption.label);
+ fireEvent[eventName](toSelectOption, eventArgs);
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe(expectSelectedOption);
+ },
+ {
+ 'single select > clicking on an option > should select the clicked option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ menuIsOpen: true,
+ },
+ event: ['click' as const, { button: 0 }] as const,
+ selectOption: OPTIONS[2],
+ expectSelectedOption: 'two',
+ },
+ 'multi select > clicking on an option > should select the clicked option': {
+ props: {
+ ...BASIC_PROPS,
+ delimiter: ', ',
+ isMulti: true,
+ menuIsOpen: true,
+ },
+ event: ['click' as const, { button: 0 }] as const,
+ selectOption: OPTIONS[2],
+ expectSelectedOption: 'two',
+ },
+ }
+);
+
+interface KeyboardInteractionOptsProps extends BasicProps {
+ readonly isMulti?: boolean;
+}
+
+interface KeyboardInteractionOpts {
+ readonly props?: KeyboardInteractionOptsProps;
+ readonly eventsToSimulate: readonly [EventType, {}][];
+ readonly expectedSelectedOption: string;
+}
+
+cases(
+ 'Integration tests > selection an option > keyboard interaction',
+ ({
+ props = { ...BASIC_PROPS },
+ eventsToSimulate,
+ expectedSelectedOption,
+ }) => {
+ let { container } = render( );
+ openMenu(container);
+ eventsToSimulate.map(([eventName, eventArgs]) => {
+ fireEvent[eventName](
+ container.querySelector('.react-select__menu')!,
+ eventArgs
+ );
+ });
+ fireEvent.keyDown(container.querySelector('.react-select__menu')!, {
+ keyCode: 13,
+ key: 'Enter',
+ });
+ expect(
+ container.querySelector('input[type="hidden"]')!.value
+ ).toBe(expectedSelectedOption);
+ },
+ {
+ 'single select > open select and hit enter > should select first option': {
+ eventsToSimulate: [],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'single select > (open select -> 3 x ArrowDown -> Enter) > should select the forth option in the select':
+ {
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ],
+ expectedSelectedOption: OPTIONS[3].value,
+ },
+ 'single select > (open select -> 2 x ArrowDown -> 2 x ArrowUp -> Enter) > should select the first option in the select':
+ {
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 38, key: 'ArrowUp' }],
+ ['keyDown', { keyCode: 38, key: 'ArrowUp' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'single select > (open select -> 1 x ArrowUp -> Enter) > should select the last option in the select':
+ {
+ eventsToSimulate: [['keyDown', { keyCode: 38, key: 'ArrowUp' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ 'single select > (open select -> 1 x PageDown -> Enter) > should select the first option on next page - default pageSize 5':
+ {
+ eventsToSimulate: [['keyDown', { keyCode: 34, key: 'PageDown' }]],
+ expectedSelectedOption: OPTIONS[5].value,
+ },
+ 'single select > (open select -> 1 x PageDown -> 1 x ArrowDown -> 1 x PageUp -> Enter) > should select the second option - default pageSize 5':
+ {
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 33, key: 'PageUp' }],
+ ],
+ expectedSelectedOption: OPTIONS[1].value,
+ },
+ 'single select > (open select -> End -> Enter) > should select the last option':
+ {
+ eventsToSimulate: [['keyDown', { keyCode: 35, key: 'End' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ 'single select > (open select -> 3 x PageDown -> Home -> Enter) > should select the last option':
+ {
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 36, key: 'Home' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'single select > cycle options > ( open select -> End -> ArrowDown -> Enter) > should select the first option':
+ {
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 35, key: 'End' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'single select > cycle options > (open select -> ArrowUp -> Enter) > should select the last option':
+ {
+ eventsToSimulate: [['keyDown', { keyCode: 38, key: 'ArrowUp' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ 'multi select > open select and hit enter > should select first option': {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'multi select > (open select -> 3 x ArrowDown -> Enter) > should select the forth option in the select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ],
+ expectedSelectedOption: OPTIONS[3].value,
+ },
+ 'multi select > (open select -> 2 x ArrowDown -> 2 x ArrowUp -> Enter) > should select the first option in the select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 38, key: 'ArrowUp' }],
+ ['keyDown', { keyCode: 38, key: 'ArrowUp' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'multi select > (open select -> 1 x ArrowUp -> Enter) > should select the last option in the select':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [['keyDown', { keyCode: 38, key: 'ArrowUp' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ 'multi select > (open select -> 1 x PageDown -> Enter) > should select the first option on next page - default pageSize 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [['keyDown', { keyCode: 34, key: 'PageDown' }]],
+ expectedSelectedOption: OPTIONS[5].value,
+ },
+ 'multi select > (open select -> 1 x PageDown -> 1 x ArrowDown -> 1 x PageUp -> Enter) > should select the second option - default pageSize 5':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ['keyDown', { keyCode: 33, key: 'PageUp' }],
+ ],
+ expectedSelectedOption: OPTIONS[1].value,
+ },
+ 'multi select > (open select -> End -> Enter) > should select the last option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [['keyDown', { keyCode: 35, key: 'End' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ 'multi select > (open select -> 3 x PageDown -> Home -> Enter) > should select the last option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 34, key: 'PageDown' }],
+ ['keyDown', { keyCode: 36, key: 'Home' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'multi select > cycle options > ( open select -> End -> ArrowDown -> Enter) > should select the first option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [
+ ['keyDown', { keyCode: 35, key: 'End' }],
+ ['keyDown', { keyCode: 40, key: 'ArrowDown' }],
+ ],
+ expectedSelectedOption: OPTIONS[0].value,
+ },
+ 'multi select > cycle options > (open select -> ArrowUp -> Enter) > should select the last option':
+ {
+ props: {
+ ...BASIC_PROPS,
+ isMulti: true,
+ },
+ eventsToSimulate: [['keyDown', { keyCode: 38, key: 'ArrowUp' }]],
+ expectedSelectedOption: OPTIONS[OPTIONS.length - 1].value,
+ },
+ }
+);
+
+test('`required` prop > should validate', () => {
+ const { container } = render(
+
+ );
+
+ expect(
+ container.querySelector('#formTest')?.checkValidity()
+ ).toEqual(false);
+
+ let selectOption = container.querySelectorAll('div.react-select__option')[3];
+
+ userEvent.click(selectOption);
+
+ expect(
+ container.querySelector('#formTest')?.checkValidity()
+ ).toEqual(true);
+});
diff --git a/packages/react-select/src/__tests__/__snapshots__/Async.test.tsx.snap b/packages/react-select/src/__tests__/__snapshots__/Async.test.tsx.snap
new file mode 100644
index 0000000000..b304477288
--- /dev/null
+++ b/packages/react-select/src/__tests__/__snapshots__/Async.test.tsx.snap
@@ -0,0 +1,242 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`defaults - snapshot 1`] = `
+.emotion-0 {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.emotion-1 {
+ z-index: 9999;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ width: 1px;
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.emotion-3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: default;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ min-height: 38px;
+ outline: 0!important;
+ position: relative;
+ -webkit-transition: all 100ms;
+ transition: all 100ms;
+ background-color: hsl(0, 0%, 100%);
+ border-color: hsl(0, 0%, 80%);
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+}
+
+.emotion-3:hover {
+ border-color: hsl(0, 0%, 70%);
+}
+
+.emotion-4 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: grid;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-overflow-scrolling: touch;
+ position: relative;
+ overflow: hidden;
+ padding: 2px 8px;
+ box-sizing: border-box;
+}
+
+.emotion-5 {
+ grid-area: 1/1/2/3;
+ color: hsl(0, 0%, 50%);
+ margin-left: 2px;
+ margin-right: 2px;
+ box-sizing: border-box;
+}
+
+.emotion-6 {
+ visibility: visible;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: inline-grid;
+ grid-area: 1/1/2/3;
+ grid-template-columns: 0 min-content;
+ margin: 2px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+ color: hsl(0, 0%, 20%);
+ box-sizing: border-box;
+}
+
+.emotion-6:after {
+ content: attr(data-value) " ";
+ visibility: hidden;
+ white-space: pre;
+ grid-area: 1/2;
+ font: inherit;
+ min-width: 2px;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+}
+
+.emotion-7 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+}
+
+.emotion-8 {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ width: 1px;
+ background-color: hsl(0, 0%, 80%);
+ margin-bottom: 8px;
+ margin-top: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-transition: color 150ms;
+ transition: color 150ms;
+ color: hsl(0, 0%, 80%);
+ padding: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9:hover {
+ color: hsl(0, 0%, 60%);
+}
+
+.emotion-10 {
+ display: inline-block;
+ fill: currentColor;
+ line-height: 1;
+ stroke: currentColor;
+ stroke-width: 0;
+}
+
+
+`;
diff --git a/packages/react-select/src/__tests__/__snapshots__/AsyncCreatable.test.tsx.snap b/packages/react-select/src/__tests__/__snapshots__/AsyncCreatable.test.tsx.snap
new file mode 100644
index 0000000000..b304477288
--- /dev/null
+++ b/packages/react-select/src/__tests__/__snapshots__/AsyncCreatable.test.tsx.snap
@@ -0,0 +1,242 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`defaults - snapshot 1`] = `
+.emotion-0 {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.emotion-1 {
+ z-index: 9999;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ width: 1px;
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.emotion-3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: default;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ min-height: 38px;
+ outline: 0!important;
+ position: relative;
+ -webkit-transition: all 100ms;
+ transition: all 100ms;
+ background-color: hsl(0, 0%, 100%);
+ border-color: hsl(0, 0%, 80%);
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+}
+
+.emotion-3:hover {
+ border-color: hsl(0, 0%, 70%);
+}
+
+.emotion-4 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: grid;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-overflow-scrolling: touch;
+ position: relative;
+ overflow: hidden;
+ padding: 2px 8px;
+ box-sizing: border-box;
+}
+
+.emotion-5 {
+ grid-area: 1/1/2/3;
+ color: hsl(0, 0%, 50%);
+ margin-left: 2px;
+ margin-right: 2px;
+ box-sizing: border-box;
+}
+
+.emotion-6 {
+ visibility: visible;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: inline-grid;
+ grid-area: 1/1/2/3;
+ grid-template-columns: 0 min-content;
+ margin: 2px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+ color: hsl(0, 0%, 20%);
+ box-sizing: border-box;
+}
+
+.emotion-6:after {
+ content: attr(data-value) " ";
+ visibility: hidden;
+ white-space: pre;
+ grid-area: 1/2;
+ font: inherit;
+ min-width: 2px;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+}
+
+.emotion-7 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+}
+
+.emotion-8 {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ width: 1px;
+ background-color: hsl(0, 0%, 80%);
+ margin-bottom: 8px;
+ margin-top: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-transition: color 150ms;
+ transition: color 150ms;
+ color: hsl(0, 0%, 80%);
+ padding: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9:hover {
+ color: hsl(0, 0%, 60%);
+}
+
+.emotion-10 {
+ display: inline-block;
+ fill: currentColor;
+ line-height: 1;
+ stroke: currentColor;
+ stroke-width: 0;
+}
+
+
+`;
diff --git a/packages/react-select/src/__tests__/__snapshots__/Creatable.test.tsx.snap b/packages/react-select/src/__tests__/__snapshots__/Creatable.test.tsx.snap
new file mode 100644
index 0000000000..b304477288
--- /dev/null
+++ b/packages/react-select/src/__tests__/__snapshots__/Creatable.test.tsx.snap
@@ -0,0 +1,242 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`defaults - snapshot 1`] = `
+.emotion-0 {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.emotion-1 {
+ z-index: 9999;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ width: 1px;
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.emotion-3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: default;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ min-height: 38px;
+ outline: 0!important;
+ position: relative;
+ -webkit-transition: all 100ms;
+ transition: all 100ms;
+ background-color: hsl(0, 0%, 100%);
+ border-color: hsl(0, 0%, 80%);
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+}
+
+.emotion-3:hover {
+ border-color: hsl(0, 0%, 70%);
+}
+
+.emotion-4 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: grid;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-overflow-scrolling: touch;
+ position: relative;
+ overflow: hidden;
+ padding: 2px 8px;
+ box-sizing: border-box;
+}
+
+.emotion-5 {
+ grid-area: 1/1/2/3;
+ color: hsl(0, 0%, 50%);
+ margin-left: 2px;
+ margin-right: 2px;
+ box-sizing: border-box;
+}
+
+.emotion-6 {
+ visibility: visible;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: inline-grid;
+ grid-area: 1/1/2/3;
+ grid-template-columns: 0 min-content;
+ margin: 2px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+ color: hsl(0, 0%, 20%);
+ box-sizing: border-box;
+}
+
+.emotion-6:after {
+ content: attr(data-value) " ";
+ visibility: hidden;
+ white-space: pre;
+ grid-area: 1/2;
+ font: inherit;
+ min-width: 2px;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+}
+
+.emotion-7 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+}
+
+.emotion-8 {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ width: 1px;
+ background-color: hsl(0, 0%, 80%);
+ margin-bottom: 8px;
+ margin-top: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-transition: color 150ms;
+ transition: color 150ms;
+ color: hsl(0, 0%, 80%);
+ padding: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9:hover {
+ color: hsl(0, 0%, 60%);
+}
+
+.emotion-10 {
+ display: inline-block;
+ fill: currentColor;
+ line-height: 1;
+ stroke: currentColor;
+ stroke-width: 0;
+}
+
+
+`;
diff --git a/packages/react-select/src/__tests__/__snapshots__/Select.test.tsx.snap b/packages/react-select/src/__tests__/__snapshots__/Select.test.tsx.snap
new file mode 100644
index 0000000000..95d4fe295d
--- /dev/null
+++ b/packages/react-select/src/__tests__/__snapshots__/Select.test.tsx.snap
@@ -0,0 +1,242 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`snapshot - defaults 1`] = `
+.emotion-0 {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.emotion-1 {
+ z-index: 9999;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ width: 1px;
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.emotion-3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: default;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ min-height: 38px;
+ outline: 0!important;
+ position: relative;
+ -webkit-transition: all 100ms;
+ transition: all 100ms;
+ background-color: hsl(0, 0%, 100%);
+ border-color: hsl(0, 0%, 80%);
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+}
+
+.emotion-3:hover {
+ border-color: hsl(0, 0%, 70%);
+}
+
+.emotion-4 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: grid;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-overflow-scrolling: touch;
+ position: relative;
+ overflow: hidden;
+ padding: 2px 8px;
+ box-sizing: border-box;
+}
+
+.emotion-5 {
+ grid-area: 1/1/2/3;
+ color: hsl(0, 0%, 50%);
+ margin-left: 2px;
+ margin-right: 2px;
+ box-sizing: border-box;
+}
+
+.emotion-6 {
+ visibility: visible;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: inline-grid;
+ grid-area: 1/1/2/3;
+ grid-template-columns: 0 min-content;
+ margin: 2px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+ color: hsl(0, 0%, 20%);
+ box-sizing: border-box;
+}
+
+.emotion-6:after {
+ content: attr(data-value) " ";
+ visibility: hidden;
+ white-space: pre;
+ grid-area: 1/2;
+ font: inherit;
+ min-width: 2px;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+}
+
+.emotion-7 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+}
+
+.emotion-8 {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ width: 1px;
+ background-color: hsl(0, 0%, 80%);
+ margin-bottom: 8px;
+ margin-top: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-transition: color 150ms;
+ transition: color 150ms;
+ color: hsl(0, 0%, 80%);
+ padding: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9:hover {
+ color: hsl(0, 0%, 60%);
+}
+
+.emotion-10 {
+ display: inline-block;
+ fill: currentColor;
+ line-height: 1;
+ stroke: currentColor;
+ stroke-width: 0;
+}
+
+
+`;
diff --git a/packages/react-select/src/__tests__/__snapshots__/StateManaged.test.tsx.snap b/packages/react-select/src/__tests__/__snapshots__/StateManaged.test.tsx.snap
new file mode 100644
index 0000000000..66836e4a95
--- /dev/null
+++ b/packages/react-select/src/__tests__/__snapshots__/StateManaged.test.tsx.snap
@@ -0,0 +1,242 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`defaults > snapshot 1`] = `
+.emotion-0 {
+ position: relative;
+ box-sizing: border-box;
+}
+
+.emotion-1 {
+ z-index: 9999;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ width: 1px;
+ position: absolute;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.emotion-3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: default;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ justify-content: space-between;
+ min-height: 38px;
+ outline: 0!important;
+ position: relative;
+ -webkit-transition: all 100ms;
+ transition: all 100ms;
+ background-color: hsl(0, 0%, 100%);
+ border-color: hsl(0, 0%, 80%);
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+}
+
+.emotion-3:hover {
+ border-color: hsl(0, 0%, 70%);
+}
+
+.emotion-4 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: grid;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-flex-wrap: wrap;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-overflow-scrolling: touch;
+ position: relative;
+ overflow: hidden;
+ padding: 2px 8px;
+ box-sizing: border-box;
+}
+
+.emotion-5 {
+ grid-area: 1/1/2/3;
+ color: hsl(0, 0%, 50%);
+ margin-left: 2px;
+ margin-right: 2px;
+ box-sizing: border-box;
+}
+
+.emotion-6 {
+ visibility: visible;
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: inline-grid;
+ grid-area: 1/1/2/3;
+ grid-template-columns: 0 min-content;
+ margin: 2px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+ color: hsl(0, 0%, 20%);
+ box-sizing: border-box;
+}
+
+.emotion-6:after {
+ content: attr(data-value) " ";
+ visibility: hidden;
+ white-space: pre;
+ grid-area: 1/2;
+ font: inherit;
+ min-width: 2px;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+}
+
+.emotion-7 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-shrink: 0;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+ box-sizing: border-box;
+}
+
+.emotion-8 {
+ -webkit-align-self: stretch;
+ -ms-flex-item-align: stretch;
+ align-self: stretch;
+ width: 1px;
+ background-color: hsl(0, 0%, 80%);
+ margin-bottom: 8px;
+ margin-top: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-transition: color 150ms;
+ transition: color 150ms;
+ color: hsl(0, 0%, 80%);
+ padding: 8px;
+ box-sizing: border-box;
+}
+
+.emotion-9:hover {
+ color: hsl(0, 0%, 60%);
+}
+
+.emotion-10 {
+ display: inline-block;
+ fill: currentColor;
+ line-height: 1;
+ stroke: currentColor;
+ stroke-width: 0;
+}
+
+
+`;
diff --git a/packages/react-select/src/__tests__/constants.ts b/packages/react-select/src/__tests__/constants.ts
new file mode 100644
index 0000000000..7c4e1ca9f2
--- /dev/null
+++ b/packages/react-select/src/__tests__/constants.ts
@@ -0,0 +1,107 @@
+export interface Option {
+ readonly label: string;
+ readonly value: string;
+}
+
+export const OPTIONS: readonly Option[] = [
+ { label: '0', value: 'zero' },
+ { label: '1', value: 'one' },
+ { label: '2', value: 'two' },
+ { label: '3', value: 'three' },
+ { label: '4', value: 'four' },
+ { label: '5', value: 'five' },
+ { label: '6', value: 'six' },
+ { label: '7', value: 'seven' },
+ { label: '8', value: 'eight' },
+ { label: '9', value: 'nine' },
+ { label: '10', value: 'ten' },
+ { label: '11', value: 'eleven' },
+ { label: '12', value: 'twelve' },
+ { label: '13', value: 'thirteen' },
+ { label: '14', value: 'fourteen' },
+ { label: '15', value: 'fifteen' },
+ { label: '16', value: 'sixteen' },
+];
+
+export interface OptionDisabled {
+ readonly label: string;
+ readonly value: string;
+ readonly isDisabled?: boolean;
+}
+
+export const OPTIONS_DISABLED: readonly OptionDisabled[] = [
+ { label: '0', value: 'zero' },
+ { label: '1', value: 'one', isDisabled: true },
+ { label: '2', value: 'two' },
+ { label: '3', value: 'three' },
+ { label: '4', value: 'four' },
+ { label: '5', value: 'five' },
+ { label: '6', value: 'six' },
+ { label: '7', value: 'seven' },
+ { label: '8', value: 'eight' },
+ { label: '9', value: 'nine' },
+ { label: '10', value: 'ten' },
+ { label: '11', value: 'eleven' },
+ { label: '12', value: 'twelve' },
+ { label: '13', value: 'thirteen' },
+ { label: '14', value: 'fourteen' },
+ { label: '15', value: 'fifteen' },
+ { label: '16', value: 'sixteen' },
+];
+
+export interface OptionNumberValue {
+ readonly label: string;
+ readonly value: number;
+}
+
+export const OPTIONS_NUMBER_VALUE: readonly OptionNumberValue[] = [
+ { label: '0', value: 0 },
+ { label: '1', value: 1 },
+ { label: '2', value: 2 },
+ { label: '3', value: 3 },
+ { label: '4', value: 4 },
+ { label: '5', value: 5 },
+ { label: '6', value: 6 },
+ { label: '7', value: 7 },
+ { label: '8', value: 8 },
+ { label: '9', value: 9 },
+ { label: '10', value: 10 },
+];
+
+export interface OptionBooleanValue {
+ readonly label: string;
+ readonly value: boolean;
+}
+
+export const OPTIONS_BOOLEAN_VALUE: readonly OptionBooleanValue[] = [
+ { label: 'true', value: true },
+ { label: 'false', value: false },
+];
+
+export interface OptionAccented {
+ readonly label: string;
+ readonly value: string;
+}
+
+export const OPTIONS_ACCENTED: readonly OptionAccented[] = [
+ { label: 'school', value: 'en' },
+ { label: 'école', value: 'fr' },
+];
+
+export interface GroupedOption {
+ readonly label: string;
+ readonly options:
+ | readonly OptionNumberValue[]
+ | readonly OptionBooleanValue[];
+}
+
+export const OPTIONS_GROUPED: readonly GroupedOption[] = [
+ {
+ label: 'Numbers',
+ options: OPTIONS_NUMBER_VALUE,
+ },
+ {
+ label: 'Booleans',
+ options: OPTIONS_BOOLEAN_VALUE,
+ },
+];
diff --git a/packages/react-select/src/__tests__/tsconfig.json b/packages/react-select/src/__tests__/tsconfig.json
new file mode 100644
index 0000000000..9183baf05d
--- /dev/null
+++ b/packages/react-select/src/__tests__/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "commonjs",
+ "jsx": "react",
+ "noEmit": true,
+ "strict": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true
+ }
+}
diff --git a/packages/react-select/src/accessibility/helpers.ts b/packages/react-select/src/accessibility/helpers.ts
new file mode 100644
index 0000000000..9331e3e16b
--- /dev/null
+++ b/packages/react-select/src/accessibility/helpers.ts
@@ -0,0 +1,33 @@
+///
+
+function testPlatform(re: RegExp) {
+ return typeof window !== 'undefined' && window.navigator != null
+ ? re.test(
+ window.navigator['userAgentData']?.platform || window.navigator.platform
+ )
+ : false;
+}
+
+export function isIPhone() {
+ return testPlatform(/^iPhone/i);
+}
+
+export function isMac() {
+ return testPlatform(/^Mac/i);
+}
+
+export function isIPad() {
+ return (
+ testPlatform(/^iPad/i) ||
+ // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
+ (isMac() && navigator.maxTouchPoints > 1)
+ );
+}
+
+export function isIOS() {
+ return isIPhone() || isIPad();
+}
+
+export function isAppleDevice() {
+ return isMac() || isIOS();
+}
diff --git a/packages/react-select/src/accessibility/index.ts b/packages/react-select/src/accessibility/index.ts
new file mode 100644
index 0000000000..0a29be42c0
--- /dev/null
+++ b/packages/react-select/src/accessibility/index.ts
@@ -0,0 +1,188 @@
+import type { AriaAttributes } from 'react';
+import {
+ ActionMeta,
+ GroupBase,
+ InitialInputFocusedActionMeta,
+ OnChangeValue,
+ Options,
+ OptionsOrGroups,
+} from '../types';
+
+export type OptionContext = 'menu' | 'value';
+
+export type GuidanceContext = 'menu' | 'input' | 'value';
+
+export type AriaSelection =
+ | InitialInputFocusedActionMeta
+ | (ActionMeta & {
+ value: OnChangeValue ;
+ option?: Option;
+ options?: Options ;
+ });
+
+export interface AriaGuidanceProps {
+ /** String value of selectProp aria-label */
+ 'aria-label': AriaAttributes['aria-label'];
+ /** String indicating user's current context and available keyboard interactivity */
+ context: GuidanceContext;
+ /** Boolean value of selectProp isSearchable */
+ isSearchable: boolean;
+ /** Boolean value of selectProp isMulti */
+ isMulti: boolean;
+ /** Boolean value of selectProp isDisabled */
+ isDisabled: boolean | null;
+ /** Boolean value of selectProp tabSelectsValue */
+ tabSelectsValue: boolean;
+ /** Boolean value indicating if user focused the input for the first time */
+ isInitialFocus: boolean;
+}
+
+export type AriaOnChangeProps = AriaSelection<
+ Option,
+ IsMulti
+> & {
+ /** String derived label from selected or removed option/value */
+ label: string;
+ /** Array of labels derived from multiple selected or cleared options */
+ labels: string[];
+ /** Boolean indicating if the selected menu option is disabled */
+ isDisabled: boolean | null;
+};
+
+export interface AriaOnFilterProps {
+ /** String indicating current inputValue of the input */
+ inputValue: string;
+ /** String derived from selectProp screenReaderStatus */
+ resultsMessage: string;
+}
+
+export interface AriaOnFocusProps > {
+ /** String indicating whether the option was focused in the menu or as (multi-) value */
+ context: OptionContext;
+ /** Option that is being focused */
+ focused: Option;
+ /** Boolean indicating whether focused menu option has been disabled */
+ isDisabled: boolean;
+ /** Boolean indicating whether focused menu option is an already selected option */
+ isSelected: boolean;
+ /** String derived label from focused option/value */
+ label: string;
+ /** Options provided as props to Select used to determine indexing */
+ options: OptionsOrGroups ;
+ /** selected option(s) of the Select */
+ selectValue: Options ;
+ /** Boolean indicating whether user uses Apple device */
+ isAppleDevice: boolean;
+}
+
+export type AriaGuidance = (props: AriaGuidanceProps) => string;
+export type AriaOnChange = (
+ props: AriaOnChangeProps
+) => string;
+export type AriaOnFilter = (props: AriaOnFilterProps) => string;
+export type AriaOnFocus<
+ Option,
+ Group extends GroupBase = GroupBase
+> = (props: AriaOnFocusProps ) => string;
+
+export interface AriaLiveMessages<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ /** Guidance message used to convey component state and specific keyboard interactivity */
+ guidance?: (props: AriaGuidanceProps) => string;
+ /** OnChange message used to convey changes to value but also called when user selects disabled option */
+ onChange?: (props: AriaOnChangeProps ) => string;
+ /** OnFilter message used to convey information about filtered results displayed in the menu */
+ onFilter?: (props: AriaOnFilterProps) => string;
+ /** OnFocus message used to convey information about the currently focused option or value */
+ onFocus?: (props: AriaOnFocusProps ) => string;
+}
+
+export const defaultAriaLiveMessages = {
+ guidance: (props: AriaGuidanceProps) => {
+ const { isSearchable, isMulti, tabSelectsValue, context, isInitialFocus } =
+ props;
+ switch (context) {
+ case 'menu':
+ return `Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu${
+ tabSelectsValue
+ ? ', press Tab to select the option and exit the menu'
+ : ''
+ }.`;
+ case 'input':
+ return isInitialFocus
+ ? `${props['aria-label'] || 'Select'} is focused ${
+ isSearchable ? ',type to refine list' : ''
+ }, press Down to open the menu, ${
+ isMulti ? ' press left to focus selected values' : ''
+ }`
+ : '';
+ case 'value':
+ return 'Use left and right to toggle between focused values, press Backspace to remove the currently focused value';
+ default:
+ return '';
+ }
+ },
+
+ onChange: (
+ props: AriaOnChangeProps
+ ) => {
+ const { action, label = '', labels, isDisabled } = props;
+ switch (action) {
+ case 'deselect-option':
+ case 'pop-value':
+ case 'remove-value':
+ return `option ${label}, deselected.`;
+ case 'clear':
+ return 'All selected options have been cleared.';
+ case 'initial-input-focus':
+ return `option${labels.length > 1 ? 's' : ''} ${labels.join(
+ ','
+ )}, selected.`;
+ case 'select-option':
+ return isDisabled
+ ? `option ${label} is disabled. Select another option.`
+ : `option ${label}, selected.`;
+ default:
+ return '';
+ }
+ },
+
+ onFocus: >(
+ props: AriaOnFocusProps
+ ) => {
+ const {
+ context,
+ focused,
+ options,
+ label = '',
+ selectValue,
+ isDisabled,
+ isSelected,
+ isAppleDevice,
+ } = props;
+
+ const getArrayIndex = (arr: OptionsOrGroups , item: Option) =>
+ arr && arr.length ? `${arr.indexOf(item) + 1} of ${arr.length}` : '';
+
+ if (context === 'value' && selectValue) {
+ return `value ${label} focused, ${getArrayIndex(selectValue, focused)}.`;
+ }
+
+ if (context === 'menu' && isAppleDevice) {
+ const disabled = isDisabled ? ' disabled' : '';
+ const status = `${isSelected ? ' selected' : ''}${disabled}`;
+ return `${label}${status}, ${getArrayIndex(options, focused)}.`;
+ }
+ return '';
+ },
+
+ onFilter: (props: AriaOnFilterProps) => {
+ const { inputValue, resultsMessage } = props;
+ return `${resultsMessage}${
+ inputValue ? ' for search term ' + inputValue : ''
+ }.`;
+ },
+};
diff --git a/packages/react-select/src/animated/Input.tsx b/packages/react-select/src/animated/Input.tsx
new file mode 100644
index 0000000000..b96840cce9
--- /dev/null
+++ b/packages/react-select/src/animated/Input.tsx
@@ -0,0 +1,35 @@
+import * as React from 'react';
+import { ReactElement } from 'react';
+import { TransitionProps } from 'react-transition-group/Transition';
+import { InputProps } from '../components/Input';
+import { GroupBase } from '../types';
+
+export type InputComponent = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: InputProps
+) => ReactElement;
+
+export type AnimatedInputProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = InputProps & Partial;
+
+// strip transition props off before spreading onto select component
+const AnimatedInput = (WrappedComponent: InputComponent): InputComponent => {
+ return >({
+ in: inProp,
+ onExited,
+ appear,
+ enter,
+ exit,
+ ...props
+ }: AnimatedInputProps ) => (
+
+ );
+};
+
+export default AnimatedInput;
diff --git a/packages/react-select/src/animated/MultiValue.tsx b/packages/react-select/src/animated/MultiValue.tsx
new file mode 100644
index 0000000000..3a11c6b699
--- /dev/null
+++ b/packages/react-select/src/animated/MultiValue.tsx
@@ -0,0 +1,36 @@
+import * as React from 'react';
+import { ReactElement } from 'react';
+import { TransitionProps } from 'react-transition-group/Transition';
+import { MultiValueProps } from '../components/MultiValue';
+import { Collapse } from './transitions';
+import { GroupBase } from '../types';
+
+export type MultiValueComponent = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: MultiValueProps
+) => ReactElement;
+
+export type AnimatedMultiValueProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = MultiValueProps & Partial;
+
+// strip transition props off before spreading onto actual component
+
+const AnimatedMultiValue = (WrappedComponent: MultiValueComponent) => {
+ return >({
+ in: inProp,
+ onExited,
+ ...props
+ }: AnimatedMultiValueProps ) => (
+
+
+
+ );
+};
+
+export default AnimatedMultiValue;
diff --git a/packages/react-select/src/animated/Placeholder.tsx b/packages/react-select/src/animated/Placeholder.tsx
new file mode 100644
index 0000000000..885ca3ea19
--- /dev/null
+++ b/packages/react-select/src/animated/Placeholder.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react';
+import { ReactElement } from 'react';
+import { PlaceholderProps } from '../components/Placeholder';
+import { Fade, collapseDuration } from './transitions';
+import { GroupBase } from '../types';
+
+export type PlaceholderComponent = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: PlaceholderProps
+) => ReactElement;
+
+// fade in when last multi-value removed, otherwise instant
+const AnimatedPlaceholder =
+ (WrappedComponent: PlaceholderComponent) =>
+ >(
+ props: PlaceholderProps
+ ) =>
+ (
+ >
+ component={WrappedComponent}
+ duration={props.isMulti ? collapseDuration : 1}
+ {...props}
+ />
+ );
+
+export default AnimatedPlaceholder;
diff --git a/packages/react-select/src/animated/SingleValue.tsx b/packages/react-select/src/animated/SingleValue.tsx
new file mode 100644
index 0000000000..f1095d9b59
--- /dev/null
+++ b/packages/react-select/src/animated/SingleValue.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react';
+import { ReactElement } from 'react';
+import { SingleValueProps } from '../components/SingleValue';
+import { Fade } from './transitions';
+import { GroupBase } from '../types';
+
+export type SingleValueComponent = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: SingleValueProps
+) => ReactElement;
+
+// instant fade; all transition-group children must be transitions
+
+const AnimatedSingleValue =
+ (WrappedComponent: SingleValueComponent) =>
+ >(
+ props: SingleValueProps
+ ) =>
+ (
+ >
+ component={WrappedComponent}
+ {...props}
+ />
+ );
+
+export default AnimatedSingleValue;
diff --git a/packages/react-select/src/animated/ValueContainer.tsx b/packages/react-select/src/animated/ValueContainer.tsx
new file mode 100644
index 0000000000..167e41f560
--- /dev/null
+++ b/packages/react-select/src/animated/ValueContainer.tsx
@@ -0,0 +1,103 @@
+import * as React from 'react';
+import { useEffect, useState, ReactElement, ReactNode } from 'react';
+import { TransitionGroup } from 'react-transition-group';
+import { ValueContainerProps } from '../components/containers';
+import { GroupBase } from '../types';
+
+export type ValueContainerComponent = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: ValueContainerProps
+) => ReactElement;
+
+interface IsMultiValueContainerProps extends ValueContainerProps {
+ component: ValueContainerComponent;
+}
+
+// make ValueContainer a transition group
+const AnimatedValueContainer =
+ (WrappedComponent: ValueContainerComponent) =>
+ >(
+ props: ValueContainerProps
+ ) =>
+ props.isMulti ? (
+
+ ) : (
+
+ );
+
+const IsMultiValueContainer = ({
+ component,
+ ...restProps
+}: IsMultiValueContainerProps) => {
+ const multiProps = useIsMultiValueContainer(restProps);
+
+ return ;
+};
+
+const useIsMultiValueContainer = ({
+ children,
+ ...props
+}: ValueContainerProps) => {
+ const {
+ isMulti,
+ hasValue,
+ innerProps,
+ selectProps: { components, controlShouldRenderValue },
+ } = props;
+
+ const [cssDisplayFlex, setCssDisplayFlex] = useState(
+ isMulti && controlShouldRenderValue && hasValue
+ );
+ const [removingValue, setRemovingValue] = useState(false);
+
+ useEffect(() => {
+ if (hasValue && !cssDisplayFlex) {
+ setCssDisplayFlex(true);
+ }
+ }, [hasValue, cssDisplayFlex]);
+
+ useEffect(() => {
+ if (removingValue && !hasValue && cssDisplayFlex) {
+ setCssDisplayFlex(false);
+ }
+ setRemovingValue(false);
+ }, [removingValue, hasValue, cssDisplayFlex]);
+
+ const onExited = () => setRemovingValue(true);
+
+ const childMapper = (child: ReactNode) => {
+ if (isMulti && React.isValidElement(child)) {
+ // Add onExited callback to MultiValues
+ if (child.type === components.MultiValue) {
+ return React.cloneElement(child, { onExited });
+ }
+ // While container flexed, Input cursor is shown after Placeholder text,
+ // so remove Placeholder until display is set back to grid
+ if (child.type === components.Placeholder && cssDisplayFlex) {
+ return null;
+ }
+ }
+ return child;
+ };
+
+ const newInnerProps = {
+ ...innerProps,
+ style: {
+ ...innerProps?.style,
+ display: (isMulti && hasValue) || cssDisplayFlex ? 'flex' : 'grid',
+ },
+ };
+
+ const newProps = {
+ ...props,
+ innerProps: newInnerProps,
+ children: React.Children.toArray(children).map(childMapper),
+ };
+
+ return newProps;
+};
+
+export default AnimatedValueContainer;
diff --git a/packages/react-select/src/animated/index.ts b/packages/react-select/src/animated/index.ts
new file mode 100644
index 0000000000..f54bd77049
--- /dev/null
+++ b/packages/react-select/src/animated/index.ts
@@ -0,0 +1,42 @@
+import memoize from 'memoize-one';
+import {
+ defaultComponents,
+ SelectComponentsGeneric,
+} from '../components/index';
+import { default as AnimatedInput } from './Input';
+import { default as AnimatedMultiValue } from './MultiValue';
+import { default as AnimatedPlaceholder } from './Placeholder';
+import { default as AnimatedSingleValue } from './SingleValue';
+import { default as AnimatedValueContainer } from './ValueContainer';
+
+const makeAnimated = (
+ externalComponents: Partial = {}
+): Partial => {
+ const components = defaultComponents({ components: externalComponents });
+ const {
+ Input,
+ MultiValue,
+ Placeholder,
+ SingleValue,
+ ValueContainer,
+ ...rest
+ } = components;
+ return {
+ Input: AnimatedInput(Input),
+ MultiValue: AnimatedMultiValue(MultiValue),
+ Placeholder: AnimatedPlaceholder(Placeholder),
+ SingleValue: AnimatedSingleValue(SingleValue),
+ ValueContainer: AnimatedValueContainer(ValueContainer),
+ ...rest,
+ };
+};
+
+const AnimatedComponents = makeAnimated();
+
+export const Input = AnimatedComponents.Input;
+export const MultiValue = AnimatedComponents.MultiValue;
+export const Placeholder = AnimatedComponents.Placeholder;
+export const SingleValue = AnimatedComponents.SingleValue;
+export const ValueContainer = AnimatedComponents.ValueContainer;
+
+export default memoize(makeAnimated);
diff --git a/packages/react-select/src/animated/transitions.tsx b/packages/react-select/src/animated/transitions.tsx
new file mode 100644
index 0000000000..d7742cef68
--- /dev/null
+++ b/packages/react-select/src/animated/transitions.tsx
@@ -0,0 +1,134 @@
+import * as React from 'react';
+import { useEffect, useState } from 'react';
+import { ComponentType, CSSProperties, ReactNode, useRef } from 'react';
+import { Transition } from 'react-transition-group';
+import {
+ ExitHandler,
+ TransitionStatus,
+} from 'react-transition-group/Transition';
+
+// ==============================
+// Fade Transition
+// ==============================
+
+type FadeProps = {
+ component: ComponentType;
+ in?: boolean;
+ onExited?: ExitHandler;
+ duration?: number;
+} & ComponentProps;
+export const Fade = ({
+ component: Tag,
+ duration = 1,
+ in: inProp,
+ onExited,
+ ...props
+}: FadeProps) => {
+ const nodeRef = useRef(null);
+
+ const transition: { [K in TransitionStatus]?: CSSProperties } = {
+ entering: { opacity: 0 },
+ entered: { opacity: 1, transition: `opacity ${duration}ms` },
+ exiting: { opacity: 0 },
+ exited: { opacity: 0 },
+ };
+
+ return (
+
+ {(state) => {
+ const innerProps = {
+ style: {
+ ...transition[state],
+ },
+ ref: nodeRef,
+ };
+ return ;
+ }}
+
+ );
+};
+
+// ==============================
+// Collapse Transition
+// ==============================
+
+export const collapseDuration = 260;
+
+type Width = number | 'auto';
+interface CollapseProps {
+ children: ReactNode;
+ in?: boolean;
+ onExited?: ExitHandler;
+}
+
+// wrap each MultiValue with a collapse transition; decreases width until
+// finally removing from DOM
+export const Collapse = ({ children, in: _in, onExited }: CollapseProps) => {
+ const ref = useRef(null);
+ const [width, setWidth] = useState('auto');
+
+ useEffect(() => {
+ const el = ref.current;
+ if (!el) return;
+
+ /*
+ Here we're invoking requestAnimationFrame with a callback invoking our
+ call to getBoundingClientRect and setState in order to resolve an edge case
+ around portalling. Certain portalling solutions briefly remove children from the DOM
+ before appending them to the target node. This is to avoid us trying to call getBoundingClientrect
+ while the Select component is in this state.
+ */
+ // cannot use `offsetWidth` because it is rounded
+ const rafId = window.requestAnimationFrame(() =>
+ setWidth(el.getBoundingClientRect().width)
+ );
+
+ return () => window.cancelAnimationFrame(rafId);
+ }, []);
+
+ const getStyleFromStatus = (status: TransitionStatus) => {
+ switch (status) {
+ default:
+ return { width };
+ case 'exiting':
+ return { width: 0, transition: `width ${collapseDuration}ms ease-out` };
+ case 'exited':
+ return { width: 0 };
+ }
+ };
+
+ return (
+ {
+ const el = ref.current;
+ if (!el) return;
+ onExited?.(el);
+ }}
+ timeout={collapseDuration}
+ nodeRef={ref}
+ >
+ {(status) => (
+
+ {children}
+
+ )}
+
+ );
+};
diff --git a/packages/react-select/src/async-creatable/index.ts b/packages/react-select/src/async-creatable/index.ts
new file mode 100644
index 0000000000..76ef9d9ee5
--- /dev/null
+++ b/packages/react-select/src/async-creatable/index.ts
@@ -0,0 +1,2 @@
+export * from '../AsyncCreatable';
+export { default } from '../AsyncCreatable';
diff --git a/packages/react-select/src/async/index.ts b/packages/react-select/src/async/index.ts
new file mode 100644
index 0000000000..260c255b2c
--- /dev/null
+++ b/packages/react-select/src/async/index.ts
@@ -0,0 +1,2 @@
+export * from '../Async';
+export { default } from '../Async';
diff --git a/packages/react-select/src/base/index.ts b/packages/react-select/src/base/index.ts
new file mode 100644
index 0000000000..7192f7dda0
--- /dev/null
+++ b/packages/react-select/src/base/index.ts
@@ -0,0 +1,2 @@
+export * from '../Select';
+export { default } from '../Select';
diff --git a/packages/react-select/src/builtins.ts b/packages/react-select/src/builtins.ts
new file mode 100644
index 0000000000..4d6ce23e47
--- /dev/null
+++ b/packages/react-select/src/builtins.ts
@@ -0,0 +1,14 @@
+import { GroupBase } from './types';
+
+export const formatGroupLabel = >(
+ group: Group
+): string => group.label as string;
+
+export const getOptionLabel = (option: Option): string =>
+ (option as { label?: unknown }).label as string;
+
+export const getOptionValue = (option: Option): string =>
+ (option as { value?: unknown }).value as string;
+
+export const isOptionDisabled = (option: Option): boolean =>
+ !!(option as { isDisabled?: unknown }).isDisabled;
diff --git a/packages/react-select/src/components/Control.tsx b/packages/react-select/src/components/Control.tsx
new file mode 100644
index 0000000000..c394a6a805
--- /dev/null
+++ b/packages/react-select/src/components/Control.tsx
@@ -0,0 +1,97 @@
+/** @jsx jsx */
+import { JSX, ReactNode, Ref } from 'react';
+import { jsx } from '@emotion/react';
+
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+export interface ControlProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** Children to render. */
+ children: ReactNode;
+ innerRef: Ref;
+ /** The mouse down event and the innerRef to pass down to the controller element. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** Whether the select is disabled. */
+ isDisabled: boolean;
+ /** Whether the select is focused. */
+ isFocused: boolean;
+ /** Whether the select is expanded. */
+ menuIsOpen: boolean;
+}
+
+export const css = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isDisabled,
+ isFocused,
+ theme: { colors, borderRadius, spacing },
+ }: ControlProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'control',
+ alignItems: 'center',
+ cursor: 'default',
+ display: 'flex',
+ flexWrap: 'wrap',
+ justifyContent: 'space-between',
+ minHeight: spacing.controlHeight,
+ outline: '0 !important',
+ position: 'relative',
+ transition: 'all 100ms',
+ ...(unstyled
+ ? {}
+ : {
+ backgroundColor: isDisabled ? colors.neutral5 : colors.neutral0,
+ borderColor: isDisabled
+ ? colors.neutral10
+ : isFocused
+ ? colors.primary
+ : colors.neutral20,
+ borderRadius: borderRadius,
+ borderStyle: 'solid',
+ borderWidth: 1,
+ boxShadow: isFocused ? `0 0 0 1px ${colors.primary}` : undefined,
+ '&:hover': {
+ borderColor: isFocused ? colors.primary : colors.neutral30,
+ },
+ }),
+});
+
+const Control = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: ControlProps
+) => {
+ const { children, isDisabled, isFocused, innerRef, innerProps, menuIsOpen } =
+ props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default Control;
diff --git a/packages/react-select/src/components/Group.tsx b/packages/react-select/src/components/Group.tsx
new file mode 100644
index 0000000000..aa8e67b556
--- /dev/null
+++ b/packages/react-select/src/components/Group.tsx
@@ -0,0 +1,157 @@
+/** @jsx jsx */
+import { ComponentType, JSX, ReactNode } from 'react';
+import { jsx } from '@emotion/react';
+import { cleanCommonProps, getStyleProps } from '../utils';
+
+import {
+ CommonProps,
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ CX,
+ GetStyles,
+ GroupBase,
+ Options,
+ Theme,
+} from '../types';
+import { Props } from '../Select';
+
+export interface ForwardedHeadingProps<
+ Option,
+ Group extends GroupBase
+> {
+ id: string;
+ data: Group;
+}
+
+export interface GroupProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Component to wrap the label, receives headingProps. */
+ Heading: ComponentType>;
+ /** Props to pass to Heading. */
+ headingProps: ForwardedHeadingProps;
+ /** Props to be passed to the group element. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** Label to be displayed in the heading component. */
+ label: ReactNode;
+ /** The data of the group. */
+ data: Group;
+ options: Options ;
+}
+
+export const groupCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ { theme: { spacing } }: GroupProps ,
+ unstyled: boolean
+): CSSObjectWithLabel =>
+ unstyled
+ ? {}
+ : {
+ paddingBottom: spacing.baseUnit * 2,
+ paddingTop: spacing.baseUnit * 2,
+ };
+
+const Group = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: GroupProps
+) => {
+ const {
+ children,
+ cx,
+ getStyles,
+ getClassNames,
+ Heading,
+ headingProps,
+ innerProps,
+ label,
+ theme,
+ selectProps,
+ } = props;
+ return (
+
+
+ {label}
+
+
{children}
+
+ );
+};
+
+interface GroupHeadingPropsDefinedProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends ForwardedHeadingProps {
+ className?: string | undefined;
+ selectProps: Props ;
+ theme: Theme;
+ getStyles: GetStyles ;
+ getClassNames: CommonProps ['getClassNames'];
+ cx: CX;
+}
+
+export type GroupHeadingProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> = GroupHeadingPropsDefinedProps &
+ JSX.IntrinsicElements['div'];
+
+export const groupHeadingCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ { theme: { colors, spacing } }: GroupHeadingProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'group',
+ cursor: 'default',
+ display: 'block',
+ ...(unstyled
+ ? {}
+ : {
+ color: colors.neutral40,
+ fontSize: '75%',
+ fontWeight: 500,
+ marginBottom: '0.25em',
+ paddingLeft: spacing.baseUnit * 3,
+ paddingRight: spacing.baseUnit * 3,
+ textTransform: 'uppercase',
+ }),
+});
+
+export const GroupHeading = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: GroupHeadingProps
+) => {
+ const { data, ...innerProps } = cleanCommonProps(props);
+ return (
+
+ );
+};
+
+export default Group;
diff --git a/packages/react-select/src/components/Input.tsx b/packages/react-select/src/components/Input.tsx
new file mode 100644
index 0000000000..0d57982e80
--- /dev/null
+++ b/packages/react-select/src/components/Input.tsx
@@ -0,0 +1,122 @@
+/** @jsx jsx */
+import { InputHTMLAttributes } from 'react';
+import { jsx } from '@emotion/react';
+
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { cleanCommonProps, getStyleProps } from '../utils';
+
+export interface InputSpecificProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends InputHTMLAttributes,
+ CommonPropsAndClassName {
+ /** Reference to the internal element */
+ innerRef?: (instance: HTMLInputElement | null) => void;
+ /** Set whether the input should be visible. Does not affect input size. */
+ isHidden: boolean;
+ /** Whether the input is disabled */
+ isDisabled?: boolean;
+ /** The ID of the form that the input belongs to */
+ form?: string;
+ /** Set className for the input element */
+ inputClassName?: string;
+}
+
+export type InputProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> = InputSpecificProps ;
+
+export const inputCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isDisabled,
+ value,
+ theme: { spacing, colors },
+ }: InputProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ visibility: isDisabled ? 'hidden' : 'visible',
+ // force css to recompute when value change due to @emotion bug.
+ // We can remove it whenever the bug is fixed.
+ transform: value ? 'translateZ(0)' : '',
+ ...containerStyle,
+ ...(unstyled
+ ? {}
+ : {
+ margin: spacing.baseUnit / 2,
+ paddingBottom: spacing.baseUnit / 2,
+ paddingTop: spacing.baseUnit / 2,
+ color: colors.neutral80,
+ }),
+});
+
+const spacingStyle = {
+ gridArea: '1 / 2',
+ font: 'inherit',
+ minWidth: '2px',
+ border: 0,
+ margin: 0,
+ outline: 0,
+ padding: 0,
+} as const;
+
+const containerStyle = {
+ flex: '1 1 auto',
+ display: 'inline-grid',
+ gridArea: '1 / 1 / 2 / 3',
+ gridTemplateColumns: '0 min-content',
+
+ '&:after': {
+ content: 'attr(data-value) " "',
+ visibility: 'hidden',
+ whiteSpace: 'pre',
+ ...spacingStyle,
+ },
+} as const;
+
+const inputStyle = (isHidden: boolean) => ({
+ label: 'input',
+ color: 'inherit',
+ background: 0,
+ opacity: isHidden ? 0 : 1,
+ width: '100%',
+ ...spacingStyle,
+});
+
+const Input = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: InputProps
+) => {
+ const { cx, value } = props;
+ const { innerRef, isDisabled, isHidden, inputClassName, ...innerProps } =
+ cleanCommonProps(props);
+ return (
+
+
+
+ );
+};
+
+export default Input;
diff --git a/packages/react-select/src/components/LiveRegion.tsx b/packages/react-select/src/components/LiveRegion.tsx
new file mode 100644
index 0000000000..463fe01fc5
--- /dev/null
+++ b/packages/react-select/src/components/LiveRegion.tsx
@@ -0,0 +1,225 @@
+/** @jsx jsx */
+import { Fragment, ReactNode, useMemo } from 'react';
+import { jsx } from '@emotion/react';
+import A11yText from '../internal/A11yText';
+import { defaultAriaLiveMessages, AriaSelection } from '../accessibility';
+
+import { CommonProps, GroupBase, OnChangeValue, Options } from '../types';
+
+// ==============================
+// Root Container
+// ==============================
+
+export interface LiveRegionProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends CommonProps {
+ children: ReactNode;
+ innerProps: { className?: string };
+ // Select state variables
+ ariaSelection: AriaSelection ;
+ focusedOption: Option | null;
+ focusedValue: Option | null;
+ selectValue: Options ;
+ focusableOptions: Options ;
+ isFocused: boolean;
+ id: string;
+ isAppleDevice: boolean;
+}
+
+const LiveRegion = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: LiveRegionProps
+) => {
+ const {
+ ariaSelection,
+ focusedOption,
+ focusedValue,
+ focusableOptions,
+ isFocused,
+ selectValue,
+ selectProps,
+ id,
+ isAppleDevice,
+ } = props;
+
+ const {
+ ariaLiveMessages,
+ getOptionLabel,
+ inputValue,
+ isMulti,
+ isOptionDisabled,
+ isSearchable,
+ menuIsOpen,
+ options,
+ screenReaderStatus,
+ tabSelectsValue,
+ isLoading,
+ } = selectProps;
+ const ariaLabel = selectProps['aria-label'];
+ const ariaLive = selectProps['aria-live'];
+
+ // Update aria live message configuration when prop changes
+ const messages = useMemo(
+ () => ({
+ ...defaultAriaLiveMessages,
+ ...(ariaLiveMessages || {}),
+ }),
+ [ariaLiveMessages]
+ );
+
+ // Update aria live selected option when prop changes
+ const ariaSelected = useMemo(() => {
+ let message = '';
+ if (ariaSelection && messages.onChange) {
+ const {
+ option,
+ options: selectedOptions,
+ removedValue,
+ removedValues,
+ value,
+ } = ariaSelection;
+ // select-option when !isMulti does not return option so we assume selected option is value
+ const asOption = (val: OnChangeValue ): Option | null =>
+ !Array.isArray(val) ? (val as Option) : null;
+
+ // If there is just one item from the action then get its label
+ const selected = removedValue || option || asOption(value);
+ const label = selected ? getOptionLabel(selected) : '';
+
+ // If there are multiple items from the action then return an array of labels
+ const multiSelected = selectedOptions || removedValues || undefined;
+ const labels = multiSelected ? multiSelected.map(getOptionLabel) : [];
+
+ const onChangeProps = {
+ // multiSelected items are usually items that have already been selected
+ // or set by the user as a default value so we assume they are not disabled
+ isDisabled: selected && isOptionDisabled(selected, selectValue),
+ label,
+ labels,
+ ...ariaSelection,
+ };
+
+ message = messages.onChange(onChangeProps);
+ }
+ return message;
+ }, [ariaSelection, messages, isOptionDisabled, selectValue, getOptionLabel]);
+
+ const ariaFocused = useMemo(() => {
+ let focusMsg = '';
+ const focused = focusedOption || focusedValue;
+ const isSelected = !!(
+ focusedOption &&
+ selectValue &&
+ selectValue.includes(focusedOption)
+ );
+
+ if (focused && messages.onFocus) {
+ const onFocusProps = {
+ focused,
+ label: getOptionLabel(focused),
+ isDisabled: isOptionDisabled(focused, selectValue),
+ isSelected,
+ options: focusableOptions,
+ context:
+ focused === focusedOption ? ('menu' as const) : ('value' as const),
+ selectValue,
+ isAppleDevice,
+ };
+
+ focusMsg = messages.onFocus(onFocusProps);
+ }
+ return focusMsg;
+ }, [
+ focusedOption,
+ focusedValue,
+ getOptionLabel,
+ isOptionDisabled,
+ messages,
+ focusableOptions,
+ selectValue,
+ isAppleDevice,
+ ]);
+
+ const ariaResults = useMemo(() => {
+ let resultsMsg = '';
+ if (menuIsOpen && options.length && !isLoading && messages.onFilter) {
+ const resultsMessage = screenReaderStatus({
+ count: focusableOptions.length,
+ });
+ resultsMsg = messages.onFilter({ inputValue, resultsMessage });
+ }
+ return resultsMsg;
+ }, [
+ focusableOptions,
+ inputValue,
+ menuIsOpen,
+ messages,
+ options,
+ screenReaderStatus,
+ isLoading,
+ ]);
+
+ const isInitialFocus = ariaSelection?.action === 'initial-input-focus';
+
+ const ariaGuidance = useMemo(() => {
+ let guidanceMsg = '';
+ if (messages.guidance) {
+ const context = focusedValue ? 'value' : menuIsOpen ? 'menu' : 'input';
+ guidanceMsg = messages.guidance({
+ 'aria-label': ariaLabel,
+ context,
+ isDisabled:
+ focusedOption && isOptionDisabled(focusedOption, selectValue),
+ isMulti,
+ isSearchable,
+ tabSelectsValue,
+ isInitialFocus,
+ });
+ }
+ return guidanceMsg;
+ }, [
+ ariaLabel,
+ focusedOption,
+ focusedValue,
+ isMulti,
+ isOptionDisabled,
+ isSearchable,
+ menuIsOpen,
+ messages,
+ selectValue,
+ tabSelectsValue,
+ isInitialFocus,
+ ]);
+
+ const ScreenReaderText = (
+
+ {ariaSelected}
+ {ariaFocused}
+ {ariaResults}
+ {ariaGuidance}
+
+ );
+
+ return (
+
+ {/* We use 'aria-describedby' linked to this component for the initial focus */}
+ {/* action, then for all other actions we use the live region below */}
+ {isInitialFocus && ScreenReaderText}
+
+ {isFocused && !isInitialFocus && ScreenReaderText}
+
+
+ );
+};
+
+export default LiveRegion;
diff --git a/packages/react-select/src/components/Menu.tsx b/packages/react-select/src/components/Menu.tsx
new file mode 100644
index 0000000000..46c310774b
--- /dev/null
+++ b/packages/react-select/src/components/Menu.tsx
@@ -0,0 +1,705 @@
+/** @jsx jsx */
+import {
+ createContext,
+ JSX,
+ ReactElement,
+ ReactNode,
+ Ref,
+ useCallback,
+ useContext,
+ useMemo,
+ useRef,
+ useState,
+} from 'react';
+import { jsx } from '@emotion/react';
+import { createPortal } from 'react-dom';
+import { autoUpdate } from '@floating-ui/dom';
+import useLayoutEffect from 'use-isomorphic-layout-effect';
+
+import {
+ animatedScrollTo,
+ getBoundingClientObj,
+ getScrollParent,
+ getScrollTop,
+ getStyleProps,
+ normalizedHeight,
+ scrollTo,
+} from '../utils';
+import {
+ MenuPlacement,
+ MenuPosition,
+ CommonProps,
+ GroupBase,
+ CommonPropsAndClassName,
+ CoercedMenuPlacement,
+ CSSObjectWithLabel,
+} from '../types';
+
+// ==============================
+// Menu
+// ==============================
+
+// Get Menu Placement
+// ------------------------------
+
+interface CalculatedMenuPlacementAndHeight {
+ placement: CoercedMenuPlacement;
+ maxHeight: number;
+}
+interface PlacementArgs {
+ maxHeight: number;
+ menuEl: HTMLDivElement | null;
+ minHeight: number;
+ placement: MenuPlacement;
+ shouldScroll: boolean;
+ isFixedPosition: boolean;
+ controlHeight: number;
+}
+
+export function getMenuPlacement({
+ maxHeight: preferredMaxHeight,
+ menuEl,
+ minHeight,
+ placement: preferredPlacement,
+ shouldScroll,
+ isFixedPosition,
+ controlHeight,
+}: PlacementArgs): CalculatedMenuPlacementAndHeight {
+ const scrollParent = getScrollParent(menuEl!);
+ const defaultState: CalculatedMenuPlacementAndHeight = {
+ placement: 'bottom',
+ maxHeight: preferredMaxHeight,
+ };
+
+ // something went wrong, return default state
+ if (!menuEl || !menuEl.offsetParent) return defaultState;
+
+ // we can't trust `scrollParent.scrollHeight` --> it may increase when
+ // the menu is rendered
+ const { height: scrollHeight } = scrollParent.getBoundingClientRect();
+ const {
+ bottom: menuBottom,
+ height: menuHeight,
+ top: menuTop,
+ } = menuEl.getBoundingClientRect();
+
+ const { top: containerTop } = menuEl.offsetParent.getBoundingClientRect();
+ const viewHeight = isFixedPosition
+ ? window.innerHeight
+ : normalizedHeight(scrollParent);
+ const scrollTop = getScrollTop(scrollParent);
+
+ const marginBottom = parseInt(getComputedStyle(menuEl).marginBottom, 10);
+ const marginTop = parseInt(getComputedStyle(menuEl).marginTop, 10);
+ const viewSpaceAbove = containerTop - marginTop;
+ const viewSpaceBelow = viewHeight - menuTop;
+ const scrollSpaceAbove = viewSpaceAbove + scrollTop;
+ const scrollSpaceBelow = scrollHeight - scrollTop - menuTop;
+
+ const scrollDown = menuBottom - viewHeight + scrollTop + marginBottom;
+ const scrollUp = scrollTop + menuTop - marginTop;
+ const scrollDuration = 160;
+
+ switch (preferredPlacement) {
+ case 'auto':
+ case 'bottom':
+ // 1: the menu will fit, do nothing
+ if (viewSpaceBelow >= menuHeight) {
+ return { placement: 'bottom', maxHeight: preferredMaxHeight };
+ }
+
+ // 2: the menu will fit, if scrolled
+ if (scrollSpaceBelow >= menuHeight && !isFixedPosition) {
+ if (shouldScroll) {
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
+ }
+
+ return { placement: 'bottom', maxHeight: preferredMaxHeight };
+ }
+
+ // 3: the menu will fit, if constrained
+ if (
+ (!isFixedPosition && scrollSpaceBelow >= minHeight) ||
+ (isFixedPosition && viewSpaceBelow >= minHeight)
+ ) {
+ if (shouldScroll) {
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
+ }
+
+ // we want to provide as much of the menu as possible to the user,
+ // so give them whatever is available below rather than the minHeight.
+ const constrainedHeight = isFixedPosition
+ ? viewSpaceBelow - marginBottom
+ : scrollSpaceBelow - marginBottom;
+
+ return {
+ placement: 'bottom',
+ maxHeight: constrainedHeight,
+ };
+ }
+
+ // 4. Forked beviour when there isn't enough space below
+
+ // AUTO: flip the menu, render above
+ if (preferredPlacement === 'auto' || isFixedPosition) {
+ // may need to be constrained after flipping
+ let constrainedHeight = preferredMaxHeight;
+ const spaceAbove = isFixedPosition ? viewSpaceAbove : scrollSpaceAbove;
+
+ if (spaceAbove >= minHeight) {
+ constrainedHeight = Math.min(
+ spaceAbove - marginBottom - controlHeight,
+ preferredMaxHeight
+ );
+ }
+
+ return { placement: 'top', maxHeight: constrainedHeight };
+ }
+
+ // BOTTOM: allow browser to increase scrollable area and immediately set scroll
+ if (preferredPlacement === 'bottom') {
+ if (shouldScroll) {
+ scrollTo(scrollParent, scrollDown);
+ }
+ return { placement: 'bottom', maxHeight: preferredMaxHeight };
+ }
+ break;
+ case 'top':
+ // 1: the menu will fit, do nothing
+ if (viewSpaceAbove >= menuHeight) {
+ return { placement: 'top', maxHeight: preferredMaxHeight };
+ }
+
+ // 2: the menu will fit, if scrolled
+ if (scrollSpaceAbove >= menuHeight && !isFixedPosition) {
+ if (shouldScroll) {
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
+ }
+
+ return { placement: 'top', maxHeight: preferredMaxHeight };
+ }
+
+ // 3: the menu will fit, if constrained
+ if (
+ (!isFixedPosition && scrollSpaceAbove >= minHeight) ||
+ (isFixedPosition && viewSpaceAbove >= minHeight)
+ ) {
+ let constrainedHeight = preferredMaxHeight;
+
+ // we want to provide as much of the menu as possible to the user,
+ // so give them whatever is available below rather than the minHeight.
+ if (
+ (!isFixedPosition && scrollSpaceAbove >= minHeight) ||
+ (isFixedPosition && viewSpaceAbove >= minHeight)
+ ) {
+ constrainedHeight = isFixedPosition
+ ? viewSpaceAbove - marginTop
+ : scrollSpaceAbove - marginTop;
+ }
+
+ if (shouldScroll) {
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
+ }
+
+ return {
+ placement: 'top',
+ maxHeight: constrainedHeight,
+ };
+ }
+
+ // 4. not enough space, the browser WILL NOT increase scrollable area when
+ // absolutely positioned element rendered above the viewport (only below).
+ // Flip the menu, render below
+ return { placement: 'bottom', maxHeight: preferredMaxHeight };
+ default:
+ throw new Error(`Invalid placement provided "${preferredPlacement}".`);
+ }
+
+ return defaultState;
+}
+
+// Menu Component
+// ------------------------------
+
+export interface MenuPlacementProps {
+ /** Set the minimum height of the menu. */
+ minMenuHeight: number;
+ /** Set the maximum height of the menu. */
+ maxMenuHeight: number;
+ /** Set whether the menu should be at the top, at the bottom. The auto options sets it to bottom. */
+ menuPlacement: MenuPlacement;
+ /** The CSS position value of the menu, when "fixed" extra layout management is required */
+ menuPosition: MenuPosition;
+ /** Set whether the page should scroll to show the menu. */
+ menuShouldScrollIntoView: boolean;
+}
+
+export interface MenuProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName ,
+ MenuPlacementProps {
+ /** Reference to the internal element, consumed by the MenuPlacer component */
+ innerRef: Ref;
+ innerProps: JSX.IntrinsicElements['div'];
+ isLoading: boolean;
+ placement: CoercedMenuPlacement;
+ /** The children to be rendered. */
+ children: ReactNode;
+}
+
+interface PlacerProps {
+ placement: CoercedMenuPlacement;
+ maxHeight: number;
+}
+
+interface ChildrenProps {
+ ref: Ref;
+ placerProps: PlacerProps;
+}
+
+export interface MenuPlacerProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends CommonProps ,
+ MenuPlacementProps {
+ /** The children to be rendered. */
+ children: (childrenProps: ChildrenProps) => ReactElement;
+}
+
+function alignToControl(placement: CoercedMenuPlacement) {
+ const placementToCSSProp = { bottom: 'top', top: 'bottom' };
+ return placement ? placementToCSSProp[placement] : 'bottom';
+}
+const coercePlacement = (p: MenuPlacement) => (p === 'auto' ? 'bottom' : p);
+
+export const menuCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ placement,
+ theme: { borderRadius, spacing, colors },
+ }: MenuProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'menu',
+ [alignToControl(placement)]: '100%',
+ position: 'absolute',
+ width: '100%',
+ zIndex: 1,
+ ...(unstyled
+ ? {}
+ : {
+ backgroundColor: colors.neutral0,
+ borderRadius: borderRadius,
+ boxShadow:
+ '0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1)',
+ marginBottom: spacing.menuGutter,
+ marginTop: spacing.menuGutter,
+ }),
+});
+
+const PortalPlacementContext =
+ createContext<{
+ setPortalPlacement: (placement: CoercedMenuPlacement) => void;
+ } | null>(null);
+
+// NOTE: internal only
+export const MenuPlacer = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: MenuPlacerProps
+) => {
+ const {
+ children,
+ minMenuHeight,
+ maxMenuHeight,
+ menuPlacement,
+ menuPosition,
+ menuShouldScrollIntoView,
+ theme,
+ } = props;
+
+ const { setPortalPlacement } = useContext(PortalPlacementContext) || {};
+ const ref = useRef(null);
+ const [maxHeight, setMaxHeight] = useState(maxMenuHeight);
+ const [placement, setPlacement] = useState(null);
+ const { controlHeight } = theme.spacing;
+
+ useLayoutEffect(() => {
+ const menuEl = ref.current;
+ if (!menuEl) return;
+
+ // DO NOT scroll if position is fixed
+ const isFixedPosition = menuPosition === 'fixed';
+ const shouldScroll = menuShouldScrollIntoView && !isFixedPosition;
+
+ const state = getMenuPlacement({
+ maxHeight: maxMenuHeight,
+ menuEl,
+ minHeight: minMenuHeight,
+ placement: menuPlacement,
+ shouldScroll,
+ isFixedPosition,
+ controlHeight,
+ });
+
+ setMaxHeight(state.maxHeight);
+ setPlacement(state.placement);
+ setPortalPlacement?.(state.placement);
+ }, [
+ maxMenuHeight,
+ menuPlacement,
+ menuPosition,
+ menuShouldScrollIntoView,
+ minMenuHeight,
+ setPortalPlacement,
+ controlHeight,
+ ]);
+
+ return children({
+ ref,
+ placerProps: {
+ ...props,
+ placement: placement || coercePlacement(menuPlacement),
+ maxHeight,
+ },
+ });
+};
+
+const Menu = >(
+ props: MenuProps
+) => {
+ const { children, innerRef, innerProps } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default Menu;
+
+// ==============================
+// Menu List
+// ==============================
+
+export interface MenuListProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** Set the max height of the Menu component */
+ maxHeight: number;
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Inner ref to DOM ReactNode */
+ innerRef: Ref;
+ /** The currently focused option */
+ focusedOption: Option;
+ /** Props to be passed to the menu-list wrapper. */
+ innerProps: JSX.IntrinsicElements['div'];
+}
+export const menuListCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ maxHeight,
+ theme: {
+ spacing: { baseUnit },
+ },
+ }: MenuListProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ maxHeight,
+ overflowY: 'auto',
+ position: 'relative', // required for offset[Height, Top] > keyboard scroll
+ WebkitOverflowScrolling: 'touch',
+ ...(unstyled
+ ? {}
+ : {
+ paddingBottom: baseUnit,
+ paddingTop: baseUnit,
+ }),
+});
+export const MenuList = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: MenuListProps
+) => {
+ const { children, innerProps, innerRef, isMulti } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+// ==============================
+// Menu Notices
+// ==============================
+
+const noticeCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ theme: {
+ spacing: { baseUnit },
+ colors,
+ },
+ }: NoticeProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ textAlign: 'center',
+ ...(unstyled
+ ? {}
+ : {
+ color: colors.neutral40,
+ padding: `${baseUnit * 2}px ${baseUnit * 3}px`,
+ }),
+});
+export const noOptionsMessageCSS = noticeCSS;
+export const loadingMessageCSS = noticeCSS;
+
+export interface NoticeProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Props to be passed on to the wrapper. */
+ innerProps: JSX.IntrinsicElements['div'];
+}
+
+export const NoOptionsMessage = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ children = 'No options',
+ innerProps,
+ ...restProps
+}: NoticeProps ) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export const LoadingMessage = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ children = 'Loading...',
+ innerProps,
+ ...restProps
+}: NoticeProps ) => {
+ return (
+
+ {children}
+
+ );
+};
+
+// ==============================
+// Menu Portal
+// ==============================
+
+export interface MenuPortalProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends CommonPropsAndClassName {
+ appendTo: HTMLElement | undefined;
+ children: ReactNode; // ideally Menu
+ controlElement: HTMLDivElement | null;
+ innerProps: JSX.IntrinsicElements['div'];
+ menuPlacement: MenuPlacement;
+ menuPosition: MenuPosition;
+}
+
+export interface PortalStyleArgs {
+ offset: number;
+ position: MenuPosition;
+ rect: { left: number; width: number };
+}
+
+export const menuPortalCSS = ({
+ rect,
+ offset,
+ position,
+}: PortalStyleArgs): CSSObjectWithLabel => ({
+ left: rect.left,
+ position: position,
+ top: offset,
+ width: rect.width,
+ zIndex: 1,
+});
+
+interface ComputedPosition {
+ offset: number;
+ rect: { left: number; width: number };
+}
+
+export const MenuPortal = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: MenuPortalProps
+) => {
+ const {
+ appendTo,
+ children,
+ controlElement,
+ innerProps,
+ menuPlacement,
+ menuPosition,
+ } = props;
+
+ const menuPortalRef = useRef(null);
+ const cleanupRef = useRef<(() => void) | void | null>(null);
+
+ const [placement, setPortalPlacement] = useState<'bottom' | 'top'>(
+ coercePlacement(menuPlacement)
+ );
+ const portalPlacementContext = useMemo(
+ () => ({
+ setPortalPlacement,
+ }),
+ []
+ );
+ const [computedPosition, setComputedPosition] =
+ useState(null);
+
+ const updateComputedPosition = useCallback(() => {
+ if (!controlElement) return;
+
+ const rect = getBoundingClientObj(controlElement);
+ const scrollDistance = menuPosition === 'fixed' ? 0 : window.pageYOffset;
+ const offset = rect[placement] + scrollDistance;
+ if (
+ offset !== computedPosition?.offset ||
+ rect.left !== computedPosition?.rect.left ||
+ rect.width !== computedPosition?.rect.width
+ ) {
+ setComputedPosition({ offset, rect });
+ }
+ }, [
+ controlElement,
+ menuPosition,
+ placement,
+ computedPosition?.offset,
+ computedPosition?.rect.left,
+ computedPosition?.rect.width,
+ ]);
+
+ useLayoutEffect(() => {
+ updateComputedPosition();
+ }, [updateComputedPosition]);
+
+ const runAutoUpdate = useCallback(() => {
+ if (typeof cleanupRef.current === 'function') {
+ cleanupRef.current();
+ cleanupRef.current = null;
+ }
+
+ if (controlElement && menuPortalRef.current) {
+ cleanupRef.current = autoUpdate(
+ controlElement,
+ menuPortalRef.current,
+ updateComputedPosition,
+ { elementResize: 'ResizeObserver' in window }
+ );
+ }
+ }, [controlElement, updateComputedPosition]);
+
+ useLayoutEffect(() => {
+ runAutoUpdate();
+ }, [runAutoUpdate]);
+
+ const setMenuPortalElement = useCallback(
+ (menuPortalElement: HTMLDivElement) => {
+ menuPortalRef.current = menuPortalElement;
+ runAutoUpdate();
+ },
+ [runAutoUpdate]
+ );
+
+ // bail early if required elements aren't present
+ if ((!appendTo && menuPosition !== 'fixed') || !computedPosition) return null;
+
+ // same wrapper element whether fixed or portalled
+ const menuWrapper = (
+
+ {children}
+
+ );
+
+ return (
+
+ {appendTo ? createPortal(menuWrapper, appendTo) : menuWrapper}
+
+ );
+};
diff --git a/packages/react-select/src/components/MultiValue.tsx b/packages/react-select/src/components/MultiValue.tsx
new file mode 100644
index 0000000000..56ae90b3b5
--- /dev/null
+++ b/packages/react-select/src/components/MultiValue.tsx
@@ -0,0 +1,216 @@
+/** @jsx jsx */
+import { ComponentType, JSX, ReactNode } from 'react';
+import { jsx } from '@emotion/react';
+import { CrossIcon } from './indicators';
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { Props } from '../Select';
+import { getStyleProps } from '../utils';
+
+interface MultiValueComponents<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ Container: ComponentType>;
+ Label: ComponentType>;
+ Remove: ComponentType>;
+}
+
+export interface MultiValueProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ children: ReactNode;
+ components: MultiValueComponents ;
+ cropWithEllipsis?: boolean;
+ data: Option;
+ innerProps: JSX.IntrinsicElements['div'];
+ isFocused: boolean;
+ isDisabled: boolean;
+ removeProps: JSX.IntrinsicElements['div'];
+ index: number;
+}
+
+export const multiValueCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ theme: { spacing, borderRadius, colors },
+ }: MultiValueProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'multiValue',
+ display: 'flex',
+ minWidth: 0, // resolves flex/text-overflow bug
+ ...(unstyled
+ ? {}
+ : {
+ backgroundColor: colors.neutral10,
+ borderRadius: borderRadius / 2,
+ margin: spacing.baseUnit / 2,
+ }),
+});
+
+export const multiValueLabelCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ theme: { borderRadius, colors },
+ cropWithEllipsis,
+ }: MultiValueProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ overflow: 'hidden',
+ textOverflow:
+ cropWithEllipsis || cropWithEllipsis === undefined ? 'ellipsis' : undefined,
+ whiteSpace: 'nowrap',
+ ...(unstyled
+ ? {}
+ : {
+ borderRadius: borderRadius / 2,
+ color: colors.neutral80,
+ fontSize: '85%',
+ padding: 3,
+ paddingLeft: 6,
+ }),
+});
+
+export const multiValueRemoveCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ theme: { spacing, borderRadius, colors },
+ isFocused,
+ }: MultiValueProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ alignItems: 'center',
+ display: 'flex',
+ ...(unstyled
+ ? {}
+ : {
+ borderRadius: borderRadius / 2,
+ backgroundColor: isFocused ? colors.dangerLight : undefined,
+ paddingLeft: spacing.baseUnit,
+ paddingRight: spacing.baseUnit,
+ ':hover': {
+ backgroundColor: colors.dangerLight,
+ color: colors.danger,
+ },
+ }),
+});
+
+export interface MultiValueGenericProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> {
+ children: ReactNode;
+ data: any;
+ innerProps: { className?: string };
+ selectProps: Props ;
+}
+export const MultiValueGeneric = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ children,
+ innerProps,
+}: MultiValueGenericProps ) => (
+ {children}
+);
+
+export const MultiValueContainer = MultiValueGeneric;
+export const MultiValueLabel = MultiValueGeneric;
+export interface MultiValueRemoveProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> {
+ children?: ReactNode;
+ data: Option;
+ innerProps: JSX.IntrinsicElements['div'];
+ selectProps: Props ;
+}
+export function MultiValueRemove<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({ children, innerProps }: MultiValueRemoveProps ) {
+ return (
+
+ {children || }
+
+ );
+}
+
+const MultiValue = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: MultiValueProps
+) => {
+ const {
+ children,
+ components,
+ data,
+ innerProps,
+ isDisabled,
+ removeProps,
+ selectProps,
+ } = props;
+
+ const { Container, Label, Remove } = components;
+
+ return (
+
+
+ {children}
+
+
+
+ );
+};
+
+export default MultiValue;
diff --git a/packages/react-select/src/components/Option.tsx b/packages/react-select/src/components/Option.tsx
new file mode 100644
index 0000000000..39592b1098
--- /dev/null
+++ b/packages/react-select/src/components/Option.tsx
@@ -0,0 +1,109 @@
+/** @jsx jsx */
+import { JSX, ReactNode, RefCallback } from 'react';
+import { jsx } from '@emotion/react';
+
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+export interface OptionProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Inner ref to DOM Node */
+ innerRef: RefCallback;
+ /** props passed to the wrapping element for the group. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** Text to be displayed representing the option. */
+ label: string;
+ /** Type is used by the menu to determine whether this is an option or a group.
+ In the case of option this is always `option`. **/
+ type: 'option';
+ /** The data of the selected option. */
+ data: Option;
+ /** Whether the option is disabled. */
+ isDisabled: boolean;
+ /** Whether the option is focused. */
+ isFocused: boolean;
+ /** Whether the option is selected. */
+ isSelected: boolean;
+}
+
+export const optionCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isDisabled,
+ isFocused,
+ isSelected,
+ theme: { spacing, colors },
+ }: OptionProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'option',
+ cursor: 'default',
+ display: 'block',
+ fontSize: 'inherit',
+ width: '100%',
+ userSelect: 'none',
+ WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',
+ ...(unstyled
+ ? {}
+ : {
+ backgroundColor: isSelected
+ ? colors.primary
+ : isFocused
+ ? colors.primary25
+ : 'transparent',
+ color: isDisabled
+ ? colors.neutral20
+ : isSelected
+ ? colors.neutral0
+ : 'inherit',
+ padding: `${spacing.baseUnit * 2}px ${spacing.baseUnit * 3}px`,
+ // provide some affordance on touch devices
+ ':active': {
+ backgroundColor: !isDisabled
+ ? isSelected
+ ? colors.primary
+ : colors.primary50
+ : undefined,
+ },
+ }),
+});
+
+const Option = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: OptionProps
+) => {
+ const { children, isDisabled, isFocused, isSelected, innerRef, innerProps } =
+ props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default Option;
diff --git a/packages/react-select/src/components/Placeholder.tsx b/packages/react-select/src/components/Placeholder.tsx
new file mode 100644
index 0000000000..692e6a249e
--- /dev/null
+++ b/packages/react-select/src/components/Placeholder.tsx
@@ -0,0 +1,63 @@
+/** @jsx jsx */
+import { JSX, ReactNode } from 'react';
+import { jsx } from '@emotion/react';
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+export interface PlaceholderProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** props passed to the wrapping element for the group. */
+ innerProps: JSX.IntrinsicElements['div'];
+ isDisabled: boolean;
+ isFocused: boolean;
+}
+
+export const placeholderCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ { theme: { spacing, colors } }: PlaceholderProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'placeholder',
+ gridArea: '1 / 1 / 2 / 3',
+ ...(unstyled
+ ? {}
+ : {
+ color: colors.neutral50,
+ marginLeft: spacing.baseUnit / 2,
+ marginRight: spacing.baseUnit / 2,
+ }),
+});
+
+const Placeholder = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: PlaceholderProps
+) => {
+ const { children, innerProps } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default Placeholder;
diff --git a/packages/react-select/src/components/SingleValue.tsx b/packages/react-select/src/components/SingleValue.tsx
new file mode 100644
index 0000000000..f74bd4d35e
--- /dev/null
+++ b/packages/react-select/src/components/SingleValue.tsx
@@ -0,0 +1,73 @@
+/** @jsx jsx */
+import { JSX, ReactNode } from 'react';
+import { jsx } from '@emotion/react';
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+export interface SingleValueProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** The data of the selected option rendered in the Single Value component. */
+ data: Option;
+ /** Props passed to the wrapping element for the group. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** Whether this is disabled. */
+ isDisabled: boolean;
+}
+
+export const css = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isDisabled,
+ theme: { spacing, colors },
+ }: SingleValueProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'singleValue',
+ gridArea: '1 / 1 / 2 / 3',
+ maxWidth: '100%',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ ...(unstyled
+ ? {}
+ : {
+ color: isDisabled ? colors.neutral40 : colors.neutral80,
+ marginLeft: spacing.baseUnit / 2,
+ marginRight: spacing.baseUnit / 2,
+ }),
+});
+
+const SingleValue = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: SingleValueProps
+) => {
+ const { children, isDisabled, innerProps } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+export default SingleValue;
diff --git a/packages/react-select/src/components/containers.tsx b/packages/react-select/src/components/containers.tsx
new file mode 100644
index 0000000000..e673cb384a
--- /dev/null
+++ b/packages/react-select/src/components/containers.tsx
@@ -0,0 +1,167 @@
+/** @jsx jsx */
+import { JSX, ReactNode } from 'react';
+import { jsx } from '@emotion/react';
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+// ==============================
+// Root Container
+// ==============================
+
+export interface ContainerProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** Whether the select is disabled. */
+ isDisabled: boolean;
+ isFocused: boolean;
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Inner props to be passed down to the container. */
+ innerProps: JSX.IntrinsicElements['div'];
+}
+export const containerCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ isDisabled,
+ isRtl,
+}: ContainerProps ): CSSObjectWithLabel => ({
+ label: 'container',
+ direction: isRtl ? 'rtl' : undefined,
+ pointerEvents: isDisabled ? 'none' : undefined, // cancel mouse events when disabled
+ position: 'relative',
+});
+export const SelectContainer = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: ContainerProps
+) => {
+ const { children, innerProps, isDisabled, isRtl } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+// ==============================
+// Value Container
+// ==============================
+
+export interface ValueContainerProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** Props to be passed to the value container element. */
+ innerProps?: JSX.IntrinsicElements['div'];
+ /** The children to be rendered. */
+ children: ReactNode;
+ isDisabled: boolean;
+}
+export const valueContainerCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ theme: { spacing },
+ isMulti,
+ hasValue,
+ selectProps: { controlShouldRenderValue },
+ }: ValueContainerProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ alignItems: 'center',
+ display: isMulti && hasValue && controlShouldRenderValue ? 'flex' : 'grid',
+ flex: 1,
+ flexWrap: 'wrap',
+ WebkitOverflowScrolling: 'touch',
+ position: 'relative',
+ overflow: 'hidden',
+ ...(unstyled
+ ? {}
+ : {
+ padding: `${spacing.baseUnit / 2}px ${spacing.baseUnit * 2}px`,
+ }),
+});
+export const ValueContainer = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: ValueContainerProps
+) => {
+ const { children, innerProps, isMulti, hasValue } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+// ==============================
+// Indicator Container
+// ==============================
+
+export interface IndicatorsContainerProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ isDisabled: boolean;
+ /** The children to be rendered. */
+ children: ReactNode;
+ /** Props to be passed to the indicators container element. */
+ innerProps?: {};
+}
+
+export const indicatorsContainerCSS = (): CSSObjectWithLabel => ({
+ alignItems: 'center',
+ alignSelf: 'stretch',
+ display: 'flex',
+ flexShrink: 0,
+});
+export const IndicatorsContainer = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: IndicatorsContainerProps
+) => {
+ const { children, innerProps } = props;
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/react-select/src/components/index.ts b/packages/react-select/src/components/index.ts
new file mode 100644
index 0000000000..d2c9b84c5e
--- /dev/null
+++ b/packages/react-select/src/components/index.ts
@@ -0,0 +1,151 @@
+import { ComponentType } from 'react';
+import {
+ ContainerProps,
+ IndicatorsContainer,
+ IndicatorsContainerProps,
+ SelectContainer,
+ ValueContainer,
+ ValueContainerProps,
+} from './containers';
+import {
+ ClearIndicator,
+ ClearIndicatorProps,
+ CrossIcon,
+ CrossIconProps,
+ DownChevron,
+ DownChevronProps,
+ DropdownIndicator,
+ DropdownIndicatorProps,
+ IndicatorSeparator,
+ IndicatorSeparatorProps,
+ LoadingIndicator,
+ LoadingIndicatorProps,
+} from './indicators';
+
+import Control, { ControlProps } from './Control';
+import Group, { GroupHeading, GroupHeadingProps, GroupProps } from './Group';
+import Input, { InputProps } from './Input';
+import Menu, {
+ LoadingMessage,
+ MenuList,
+ MenuListProps,
+ MenuPortal,
+ MenuPortalProps,
+ MenuProps,
+ NoOptionsMessage,
+ NoticeProps,
+} from './Menu';
+import MultiValue, {
+ MultiValueContainer,
+ MultiValueGenericProps,
+ MultiValueLabel,
+ MultiValueProps,
+ MultiValueRemove,
+ MultiValueRemoveProps,
+} from './MultiValue';
+import Option, { OptionProps } from './Option';
+import Placeholder, { PlaceholderProps } from './Placeholder';
+import SingleValue, { SingleValueProps } from './SingleValue';
+import { GroupBase } from '../types';
+
+export interface SelectComponents<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ ClearIndicator: ComponentType>;
+ Control: ComponentType>;
+ DropdownIndicator: ComponentType<
+ DropdownIndicatorProps
+ > | null;
+ DownChevron: ComponentType;
+ CrossIcon: ComponentType;
+ Group: ComponentType>;
+ GroupHeading: ComponentType>;
+ IndicatorsContainer: ComponentType<
+ IndicatorsContainerProps
+ >;
+ IndicatorSeparator: ComponentType<
+ IndicatorSeparatorProps
+ > | null;
+ Input: ComponentType>;
+ LoadingIndicator: ComponentType<
+ LoadingIndicatorProps
+ >;
+ Menu: ComponentType>;
+ MenuList: ComponentType>;
+ MenuPortal: ComponentType>;
+ LoadingMessage: ComponentType>;
+ NoOptionsMessage: ComponentType>;
+ MultiValue: ComponentType>;
+ MultiValueContainer: ComponentType<
+ MultiValueGenericProps
+ >;
+ MultiValueLabel: ComponentType<
+ MultiValueGenericProps
+ >;
+ MultiValueRemove: ComponentType<
+ MultiValueRemoveProps
+ >;
+ Option: ComponentType>;
+ Placeholder: ComponentType>;
+ SelectContainer: ComponentType>;
+ SingleValue: ComponentType>;
+ ValueContainer: ComponentType>;
+}
+
+export type SelectComponentsConfig<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = Partial>;
+
+export const components = {
+ ClearIndicator: ClearIndicator,
+ Control: Control,
+ DropdownIndicator: DropdownIndicator,
+ DownChevron: DownChevron,
+ CrossIcon: CrossIcon,
+ Group: Group,
+ GroupHeading: GroupHeading,
+ IndicatorsContainer: IndicatorsContainer,
+ IndicatorSeparator: IndicatorSeparator,
+ Input: Input,
+ LoadingIndicator: LoadingIndicator,
+ Menu: Menu,
+ MenuList: MenuList,
+ MenuPortal: MenuPortal,
+ LoadingMessage: LoadingMessage,
+ NoOptionsMessage: NoOptionsMessage,
+ MultiValue: MultiValue,
+ MultiValueContainer: MultiValueContainer,
+ MultiValueLabel: MultiValueLabel,
+ MultiValueRemove: MultiValueRemove,
+ Option: Option,
+ Placeholder: Placeholder,
+ SelectContainer: SelectContainer,
+ SingleValue: SingleValue,
+ ValueContainer: ValueContainer,
+};
+
+export type SelectComponentsGeneric = typeof components;
+
+interface Props<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ components: SelectComponentsConfig ;
+}
+
+export const defaultComponents = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: Props
+): SelectComponentsGeneric =>
+ ({
+ ...components,
+ ...props.components,
+ } as SelectComponentsGeneric);
diff --git a/packages/react-select/src/components/indicators.tsx b/packages/react-select/src/components/indicators.tsx
new file mode 100644
index 0000000000..a668ab7a57
--- /dev/null
+++ b/packages/react-select/src/components/indicators.tsx
@@ -0,0 +1,313 @@
+/** @jsx jsx */
+import { JSX, ReactNode } from 'react';
+import { jsx, keyframes } from '@emotion/react';
+
+import {
+ CommonPropsAndClassName,
+ CSSObjectWithLabel,
+ GroupBase,
+} from '../types';
+import { getStyleProps } from '../utils';
+
+// ==============================
+// Dropdown & Clear Icons
+// ==============================
+
+const Svg = ({
+ size,
+ ...props
+}: JSX.IntrinsicElements['svg'] & { size: number }) => (
+
+);
+
+export type CrossIconProps = JSX.IntrinsicElements['svg'] & { size?: number };
+export const CrossIcon = (props: CrossIconProps) => (
+
+
+
+);
+export type DownChevronProps = JSX.IntrinsicElements['svg'] & { size?: number };
+export const DownChevron = (props: DownChevronProps) => (
+
+
+
+);
+
+// ==============================
+// Dropdown & Clear Buttons
+// ==============================
+
+export interface DropdownIndicatorProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered inside the indicator. */
+ children?: ReactNode;
+ /** Props that will be passed on to the children. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** The focused state of the select. */
+ isFocused: boolean;
+ isDisabled: boolean;
+}
+
+const baseCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isFocused,
+ theme: {
+ spacing: { baseUnit },
+ colors,
+ },
+ }:
+ | DropdownIndicatorProps
+ | ClearIndicatorProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'indicatorContainer',
+ display: 'flex',
+ transition: 'color 150ms',
+ ...(unstyled
+ ? {}
+ : {
+ color: isFocused ? colors.neutral60 : colors.neutral20,
+ padding: baseUnit * 2,
+ ':hover': {
+ color: isFocused ? colors.neutral80 : colors.neutral40,
+ },
+ }),
+});
+
+export const dropdownIndicatorCSS = baseCSS;
+export const DropdownIndicator = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: DropdownIndicatorProps
+) => {
+ const { children, innerProps } = props;
+ return (
+
+ {children || }
+
+ );
+};
+
+export interface ClearIndicatorProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** The children to be rendered inside the indicator. */
+ children?: ReactNode;
+ /** Props that will be passed on to the children. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** The focused state of the select. */
+ isFocused: boolean;
+}
+
+export const clearIndicatorCSS = baseCSS;
+export const ClearIndicator = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: ClearIndicatorProps
+) => {
+ const { children, innerProps } = props;
+ return (
+
+ {children || }
+
+ );
+};
+
+// ==============================
+// Separator
+// ==============================
+
+export interface IndicatorSeparatorProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ isDisabled: boolean;
+ isFocused: boolean;
+ innerProps?: JSX.IntrinsicElements['span'];
+}
+
+export const indicatorSeparatorCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isDisabled,
+ theme: {
+ spacing: { baseUnit },
+ colors,
+ },
+ }: IndicatorSeparatorProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'indicatorSeparator',
+ alignSelf: 'stretch',
+ width: 1,
+ ...(unstyled
+ ? {}
+ : {
+ backgroundColor: isDisabled ? colors.neutral10 : colors.neutral20,
+ marginBottom: baseUnit * 2,
+ marginTop: baseUnit * 2,
+ }),
+});
+
+export const IndicatorSeparator = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ props: IndicatorSeparatorProps
+) => {
+ const { innerProps } = props;
+ return (
+
+ );
+};
+
+// ==============================
+// Loading
+// ==============================
+
+const loadingDotAnimations = keyframes`
+ 0%, 80%, 100% { opacity: 0; }
+ 40% { opacity: 1; }
+`;
+
+export const loadingIndicatorCSS = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ {
+ isFocused,
+ size,
+ theme: {
+ colors,
+ spacing: { baseUnit },
+ },
+ }: LoadingIndicatorProps ,
+ unstyled: boolean
+): CSSObjectWithLabel => ({
+ label: 'loadingIndicator',
+ display: 'flex',
+ transition: 'color 150ms',
+ alignSelf: 'center',
+ fontSize: size,
+ lineHeight: 1,
+ marginRight: size,
+ textAlign: 'center',
+ verticalAlign: 'middle',
+ ...(unstyled
+ ? {}
+ : {
+ color: isFocused ? colors.neutral60 : colors.neutral20,
+ padding: baseUnit * 2,
+ }),
+});
+
+interface LoadingDotProps {
+ delay: number;
+ offset: boolean;
+}
+const LoadingDot = ({ delay, offset }: LoadingDotProps) => (
+
+);
+
+export interface LoadingIndicatorProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> extends CommonPropsAndClassName {
+ /** Props that will be passed on to the children. */
+ innerProps: JSX.IntrinsicElements['div'];
+ /** The focused state of the select. */
+ isFocused: boolean;
+ isDisabled: boolean;
+ /** Set size of the container. */
+ size: number;
+}
+export const LoadingIndicator = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ innerProps,
+ isRtl,
+ size = 4,
+ ...restProps
+}: LoadingIndicatorProps ) => {
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/react-select/src/creatable/index.ts b/packages/react-select/src/creatable/index.ts
new file mode 100644
index 0000000000..b17a1adb0f
--- /dev/null
+++ b/packages/react-select/src/creatable/index.ts
@@ -0,0 +1,2 @@
+export * from '../Creatable';
+export { default } from '../Creatable';
diff --git a/packages/react-select/src/diacritics.ts b/packages/react-select/src/diacritics.ts
new file mode 100644
index 0000000000..3d28c1e0a4
--- /dev/null
+++ b/packages/react-select/src/diacritics.ts
@@ -0,0 +1,258 @@
+const diacritics = [
+ {
+ base: 'A',
+ letters:
+ '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
+ },
+ { base: 'AA', letters: '\uA732' },
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
+ { base: 'AO', letters: '\uA734' },
+ { base: 'AU', letters: '\uA736' },
+ { base: 'AV', letters: '\uA738\uA73A' },
+ { base: 'AY', letters: '\uA73C' },
+ {
+ base: 'B',
+ letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
+ },
+ {
+ base: 'C',
+ letters:
+ '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
+ },
+ {
+ base: 'D',
+ letters:
+ '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779',
+ },
+ { base: 'DZ', letters: '\u01F1\u01C4' },
+ { base: 'Dz', letters: '\u01F2\u01C5' },
+ {
+ base: 'E',
+ letters:
+ '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
+ },
+ { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
+ {
+ base: 'G',
+ letters:
+ '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
+ },
+ {
+ base: 'H',
+ letters:
+ '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
+ },
+ {
+ base: 'I',
+ letters:
+ '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
+ },
+ { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
+ {
+ base: 'K',
+ letters:
+ '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
+ },
+ {
+ base: 'L',
+ letters:
+ '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
+ },
+ { base: 'LJ', letters: '\u01C7' },
+ { base: 'Lj', letters: '\u01C8' },
+ { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
+ {
+ base: 'N',
+ letters:
+ '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
+ },
+ { base: 'NJ', letters: '\u01CA' },
+ { base: 'Nj', letters: '\u01CB' },
+ {
+ base: 'O',
+ letters:
+ '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
+ },
+ { base: 'OI', letters: '\u01A2' },
+ { base: 'OO', letters: '\uA74E' },
+ { base: 'OU', letters: '\u0222' },
+ {
+ base: 'P',
+ letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
+ },
+ { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
+ {
+ base: 'R',
+ letters:
+ '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
+ },
+ {
+ base: 'S',
+ letters:
+ '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
+ },
+ {
+ base: 'T',
+ letters:
+ '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
+ },
+ { base: 'TZ', letters: '\uA728' },
+ {
+ base: 'U',
+ letters:
+ '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
+ },
+ { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
+ { base: 'VY', letters: '\uA760' },
+ {
+ base: 'W',
+ letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
+ },
+ { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
+ {
+ base: 'Y',
+ letters:
+ '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
+ },
+ {
+ base: 'Z',
+ letters:
+ '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
+ },
+ {
+ base: 'a',
+ letters:
+ '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
+ },
+ { base: 'aa', letters: '\uA733' },
+ { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
+ { base: 'ao', letters: '\uA735' },
+ { base: 'au', letters: '\uA737' },
+ { base: 'av', letters: '\uA739\uA73B' },
+ { base: 'ay', letters: '\uA73D' },
+ {
+ base: 'b',
+ letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
+ },
+ {
+ base: 'c',
+ letters:
+ '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
+ },
+ {
+ base: 'd',
+ letters:
+ '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
+ },
+ { base: 'dz', letters: '\u01F3\u01C6' },
+ {
+ base: 'e',
+ letters:
+ '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
+ },
+ { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
+ {
+ base: 'g',
+ letters:
+ '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
+ },
+ {
+ base: 'h',
+ letters:
+ '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
+ },
+ { base: 'hv', letters: '\u0195' },
+ {
+ base: 'i',
+ letters:
+ '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
+ },
+ { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
+ {
+ base: 'k',
+ letters:
+ '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
+ },
+ {
+ base: 'l',
+ letters:
+ '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
+ },
+ { base: 'lj', letters: '\u01C9' },
+ { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
+ {
+ base: 'n',
+ letters:
+ '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
+ },
+ { base: 'nj', letters: '\u01CC' },
+ {
+ base: 'o',
+ letters:
+ '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
+ },
+ { base: 'oi', letters: '\u01A3' },
+ { base: 'ou', letters: '\u0223' },
+ { base: 'oo', letters: '\uA74F' },
+ {
+ base: 'p',
+ letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
+ },
+ { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
+ {
+ base: 'r',
+ letters:
+ '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
+ },
+ {
+ base: 's',
+ letters:
+ '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
+ },
+ {
+ base: 't',
+ letters:
+ '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
+ },
+ { base: 'tz', letters: '\uA729' },
+ {
+ base: 'u',
+ letters:
+ '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
+ },
+ { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
+ { base: 'vy', letters: '\uA761' },
+ {
+ base: 'w',
+ letters:
+ '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
+ },
+ { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
+ {
+ base: 'y',
+ letters:
+ '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
+ },
+ {
+ base: 'z',
+ letters:
+ '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
+ },
+];
+
+const anyDiacritic = new RegExp(
+ '[' + diacritics.map((d) => d.letters).join('') + ']',
+ 'g'
+);
+const diacriticToBase: { [letters: string]: string } = {};
+
+for (let i = 0; i < diacritics.length; i++) {
+ let diacritic = diacritics[i];
+ for (let j = 0; j < diacritic.letters.length; j++) {
+ diacriticToBase[diacritic.letters[j]] = diacritic.base;
+ }
+}
+
+export const stripDiacritics = (str: string) => {
+ return str.replace(anyDiacritic, (match) => diacriticToBase[match]);
+};
diff --git a/packages/react-select/src/filters.ts b/packages/react-select/src/filters.ts
new file mode 100644
index 0000000000..28758fd0cf
--- /dev/null
+++ b/packages/react-select/src/filters.ts
@@ -0,0 +1,50 @@
+import memoizeOne from 'memoize-one';
+import { stripDiacritics } from './diacritics';
+
+export interface FilterOptionOption {
+ readonly label: string;
+ readonly value: string;
+ readonly data: Option;
+}
+
+interface Config {
+ readonly ignoreCase?: boolean;
+ readonly ignoreAccents?: boolean;
+ readonly stringify?: (option: FilterOptionOption ) => string;
+ readonly trim?: boolean;
+ readonly matchFrom?: 'any' | 'start';
+}
+
+const memoizedStripDiacriticsForInput = memoizeOne(stripDiacritics);
+
+const trimString = (str: string) => str.replace(/^\s+|\s+$/g, '');
+const defaultStringify = (option: FilterOptionOption ) =>
+ `${option.label} ${option.value}`;
+
+export const createFilter =
+ (config?: Config ) =>
+ (option: FilterOptionOption , rawInput: string): boolean => {
+ // eslint-disable-next-line no-underscore-dangle
+ if ((option.data as { __isNew__?: unknown }).__isNew__) return true;
+ const { ignoreCase, ignoreAccents, stringify, trim, matchFrom } = {
+ ignoreCase: true,
+ ignoreAccents: true,
+ stringify: defaultStringify,
+ trim: true,
+ matchFrom: 'any',
+ ...config,
+ };
+ let input = trim ? trimString(rawInput) : rawInput;
+ let candidate = trim ? trimString(stringify(option)) : stringify(option);
+ if (ignoreCase) {
+ input = input.toLowerCase();
+ candidate = candidate.toLowerCase();
+ }
+ if (ignoreAccents) {
+ input = memoizedStripDiacriticsForInput(input);
+ candidate = stripDiacritics(candidate);
+ }
+ return matchFrom === 'start'
+ ? candidate.substr(0, input.length) === input
+ : candidate.indexOf(input) > -1;
+ };
diff --git a/packages/react-select/src/index.ts b/packages/react-select/src/index.ts
new file mode 100644
index 0000000000..312aab9f03
--- /dev/null
+++ b/packages/react-select/src/index.ts
@@ -0,0 +1,60 @@
+import Select from './Select';
+import type { GroupBase } from './types';
+export type { FilterOptionOption } from './filters';
+import useStateManager from './useStateManager';
+
+export { default } from './stateManager';
+export { default as NonceProvider } from './NonceProvider';
+export { mergeStyles } from './styles';
+export { defaultTheme } from './theme';
+export { createFilter } from './filters';
+export { components } from './components';
+export type SelectInstance<
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+> = Select ;
+export type { StateManagerProps as Props } from './useStateManager';
+export { useStateManager };
+
+export type { SelectComponentsConfig } from './components';
+export type {
+ ContainerProps,
+ IndicatorsContainerProps,
+ ValueContainerProps,
+} from './components/containers';
+export type { ControlProps } from './components/Control';
+export type { GroupProps, GroupHeadingProps } from './components/Group';
+export type {
+ ClearIndicatorProps,
+ DropdownIndicatorProps,
+ IndicatorSeparatorProps,
+ LoadingIndicatorProps,
+} from './components/indicators';
+export type { InputProps } from './components/Input';
+export type { MenuListProps, MenuProps, NoticeProps } from './components/Menu';
+export type {
+ MultiValueGenericProps,
+ MultiValueProps,
+ MultiValueRemoveProps,
+} from './components/MultiValue';
+export type { OptionProps } from './components/Option';
+export type { PlaceholderProps } from './components/Placeholder';
+export type { SingleValueProps } from './components/SingleValue';
+export type { ThemeConfig } from './theme';
+export type { ClassNamesConfig, StylesConfig } from './styles';
+export * from './types';
+export type {
+ OptionContext,
+ GuidanceContext,
+ AriaGuidanceProps,
+ AriaOnChangeProps,
+ AriaOnFilterProps,
+ AriaOnFocusProps,
+ AriaLiveMessages,
+ AriaGuidance,
+ AriaOnChange,
+ AriaOnFilter,
+ AriaOnFocus,
+} from './accessibility';
+export type { FormatOptionLabelContext, FormatOptionLabelMeta } from './Select';
diff --git a/packages/react-select/src/internal/A11yText.tsx b/packages/react-select/src/internal/A11yText.tsx
new file mode 100644
index 0000000000..f7e2b5e036
--- /dev/null
+++ b/packages/react-select/src/internal/A11yText.tsx
@@ -0,0 +1,24 @@
+/** @jsx jsx */
+import { JSX } from 'react';
+import { jsx } from '@emotion/react';
+
+// Assistive text to describe visual elements. Hidden for sighted users.
+const A11yText = (props: JSX.IntrinsicElements['span']) => (
+
+);
+
+export default A11yText;
diff --git a/packages/react-select/src/internal/DummyInput.tsx b/packages/react-select/src/internal/DummyInput.tsx
new file mode 100644
index 0000000000..0d73c9d313
--- /dev/null
+++ b/packages/react-select/src/internal/DummyInput.tsx
@@ -0,0 +1,51 @@
+/** @jsx jsx */
+import { JSX, Ref } from 'react';
+import { jsx } from '@emotion/react';
+import { removeProps } from '../utils';
+
+export default function DummyInput({
+ innerRef,
+ ...props
+}: JSX.IntrinsicElements['input'] & {
+ readonly innerRef: Ref;
+}) {
+ // Remove animation props not meant for HTML elements
+ const filteredProps = removeProps(
+ props,
+ 'onExited',
+ 'in',
+ 'enter',
+ 'exit',
+ 'appear'
+ );
+
+ return (
+
+ );
+}
diff --git a/packages/react-select/src/internal/RequiredInput.tsx b/packages/react-select/src/internal/RequiredInput.tsx
new file mode 100644
index 0000000000..834dfca3b3
--- /dev/null
+++ b/packages/react-select/src/internal/RequiredInput.tsx
@@ -0,0 +1,31 @@
+/** @jsx jsx */
+import { FocusEventHandler, FunctionComponent } from 'react';
+import { jsx } from '@emotion/react';
+
+const RequiredInput: FunctionComponent<{
+ readonly name?: string;
+ readonly onFocus: FocusEventHandler;
+}> = ({ name, onFocus }) => (
+ {}}
+ />
+);
+
+export default RequiredInput;
diff --git a/packages/react-select/src/internal/ScrollManager.tsx b/packages/react-select/src/internal/ScrollManager.tsx
new file mode 100644
index 0000000000..4e1440008f
--- /dev/null
+++ b/packages/react-select/src/internal/ScrollManager.tsx
@@ -0,0 +1,59 @@
+/** @jsx jsx */
+import { jsx } from '@emotion/react';
+import { Fragment, ReactElement, RefCallback, MouseEvent } from 'react';
+import useScrollCapture from './useScrollCapture';
+import useScrollLock from './useScrollLock';
+
+interface Props {
+ readonly children: (ref: RefCallback) => ReactElement;
+ readonly lockEnabled: boolean;
+ readonly captureEnabled: boolean;
+ readonly onBottomArrive?: (event: WheelEvent | TouchEvent) => void;
+ readonly onBottomLeave?: (event: WheelEvent | TouchEvent) => void;
+ readonly onTopArrive?: (event: WheelEvent | TouchEvent) => void;
+ readonly onTopLeave?: (event: WheelEvent | TouchEvent) => void;
+}
+
+const blurSelectInput = (event: MouseEvent) => {
+ const element = event.target as HTMLDivElement;
+ return (
+ element.ownerDocument.activeElement &&
+ (element.ownerDocument.activeElement as HTMLElement).blur()
+ );
+};
+
+export default function ScrollManager({
+ children,
+ lockEnabled,
+ captureEnabled = true,
+ onBottomArrive,
+ onBottomLeave,
+ onTopArrive,
+ onTopLeave,
+}: Props) {
+ const setScrollCaptureTarget = useScrollCapture({
+ isEnabled: captureEnabled,
+ onBottomArrive,
+ onBottomLeave,
+ onTopArrive,
+ onTopLeave,
+ });
+ const setScrollLockTarget = useScrollLock({ isEnabled: lockEnabled });
+
+ const targetRef: RefCallback = (element) => {
+ setScrollCaptureTarget(element);
+ setScrollLockTarget(element);
+ };
+
+ return (
+
+ {lockEnabled && (
+
+ )}
+ {children(targetRef)}
+
+ );
+}
diff --git a/packages/react-select/src/internal/index.ts b/packages/react-select/src/internal/index.ts
new file mode 100644
index 0000000000..77823425dc
--- /dev/null
+++ b/packages/react-select/src/internal/index.ts
@@ -0,0 +1,4 @@
+export { default as A11yText } from './A11yText';
+export { default as DummyInput } from './DummyInput';
+export { default as ScrollManager } from './ScrollManager';
+export { default as RequiredInput } from './RequiredInput';
diff --git a/packages/react-select/src/internal/useScrollCapture.ts b/packages/react-select/src/internal/useScrollCapture.ts
new file mode 100644
index 0000000000..03b8bd9f59
--- /dev/null
+++ b/packages/react-select/src/internal/useScrollCapture.ts
@@ -0,0 +1,133 @@
+import { useCallback, useEffect, useRef } from 'react';
+import { supportsPassiveEvents } from '../utils';
+
+const cancelScroll = (event: WheelEvent | TouchEvent) => {
+ if (event.cancelable) event.preventDefault();
+ event.stopPropagation();
+};
+
+interface Options {
+ readonly isEnabled: boolean;
+ readonly onBottomArrive?: (event: WheelEvent | TouchEvent) => void;
+ readonly onBottomLeave?: (event: WheelEvent | TouchEvent) => void;
+ readonly onTopArrive?: (event: WheelEvent | TouchEvent) => void;
+ readonly onTopLeave?: (event: WheelEvent | TouchEvent) => void;
+}
+
+export default function useScrollCapture({
+ isEnabled,
+ onBottomArrive,
+ onBottomLeave,
+ onTopArrive,
+ onTopLeave,
+}: Options) {
+ const isBottom = useRef(false);
+ const isTop = useRef(false);
+ const touchStart = useRef(0);
+ const scrollTarget = useRef(null);
+
+ const handleEventDelta = useCallback(
+ (event: WheelEvent | TouchEvent, delta: number) => {
+ if (scrollTarget.current === null) return;
+
+ const { scrollTop, scrollHeight, clientHeight } = scrollTarget.current;
+ const target = scrollTarget.current;
+ const isDeltaPositive = delta > 0;
+ const availableScroll = scrollHeight - clientHeight - scrollTop;
+ let shouldCancelScroll = false;
+
+ // reset bottom/top flags
+ if (availableScroll > delta && isBottom.current) {
+ if (onBottomLeave) onBottomLeave(event);
+ isBottom.current = false;
+ }
+ if (isDeltaPositive && isTop.current) {
+ if (onTopLeave) onTopLeave(event);
+ isTop.current = false;
+ }
+
+ // bottom limit
+ if (isDeltaPositive && delta > availableScroll) {
+ if (onBottomArrive && !isBottom.current) {
+ onBottomArrive(event);
+ }
+ target.scrollTop = scrollHeight;
+ shouldCancelScroll = true;
+ isBottom.current = true;
+
+ // top limit
+ } else if (!isDeltaPositive && -delta > scrollTop) {
+ if (onTopArrive && !isTop.current) {
+ onTopArrive(event);
+ }
+ target.scrollTop = 0;
+ shouldCancelScroll = true;
+ isTop.current = true;
+ }
+
+ // cancel scroll
+ if (shouldCancelScroll) {
+ cancelScroll(event);
+ }
+ },
+ [onBottomArrive, onBottomLeave, onTopArrive, onTopLeave]
+ );
+
+ const onWheel = useCallback(
+ (event: WheelEvent) => {
+ handleEventDelta(event, event.deltaY);
+ },
+ [handleEventDelta]
+ );
+ const onTouchStart = useCallback((event: TouchEvent) => {
+ // set touch start so we can calculate touchmove delta
+ touchStart.current = event.changedTouches[0].clientY;
+ }, []);
+ const onTouchMove = useCallback(
+ (event: TouchEvent) => {
+ const deltaY = touchStart.current - event.changedTouches[0].clientY;
+ handleEventDelta(event, deltaY);
+ },
+ [handleEventDelta]
+ );
+
+ const startListening = useCallback(
+ (el) => {
+ // bail early if no element is available to attach to
+ if (!el) return;
+
+ const notPassive = supportsPassiveEvents ? { passive: false } : false;
+ el.addEventListener('wheel', onWheel, notPassive);
+ el.addEventListener('touchstart', onTouchStart, notPassive);
+ el.addEventListener('touchmove', onTouchMove, notPassive);
+ },
+ [onTouchMove, onTouchStart, onWheel]
+ );
+
+ const stopListening = useCallback(
+ (el) => {
+ // bail early if no element is available to detach from
+ if (!el) return;
+
+ el.removeEventListener('wheel', onWheel, false);
+ el.removeEventListener('touchstart', onTouchStart, false);
+ el.removeEventListener('touchmove', onTouchMove, false);
+ },
+ [onTouchMove, onTouchStart, onWheel]
+ );
+
+ useEffect(() => {
+ if (!isEnabled) return;
+
+ const element = scrollTarget.current;
+ startListening(element);
+
+ return () => {
+ stopListening(element);
+ };
+ }, [isEnabled, startListening, stopListening]);
+
+ return (element: HTMLElement | null) => {
+ scrollTarget.current = element;
+ };
+}
diff --git a/packages/react-select/src/internal/useScrollLock.ts b/packages/react-select/src/internal/useScrollLock.ts
new file mode 100644
index 0000000000..150a0a6f99
--- /dev/null
+++ b/packages/react-select/src/internal/useScrollLock.ts
@@ -0,0 +1,189 @@
+import { useCallback, useEffect, useRef } from 'react';
+
+const STYLE_KEYS = [
+ 'boxSizing',
+ 'height',
+ 'overflow',
+ 'paddingRight',
+ 'position',
+] as const;
+
+const LOCK_STYLES = {
+ boxSizing: 'border-box', // account for possible declaration `width: 100%;` on body
+ overflow: 'hidden',
+ position: 'relative',
+ height: '100%',
+};
+
+function preventTouchMove(e: TouchEvent) {
+ if (e.cancelable) e.preventDefault();
+}
+
+function allowTouchMove(e: TouchEvent) {
+ e.stopPropagation();
+}
+
+function preventInertiaScroll(this: HTMLElement) {
+ const top = this.scrollTop;
+ const totalScroll = this.scrollHeight;
+ const currentScroll = top + this.offsetHeight;
+
+ if (top === 0) {
+ this.scrollTop = 1;
+ } else if (currentScroll === totalScroll) {
+ this.scrollTop = top - 1;
+ }
+}
+
+// `ontouchstart` check works on most browsers
+// `maxTouchPoints` works on IE10/11 and Surface
+function isTouchDevice() {
+ return 'ontouchstart' in window || navigator.maxTouchPoints;
+}
+
+const canUseDOM = !!(
+ typeof window !== 'undefined' &&
+ window.document &&
+ window.document.createElement
+);
+
+let activeScrollLocks = 0;
+
+interface Options {
+ readonly isEnabled: boolean;
+ readonly accountForScrollbars?: boolean;
+}
+
+const listenerOptions = {
+ capture: false,
+ passive: false,
+};
+
+export default function useScrollLock({
+ isEnabled,
+ accountForScrollbars = true,
+}: Options) {
+ const originalStyles = useRef<{ [key: string]: string }>({});
+ const scrollTarget = useRef(null);
+
+ const addScrollLock = useCallback(
+ (touchScrollTarget: HTMLElement | null) => {
+ if (!canUseDOM) return;
+
+ const target = document.body;
+ const targetStyle = target && target.style;
+
+ if (accountForScrollbars) {
+ // store any styles already applied to the body
+ STYLE_KEYS.forEach((key) => {
+ const val = targetStyle && targetStyle[key];
+ originalStyles.current[key] = val;
+ });
+ }
+
+ // apply the lock styles and padding if this is the first scroll lock
+ if (accountForScrollbars && activeScrollLocks < 1) {
+ const currentPadding =
+ parseInt(originalStyles.current.paddingRight, 10) || 0;
+ const clientWidth = document.body ? document.body.clientWidth : 0;
+ const adjustedPadding =
+ window.innerWidth - clientWidth + currentPadding || 0;
+
+ Object.keys(LOCK_STYLES).forEach((key) => {
+ const val = LOCK_STYLES[key as keyof typeof LOCK_STYLES];
+ if (targetStyle) {
+ targetStyle[key as keyof typeof LOCK_STYLES] = val;
+ }
+ });
+
+ if (targetStyle) {
+ targetStyle.paddingRight = `${adjustedPadding}px`;
+ }
+ }
+
+ // account for touch devices
+ if (target && isTouchDevice()) {
+ // Mobile Safari ignores { overflow: hidden } declaration on the body.
+ target.addEventListener('touchmove', preventTouchMove, listenerOptions);
+
+ // Allow scroll on provided target
+ if (touchScrollTarget) {
+ touchScrollTarget.addEventListener(
+ 'touchstart',
+ preventInertiaScroll,
+ listenerOptions
+ );
+ touchScrollTarget.addEventListener(
+ 'touchmove',
+ allowTouchMove,
+ listenerOptions
+ );
+ }
+ }
+
+ // increment active scroll locks
+ activeScrollLocks += 1;
+ },
+ [accountForScrollbars]
+ );
+
+ const removeScrollLock = useCallback(
+ (touchScrollTarget: HTMLElement | null) => {
+ if (!canUseDOM) return;
+
+ const target = document.body;
+ const targetStyle = target && target.style;
+
+ // safely decrement active scroll locks
+ activeScrollLocks = Math.max(activeScrollLocks - 1, 0);
+
+ // reapply original body styles, if any
+ if (accountForScrollbars && activeScrollLocks < 1) {
+ STYLE_KEYS.forEach((key) => {
+ const val = originalStyles.current[key];
+ if (targetStyle) {
+ targetStyle[key] = val;
+ }
+ });
+ }
+
+ // remove touch listeners
+ if (target && isTouchDevice()) {
+ target.removeEventListener(
+ 'touchmove',
+ preventTouchMove,
+ listenerOptions
+ );
+
+ if (touchScrollTarget) {
+ touchScrollTarget.removeEventListener(
+ 'touchstart',
+ preventInertiaScroll,
+ listenerOptions
+ );
+ touchScrollTarget.removeEventListener(
+ 'touchmove',
+ allowTouchMove,
+ listenerOptions
+ );
+ }
+ }
+ },
+ [accountForScrollbars]
+ );
+
+ useEffect(() => {
+ if (!isEnabled) return;
+
+ const element = scrollTarget.current;
+ addScrollLock(element);
+
+ return () => {
+ removeScrollLock(element);
+ };
+ }, [isEnabled, addScrollLock, removeScrollLock]);
+
+ return (element: HTMLElement | null) => {
+ scrollTarget.current = element;
+ };
+}
diff --git a/packages/react-select/src/stateManager.tsx b/packages/react-select/src/stateManager.tsx
new file mode 100644
index 0000000000..3efe781536
--- /dev/null
+++ b/packages/react-select/src/stateManager.tsx
@@ -0,0 +1,38 @@
+import * as React from 'react';
+import {
+ forwardRef,
+ MutableRefObject,
+ ReactElement,
+ RefAttributes,
+} from 'react';
+
+import { GroupBase } from './types';
+import Select from './Select';
+import useStateManager from './useStateManager';
+import type { StateManagerProps } from './useStateManager';
+export type { StateManagerProps };
+
+type StateManagedSelect = <
+ Option = unknown,
+ IsMulti extends boolean = false,
+ Group extends GroupBase = GroupBase
+>(
+ props: StateManagerProps &
+ RefAttributes>
+) => ReactElement;
+
+const StateManagedSelect = forwardRef(
+ >(
+ props: StateManagerProps ,
+ ref:
+ | ((instance: Select | null) => void)
+ | MutableRefObject | null>
+ | null
+ ) => {
+ const baseSelectProps = useStateManager(props);
+
+ return ;
+ }
+) as StateManagedSelect;
+
+export default StateManagedSelect;
diff --git a/packages/react-select/src/styles.ts b/packages/react-select/src/styles.ts
new file mode 100644
index 0000000000..0e0e1b863b
--- /dev/null
+++ b/packages/react-select/src/styles.ts
@@ -0,0 +1,159 @@
+import {
+ containerCSS,
+ ContainerProps,
+ indicatorsContainerCSS,
+ IndicatorsContainerProps,
+ valueContainerCSS,
+ ValueContainerProps,
+} from './components/containers';
+import { ControlProps, css as controlCSS } from './components/Control';
+import {
+ groupCSS,
+ groupHeadingCSS,
+ GroupHeadingProps,
+ GroupProps,
+} from './components/Group';
+import {
+ clearIndicatorCSS,
+ dropdownIndicatorCSS,
+ loadingIndicatorCSS,
+ indicatorSeparatorCSS,
+ ClearIndicatorProps,
+ DropdownIndicatorProps,
+ IndicatorSeparatorProps,
+ LoadingIndicatorProps,
+} from './components/indicators';
+import { inputCSS, InputProps } from './components/Input';
+import { placeholderCSS, PlaceholderProps } from './components/Placeholder';
+import { optionCSS, OptionProps } from './components/Option';
+import {
+ menuCSS,
+ menuListCSS,
+ menuPortalCSS,
+ noOptionsMessageCSS,
+ loadingMessageCSS,
+ NoticeProps,
+ MenuProps,
+ MenuListProps,
+ PortalStyleArgs,
+} from './components/Menu';
+import {
+ css as singleValueCSS,
+ SingleValueProps,
+} from './components/SingleValue';
+import {
+ multiValueCSS,
+ multiValueLabelCSS,
+ MultiValueProps,
+ multiValueRemoveCSS,
+} from './components/MultiValue';
+import { CSSObjectWithLabel, GroupBase } from './types';
+
+export interface StylesProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ clearIndicator: ClearIndicatorProps ;
+ container: ContainerProps ;
+ control: ControlProps ;
+ dropdownIndicator: DropdownIndicatorProps ;
+ group: GroupProps ;
+ groupHeading: GroupHeadingProps ;
+ indicatorsContainer: IndicatorsContainerProps ;
+ indicatorSeparator: IndicatorSeparatorProps ;
+ input: InputProps ;
+ loadingIndicator: LoadingIndicatorProps ;
+ loadingMessage: NoticeProps ;
+ menu: MenuProps ;
+ menuList: MenuListProps ;
+ menuPortal: PortalStyleArgs;
+ multiValue: MultiValueProps ;
+ multiValueLabel: MultiValueProps ;
+ multiValueRemove: MultiValueProps ;
+ noOptionsMessage: NoticeProps ;
+ option: OptionProps ;
+ placeholder: PlaceholderProps ;
+ singleValue: SingleValueProps ;
+ valueContainer: ValueContainerProps ;
+}
+
+export const defaultStyles: {
+ [K in keyof StylesProps]: (
+ props: StylesProps>[K],
+ unstyled: boolean
+ ) => CSSObjectWithLabel;
+} = {
+ clearIndicator: clearIndicatorCSS,
+ container: containerCSS,
+ control: controlCSS,
+ dropdownIndicator: dropdownIndicatorCSS,
+ group: groupCSS,
+ groupHeading: groupHeadingCSS,
+ indicatorsContainer: indicatorsContainerCSS,
+ indicatorSeparator: indicatorSeparatorCSS,
+ input: inputCSS,
+ loadingIndicator: loadingIndicatorCSS,
+ loadingMessage: loadingMessageCSS,
+ menu: menuCSS,
+ menuList: menuListCSS,
+ menuPortal: menuPortalCSS,
+ multiValue: multiValueCSS,
+ multiValueLabel: multiValueLabelCSS,
+ multiValueRemove: multiValueRemoveCSS,
+ noOptionsMessage: noOptionsMessageCSS,
+ option: optionCSS,
+ placeholder: placeholderCSS,
+ singleValue: singleValueCSS,
+ valueContainer: valueContainerCSS,
+};
+
+export type StylesConfig<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> = {
+ [K in keyof StylesProps ]?: (
+ base: CSSObjectWithLabel,
+ props: StylesProps [K]
+ ) => CSSObjectWithLabel;
+};
+
+export type ClassNamesConfig<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> = {
+ [K in keyof StylesProps ]?: (
+ props: StylesProps [K]
+ ) => string;
+};
+
+// Merge Utility
+// Allows consumers to extend a base Select with additional styles
+
+export function mergeStyles<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>(
+ source: StylesConfig ,
+ target: StylesConfig = {}
+) {
+ // initialize with source styles
+ const styles = { ...source };
+
+ // massage in target styles
+ Object.keys(target).forEach((keyAsString) => {
+ const key = keyAsString as keyof StylesConfig ;
+ if (source[key]) {
+ styles[key] = (rsCss: any, props: any) => {
+ return target[key]!(source[key]!(rsCss, props), props);
+ };
+ } else {
+ styles[key] = target[key] as any;
+ }
+ });
+
+ return styles;
+}
diff --git a/packages/react-select/src/theme.ts b/packages/react-select/src/theme.ts
new file mode 100644
index 0000000000..9658996c5d
--- /dev/null
+++ b/packages/react-select/src/theme.ts
@@ -0,0 +1,45 @@
+import { Theme } from './types';
+
+export const colors = {
+ primary: '#2684FF',
+ primary75: '#4C9AFF',
+ primary50: '#B2D4FF',
+ primary25: '#DEEBFF',
+
+ danger: '#DE350B',
+ dangerLight: '#FFBDAD',
+
+ neutral0: 'hsl(0, 0%, 100%)',
+ neutral5: 'hsl(0, 0%, 95%)',
+ neutral10: 'hsl(0, 0%, 90%)',
+ neutral20: 'hsl(0, 0%, 80%)',
+ neutral30: 'hsl(0, 0%, 70%)',
+ neutral40: 'hsl(0, 0%, 60%)',
+ neutral50: 'hsl(0, 0%, 50%)',
+ neutral60: 'hsl(0, 0%, 40%)',
+ neutral70: 'hsl(0, 0%, 30%)',
+ neutral80: 'hsl(0, 0%, 20%)',
+ neutral90: 'hsl(0, 0%, 10%)',
+};
+
+const borderRadius = 4;
+// Used to calculate consistent margin/padding on elements
+const baseUnit = 4;
+// The minimum height of the control
+const controlHeight = 38;
+// The amount of space between the control and menu */
+const menuGutter = baseUnit * 2;
+
+export const spacing = {
+ baseUnit,
+ controlHeight,
+ menuGutter,
+};
+
+export const defaultTheme: Theme = {
+ borderRadius,
+ colors,
+ spacing,
+};
+
+export type ThemeConfig = Theme | ((theme: Theme) => Theme);
diff --git a/packages/react-select/src/types.ts b/packages/react-select/src/types.ts
new file mode 100644
index 0000000000..516b657aed
--- /dev/null
+++ b/packages/react-select/src/types.ts
@@ -0,0 +1,200 @@
+import { CSSObject } from '@emotion/react';
+import { Props } from './Select';
+import { StylesProps } from './styles';
+
+export interface GroupBase {
+ readonly options: readonly Option[];
+ readonly label?: string;
+}
+
+export type OptionsOrGroups > =
+ readonly (Option | Group)[];
+
+export type Options = readonly Option[];
+
+export type SingleValue = Option | null;
+export type MultiValue = readonly Option[];
+
+export type PropsValue = MultiValue | SingleValue ;
+
+export type OnChangeValue =
+ IsMulti extends true ? MultiValue : SingleValue ;
+
+export interface Colors {
+ primary: string;
+ primary75: string;
+ primary50: string;
+ primary25: string;
+
+ danger: string;
+ dangerLight: string;
+
+ neutral0: string;
+ neutral5: string;
+ neutral10: string;
+ neutral20: string;
+ neutral30: string;
+ neutral40: string;
+ neutral50: string;
+ neutral60: string;
+ neutral70: string;
+ neutral80: string;
+ neutral90: string;
+}
+
+export interface ThemeSpacing {
+ baseUnit: number;
+ controlHeight: number;
+ menuGutter: number;
+}
+
+export interface Theme {
+ borderRadius: number;
+ colors: Colors;
+ spacing: ThemeSpacing;
+}
+
+export type ClassNamesState = { [key: string]: boolean };
+
+export type CX = (
+ state: ClassNamesState,
+ ...classNames: (string | undefined)[]
+) => string;
+export type GetStyles<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = >(
+ propertyName: Key,
+ props: StylesProps[Key]
+) => CSSObjectWithLabel;
+
+export interface CommonProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> {
+ clearValue: () => void;
+ cx: CX;
+ /**
+ Get the styles of a particular part of the select. Pass in the name of the
+ property as the first argument, and the current props as the second argument.
+ See the `styles` object for the properties available.
+ */
+ getStyles: GetStyles ;
+ getClassNames: >(
+ propertyName: Key,
+ props: StylesProps[Key]
+ ) => string | undefined;
+ getValue: () => Options ;
+ hasValue: boolean;
+ isMulti: boolean;
+ isRtl: boolean;
+ options: OptionsOrGroups ;
+ selectOption: (newValue: Option) => void;
+ selectProps: Props ;
+ setValue: (
+ newValue: OnChangeValue ,
+ action: SetValueAction,
+ option?: Option
+ ) => void;
+ theme: Theme;
+}
+
+export interface CommonPropsAndClassName<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> extends CommonProps {
+ className?: string | undefined;
+}
+
+export interface ActionMetaBase {
+ option?: Option | undefined;
+ removedValue?: Option;
+ removedValues?: Options ;
+ name?: string;
+}
+
+export interface SelectOptionActionMeta extends ActionMetaBase {
+ action: 'select-option';
+ option: Option | undefined;
+ name?: string;
+}
+
+export interface DeselectOptionActionMeta
+ extends ActionMetaBase {
+ action: 'deselect-option';
+ option: Option | undefined;
+ name?: string;
+}
+
+export interface RemoveValueActionMeta extends ActionMetaBase {
+ action: 'remove-value';
+ removedValue: Option;
+ name?: string;
+}
+
+export interface PopValueActionMeta extends ActionMetaBase {
+ action: 'pop-value';
+ removedValue: Option;
+ name?: string;
+}
+
+export interface ClearActionMeta extends ActionMetaBase {
+ action: 'clear';
+ removedValues: Options ;
+ name?: string;
+}
+
+export interface CreateOptionActionMeta extends ActionMetaBase {
+ action: 'create-option';
+ name?: string;
+ option: Option;
+}
+
+export interface InitialInputFocusedActionMeta
+ extends ActionMetaBase {
+ action: 'initial-input-focus';
+ value: OnChangeValue ;
+ options?: Options ;
+}
+
+export type ActionMeta =
+ | SelectOptionActionMeta
+ | DeselectOptionActionMeta
+ | RemoveValueActionMeta
+ | PopValueActionMeta
+ | ClearActionMeta
+ | CreateOptionActionMeta ;
+
+export type SetValueAction = 'select-option' | 'deselect-option';
+
+export type InputAction =
+ | 'set-value'
+ | 'input-change'
+ | 'input-blur'
+ | 'menu-close';
+
+export interface InputActionMeta {
+ action: InputAction;
+ /** The previous value of the search input. */
+ prevInputValue: string;
+}
+
+export type MenuPlacement = 'auto' | 'bottom' | 'top';
+export type CoercedMenuPlacement = 'bottom' | 'top';
+export type MenuPosition = 'absolute' | 'fixed';
+
+export type FocusDirection =
+ | 'up'
+ | 'down'
+ | 'pageup'
+ | 'pagedown'
+ | 'first'
+ | 'last';
+
+export type GetOptionLabel = (option: Option) => string;
+export type GetOptionValue = (option: Option) => string;
+
+export type CSSObjectWithLabel = CSSObject & { label?: string };
diff --git a/packages/react-select/src/useAsync.ts b/packages/react-select/src/useAsync.ts
new file mode 100644
index 0000000000..334f66d7f2
--- /dev/null
+++ b/packages/react-select/src/useAsync.ts
@@ -0,0 +1,202 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { handleInputChange } from './utils';
+import { StateManagerProps } from './useStateManager';
+import { GroupBase, InputActionMeta, OptionsOrGroups } from './types';
+
+type AsyncManagedPropKeys =
+ | 'options'
+ | 'isLoading'
+ | 'onInputChange'
+ | 'filterOption';
+
+export interface AsyncAdditionalProps > {
+ /**
+ * The default set of options to show before the user starts searching. When
+ * set to `true`, the results for loadOptions('') will be autoloaded.
+ */
+ defaultOptions?: OptionsOrGroups | boolean;
+ /**
+ * If cacheOptions is truthy, then the loaded data will be cached. The cache
+ * will remain until `cacheOptions` changes value.
+ */
+ cacheOptions?: any;
+ /**
+ * Function that returns a promise, which is the set of options to be used
+ * once the promise resolves.
+ */
+ loadOptions?: (
+ inputValue: string,
+ callback: (options: OptionsOrGroups ) => void
+ ) => Promise> | void;
+ /**
+ * Will cause the select to be displayed in the loading state, even if the
+ * Async select is not currently waiting for loadOptions to resolve
+ */
+ isLoading?: boolean;
+}
+
+export type AsyncProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = StateManagerProps &
+ AsyncAdditionalProps ;
+
+export default function useAsync<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase ,
+ AdditionalProps
+>({
+ defaultOptions: propsDefaultOptions = false,
+ cacheOptions = false,
+ loadOptions: propsLoadOptions,
+ options: propsOptions,
+ isLoading: propsIsLoading = false,
+ onInputChange: propsOnInputChange,
+ filterOption = null,
+ ...restSelectProps
+}: AsyncProps & AdditionalProps): StateManagerProps<
+ Option,
+ IsMulti,
+ Group
+> &
+ Omit<
+ AdditionalProps,
+ keyof AsyncAdditionalProps | AsyncManagedPropKeys
+ > {
+ const { inputValue: propsInputValue } = restSelectProps;
+
+ const lastRequest = useRef(undefined);
+ const mounted = useRef(false);
+
+ const [defaultOptions, setDefaultOptions] = useState<
+ OptionsOrGroups | boolean | undefined
+ >(Array.isArray(propsDefaultOptions) ? propsDefaultOptions : undefined);
+ const [stateInputValue, setStateInputValue] = useState(
+ typeof propsInputValue !== 'undefined' ? (propsInputValue as string) : ''
+ );
+ const [isLoading, setIsLoading] = useState(propsDefaultOptions === true);
+ const [loadedInputValue, setLoadedInputValue] =
+ useState(undefined);
+ const [loadedOptions, setLoadedOptions] = useState<
+ OptionsOrGroups
+ >([]);
+ const [passEmptyOptions, setPassEmptyOptions] = useState(false);
+ const [optionsCache, setOptionsCache] = useState<
+ Record>
+ >({});
+ const [prevDefaultOptions, setPrevDefaultOptions] =
+ useState | boolean | undefined>(undefined);
+ const [prevCacheOptions, setPrevCacheOptions] = useState(undefined);
+
+ if (cacheOptions !== prevCacheOptions) {
+ setOptionsCache({});
+ setPrevCacheOptions(cacheOptions);
+ }
+
+ if (propsDefaultOptions !== prevDefaultOptions) {
+ setDefaultOptions(
+ Array.isArray(propsDefaultOptions) ? propsDefaultOptions : undefined
+ );
+ setPrevDefaultOptions(propsDefaultOptions);
+ }
+
+ useEffect(() => {
+ mounted.current = true;
+ return () => {
+ mounted.current = false;
+ };
+ }, []);
+
+ const loadOptions = useCallback(
+ (
+ inputValue: string,
+ callback: (options?: OptionsOrGroups) => void
+ ) => {
+ if (!propsLoadOptions) return callback();
+ const loader = propsLoadOptions(inputValue, callback);
+ if (loader && typeof loader.then === 'function') {
+ loader.then(callback, () => callback());
+ }
+ },
+ [propsLoadOptions]
+ );
+
+ useEffect(() => {
+ if (propsDefaultOptions === true) {
+ loadOptions(stateInputValue, (options) => {
+ if (!mounted.current) return;
+ setDefaultOptions(options || []);
+ setIsLoading(!!lastRequest.current);
+ });
+ }
+ // NOTE: this effect is designed to only run when the component mounts,
+ // so we don't want to include any hook dependencies
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const onInputChange = useCallback(
+ (newValue: string, actionMeta: InputActionMeta) => {
+ const inputValue = handleInputChange(
+ newValue,
+ actionMeta,
+ propsOnInputChange
+ );
+ if (!inputValue) {
+ lastRequest.current = undefined;
+ setStateInputValue('');
+ setLoadedInputValue('');
+ setLoadedOptions([]);
+ setIsLoading(false);
+ setPassEmptyOptions(false);
+ return;
+ }
+ if (cacheOptions && optionsCache[inputValue]) {
+ setStateInputValue(inputValue);
+ setLoadedInputValue(inputValue);
+ setLoadedOptions(optionsCache[inputValue]);
+ setIsLoading(false);
+ setPassEmptyOptions(false);
+ } else {
+ const request = (lastRequest.current = {});
+ setStateInputValue(inputValue);
+ setIsLoading(true);
+ setPassEmptyOptions(!loadedInputValue);
+ loadOptions(inputValue, (options) => {
+ if (!mounted) return;
+ if (request !== lastRequest.current) return;
+ lastRequest.current = undefined;
+ setIsLoading(false);
+ setLoadedInputValue(inputValue);
+ setLoadedOptions(options || []);
+ setPassEmptyOptions(false);
+ setOptionsCache(
+ options ? { ...optionsCache, [inputValue]: options } : optionsCache
+ );
+ });
+ }
+ },
+ [
+ cacheOptions,
+ loadOptions,
+ loadedInputValue,
+ optionsCache,
+ propsOnInputChange,
+ ]
+ );
+
+ const options = passEmptyOptions
+ ? []
+ : stateInputValue && loadedInputValue
+ ? loadedOptions
+ : ((defaultOptions || []) as OptionsOrGroups );
+
+ return {
+ ...restSelectProps,
+ options,
+ isLoading: isLoading || propsIsLoading,
+ onInputChange,
+ filterOption,
+ };
+}
diff --git a/packages/react-select/src/useCreatable.ts b/packages/react-select/src/useCreatable.ts
new file mode 100644
index 0000000000..b6b3ed7708
--- /dev/null
+++ b/packages/react-select/src/useCreatable.ts
@@ -0,0 +1,220 @@
+import { ReactNode, useCallback, useMemo } from 'react';
+import { PublicBaseSelectProps } from './Select';
+import {
+ ActionMeta,
+ GetOptionLabel,
+ GetOptionValue,
+ GroupBase,
+ OnChangeValue,
+ Options,
+ OptionsOrGroups,
+} from './types';
+import { cleanValue, valueTernary } from './utils';
+import {
+ getOptionValue as baseGetOptionValue,
+ getOptionLabel as baseGetOptionLabel,
+} from './builtins';
+
+export interface Accessors {
+ getOptionValue: GetOptionValue ;
+ getOptionLabel: GetOptionLabel ;
+}
+
+export interface CreatableAdditionalProps<
+ Option,
+ Group extends GroupBase
+> {
+ /**
+ * Allow options to be created while the `isLoading` prop is true. Useful to
+ * prevent the "create new ..." option being displayed while async results are
+ * still being loaded.
+ */
+ allowCreateWhileLoading?: boolean;
+ /** Sets the position of the createOption element in your options list. Defaults to 'last' */
+ createOptionPosition?: 'first' | 'last';
+ /**
+ * Gets the label for the "create new ..." option in the menu. Is given the
+ * current input value.
+ */
+ formatCreateLabel?: (inputValue: string) => ReactNode;
+ /**
+ * Determines whether the "create new ..." option should be displayed based on
+ * the current input value, select value and options array.
+ */
+ isValidNewOption?: (
+ inputValue: string,
+ value: Options ,
+ options: OptionsOrGroups ,
+ accessors: Accessors
+ ) => boolean;
+ /**
+ * Returns the data for the new option when it is created. Used to display the
+ * value, and is passed to `onChange`.
+ */
+ getNewOptionData?: (inputValue: string, optionLabel: ReactNode) => Option;
+ /**
+ * If provided, this will be called with the input value when a new option is
+ * created, and `onChange` will **not** be called. Use this when you need more
+ * control over what happens when new options are created.
+ */
+ onCreateOption?: (inputValue: string) => void;
+}
+
+type BaseCreatableProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = PublicBaseSelectProps &
+ CreatableAdditionalProps ;
+
+const compareOption = (
+ inputValue = '',
+ option: Option,
+ accessors: Accessors
+) => {
+ const candidate = String(inputValue).toLowerCase();
+ const optionValue = String(accessors.getOptionValue(option)).toLowerCase();
+ const optionLabel = String(accessors.getOptionLabel(option)).toLowerCase();
+ return optionValue === candidate || optionLabel === candidate;
+};
+
+const builtins = {
+ formatCreateLabel: (inputValue: string) => `Create "${inputValue}"`,
+ isValidNewOption: >(
+ inputValue: string,
+ selectValue: Options ,
+ selectOptions: OptionsOrGroups ,
+ accessors: Accessors
+ ) =>
+ !(
+ !inputValue ||
+ selectValue.some((option) =>
+ compareOption(inputValue, option, accessors)
+ ) ||
+ selectOptions.some((option) =>
+ compareOption(inputValue, option as Option, accessors)
+ )
+ ),
+ getNewOptionData: (inputValue: string, optionLabel: ReactNode) => ({
+ label: optionLabel,
+ value: inputValue,
+ __isNew__: true,
+ }),
+};
+
+export default function useCreatable<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+>({
+ allowCreateWhileLoading = false,
+ createOptionPosition = 'last',
+ formatCreateLabel = builtins.formatCreateLabel,
+ isValidNewOption = builtins.isValidNewOption,
+ // @ts-ignore
+ getNewOptionData = builtins.getNewOptionData,
+ onCreateOption,
+ options: propsOptions = [],
+ onChange: propsOnChange,
+ ...restSelectProps
+}: BaseCreatableProps ): PublicBaseSelectProps<
+ Option,
+ IsMulti,
+ Group
+> {
+ const {
+ getOptionValue = baseGetOptionValue,
+ getOptionLabel = baseGetOptionLabel,
+ inputValue,
+ isLoading,
+ isMulti,
+ value,
+ name,
+ } = restSelectProps;
+
+ const newOption = useMemo(
+ () =>
+ isValidNewOption(inputValue, cleanValue(value), propsOptions, {
+ getOptionValue,
+ getOptionLabel,
+ })
+ ? getNewOptionData(inputValue, formatCreateLabel(inputValue))
+ : undefined,
+ [
+ formatCreateLabel,
+ getNewOptionData,
+ getOptionLabel,
+ getOptionValue,
+ inputValue,
+ isValidNewOption,
+ propsOptions,
+ value,
+ ]
+ );
+
+ const options = useMemo(
+ () =>
+ (allowCreateWhileLoading || !isLoading) && newOption
+ ? createOptionPosition === 'first'
+ ? [newOption, ...propsOptions]
+ : [...propsOptions, newOption]
+ : propsOptions,
+ [
+ allowCreateWhileLoading,
+ createOptionPosition,
+ isLoading,
+ newOption,
+ propsOptions,
+ ]
+ );
+
+ const onChange = useCallback(
+ (
+ newValue: OnChangeValue ,
+ actionMeta: ActionMeta
+ ) => {
+ if (actionMeta.action !== 'select-option') {
+ return propsOnChange(newValue, actionMeta);
+ }
+ const valueArray = Array.isArray(newValue) ? newValue : [newValue];
+
+ if (valueArray[valueArray.length - 1] === newOption) {
+ if (onCreateOption) onCreateOption(inputValue);
+ else {
+ const newOptionData = getNewOptionData(inputValue, inputValue);
+ const newActionMeta: ActionMeta = {
+ action: 'create-option',
+ name,
+ option: newOptionData,
+ };
+ propsOnChange(
+ valueTernary(
+ isMulti,
+ [...cleanValue(value), newOptionData],
+ newOptionData
+ ),
+ newActionMeta
+ );
+ }
+ return;
+ }
+ propsOnChange(newValue, actionMeta);
+ },
+ [
+ getNewOptionData,
+ inputValue,
+ isMulti,
+ name,
+ newOption,
+ onCreateOption,
+ propsOnChange,
+ value,
+ ]
+ );
+
+ return {
+ ...restSelectProps,
+ options,
+ onChange,
+ };
+}
diff --git a/packages/react-select/src/useStateManager.ts b/packages/react-select/src/useStateManager.ts
new file mode 100644
index 0000000000..262ecdbea0
--- /dev/null
+++ b/packages/react-select/src/useStateManager.ts
@@ -0,0 +1,121 @@
+import {
+ ActionMeta,
+ GroupBase,
+ InputActionMeta,
+ OnChangeValue,
+ PropsValue,
+} from './types';
+import { PublicBaseSelectProps } from './Select';
+import { useCallback, useState } from 'react';
+
+type StateManagedPropKeys =
+ | 'inputValue'
+ | 'menuIsOpen'
+ | 'onChange'
+ | 'onInputChange'
+ | 'onMenuClose'
+ | 'onMenuOpen'
+ | 'value';
+
+type SelectPropsWithOptionalStateManagedProps<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase
+> = Omit, StateManagedPropKeys> &
+ Partial>;
+
+export interface StateManagerAdditionalProps {
+ defaultInputValue?: string;
+ defaultMenuIsOpen?: boolean;
+ defaultValue?: PropsValue ;
+}
+
+export type StateManagerProps<
+ Option = unknown,
+ IsMulti extends boolean = boolean,
+ Group extends GroupBase = GroupBase
+> = SelectPropsWithOptionalStateManagedProps &
+ StateManagerAdditionalProps ;
+
+export default function useStateManager<
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase ,
+ AdditionalProps
+>({
+ defaultInputValue = '',
+ defaultMenuIsOpen = false,
+ defaultValue = null,
+ inputValue: propsInputValue,
+ menuIsOpen: propsMenuIsOpen,
+ onChange: propsOnChange,
+ onInputChange: propsOnInputChange,
+ onMenuClose: propsOnMenuClose,
+ onMenuOpen: propsOnMenuOpen,
+ value: propsValue,
+ ...restSelectProps
+}: StateManagerProps &
+ AdditionalProps): PublicBaseSelectProps &
+ Omit<
+ AdditionalProps,
+ keyof StateManagerAdditionalProps | StateManagedPropKeys
+ > {
+ const [stateInputValue, setStateInputValue] = useState(
+ propsInputValue !== undefined ? propsInputValue : defaultInputValue
+ );
+ const [stateMenuIsOpen, setStateMenuIsOpen] = useState(
+ propsMenuIsOpen !== undefined ? propsMenuIsOpen : defaultMenuIsOpen
+ );
+ const [stateValue, setStateValue] = useState(
+ propsValue !== undefined ? propsValue : defaultValue
+ );
+
+ const onChange = useCallback(
+ (value: OnChangeValue , actionMeta: ActionMeta ) => {
+ if (typeof propsOnChange === 'function') {
+ propsOnChange(value, actionMeta);
+ }
+ setStateValue(value);
+ },
+ [propsOnChange]
+ );
+ const onInputChange = useCallback(
+ (value: string, actionMeta: InputActionMeta) => {
+ let newValue;
+ if (typeof propsOnInputChange === 'function') {
+ newValue = propsOnInputChange(value, actionMeta);
+ }
+ setStateInputValue(newValue !== undefined ? newValue : value);
+ },
+ [propsOnInputChange]
+ );
+ const onMenuOpen = useCallback(() => {
+ if (typeof propsOnMenuOpen === 'function') {
+ propsOnMenuOpen();
+ }
+ setStateMenuIsOpen(true);
+ }, [propsOnMenuOpen]);
+ const onMenuClose = useCallback(() => {
+ if (typeof propsOnMenuClose === 'function') {
+ propsOnMenuClose();
+ }
+ setStateMenuIsOpen(false);
+ }, [propsOnMenuClose]);
+
+ const inputValue =
+ propsInputValue !== undefined ? propsInputValue : stateInputValue;
+ const menuIsOpen =
+ propsMenuIsOpen !== undefined ? propsMenuIsOpen : stateMenuIsOpen;
+ const value = propsValue !== undefined ? propsValue : stateValue;
+
+ return {
+ ...restSelectProps,
+ inputValue,
+ menuIsOpen,
+ onChange,
+ onInputChange,
+ onMenuClose,
+ onMenuOpen,
+ value,
+ };
+}
diff --git a/packages/react-select/src/utils.ts b/packages/react-select/src/utils.ts
new file mode 100644
index 0000000000..5fb746ac55
--- /dev/null
+++ b/packages/react-select/src/utils.ts
@@ -0,0 +1,410 @@
+import type { StylesProps } from './styles';
+import type {
+ ClassNamesState,
+ CommonPropsAndClassName,
+ GroupBase,
+ InputActionMeta,
+ MultiValue,
+ OnChangeValue,
+ Options,
+ PropsValue,
+ SingleValue,
+} from './types';
+
+// ==============================
+// NO OP
+// ==============================
+
+export const noop = () => {};
+export const emptyString = () => '';
+
+// ==============================
+// Class Name Prefixer
+// ==============================
+
+/**
+ String representation of component state for styling with class names.
+
+ Expects an array of strings OR a string/object pair:
+ - className(['comp', 'comp-arg', 'comp-arg-2'])
+ @returns 'react-select__comp react-select__comp-arg react-select__comp-arg-2'
+ - className('comp', { some: true, state: false })
+ @returns 'react-select__comp react-select__comp--some'
+*/
+function applyPrefixToName(prefix: string, name: string) {
+ if (!name) {
+ return prefix;
+ } else if (name[0] === '-') {
+ return prefix + name;
+ } else {
+ return prefix + '__' + name;
+ }
+}
+
+export function classNames(
+ prefix?: string | null,
+ state?: ClassNamesState,
+ ...classNameList: string[]
+) {
+ const arr = [...classNameList];
+ if (state && prefix) {
+ for (let key in state) {
+ if (state.hasOwnProperty(key) && state[key]) {
+ arr.push(`${applyPrefixToName(prefix, key)}`);
+ }
+ }
+ }
+
+ return arr
+ .filter((i) => i)
+ .map((i) => String(i).trim())
+ .join(' ');
+}
+// ==============================
+// Clean Value
+// ==============================
+
+export const cleanValue = (
+ value: PropsValue
+): Options => {
+ if (isArray(value)) return value.filter(Boolean);
+ if (typeof value === 'object' && value !== null) return [value];
+ return [];
+};
+
+// ==============================
+// Clean Common Props
+// ==============================
+
+export const cleanCommonProps = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase ,
+ AdditionalProps
+>(
+ props: Partial> &
+ AdditionalProps
+): Omit<
+ AdditionalProps,
+ keyof CommonPropsAndClassName
+> => {
+ //className
+ const {
+ className, // not listed in commonProps documentation, needs to be removed to allow Emotion to generate classNames
+ clearValue,
+ cx,
+ getStyles,
+ getClassNames,
+ getValue,
+ hasValue,
+ isMulti,
+ isRtl,
+ options, // not listed in commonProps documentation
+ selectOption,
+ selectProps,
+ setValue,
+ theme, // not listed in commonProps documentation
+ ...innerProps
+ } = props;
+ return { ...innerProps };
+};
+
+// ==============================
+// Get Style Props
+// ==============================
+
+export const getStyleProps = <
+ Option,
+ IsMulti extends boolean,
+ Group extends GroupBase ,
+ Key extends keyof StylesProps
+>(
+ props: Pick<
+ CommonPropsAndClassName ,
+ 'cx' | 'getStyles' | 'getClassNames' | 'className'
+ > &
+ StylesProps [Key],
+ name: Key,
+ classNamesState?: ClassNamesState
+) => {
+ const { cx, getStyles, getClassNames, className } = props;
+ return {
+ css: getStyles(name, props),
+ className: cx(classNamesState ?? {}, getClassNames(name, props), className),
+ };
+};
+
+// ==============================
+// Handle Input Change
+// ==============================
+
+export function handleInputChange(
+ inputValue: string,
+ actionMeta: InputActionMeta,
+ onInputChange?: (
+ newValue: string,
+ actionMeta: InputActionMeta
+ ) => string | void
+) {
+ if (onInputChange) {
+ const newValue = onInputChange(inputValue, actionMeta);
+ if (typeof newValue === 'string') return newValue;
+ }
+ return inputValue;
+}
+
+// ==============================
+// Scroll Helpers
+// ==============================
+
+export function isDocumentElement(
+ el: HTMLElement | typeof window
+): el is typeof window {
+ return [document.documentElement, document.body, window].indexOf(el) > -1;
+}
+
+// Normalized Scroll Top
+// ------------------------------
+
+export function normalizedHeight(el: HTMLElement | typeof window): number {
+ if (isDocumentElement(el)) {
+ return window.innerHeight;
+ }
+
+ return el.clientHeight;
+}
+
+// Normalized scrollTo & scrollTop
+// ------------------------------
+
+export function getScrollTop(el: HTMLElement | typeof window): number {
+ if (isDocumentElement(el)) {
+ return window.pageYOffset;
+ }
+ return el.scrollTop;
+}
+
+export function scrollTo(el: HTMLElement | typeof window, top: number): void {
+ // with a scroll distance, we perform scroll on the element
+ if (isDocumentElement(el)) {
+ window.scrollTo(0, top);
+ return;
+ }
+
+ el.scrollTop = top;
+}
+
+// Get Scroll Parent
+// ------------------------------
+
+export function getScrollParent(element: HTMLElement) {
+ let style = getComputedStyle(element);
+ const excludeStaticParent = style.position === 'absolute';
+ const overflowRx = /(auto|scroll)/;
+
+ if (style.position === 'fixed') return document.documentElement;
+
+ for (
+ let parent: HTMLElement | null = element;
+ (parent = parent.parentElement);
+
+ ) {
+ style = getComputedStyle(parent);
+ if (excludeStaticParent && style.position === 'static') {
+ continue;
+ }
+ if (overflowRx.test(style.overflow + style.overflowY + style.overflowX)) {
+ return parent;
+ }
+ }
+
+ return document.documentElement;
+}
+
+// Animated Scroll To
+// ------------------------------
+
+/**
+ @param t: time (elapsed)
+ @param b: initial value
+ @param c: amount of change
+ @param d: duration
+*/
+function easeOutCubic(t: number, b: number, c: number, d: number): number {
+ return c * ((t = t / d - 1) * t * t + 1) + b;
+}
+
+export function animatedScrollTo(
+ element: HTMLElement | typeof window,
+ to: number,
+ duration = 200,
+ callback: (element: HTMLElement | typeof window) => void = noop
+) {
+ const start = getScrollTop(element);
+ const change = to - start;
+ const increment = 10;
+ let currentTime = 0;
+
+ function animateScroll() {
+ currentTime += increment;
+ const val = easeOutCubic(currentTime, start, change, duration);
+ scrollTo(element, val);
+ if (currentTime < duration) {
+ window.requestAnimationFrame(animateScroll);
+ } else {
+ callback(element);
+ }
+ }
+ animateScroll();
+}
+
+// Scroll Into View
+// ------------------------------
+
+export function scrollIntoView(
+ menuEl: HTMLElement,
+ focusedEl: HTMLElement
+): void {
+ const menuRect = menuEl.getBoundingClientRect();
+ const focusedRect = focusedEl.getBoundingClientRect();
+ const overScroll = focusedEl.offsetHeight / 3;
+
+ if (focusedRect.bottom + overScroll > menuRect.bottom) {
+ scrollTo(
+ menuEl,
+ Math.min(
+ focusedEl.offsetTop +
+ focusedEl.clientHeight -
+ menuEl.offsetHeight +
+ overScroll,
+ menuEl.scrollHeight
+ )
+ );
+ } else if (focusedRect.top - overScroll < menuRect.top) {
+ scrollTo(menuEl, Math.max(focusedEl.offsetTop - overScroll, 0));
+ }
+}
+
+// ==============================
+// Get bounding client object
+// ==============================
+
+// cannot get keys using array notation with DOMRect
+export function getBoundingClientObj(element: HTMLElement) {
+ const rect = element.getBoundingClientRect();
+ return {
+ bottom: rect.bottom,
+ height: rect.height,
+ left: rect.left,
+ right: rect.right,
+ top: rect.top,
+ width: rect.width,
+ };
+}
+export interface RectType {
+ left: number;
+ right: number;
+ bottom: number;
+ height: number;
+ width: number;
+}
+
+// ==============================
+// String to Key (kebabify)
+// ==============================
+
+export function toKey(str: string) {
+ return str.replace(/\W/g, '-');
+}
+
+// ==============================
+// Touch Capability Detector
+// ==============================
+
+export function isTouchCapable() {
+ try {
+ document.createEvent('TouchEvent');
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+// ==============================
+// Mobile Device Detector
+// ==============================
+
+export function isMobileDevice() {
+ try {
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
+ navigator.userAgent
+ );
+ } catch (e) {
+ return false;
+ }
+}
+
+// ==============================
+// Passive Event Detector
+// ==============================
+
+// https://github.com/rafgraph/detect-it/blob/main/src/index.ts#L19-L36
+let passiveOptionAccessed = false;
+const options = {
+ get passive() {
+ return (passiveOptionAccessed = true);
+ },
+};
+// check for SSR
+const w:
+ | typeof window
+ | { addEventListener?: never; removeEventListener?: never } =
+ typeof window !== 'undefined' ? window : {};
+if (w.addEventListener && w.removeEventListener) {
+ w.addEventListener('p', noop, options);
+ w.removeEventListener('p', noop, false);
+}
+
+export const supportsPassiveEvents: boolean = passiveOptionAccessed;
+
+export function notNullish(item: T | null | undefined): item is T {
+ return item != null;
+}
+
+export function isArray(arg: unknown): arg is readonly T[] {
+ return Array.isArray(arg);
+}
+
+export function valueTernary(
+ isMulti: IsMulti | undefined,
+ multiValue: MultiValue ,
+ singleValue: SingleValue
+): OnChangeValue {
+ return (isMulti ? multiValue : singleValue) as OnChangeValue ;
+}
+
+export function singleValueAsValue (
+ singleValue: SingleValue
+): OnChangeValue {
+ return singleValue as OnChangeValue ;
+}
+
+export function multiValueAsValue (
+ multiValue: MultiValue
+): OnChangeValue {
+ return multiValue as OnChangeValue ;
+}
+
+export const removeProps = (
+ propsObj: Props,
+ ...properties: K
+): Omit => {
+ let propsMap = Object.entries(propsObj).filter(
+ ([key]) => !properties.includes(key)
+ );
+
+ return propsMap.reduce((newProps: { [key: string]: any }, [key, val]) => {
+ newProps[key] = val;
+ return newProps;
+ }, {}) as Omit;
+};
diff --git a/packages/react-select/tsconfig.json b/packages/react-select/tsconfig.json
new file mode 100644
index 0000000000..b9c2c7175d
--- /dev/null
+++ b/packages/react-select/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "module": "commonjs",
+ "jsx": "react",
+ "noEmit": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true
+ },
+ "exclude": ["src/__tests__"]
+}
diff --git a/scss/components.scss b/scss/components.scss
deleted file mode 100644
index ae85298368..0000000000
--- a/scss/components.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-@import "control";
-@import "menu";
-@import "mixins";
-@import "multi";
-@import "spinner";
diff --git a/scss/control.scss b/scss/control.scss
deleted file mode 100644
index 360a32f9ac..0000000000
--- a/scss/control.scss
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-// Control
-// ------------------------------
-
-@import 'spinner';
-@import 'mixins';
-
-.Select {
- position: relative;
-
- // preferred box model
- &,
- & div,
- & input,
- & span {
- @include box-sizing(border-box);
- }
-
- // handle disabled state
- &.is-disabled > .Select-control {
- background-color: $select-input-bg-disabled;
- &:hover {
- box-shadow: none;
- }
- }
- &.is-disabled .Select-arrow-zone {
- cursor: default;
- pointer-events: none;
- }
-}
-
-// base
-
-.Select-control {
- background-color: $select-input-bg;
- border-color: lighten($select-input-border-color, 5%) $select-input-border-color darken($select-input-border-color, 10%);
- border-radius: $select-input-border-radius;
- border: $select-input-border-width solid $select-input-border-color;
- color: $select-text-color;
- cursor: default;
- display: table;
- border-spacing: 0;
- border-collapse: separate;
- height: $select-input-height;
- outline: none;
- overflow: hidden;
- position: relative;
- width: 100%;
-
- &:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- }
-
- .Select-input:focus {
- outline: none;
- }
-}
-
-.is-searchable {
- &.is-open > .Select-control {
- cursor: text;
- }
-}
-
-.is-open > .Select-control {
- @include border-bottom-radius( 0 );
- background: $select-input-bg;
- border-color: darken($select-input-border-color, 10%) $select-input-border-color lighten($select-input-border-color, 5%);
-
- // flip the arrow so its pointing up when the menu is open
- .Select-arrow {
- top: -2px;
- border-color: transparent transparent $select-arrow-color;
- border-width: 0 $select-arrow-width $select-arrow-width;
- }
-}
-
-.is-searchable {
- &.is-focused:not(.is-open) > .Select-control {
- cursor: text;
- }
-}
-
-.is-focused:not(.is-open) > .Select-control {
- border-color: $select-input-border-focus lighten($select-input-border-focus, 5%) lighten($select-input-border-focus, 5%);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade($select-input-border-focus,50%);
-}
-
-// placeholder
-.Select-placeholder,
-.Select--single > .Select-control .Select-value {
- bottom: 0;
- color: $select-input-placeholder;
- left: 0;
- line-height: $select-input-internal-height;
- padding-left: $select-padding-horizontal;
- padding-right: $select-padding-horizontal;
- position: absolute;
- right: 0;
- top: 0;
-
- // crop text
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.has-value.Select--single > .Select-control .Select-value,
-.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value {
- .Select-value-label {
- color: $select-text-color;
- }
- a.Select-value-label {
- cursor: pointer;
- text-decoration: none;
-
- &:hover,
- &:focus {
- color: $select-link-hover-color;
- outline: none;
- text-decoration: underline;
- }
- }
-}
-
-
-// the element users type in
-
-.Select-input {
- // inherits `display: inline-block` from "react-input-autosize"
- height: $select-input-internal-height;
- padding-left: $select-padding-horizontal;
- padding-right: $select-padding-horizontal;
- vertical-align: middle;
-
- > input {
- background: none transparent;
- border: 0 none;
- box-shadow: none;
- cursor: default;
- display: inline-block;
- font-family: inherit;
- font-size: inherit;
- // height: $select-input-internal-height;
- margin: 0;
- outline: none;
- // padding: 0;
- line-height: 14px; /* For IE 8 compatibility */
- padding: (($select-input-internal-height - 14) / 2 - 2) 0 (($select-input-internal-height - 14) / 2 + 2); /* For IE 8 compatibility */
- -webkit-appearance: none;
-
- .is-focused & {
- cursor: text;
- }
- }
-
-}
-
-// fake-hide the input when the control is pseudo-focused
-.has-value.is-pseudo-focused .Select-input {
- opacity: 0;
-}
-
-// fake input
-.Select-control:not(.is-searchable) > .Select-input {
- outline: none;
-}
-
-// loading indicator
-.Select-loading-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: $select-loading-size;
-}
-.Select-loading {
- @include Select-spinner($select-loading-size, $select-loading-color-bg, $select-loading-color);
- vertical-align: middle;
-}
-
-
-// the little cross that clears the field
-
-.Select-clear-zone {
- @include animation( Select-animation-fadeIn 200ms );
- color: $select-clear-color;
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: $select-clear-width;
-
- &:hover {
- color: $select-clear-hover-color;
- }
-}
-.Select-clear {
- display: inline-block;
- font-size: $select-clear-size;
- line-height: 1;
-}
-.Select--multi .Select-clear-zone {
- width: $select-clear-width;
-}
-
-.Select--multi .Select-multi-value-wrapper {
- display: inline-block;
-}
-.Select .Select-aria-only {
- display: inline-block;
- height: 1px;
- width: 1px;
- margin: -1px;
- clip: rect(0,0,0,0);
- overflow: hidden;
-}
-
-
-// arrow indicator
-
-.Select-arrow-zone {
- cursor: pointer;
- display: table-cell;
- position: relative;
- text-align: center;
- vertical-align: middle;
- width: ($select-arrow-width * 5);
- padding-right: $select-arrow-width;
-}
-
-.Select-arrow {
- border-color: $select-arrow-color transparent transparent;
- border-style: solid;
- border-width: $select-arrow-width $select-arrow-width ($select-arrow-width / 2);
- display: inline-block;
- height: 0;
- width: 0;
- position: relative;
-}
-.is-open .Select-arrow,
-.Select-arrow-zone:hover > .Select-arrow {
- border-top-color: $select-arrow-color-hover;
-}
-
-
-
-
-// Animation
-// ------------------------------
-
-// fade in
-
-@-webkit-keyframes Select-animation-fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-@keyframes Select-animation-fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
diff --git a/scss/default.scss b/scss/default.scss
deleted file mode 100644
index 696d9feee9..0000000000
--- a/scss/default.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-@import "select";
-@import "control";
-@import "menu";
-@import "mixins";
-@import "multi";
-@import "spinner";
diff --git a/scss/menu.scss b/scss/menu.scss
deleted file mode 100644
index 8c220333f0..0000000000
--- a/scss/menu.scss
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// Select Menu
-// ------------------------------
-
-
-// wrapper around the menu
-
-.Select-menu-outer {
- // Unfortunately, having both border-radius and allows scrolling using overflow defined on the same
- // element forces the browser to repaint on scroll. However, if these definitions are split into an
- // outer and an inner element, the browser is able to optimize the scrolling behavior and does not
- // have to repaint on scroll.
- @include border-bottom-radius( $select-input-border-radius );
- background-color: $select-input-bg;
- border: 1px solid $select-input-border-color;
- border-top-color: mix($select-input-bg, $select-input-border-color, 50%);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- box-sizing: border-box;
- margin-top: -1px;
- max-height: $select-menu-max-height;
- position: absolute;
- top: 100%;
- width: 100%;
- z-index: $select-menu-zindex;
- -webkit-overflow-scrolling: touch;
-}
-
-
-// wrapper
-
-.Select-menu {
- max-height: ($select-menu-max-height - 2px);
- overflow-y: auto;
-}
-
-
-// options
-
-.Select-option {
- box-sizing: border-box;
- background-color: $select-option-bg;
- color: $select-option-color;
- cursor: pointer;
- display: block;
- padding: $select-padding-vertical $select-padding-horizontal;
-
- &:last-child {
- @include border-bottom-radius( $select-input-border-radius );
- }
-
- &.is-selected {
- background-color: $select-option-selected-bg;
- color: $select-option-selected-color;
- }
-
- &.is-focused {
- background-color: $select-option-focused-bg;
- color: $select-option-focused-color;
- }
-
- &.is-disabled {
- color: $select-option-disabled-color;
- cursor: default;
- }
-
-}
-
-
-// no results
-
-.Select-noresults {
- box-sizing: border-box;
- color: $select-noresults-color;
- cursor: default;
- display: block;
- padding: $select-padding-vertical $select-padding-horizontal;
-}
diff --git a/scss/mixins.scss b/scss/mixins.scss
deleted file mode 100644
index c6de744d82..0000000000
--- a/scss/mixins.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Mixins
-// ------------------------------
-
-
-// Utilities
-
-@mixin size($width, $height)
-{
- width: $width;
- height: $height;
-}
-@mixin square($size)
-{
- @include size($size, $size);
-}
-@mixin border-top-radius($radius)
-{
- border-top-right-radius: $radius;
- border-top-left-radius: $radius;
-}
-@mixin border-right-radius($radius)
-{
- border-bottom-right-radius: $radius;
- border-top-right-radius: $radius;
-}
-@mixin border-bottom-radius($radius)
-{
- border-bottom-right-radius: $radius;
- border-bottom-left-radius: $radius;
-}
-@mixin border-left-radius($radius)
-{
- border-bottom-left-radius: $radius;
- border-top-left-radius: $radius;
-}
-
-
-// Vendor Prefixes
-
-@mixin animation($animation)
-{
- -webkit-animation: $animation;
- -o-animation: $animation;
- animation: $animation;
-}
-@mixin box-sizing($boxmodel)
-{
- -webkit-box-sizing: $boxmodel;
- -moz-box-sizing: $boxmodel;
- box-sizing: $boxmodel;
-}
diff --git a/scss/multi.scss b/scss/multi.scss
deleted file mode 100644
index fce8369012..0000000000
--- a/scss/multi.scss
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Multi-Select
-// ------------------------------
-
-
-// Base
-
-.Select--multi {
-
- // add margin to the input element
- .Select-input {
- vertical-align: middle;
- // border: 1px solid transparent;
- margin-left: $select-padding-horizontal;
- padding: 0;
- }
-
- // reduce margin once there is value
- &.has-value .Select-input {
- margin-left: $select-item-gutter;
- }
-
- // Items
- .Select-value {
- background-color: $select-item-bg;
- border-radius: $select-item-border-radius;
- border: 1px solid $select-item-border-color;
- color: $select-item-color;
- display: inline-block;
- font-size: $select-item-font-size;
- margin-left: $select-item-gutter;
- margin-top: $select-item-gutter;
- vertical-align: top;
- }
-
- // common
- .Select-value-icon,
- .Select-value-label {
- display: inline-block;
- vertical-align: middle;
- }
-
- // label
- .Select-value-label {
- @include border-right-radius( $select-item-border-radius );
- cursor: default;
- padding: $select-item-padding-vertical $select-item-padding-horizontal;
- }
- a.Select-value-label {
- color: $select-item-color;
- cursor: pointer;
- text-decoration: none;
-
- &:hover {
- text-decoration: underline;
- }
- }
-
- // icon
- .Select-value-icon {
- cursor: pointer;
- @include border-left-radius( $select-item-border-radius );
- border-right: 1px solid $select-item-border-color;
-
- // move the baseline up by 1px
- padding: ($select-item-padding-vertical - 1) $select-item-padding-horizontal ($select-item-padding-vertical + 1);
-
- &:hover,
- &:focus {
- background-color: $select-item-hover-bg;
- color: $select-item-hover-color;
- }
- &:active {
- background-color: $select-item-border-color;
- }
- }
-
-}
-
-.Select--multi.is-disabled {
- .Select-value {
- background-color: $select-item-disabled-bg;
- border: 1px solid $select-item-disabled-border-color;
- color: $select-item-disabled-color;
- }
- // icon
- .Select-value-icon {
- cursor: not-allowed;
- border-right: 1px solid $select-item-disabled-border-color;
-
- &:hover,
- &:focus,
- &:active {
- background-color: $select-item-disabled-bg;
- }
- }
-}
diff --git a/scss/select.scss b/scss/select.scss
deleted file mode 100644
index de78f9d168..0000000000
--- a/scss/select.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/JedWatson/react-select
-*/
-
-// Variables
-// ------------------------------
-
-// control options
-$select-input-bg: #fff !default;
-$select-input-bg-disabled: #f9f9f9 !default;
-$select-input-border-color: #ccc !default;
-$select-input-border-radius: 4px !default;
-$select-input-border-focus: #08c !default; // blue
-$select-input-border-width: 1px !default;
-$select-input-height: 36px !default;
-$select-input-internal-height: ($select-input-height - ($select-input-border-width * 2)) !default;
-$select-input-placeholder: #aaa !default;
-$select-text-color: #333 !default;
-$select-link-hover-color: $select-input-border-focus !default;
-
-$select-padding-vertical: 8px !default;
-$select-padding-horizontal: 10px !default;
-
-// menu options
-$select-menu-zindex: 1000 !default;
-$select-menu-max-height: 200px !default;
-
-$select-option-color: lighten($select-text-color, 20%) !default;
-$select-option-bg: $select-input-bg !default;
-$select-option-focused-color: $select-text-color !default;
-$select-option-focused-bg: #f2f9fc !default; // pale blue
-$select-option-selected-color: $select-text-color !default;
-$select-option-selected-bg: #f5faff !default; // lightest blue
-$select-option-disabled-color: lighten($select-text-color, 60%) !default;
-
-$select-noresults-color: lighten($select-text-color, 40%) !default;
-
-// clear "x" button
-$select-clear-size: floor(($select-input-height / 2)) !default;
-$select-clear-color: #999 !default;
-$select-clear-hover-color: #D0021B !default; // red
-$select-clear-width: ($select-input-internal-height / 2) !default;
-
-// arrow indicator
-$select-arrow-color: #999 !default;
-$select-arrow-color-hover: #666 !default;
-$select-arrow-width: 5px !default;
-
-// loading indicator
-$select-loading-size: 16px !default;
-$select-loading-color: $select-text-color !default;
-$select-loading-color-bg: $select-input-border-color !default;
-
-// multi-select item
-$select-item-border-radius: 2px !default;
-$select-item-gutter: 5px !default;
-$select-item-padding-vertical: 2px !default;
-$select-item-padding-horizontal: 5px !default;
-$select-item-font-size: .9em !default;
-$select-item-color: #08c !default; // pale blue
-$select-item-bg: #f2f9fc !default;
-$select-item-border-color: darken($select-item-bg, 10%) !default;
-$select-item-hover-color: darken($select-item-color, 5%) !default; // pale blue
-$select-item-hover-bg: darken($select-item-bg, 5%) !default;
-$select-item-disabled-color: #333 !default;
-$select-item-disabled-bg: #fcfcfc !default;
-$select-item-disabled-border-color: darken($select-item-disabled-bg, 10%) !default;
diff --git a/scss/spinner.scss b/scss/spinner.scss
deleted file mode 100644
index 64c922ac23..0000000000
--- a/scss/spinner.scss
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Spinner
-// ------------------------------
-@import 'mixins';
-
-@mixin Select-spinner($size, $orbit, $satellite)
-{
- @include animation( Select-animation-spin 400ms infinite linear );
- @include square($size);
- box-sizing: border-box;
- border-radius: 50%;
- border: floor(($size / 8)) solid $orbit;
- border-right-color: $satellite;
- display: inline-block;
- position: relative;
-
-}
-
-@keyframes Select-animation-spin {
- to { transform: rotate(1turn); }
-}
-@-webkit-keyframes Select-animation-spin {
- to { -webkit-transform: rotate(1turn); }
-}
diff --git a/src/Async.js b/src/Async.js
deleted file mode 100644
index d69afbb331..0000000000
--- a/src/Async.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import React, { Component, PropTypes } from 'react';
-import Select from './Select';
-import stripDiacritics from './utils/stripDiacritics';
-
-const propTypes = {
- autoload: React.PropTypes.bool.isRequired, // automatically call the `loadOptions` prop on-mount; defaults to true
- cache: React.PropTypes.any, // object to use to cache results; set to null/false to disable caching
- children: React.PropTypes.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element
- ignoreAccents: React.PropTypes.bool, // strip diacritics when filtering; defaults to true
- ignoreCase: React.PropTypes.bool, // perform case-insensitive filtering; defaults to true
- loadingPlaceholder: React.PropTypes.oneOfType([ // replaces the placeholder while options are loading
- React.PropTypes.string,
- React.PropTypes.node
- ]),
- loadOptions: React.PropTypes.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise
- options: PropTypes.array.isRequired, // array of options
- placeholder: React.PropTypes.oneOfType([ // field placeholder, displayed when there's no value (shared with Select)
- React.PropTypes.string,
- React.PropTypes.node
- ]),
- noResultsText: React.PropTypes.oneOfType([ // field noResultsText, displayed when no options come back from the server
- React.PropTypes.string,
- React.PropTypes.node
- ]),
- onChange: React.PropTypes.func, // onChange handler: function (newValue) {}
- searchPromptText: React.PropTypes.oneOfType([ // label to prompt for search input
- React.PropTypes.string,
- React.PropTypes.node
- ]),
- onInputChange: React.PropTypes.func, // optional for keeping track of what is being typed
- value: React.PropTypes.any, // initial field value
-};
-
-const defaultCache = {};
-
-const defaultProps = {
- autoload: true,
- cache: defaultCache,
- children: defaultChildren,
- ignoreAccents: true,
- ignoreCase: true,
- loadingPlaceholder: 'Loading...',
- options: [],
- searchPromptText: 'Type to search',
-};
-
-export default class Async extends Component {
- constructor (props, context) {
- super(props, context);
-
- this._cache = props.cache === defaultCache ? {} : props.cache;
-
- this.state = {
- isLoading: false,
- options: props.options,
- };
-
- this._onInputChange = this._onInputChange.bind(this);
- }
-
- componentDidMount () {
- const { autoload } = this.props;
-
- if (autoload) {
- this.loadOptions('');
- }
- }
-
- componentWillUpdate (nextProps, nextState) {
- const propertiesToSync = ['options'];
- propertiesToSync.forEach((prop) => {
- if (this.props[prop] !== nextProps[prop]) {
- this.setState({
- [prop]: nextProps[prop]
- });
- }
- });
- }
-
- clearOptions() {
- this.setState({ options: [] });
- }
-
- loadOptions (inputValue) {
- const { loadOptions } = this.props;
- const cache = this._cache;
-
- if (
- cache &&
- cache.hasOwnProperty(inputValue)
- ) {
- this.setState({
- options: cache[inputValue]
- });
-
- return;
- }
-
- const callback = (error, data) => {
- if (callback === this._callback) {
- this._callback = null;
-
- const options = data && data.options || [];
-
- if (cache) {
- cache[inputValue] = options;
- }
-
- this.setState({
- isLoading: false,
- options
- });
- }
- };
-
- // Ignore all but the most recent request
- this._callback = callback;
-
- const promise = loadOptions(inputValue, callback);
- if (promise) {
- promise.then(
- (data) => callback(null, data),
- (error) => callback(error)
- );
- }
-
- if (
- this._callback &&
- !this.state.isLoading
- ) {
- this.setState({
- isLoading: true
- });
- }
-
- return inputValue;
- }
-
- _onInputChange (inputValue) {
- const { ignoreAccents, ignoreCase, onInputChange } = this.props;
-
- if (ignoreAccents) {
- inputValue = stripDiacritics(inputValue);
- }
-
- if (ignoreCase) {
- inputValue = inputValue.toLowerCase();
- }
-
- if (onInputChange) {
- onInputChange(inputValue);
- }
-
- return this.loadOptions(inputValue);
- }
-
- inputValue() {
- if (this.select) {
- return this.select.state.inputValue;
- }
- return '';
- }
-
- noResultsText() {
- const { loadingPlaceholder, noResultsText, searchPromptText } = this.props;
- const { isLoading } = this.state;
-
- const inputValue = this.inputValue();
-
- if (isLoading) {
- return loadingPlaceholder;
- }
- if (inputValue && noResultsText) {
- return noResultsText;
- }
- return searchPromptText;
- }
-
- focus () {
- this.select.focus();
- }
-
- render () {
- const { children, loadingPlaceholder, placeholder } = this.props;
- const { isLoading, options } = this.state;
-
- const props = {
- noResultsText: this.noResultsText(),
- placeholder: isLoading ? loadingPlaceholder : placeholder,
- options: (isLoading && loadingPlaceholder) ? [] : options,
- ref: (ref) => (this.select = ref),
- onChange: (newValues) => {
- if (this.props.multi && this.props.value && (newValues.length > this.props.value.length)) {
- this.clearOptions();
- }
- this.props.onChange(newValues);
- }
- };
-
- return children({
- ...this.props,
- ...props,
- isLoading,
- onInputChange: this._onInputChange
- });
- }
-}
-
-Async.propTypes = propTypes;
-Async.defaultProps = defaultProps;
-
-function defaultChildren (props) {
- return (
-
- );
-};
diff --git a/src/AsyncCreatable.js b/src/AsyncCreatable.js
deleted file mode 100644
index edc51ee10b..0000000000
--- a/src/AsyncCreatable.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import Select from './Select';
-
-function reduce(obj, props = {}){
- return Object.keys(obj)
- .reduce((props, key) => {
- const value = obj[key];
- if (value !== undefined) props[key] = value;
- return props;
- }, props);
-}
-
-const AsyncCreatable = React.createClass({
- displayName: 'AsyncCreatableSelect',
-
- render () {
- return (
-
- {(asyncProps) => (
-
- {(creatableProps) => (
- {
- creatableProps.onInputChange(input);
- return asyncProps.onInputChange(input);
- }}
- ref={(ref) => {
- creatableProps.ref(ref);
- asyncProps.ref(ref);
- }}
- />
- )}
-
- )}
-
- );
- }
-});
-
-module.exports = AsyncCreatable;
diff --git a/src/Creatable.js b/src/Creatable.js
deleted file mode 100644
index 145c568aa3..0000000000
--- a/src/Creatable.js
+++ /dev/null
@@ -1,286 +0,0 @@
-import React from 'react';
-import Select from './Select';
-import defaultFilterOptions from './utils/defaultFilterOptions';
-import defaultMenuRenderer from './utils/defaultMenuRenderer';
-
-const Creatable = React.createClass({
- displayName: 'CreatableSelect',
-
- propTypes: {
- // Child function responsible for creating the inner Select component
- // This component can be used to compose HOCs (eg Creatable and Async)
- // (props: Object): PropTypes.element
- children: React.PropTypes.func,
-
- // See Select.propTypes.filterOptions
- filterOptions: React.PropTypes.any,
-
- // Searches for any matching option within the set of options.
- // This function prevents duplicate options from being created.
- // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean
- isOptionUnique: React.PropTypes.func,
-
- // Determines if the current input text represents a valid option.
- // ({ label: string }): boolean
- isValidNewOption: React.PropTypes.func,
-
- // See Select.propTypes.menuRenderer
- menuRenderer: React.PropTypes.any,
-
- // Factory to create new option.
- // ({ label: string, labelKey: string, valueKey: string }): Object
- newOptionCreator: React.PropTypes.func,
-
- // input change handler: function (inputValue) {}
- onInputChange: React.PropTypes.func,
-
- // input keyDown handler: function (event) {}
- onInputKeyDown: React.PropTypes.func,
-
- // new option click handler: function (option) {}
- onNewOptionClick: React.PropTypes.func,
-
- // See Select.propTypes.options
- options: React.PropTypes.array,
-
- // Creates prompt/placeholder option text.
- // (filterText: string): string
- promptTextCreator: React.PropTypes.func,
-
- // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option.
- shouldKeyDownEventCreateNewOption: React.PropTypes.func,
- },
-
- // Default prop methods
- statics: {
- isOptionUnique,
- isValidNewOption,
- newOptionCreator,
- promptTextCreator,
- shouldKeyDownEventCreateNewOption
- },
-
- getDefaultProps () {
- return {
- filterOptions: defaultFilterOptions,
- isOptionUnique,
- isValidNewOption,
- menuRenderer: defaultMenuRenderer,
- newOptionCreator,
- promptTextCreator,
- shouldKeyDownEventCreateNewOption,
- };
- },
-
- createNewOption () {
- const {
- isValidNewOption,
- newOptionCreator,
- onNewOptionClick,
- options = [],
- shouldKeyDownEventCreateNewOption
- } = this.props;
-
- if (isValidNewOption({ label: this.inputValue })) {
- const option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey });
- const isOptionUnique = this.isOptionUnique({ option });
-
- // Don't add the same option twice.
- if (isOptionUnique) {
- if (onNewOptionClick) {
- onNewOptionClick(option);
- } else {
- options.unshift(option);
-
- this.select.selectValue(option);
- }
- }
- }
- },
-
- filterOptions (...params) {
- const { filterOptions, isValidNewOption, options, promptTextCreator } = this.props;
-
- // TRICKY Check currently selected options as well.
- // Don't display a create-prompt for a value that's selected.
- // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array.
- const excludeOptions = params[2] || [];
-
- const filteredOptions = filterOptions(...params) || [];
-
- if (isValidNewOption({ label: this.inputValue })) {
- const { newOptionCreator } = this.props;
-
- const option = newOptionCreator({
- label: this.inputValue,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- // TRICKY Compare to all options (not just filtered options) in case option has already been selected).
- // For multi-selects, this would remove it from the filtered list.
- const isOptionUnique = this.isOptionUnique({
- option,
- options: excludeOptions.concat(filteredOptions)
- });
-
- if (isOptionUnique) {
- const prompt = promptTextCreator(this.inputValue);
-
- this._createPlaceholderOption = newOptionCreator({
- label: prompt,
- labelKey: this.labelKey,
- valueKey: this.valueKey
- });
-
- filteredOptions.unshift(this._createPlaceholderOption);
- }
- }
-
- return filteredOptions;
- },
-
- isOptionUnique ({
- option,
- options
- }) {
- const { isOptionUnique } = this.props;
-
- options = options || this.select.filterOptions();
-
- return isOptionUnique({
- labelKey: this.labelKey,
- option,
- options,
- valueKey: this.valueKey
- });
- },
-
- menuRenderer (params) {
- const { menuRenderer } = this.props;
-
- return menuRenderer({
- ...params,
- onSelect: this.onOptionSelect,
- selectValue: this.onOptionSelect
- });
- },
-
- onInputChange (input) {
- const { onInputChange } = this.props;
-
- if (onInputChange) {
- onInputChange(input);
- }
-
- // This value may be needed in between Select mounts (when this.select is null)
- this.inputValue = input;
- },
-
- onInputKeyDown (event) {
- const { shouldKeyDownEventCreateNewOption, onInputKeyDown } = this.props;
- const focusedOption = this.select.getFocusedOption();
-
- if (
- focusedOption &&
- focusedOption === this._createPlaceholderOption &&
- shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })
- ) {
- this.createNewOption();
-
- // Prevent decorated Select from doing anything additional with this keyDown event
- event.preventDefault();
- } else if (onInputKeyDown) {
- onInputKeyDown(event);
- }
- },
-
- onOptionSelect (option, event) {
- if (option === this._createPlaceholderOption) {
- this.createNewOption();
- } else {
- this.select.selectValue(option);
- }
- },
-
- render () {
- const {
- newOptionCreator,
- shouldKeyDownEventCreateNewOption,
- ...restProps
- } = this.props;
-
- let { children } = this.props;
-
- // We can't use destructuring default values to set the children,
- // because it won't apply work if `children` is null. A falsy check is
- // more reliable in real world use-cases.
- if (!children) {
- children = defaultChildren;
- }
-
- const props = {
- ...restProps,
- allowCreate: true,
- filterOptions: this.filterOptions,
- menuRenderer: this.menuRenderer,
- onInputChange: this.onInputChange,
- onInputKeyDown: this.onInputKeyDown,
- ref: (ref) => {
- this.select = ref;
-
- // These values may be needed in between Select mounts (when this.select is null)
- if (ref) {
- this.labelKey = ref.props.labelKey;
- this.valueKey = ref.props.valueKey;
- }
- }
- };
-
- return children(props);
- }
-});
-
-function defaultChildren (props) {
- return (
-
- );
-};
-
-function isOptionUnique ({ option, options, labelKey, valueKey }) {
- return options
- .filter((existingOption) =>
- existingOption[labelKey] === option[labelKey] ||
- existingOption[valueKey] === option[valueKey]
- )
- .length === 0;
-};
-
-function isValidNewOption ({ label }) {
- return !!label;
-};
-
-function newOptionCreator ({ label, labelKey, valueKey }) {
- const option = {};
- option[valueKey] = label;
- option[labelKey] = label;
- option.className = 'Select-create-option-placeholder';
- return option;
-};
-
-function promptTextCreator (label) {
- return `Create option "${label}"`;
-}
-
-function shouldKeyDownEventCreateNewOption ({ keyCode }) {
- switch (keyCode) {
- case 9: // TAB
- case 13: // ENTER
- case 188: // COMMA
- return true;
- }
-
- return false;
-};
-
-module.exports = Creatable;
diff --git a/src/Option.js b/src/Option.js
deleted file mode 100644
index 7dafa3e5ac..0000000000
--- a/src/Option.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-const Option = React.createClass({
- propTypes: {
- children: React.PropTypes.node,
- className: React.PropTypes.string, // className (based on mouse position)
- instancePrefix: React.PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
- isDisabled: React.PropTypes.bool, // the option is disabled
- isFocused: React.PropTypes.bool, // the option is focused
- isSelected: React.PropTypes.bool, // the option is selected
- onFocus: React.PropTypes.func, // method to handle mouseEnter on option element
- onSelect: React.PropTypes.func, // method to handle click on option element
- onUnfocus: React.PropTypes.func, // method to handle mouseLeave on option element
- option: React.PropTypes.object.isRequired, // object that is base for that option
- optionIndex: React.PropTypes.number, // index of the option, used to generate unique ids for aria
- },
- blockEvent (event) {
- event.preventDefault();
- event.stopPropagation();
- if ((event.target.tagName !== 'A') || !('href' in event.target)) {
- return;
- }
- if (event.target.target) {
- window.open(event.target.href, event.target.target);
- } else {
- window.location.href = event.target.href;
- }
- },
-
- handleMouseDown (event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onSelect(this.props.option, event);
- },
-
- handleMouseEnter (event) {
- this.onFocus(event);
- },
-
- handleMouseMove (event) {
- this.onFocus(event);
- },
-
- handleTouchEnd(event){
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if(this.dragging) return;
-
- this.handleMouseDown(event);
- },
-
- handleTouchMove (event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart (event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- onFocus (event) {
- if (!this.props.isFocused) {
- this.props.onFocus(this.props.option, event);
- }
- },
- render () {
- var { option, instancePrefix, optionIndex } = this.props;
- var className = classNames(this.props.className, option.className);
-
- return option.disabled ? (
-
- {this.props.children}
-
- ) : (
-
- {this.props.children}
-
- );
- }
-});
-
-module.exports = Option;
diff --git a/src/Select.js b/src/Select.js
deleted file mode 100644
index fc09e715f0..0000000000
--- a/src/Select.js
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*!
- Copyright (c) 2016 Jed Watson.
- Licensed under the MIT License (MIT), see
- http://jedwatson.github.io/react-select
-*/
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import AutosizeInput from 'react-input-autosize';
-import classNames from 'classnames';
-
-import defaultArrowRenderer from './utils/defaultArrowRenderer';
-import defaultFilterOptions from './utils/defaultFilterOptions';
-import defaultMenuRenderer from './utils/defaultMenuRenderer';
-import defaultClearRenderer from './utils/defaultClearRenderer';
-
-import Async from './Async';
-import AsyncCreatable from './AsyncCreatable';
-import Creatable from './Creatable';
-import Option from './Option';
-import Value from './Value';
-
-function stringifyValue (value) {
- const valueType = typeof value;
- if (valueType === 'string') {
- return value;
- } else if (valueType === 'object') {
- return JSON.stringify(value);
- } else if (valueType === 'number' || valueType === 'boolean') {
- return String(value);
- } else {
- return '';
- }
-}
-
-const stringOrNode = React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.node
-]);
-
-let instanceId = 1;
-
-const Select = React.createClass({
-
- displayName: 'Select',
-
- propTypes: {
- addLabelText: React.PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input
- 'aria-label': React.PropTypes.string, // Aria label (for assistive tech)
- 'aria-labelledby': React.PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
- arrowRenderer: React.PropTypes.func, // Create drop-down caret element
- autoBlur: React.PropTypes.bool, // automatically blur the component when an option is selected
- autofocus: React.PropTypes.bool, // autofocus the component on mount
- autosize: React.PropTypes.bool, // whether to enable autosizing or not
- backspaceRemoves: React.PropTypes.bool, // whether backspace removes an item if there is no text input
- backspaceToRemoveMessage: React.PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label
- className: React.PropTypes.string, // className for the outer element
- clearAllText: stringOrNode, // title for the "clear" control when multi: true
- clearRenderer: React.PropTypes.func, // create clearable x element
- clearValueText: stringOrNode, // title for the "clear" control
- clearable: React.PropTypes.bool, // should it be possible to reset value
- deleteRemoves: React.PropTypes.bool, // whether backspace removes an item if there is no text input
- delimiter: React.PropTypes.string, // delimiter to use to join multiple values for the hidden field value
- disabled: React.PropTypes.bool, // whether the Select is disabled or not
- escapeClearsValue: React.PropTypes.bool, // whether escape clears the value when the menu is closed
- filterOption: React.PropTypes.func, // method to filter a single option (option, filterString)
- filterOptions: React.PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values])
- ignoreAccents: React.PropTypes.bool, // whether to strip diacritics when filtering
- ignoreCase: React.PropTypes.bool, // whether to perform case-insensitive filtering
- inputProps: React.PropTypes.object, // custom attributes for the Input
- inputRenderer: React.PropTypes.func, // returns a custom input component
- instanceId: React.PropTypes.string, // set the components instanceId
- isLoading: React.PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded)
- joinValues: React.PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode)
- labelKey: React.PropTypes.string, // path of the label value in option objects
- matchPos: React.PropTypes.string, // (any|start) match the start or entire string when filtering
- matchProp: React.PropTypes.string, // (any|label|value) which option property to filter on
- menuBuffer: React.PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu
- menuContainerStyle: React.PropTypes.object, // optional style to apply to the menu container
- menuRenderer: React.PropTypes.func, // renders a custom menu with options
- menuStyle: React.PropTypes.object, // optional style to apply to the menu
- multi: React.PropTypes.bool, // multi-value input
- name: React.PropTypes.string, // generates a hidden tag with this field name for html forms
- noResultsText: stringOrNode, // placeholder displayed when there are no matching search results
- onBlur: React.PropTypes.func, // onBlur handler: function (event) {}
- onBlurResetsInput: React.PropTypes.bool, // whether input is cleared on blur
- onChange: React.PropTypes.func, // onChange handler: function (newValue) {}
- onClose: React.PropTypes.func, // fires when the menu is closed
- onCloseResetsInput: React.PropTypes.bool, // whether input is cleared when menu is closed through the arrow
- onFocus: React.PropTypes.func, // onFocus handler: function (event) {}
- onInputChange: React.PropTypes.func, // onInputChange handler: function (inputValue) {}
- onInputKeyDown: React.PropTypes.func, // input keyDown handler: function (event) {}
- onMenuScrollToBottom: React.PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options
- onOpen: React.PropTypes.func, // fires when the menu is opened
- onValueClick: React.PropTypes.func, // onClick handler for value labels: function (value, event) {}
- openAfterFocus: React.PropTypes.bool, // boolean to enable opening dropdown when focused
- openOnFocus: React.PropTypes.bool, // always open options menu on focus
- optionClassName: React.PropTypes.string, // additional class(es) to apply to the elements
- optionComponent: React.PropTypes.func, // option component to render in dropdown
- optionRenderer: React.PropTypes.func, // optionRenderer: function (option) {}
- options: React.PropTypes.array, // array of options
- pageSize: React.PropTypes.number, // number of entries to page when using page up/down keys
- placeholder: stringOrNode, // field placeholder, displayed when there's no value
- required: React.PropTypes.bool, // applies HTML5 required attribute when needed
- resetValue: React.PropTypes.any, // value to use when you clear the control
- scrollMenuIntoView: React.PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged
- searchable: React.PropTypes.bool, // whether to enable searching feature or not
- simpleValue: React.PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false
- style: React.PropTypes.object, // optional style to apply to the control
- tabIndex: React.PropTypes.string, // optional tab index of the control
- tabSelectsValue: React.PropTypes.bool, // whether to treat tabbing out while focused to be value selection
- value: React.PropTypes.any, // initial field value
- valueComponent: React.PropTypes.func, // value component to render
- valueKey: React.PropTypes.string, // path of the label value in option objects
- valueRenderer: React.PropTypes.func, // valueRenderer: function (option) {}
- wrapperStyle: React.PropTypes.object, // optional style to apply to the component wrapper
- },
-
- statics: { Async, AsyncCreatable, Creatable },
-
- getDefaultProps () {
- return {
- addLabelText: 'Add "{label}"?',
- arrowRenderer: defaultArrowRenderer,
- autosize: true,
- backspaceRemoves: true,
- backspaceToRemoveMessage: 'Press backspace to remove {label}',
- clearable: true,
- clearAllText: 'Clear all',
- clearRenderer: defaultClearRenderer,
- clearValueText: 'Clear value',
- deleteRemoves: true,
- delimiter: ',',
- disabled: false,
- escapeClearsValue: true,
- filterOptions: defaultFilterOptions,
- ignoreAccents: true,
- ignoreCase: true,
- inputProps: {},
- isLoading: false,
- joinValues: false,
- labelKey: 'label',
- matchPos: 'any',
- matchProp: 'any',
- menuBuffer: 0,
- menuRenderer: defaultMenuRenderer,
- multi: false,
- noResultsText: 'No results found',
- onBlurResetsInput: true,
- onCloseResetsInput: true,
- openAfterFocus: false,
- optionComponent: Option,
- pageSize: 5,
- placeholder: 'Select...',
- required: false,
- scrollMenuIntoView: true,
- searchable: true,
- simpleValue: false,
- tabSelectsValue: true,
- valueComponent: Value,
- valueKey: 'value',
- };
- },
-
- getInitialState () {
- return {
- inputValue: '',
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- required: false,
- };
- },
-
- componentWillMount () {
- this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-';
- const valueArray = this.getValueArray(this.props.value);
-
- if (this.props.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], this.props.multi),
- });
- }
- },
-
- componentDidMount () {
- if (this.props.autofocus) {
- this.focus();
- }
- },
-
- componentWillReceiveProps (nextProps) {
- const valueArray = this.getValueArray(nextProps.value, nextProps);
-
- if (nextProps.required) {
- this.setState({
- required: this.handleRequired(valueArray[0], nextProps.multi),
- });
- }
- },
-
- componentWillUpdate (nextProps, nextState) {
- if (nextState.isOpen !== this.state.isOpen) {
- this.toggleTouchOutsideEvent(nextState.isOpen);
- const handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose;
- handler && handler();
- }
- },
-
- componentDidUpdate (prevProps, prevState) {
- // focus to the selected option
- if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
- let focusedOptionNode = ReactDOM.findDOMNode(this.focused);
- let menuNode = ReactDOM.findDOMNode(this.menu);
- menuNode.scrollTop = focusedOptionNode.offsetTop;
- this.hasScrolledToOption = true;
- } else if (!this.state.isOpen) {
- this.hasScrolledToOption = false;
- }
-
- if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) {
- this._scrollToFocusedOptionOnUpdate = false;
- var focusedDOM = ReactDOM.findDOMNode(this.focused);
- var menuDOM = ReactDOM.findDOMNode(this.menu);
- var focusedRect = focusedDOM.getBoundingClientRect();
- var menuRect = menuDOM.getBoundingClientRect();
- if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) {
- menuDOM.scrollTop = (focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight);
- }
- }
- if (this.props.scrollMenuIntoView && this.menuContainer) {
- var menuContainerRect = this.menuContainer.getBoundingClientRect();
- if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) {
- window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight);
- }
- }
- if (prevProps.disabled !== this.props.disabled) {
- this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state
- this.closeMenu();
- }
- },
-
- componentWillUnmount () {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- },
-
- toggleTouchOutsideEvent (enabled) {
- if (enabled) {
- if (!document.addEventListener && document.attachEvent) {
- document.attachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.addEventListener('touchstart', this.handleTouchOutside);
- }
- } else {
- if (!document.removeEventListener && document.detachEvent) {
- document.detachEvent('ontouchstart', this.handleTouchOutside);
- } else {
- document.removeEventListener('touchstart', this.handleTouchOutside);
- }
- }
- },
-
- handleTouchOutside (event) {
- // handle touch outside on ios to dismiss menu
- if (this.wrapper && !this.wrapper.contains(event.target)) {
- this.closeMenu();
- }
- },
-
- focus () {
- if (!this.input) return;
- this.input.focus();
-
- if (this.props.openAfterFocus) {
- this.setState({
- isOpen: true,
- });
- }
- },
-
- blurInput () {
- if (!this.input) return;
- this.input.blur();
- },
-
- handleTouchMove (event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart (event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- handleTouchEnd (event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Fire the mouse events
- this.handleMouseDown(event);
- },
-
- handleTouchEndClearValue (event) {
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if (this.dragging) return;
-
- // Clear the value
- this.clearValue(event);
- },
-
- handleMouseDown (event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || (event.type === 'mousedown' && event.button !== 0)) {
- return;
- }
-
- if (event.target.tagName === 'INPUT') {
- return;
- }
-
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
-
- // for the non-searchable select, toggle the menu
- if (!this.props.searchable) {
- this.focus();
- return this.setState({
- isOpen: !this.state.isOpen,
- });
- }
-
- if (this.state.isFocused) {
- // On iOS, we can get into a state where we think the input is focused but it isn't really,
- // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event.
- // Call focus() again here to be safe.
- this.focus();
-
- let input = this.input;
- if (typeof input.getInput === 'function') {
- // Get the actual DOM input if the ref is an component
- input = input.getInput();
- }
-
- // clears the value so that the cursor will be at the end of input when the component re-renders
- input.value = '';
-
- // if the input is focused, ensure the menu is open
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- });
- } else {
- // otherwise, focus the input and open the menu
- this._openAfterFocus = this.props.openOnFocus;
- this.focus();
- }
- },
-
- handleMouseDownOnArrow (event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || (event.type === 'mousedown' && event.button !== 0)) {
- return;
- }
- // If the menu isn't open, let the event bubble to the main handleMouseDown
- if (!this.state.isOpen) {
- return;
- }
- // prevent default event handlers
- event.stopPropagation();
- event.preventDefault();
- // close the menu
- this.closeMenu();
- },
-
- handleMouseDownOnMenu (event) {
- // if the event was triggered by a mousedown and not the primary
- // button, or if the component is disabled, ignore it.
- if (this.props.disabled || (event.type === 'mousedown' && event.button !== 0)) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- this._openAfterFocus = true;
- this.focus();
- },
-
- closeMenu () {
- if(this.props.onCloseResetsInput) {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: ''
- });
- } else {
- this.setState({
- isOpen: false,
- isPseudoFocused: this.state.isFocused && !this.props.multi,
- inputValue: this.state.inputValue
- });
- }
- this.hasScrolledToOption = false;
- },
-
- handleInputFocus (event) {
- if (this.props.disabled) return;
- var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus;
- if (this.props.onFocus) {
- this.props.onFocus(event);
- }
- this.setState({
- isFocused: true,
- isOpen: isOpen
- });
- this._openAfterFocus = false;
- },
-
- handleInputBlur (event) {
- // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts.
- if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) {
- this.focus();
- return;
- }
-
- if (this.props.onBlur) {
- this.props.onBlur(event);
- }
- var onBlurredState = {
- isFocused: false,
- isOpen: false,
- isPseudoFocused: false,
- };
- if (this.props.onBlurResetsInput) {
- onBlurredState.inputValue = '';
- }
- this.setState(onBlurredState);
- },
-
- handleInputChange (event) {
- let newInputValue = event.target.value;
-
- if (this.state.inputValue !== event.target.value && this.props.onInputChange) {
- let nextState = this.props.onInputChange(newInputValue);
- // Note: != used deliberately here to catch undefined and null
- if (nextState != null && typeof nextState !== 'object') {
- newInputValue = '' + nextState;
- }
- }
-
- this.setState({
- isOpen: true,
- isPseudoFocused: false,
- inputValue: newInputValue,
- });
- },
-
- handleKeyDown (event) {
- if (this.props.disabled) return;
-
- if (typeof this.props.onInputKeyDown === 'function') {
- this.props.onInputKeyDown(event);
- if (event.defaultPrevented) {
- return;
- }
- }
-
- switch (event.keyCode) {
- case 8: // backspace
- if (!this.state.inputValue && this.props.backspaceRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- case 9: // tab
- if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) {
- return;
- }
- this.selectFocusedOption();
- return;
- case 13: // enter
- if (!this.state.isOpen) return;
- event.stopPropagation();
- this.selectFocusedOption();
- break;
- case 27: // escape
- if (this.state.isOpen) {
- this.closeMenu();
- event.stopPropagation();
- } else if (this.props.clearable && this.props.escapeClearsValue) {
- this.clearValue(event);
- event.stopPropagation();
- }
- break;
- case 38: // up
- this.focusPreviousOption();
- break;
- case 40: // down
- this.focusNextOption();
- break;
- case 33: // page up
- this.focusPageUpOption();
- break;
- case 34: // page down
- this.focusPageDownOption();
- break;
- case 35: // end key
- if (event.shiftKey) {
- return;
- }
- this.focusEndOption();
- break;
- case 36: // home key
- if (event.shiftKey) {
- return;
- }
- this.focusStartOption();
- break;
- case 46: // backspace
- if (!this.state.inputValue && this.props.deleteRemoves) {
- event.preventDefault();
- this.popValue();
- }
- return;
- default: return;
- }
- event.preventDefault();
- },
-
- handleValueClick (option, event) {
- if (!this.props.onValueClick) return;
- this.props.onValueClick(option, event);
- },
-
- handleMenuScroll (event) {
- if (!this.props.onMenuScrollToBottom) return;
- let { target } = event;
- if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) {
- this.props.onMenuScrollToBottom();
- }
- },
-
- handleRequired (value, multi) {
- if (!value) return true;
- return (multi ? value.length === 0 : Object.keys(value).length === 0);
- },
-
- getOptionLabel (op) {
- return op[this.props.labelKey];
- },
-
- /**
- * Turns a value into an array from the given options
- * @param {String|Number|Array} value - the value of the select input
- * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration
- * @returns {Array} the value of the select represented in an array
- */
- getValueArray (value, nextProps) {
- /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */
- const props = typeof nextProps === 'object' ? nextProps : this.props;
- if (props.multi) {
- if (typeof value === 'string') value = value.split(props.delimiter);
- if (!Array.isArray(value)) {
- if (value === null || value === undefined) return [];
- value = [value];
- }
- return value.map(value => this.expandValue(value, props)).filter(i => i);
- }
- var expandedValue = this.expandValue(value, props);
- return expandedValue ? [expandedValue] : [];
- },
-
- /**
- * Retrieve a value from the given options and valueKey
- * @param {String|Number|Array} value - the selected value(s)
- * @param {Object} props - the Select component's props (or nextProps)
- */
- expandValue (value, props) {
- const valueType = typeof value;
- if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value;
- let { options, valueKey } = props;
- if (!options) return;
- for (var i = 0; i < options.length; i++) {
- if (options[i][valueKey] === value) return options[i];
- }
- },
-
- setValue (value) {
- if (this.props.autoBlur){
- this.blurInput();
- }
- if (!this.props.onChange) return;
- if (this.props.required) {
- const required = this.handleRequired(value, this.props.multi);
- this.setState({ required });
- }
- if (this.props.simpleValue && value) {
- value = this.props.multi ? value.map(i => i[this.props.valueKey]).join(this.props.delimiter) : value[this.props.valueKey];
- }
- this.props.onChange(value);
- },
-
- selectValue (value) {
- //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise)
- this.hasScrolledToOption = false;
- if (this.props.multi) {
- this.setState({
- inputValue: '',
- focusedIndex: null
- }, () => {
- this.addValue(value);
- });
- } else {
- this.setState({
- isOpen: false,
- inputValue: '',
- isPseudoFocused: this.state.isFocused,
- }, () => {
- this.setValue(value);
- });
- }
- },
-
- addValue (value) {
- var valueArray = this.getValueArray(this.props.value);
- const visibleOptions = this._visibleOptions.filter(val => !val.disabled);
- const lastValueIndex = visibleOptions.indexOf(value);
- this.setValue(valueArray.concat(value));
- if (visibleOptions.length - 1 === lastValueIndex) {
- // the last option was selected; focus the second-last one
- this.focusOption(visibleOptions[lastValueIndex - 1]);
- } else if (visibleOptions.length > lastValueIndex) {
- // focus the option below the selected one
- this.focusOption(visibleOptions[lastValueIndex + 1]);
- }
- },
-
- popValue () {
- var valueArray = this.getValueArray(this.props.value);
- if (!valueArray.length) return;
- if (valueArray[valueArray.length-1].clearableValue === false) return;
- this.setValue(valueArray.slice(0, valueArray.length - 1));
- },
-
- removeValue (value) {
- var valueArray = this.getValueArray(this.props.value);
- this.setValue(valueArray.filter(i => i !== value));
- this.focus();
- },
-
- clearValue (event) {
- // if the event was triggered by a mousedown and not the primary
- // button, ignore it.
- if (event && event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- event.stopPropagation();
- event.preventDefault();
- this.setValue(this.getResetValue());
- this.setState({
- isOpen: false,
- inputValue: '',
- }, this.focus);
- },
-
- getResetValue () {
- if (this.props.resetValue !== undefined) {
- return this.props.resetValue;
- } else if (this.props.multi) {
- return [];
- } else {
- return null;
- }
- },
-
- focusOption (option) {
- this.setState({
- focusedOption: option
- });
- },
-
- focusNextOption () {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption () {
- this.focusAdjacentOption('previous');
- },
-
- focusPageUpOption () {
- this.focusAdjacentOption('page_up');
- },
-
- focusPageDownOption () {
- this.focusAdjacentOption('page_down');
- },
-
- focusStartOption () {
- this.focusAdjacentOption('start');
- },
-
- focusEndOption () {
- this.focusAdjacentOption('end');
- },
-
- focusAdjacentOption (dir) {
- var options = this._visibleOptions
- .map((option, index) => ({ option, index }))
- .filter(option => !option.option.disabled);
- this._scrollToFocusedOptionOnUpdate = true;
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: '',
- focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null)
- });
- return;
- }
- if (!options.length) return;
- var focusedIndex = -1;
- for (var i = 0; i < options.length; i++) {
- if (this._focusedOption === options[i].option) {
- focusedIndex = i;
- break;
- }
- }
- if (dir === 'next' && focusedIndex !== -1 ) {
- focusedIndex = (focusedIndex + 1) % options.length;
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedIndex = focusedIndex - 1;
- } else {
- focusedIndex = options.length - 1;
- }
- } else if (dir === 'start') {
- focusedIndex = 0;
- } else if (dir === 'end') {
- focusedIndex = options.length - 1;
- } else if (dir === 'page_up') {
- var potentialIndex = focusedIndex - this.props.pageSize;
- if (potentialIndex < 0) {
- focusedIndex = 0;
- } else {
- focusedIndex = potentialIndex;
- }
- } else if (dir === 'page_down') {
- var potentialIndex = focusedIndex + this.props.pageSize;
- if (potentialIndex > options.length - 1) {
- focusedIndex = options.length - 1;
- } else {
- focusedIndex = potentialIndex;
- }
- }
-
- if (focusedIndex === -1) {
- focusedIndex = 0;
- }
-
- this.setState({
- focusedIndex: options[focusedIndex].index,
- focusedOption: options[focusedIndex].option
- });
- },
-
- getFocusedOption () {
- return this._focusedOption;
- },
-
- getInputValue () {
- return this.state.inputValue;
- },
-
- selectFocusedOption () {
- if (this._focusedOption) {
- return this.selectValue(this._focusedOption);
- }
- },
-
- renderLoading () {
- if (!this.props.isLoading) return;
- return (
-
-
-
- );
- },
-
- renderValue (valueArray, isOpen) {
- let renderLabel = this.props.valueRenderer || this.getOptionLabel;
- let ValueComponent = this.props.valueComponent;
- if (!valueArray.length) {
- return !this.state.inputValue ? {this.props.placeholder}
: null;
- }
- let onClick = this.props.onValueClick ? this.handleValueClick : null;
- if (this.props.multi) {
- return valueArray.map((value, i) => {
- return (
-
- {renderLabel(value, i)}
-
-
- );
- });
- } else if (!this.state.inputValue) {
- if (isOpen) onClick = null;
- return (
-
- {renderLabel(valueArray[0])}
-
- );
- }
- },
-
- renderInput (valueArray, focusedOptionIndex) {
- var className = classNames('Select-input', this.props.inputProps.className);
- const isOpen = !!this.state.isOpen;
-
- const ariaOwns = classNames({
- [this._instancePrefix + '-list']: isOpen,
- [this._instancePrefix + '-backspace-remove-message']: this.props.multi
- && !this.props.disabled
- && this.state.isFocused
- && !this.state.inputValue
- });
-
- // TODO: Check how this project includes Object.assign()
- const inputProps = Object.assign({}, this.props.inputProps, {
- role: 'combobox',
- 'aria-expanded': '' + isOpen,
- 'aria-owns': ariaOwns,
- 'aria-haspopup': '' + isOpen,
- 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value',
- 'aria-labelledby': this.props['aria-labelledby'],
- 'aria-label': this.props['aria-label'],
- className: className,
- tabIndex: this.props.tabIndex,
- onBlur: this.handleInputBlur,
- onChange: this.handleInputChange,
- onFocus: this.handleInputFocus,
- ref: ref => this.input = ref,
- required: this.state.required,
- value: this.state.inputValue
- });
-
- if (this.props.inputRenderer) {
- return this.props.inputRenderer(inputProps);
- }
-
- if (this.props.disabled || !this.props.searchable) {
- const { inputClassName, ...divProps } = this.props.inputProps;
- return (
- this.input = ref}
- aria-readonly={'' + !!this.props.disabled}
- style={{ border: 0, width: 1, display:'inline-block' }}/>
- );
- }
-
- if (this.props.autosize) {
- return (
-
- );
- }
- return (
-
-
-
- );
- },
-
- renderClear () {
- if (!this.props.clearable || (!this.props.value || this.props.value === 0) || (this.props.multi && !this.props.value.length) || this.props.disabled || this.props.isLoading) return;
- const clear = this.props.clearRenderer();
-
- return (
-
- {clear}
-
- );
- },
-
- renderArrow () {
- const onMouseDown = this.handleMouseDownOnArrow;
- const isOpen = this.state.isOpen;
- const arrow = this.props.arrowRenderer({ onMouseDown, isOpen });
-
- return (
-
- {arrow}
-
- );
- },
-
- filterOptions (excludeOptions) {
- var filterValue = this.state.inputValue;
- var options = this.props.options || [];
- if (this.props.filterOptions) {
- // Maintain backwards compatibility with boolean attribute
- const filterOptions = typeof this.props.filterOptions === 'function'
- ? this.props.filterOptions
- : defaultFilterOptions;
-
- return filterOptions(
- options,
- filterValue,
- excludeOptions,
- {
- filterOption: this.props.filterOption,
- ignoreAccents: this.props.ignoreAccents,
- ignoreCase: this.props.ignoreCase,
- labelKey: this.props.labelKey,
- matchPos: this.props.matchPos,
- matchProp: this.props.matchProp,
- valueKey: this.props.valueKey,
- }
- );
- } else {
- return options;
- }
- },
-
- onOptionRef(ref, isFocused) {
- if (isFocused) {
- this.focused = ref;
- }
- },
-
- renderMenu (options, valueArray, focusedOption) {
- if (options && options.length) {
- return this.props.menuRenderer({
- focusedOption,
- focusOption: this.focusOption,
- instancePrefix: this._instancePrefix,
- labelKey: this.props.labelKey,
- onFocus: this.focusOption,
- onSelect: this.selectValue,
- optionClassName: this.props.optionClassName,
- optionComponent: this.props.optionComponent,
- optionRenderer: this.props.optionRenderer || this.getOptionLabel,
- options,
- selectValue: this.selectValue,
- valueArray,
- valueKey: this.props.valueKey,
- onOptionRef: this.onOptionRef,
- });
- } else if (this.props.noResultsText) {
- return (
-
- {this.props.noResultsText}
-
- );
- } else {
- return null;
- }
- },
-
- renderHiddenField (valueArray) {
- if (!this.props.name) return;
- if (this.props.joinValues) {
- let value = valueArray.map(i => stringifyValue(i[this.props.valueKey])).join(this.props.delimiter);
- return (
-
this.value = ref}
- name={this.props.name}
- value={value}
- disabled={this.props.disabled} />
- );
- }
- return valueArray.map((item, index) => (
-
- ));
- },
-
- getFocusableOptionIndex (selectedOption) {
- var options = this._visibleOptions;
- if (!options.length) return null;
-
- let focusedOption = this.state.focusedOption || selectedOption;
- if (focusedOption && !focusedOption.disabled) {
- const focusedOptionIndex = options.indexOf(focusedOption);
- if (focusedOptionIndex !== -1) {
- return focusedOptionIndex;
- }
- }
-
- for (var i = 0; i < options.length; i++) {
- if (!options[i].disabled) return i;
- }
- return null;
- },
-
- renderOuter (options, valueArray, focusedOption) {
- let menu = this.renderMenu(options, valueArray, focusedOption);
- if (!menu) {
- return null;
- }
-
- return (
-
this.menuContainer = ref} className="Select-menu-outer" style={this.props.menuContainerStyle}>
-
this.menu = ref} role="listbox" className="Select-menu" id={this._instancePrefix + '-list'}
- style={this.props.menuStyle}
- onScroll={this.handleMenuScroll}
- onMouseDown={this.handleMouseDownOnMenu}>
- {menu}
-
-
- );
- },
-
- render () {
- let valueArray = this.getValueArray(this.props.value);
- let options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null);
- let isOpen = this.state.isOpen;
- if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false;
- const focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]);
-
- let focusedOption = null;
- if (focusedOptionIndex !== null) {
- focusedOption = this._focusedOption = options[focusedOptionIndex];
- } else {
- focusedOption = this._focusedOption = null;
- }
- let className = classNames('Select', this.props.className, {
- 'Select--multi': this.props.multi,
- 'Select--single': !this.props.multi,
- 'is-disabled': this.props.disabled,
- 'is-focused': this.state.isFocused,
- 'is-loading': this.props.isLoading,
- 'is-open': isOpen,
- 'is-pseudo-focused': this.state.isPseudoFocused,
- 'is-searchable': this.props.searchable,
- 'has-value': valueArray.length,
- });
-
- let removeMessage = null;
- if (this.props.multi &&
- !this.props.disabled &&
- valueArray.length &&
- !this.state.inputValue &&
- this.state.isFocused &&
- this.props.backspaceRemoves) {
- removeMessage = (
-
- {this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey])}
-
- );
- }
-
- return (
-
this.wrapper = ref}
- className={className}
- style={this.props.wrapperStyle}>
- {this.renderHiddenField(valueArray)}
-
this.control = ref}
- className="Select-control"
- style={this.props.style}
- onKeyDown={this.handleKeyDown}
- onMouseDown={this.handleMouseDown}
- onTouchEnd={this.handleTouchEnd}
- onTouchStart={this.handleTouchStart}
- onTouchMove={this.handleTouchMove}
- >
-
- {this.renderValue(valueArray, isOpen)}
- {this.renderInput(valueArray, focusedOptionIndex)}
-
- {removeMessage}
- {this.renderLoading()}
- {this.renderClear()}
- {this.renderArrow()}
-
- {isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null}
-
- );
- }
-
-});
-
-export default Select;
diff --git a/src/Value.js b/src/Value.js
deleted file mode 100644
index 7114a5ff35..0000000000
--- a/src/Value.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-const Value = React.createClass({
-
- displayName: 'Value',
-
- propTypes: {
- children: React.PropTypes.node,
- disabled: React.PropTypes.bool, // disabled prop passed to ReactSelect
- id: React.PropTypes.string, // Unique id for the value - used for aria
- onClick: React.PropTypes.func, // method to handle click on value label
- onRemove: React.PropTypes.func, // method to handle removal of the value
- value: React.PropTypes.object.isRequired, // the option object for this value
- },
-
- handleMouseDown (event) {
- if (event.type === 'mousedown' && event.button !== 0) {
- return;
- }
- if (this.props.onClick) {
- event.stopPropagation();
- this.props.onClick(this.props.value, event);
- return;
- }
- if (this.props.value.href) {
- event.stopPropagation();
- }
- },
-
- onRemove (event) {
- event.preventDefault();
- event.stopPropagation();
- this.props.onRemove(this.props.value);
- },
-
- handleTouchEndRemove (event){
- // Check if the view is being dragged, In this case
- // we don't want to fire the click event (because the user only wants to scroll)
- if(this.dragging) return;
-
- // Fire the mouse events
- this.onRemove(event);
- },
-
- handleTouchMove (event) {
- // Set a flag that the view is being dragged
- this.dragging = true;
- },
-
- handleTouchStart (event) {
- // Set a flag that the view is not being dragged
- this.dragging = false;
- },
-
- renderRemoveIcon () {
- if (this.props.disabled || !this.props.onRemove) return;
- return (
-
- ×
-
- );
- },
-
- renderLabel () {
- let className = 'Select-value-label';
- return this.props.onClick || this.props.value.href ? (
-
- {this.props.children}
-
- ) : (
-
- {this.props.children}
-
- );
- },
-
- render () {
- return (
-
- {this.renderRemoveIcon()}
- {this.renderLabel()}
-
- );
- }
-
-});
-
-module.exports = Value;
diff --git a/src/utils/defaultArrowRenderer.js b/src/utils/defaultArrowRenderer.js
deleted file mode 100644
index 0654e3106b..0000000000
--- a/src/utils/defaultArrowRenderer.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-
-export default function arrowRenderer ({ onMouseDown }) {
- return (
-
- );
-};
diff --git a/src/utils/defaultClearRenderer.js b/src/utils/defaultClearRenderer.js
deleted file mode 100644
index 3f25e85d7d..0000000000
--- a/src/utils/defaultClearRenderer.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-
-export default function clearRenderer () {
- return (
-
- );
-};
diff --git a/src/utils/defaultFilterOptions.js b/src/utils/defaultFilterOptions.js
deleted file mode 100644
index 8a5a783a1b..0000000000
--- a/src/utils/defaultFilterOptions.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import stripDiacritics from './stripDiacritics';
-
-function filterOptions (options, filterValue, excludeOptions, props) {
- if (props.ignoreAccents) {
- filterValue = stripDiacritics(filterValue);
- }
-
- if (props.ignoreCase) {
- filterValue = filterValue.toLowerCase();
- }
-
- if (excludeOptions) excludeOptions = excludeOptions.map(i => i[props.valueKey]);
-
- return options.filter(option => {
- if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false;
- if (props.filterOption) return props.filterOption.call(this, option, filterValue);
- if (!filterValue) return true;
- var valueTest = String(option[props.valueKey]);
- var labelTest = String(option[props.labelKey]);
- if (props.ignoreAccents) {
- if (props.matchProp !== 'label') valueTest = stripDiacritics(valueTest);
- if (props.matchProp !== 'value') labelTest = stripDiacritics(labelTest);
- }
- if (props.ignoreCase) {
- if (props.matchProp !== 'label') valueTest = valueTest.toLowerCase();
- if (props.matchProp !== 'value') labelTest = labelTest.toLowerCase();
- }
- return props.matchPos === 'start' ? (
- (props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue) ||
- (props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue)
- ) : (
- (props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0) ||
- (props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0)
- );
- });
-}
-
-module.exports = filterOptions;
diff --git a/src/utils/defaultMenuRenderer.js b/src/utils/defaultMenuRenderer.js
deleted file mode 100644
index b5ba47b0bf..0000000000
--- a/src/utils/defaultMenuRenderer.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import classNames from 'classnames';
-import React from 'react';
-
-function menuRenderer ({
- focusedOption,
- instancePrefix,
- labelKey,
- onFocus,
- onSelect,
- optionClassName,
- optionComponent,
- optionRenderer,
- options,
- valueArray,
- valueKey,
- onOptionRef
-}) {
- let Option = optionComponent;
-
- return options.map((option, i) => {
- let isSelected = valueArray && valueArray.indexOf(option) > -1;
- let isFocused = option === focusedOption;
- let optionClass = classNames(optionClassName, {
- 'Select-option': true,
- 'is-selected': isSelected,
- 'is-focused': isFocused,
- 'is-disabled': option.disabled,
- });
-
- return (
-
{ onOptionRef(ref, isFocused); }}
- >
- {optionRenderer(option, i)}
-
- );
- });
-}
-
-module.exports = menuRenderer;
diff --git a/src/utils/stripDiacritics.js b/src/utils/stripDiacritics.js
deleted file mode 100644
index 9f91f83a6d..0000000000
--- a/src/utils/stripDiacritics.js
+++ /dev/null
@@ -1,93 +0,0 @@
-var map = [
- { 'base':'A', 'letters':/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g },
- { 'base':'AA','letters':/[\uA732]/g },
- { 'base':'AE','letters':/[\u00C6\u01FC\u01E2]/g },
- { 'base':'AO','letters':/[\uA734]/g },
- { 'base':'AU','letters':/[\uA736]/g },
- { 'base':'AV','letters':/[\uA738\uA73A]/g },
- { 'base':'AY','letters':/[\uA73C]/g },
- { 'base':'B', 'letters':/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g },
- { 'base':'C', 'letters':/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g },
- { 'base':'D', 'letters':/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g },
- { 'base':'DZ','letters':/[\u01F1\u01C4]/g },
- { 'base':'Dz','letters':/[\u01F2\u01C5]/g },
- { 'base':'E', 'letters':/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g },
- { 'base':'F', 'letters':/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g },
- { 'base':'G', 'letters':/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g },
- { 'base':'H', 'letters':/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g },
- { 'base':'I', 'letters':/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g },
- { 'base':'J', 'letters':/[\u004A\u24BF\uFF2A\u0134\u0248]/g },
- { 'base':'K', 'letters':/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g },
- { 'base':'L', 'letters':/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g },
- { 'base':'LJ','letters':/[\u01C7]/g },
- { 'base':'Lj','letters':/[\u01C8]/g },
- { 'base':'M', 'letters':/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g },
- { 'base':'N', 'letters':/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g },
- { 'base':'NJ','letters':/[\u01CA]/g },
- { 'base':'Nj','letters':/[\u01CB]/g },
- { 'base':'O', 'letters':/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g },
- { 'base':'OI','letters':/[\u01A2]/g },
- { 'base':'OO','letters':/[\uA74E]/g },
- { 'base':'OU','letters':/[\u0222]/g },
- { 'base':'P', 'letters':/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g },
- { 'base':'Q', 'letters':/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g },
- { 'base':'R', 'letters':/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g },
- { 'base':'S', 'letters':/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g },
- { 'base':'T', 'letters':/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g },
- { 'base':'TZ','letters':/[\uA728]/g },
- { 'base':'U', 'letters':/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g },
- { 'base':'V', 'letters':/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g },
- { 'base':'VY','letters':/[\uA760]/g },
- { 'base':'W', 'letters':/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g },
- { 'base':'X', 'letters':/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g },
- { 'base':'Y', 'letters':/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g },
- { 'base':'Z', 'letters':/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g },
- { 'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g },
- { 'base':'aa','letters':/[\uA733]/g },
- { 'base':'ae','letters':/[\u00E6\u01FD\u01E3]/g },
- { 'base':'ao','letters':/[\uA735]/g },
- { 'base':'au','letters':/[\uA737]/g },
- { 'base':'av','letters':/[\uA739\uA73B]/g },
- { 'base':'ay','letters':/[\uA73D]/g },
- { 'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g },
- { 'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g },
- { 'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g },
- { 'base':'dz','letters':/[\u01F3\u01C6]/g },
- { 'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g },
- { 'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g },
- { 'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g },
- { 'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g },
- { 'base':'hv','letters':/[\u0195]/g },
- { 'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g },
- { 'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g },
- { 'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g },
- { 'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g },
- { 'base':'lj','letters':/[\u01C9]/g },
- { 'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g },
- { 'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g },
- { 'base':'nj','letters':/[\u01CC]/g },
- { 'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g },
- { 'base':'oi','letters':/[\u01A3]/g },
- { 'base':'ou','letters':/[\u0223]/g },
- { 'base':'oo','letters':/[\uA74F]/g },
- { 'base':'p', 'letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g },
- { 'base':'q', 'letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g },
- { 'base':'r', 'letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g },
- { 'base':'s', 'letters':/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g },
- { 'base':'t', 'letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g },
- { 'base':'tz','letters':/[\uA729]/g },
- { 'base':'u', 'letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g },
- { 'base':'v', 'letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g },
- { 'base':'vy','letters':/[\uA761]/g },
- { 'base':'w', 'letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g },
- { 'base':'x', 'letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g },
- { 'base':'y', 'letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g },
- { 'base':'z', 'letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g },
-];
-
-module.exports = function stripDiacritics (str) {
- for (var i = 0; i < map.length; i++) {
- str = str.replace(map[i].letters, map[i].base);
- }
- return str;
-};
diff --git a/storybook/.gitignore b/storybook/.gitignore
new file mode 100644
index 0000000000..1d7f56e2d2
--- /dev/null
+++ b/storybook/.gitignore
@@ -0,0 +1,2 @@
+# Storybook
+storybook-static
diff --git a/storybook/.storybook/.babelrc b/storybook/.storybook/.babelrc
new file mode 100644
index 0000000000..0264fb9c3f
--- /dev/null
+++ b/storybook/.storybook/.babelrc
@@ -0,0 +1,8 @@
+{
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-typescript",
+ "@emotion/babel-preset-css-prop"
+ ],
+ "plugins": ["@emotion"]
+}
diff --git a/storybook/.storybook/main.ts b/storybook/.storybook/main.ts
new file mode 100644
index 0000000000..ed118331d7
--- /dev/null
+++ b/storybook/.storybook/main.ts
@@ -0,0 +1,31 @@
+import type { StorybookConfig } from '@storybook/core-common';
+import postcss from 'postcss';
+
+const config: StorybookConfig = {
+ addons: [
+ '@storybook/addon-a11y',
+ '@storybook/addon-essentials',
+ {
+ name: '@storybook/addon-postcss',
+ options: {
+ postcssLoaderOptions: {
+ implementation: postcss,
+ },
+ },
+ },
+ ],
+ core: {
+ builder: 'webpack4',
+ },
+ features: {
+ /**
+ * Enable code splitting
+ * @see https://storybook.js.org/docs/react/builders/webpack#code-splitting
+ */
+ storyStoreV7: true,
+ },
+ framework: '@storybook/react',
+ stories: ['../stories/**/*.stories.@(js|jsx|ts|tsx)'],
+};
+
+export default config;
diff --git a/storybook/.storybook/preview.tsx b/storybook/.storybook/preview.tsx
new file mode 100644
index 0000000000..3d007bc38c
--- /dev/null
+++ b/storybook/.storybook/preview.tsx
@@ -0,0 +1,43 @@
+/** @jsx jsx */
+import { jsx, Global, css } from '@emotion/react';
+import type { DecoratorFn } from '@storybook/react';
+import { Fragment } from 'react';
+
+export const parameters = {
+ options: {
+ storySort: {
+ order: [
+ 'Select',
+ ['BasicSingle', 'BasicMulti', 'AnimatedMulti', 'Grouped', 'Creatable'],
+ ],
+ },
+ },
+ docs: {
+ source: {
+ type: 'code',
+ },
+ },
+};
+
+const globalStyles = css`
+ *,
+ *::before,
+ *::after {
+ box-sizing: border-box;
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
+ 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
+ 'Noto Color Emoji';
+ }
+`;
+
+const withCssReset: DecoratorFn = (Story) => {
+ return (
+
+
+
+
+ );
+};
+
+export const decorators = [withCssReset];
diff --git a/storybook/components/field.tsx b/storybook/components/field.tsx
new file mode 100644
index 0000000000..dd625284d6
--- /dev/null
+++ b/storybook/components/field.tsx
@@ -0,0 +1,43 @@
+import * as React from 'react';
+
+type FieldProps = {
+ label?: string;
+ secondaryLabel?: string;
+ children: React.ReactNode;
+ htmlFor: string;
+};
+
+export function Field({
+ children,
+ htmlFor,
+ label = 'Select',
+ secondaryLabel,
+}: FieldProps) {
+ return (
+
+
+ {label}
+ {secondaryLabel && (
+
+ {secondaryLabel}
+
+ )}
+
+ {children}
+
+ );
+}
diff --git a/storybook/components/index.ts b/storybook/components/index.ts
new file mode 100644
index 0000000000..b16776d270
--- /dev/null
+++ b/storybook/components/index.ts
@@ -0,0 +1,4 @@
+export * from './field';
+export * from './inline';
+export * from './stack';
+export * from './svg';
diff --git a/storybook/components/inline.tsx b/storybook/components/inline.tsx
new file mode 100644
index 0000000000..eac2d3f450
--- /dev/null
+++ b/storybook/components/inline.tsx
@@ -0,0 +1,32 @@
+import * as React from 'react';
+
+type InlineProps = React.HTMLAttributes
& {
+ gap?: keyof typeof gapSize;
+};
+
+export function Inline({
+ children,
+ gap = 'small',
+ style,
+ ...consumerProps
+}: InlineProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+const gapSize = {
+ small: '0.5rem',
+ medium: '1rem',
+ large: '2rem',
+};
diff --git a/storybook/components/stack.tsx b/storybook/components/stack.tsx
new file mode 100644
index 0000000000..01bb7eb942
--- /dev/null
+++ b/storybook/components/stack.tsx
@@ -0,0 +1,32 @@
+import * as React from 'react';
+
+type StackProps = React.HTMLAttributes & {
+ gap?: keyof typeof gapSize;
+};
+
+export function Stack({
+ children,
+ gap = 'small',
+ style,
+ ...consumerProps
+}: StackProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+const gapSize = {
+ small: '0.5rem',
+ medium: '1rem',
+ large: '2rem',
+};
diff --git a/storybook/components/svg.tsx b/storybook/components/svg.tsx
new file mode 100644
index 0000000000..74245fd4bc
--- /dev/null
+++ b/storybook/components/svg.tsx
@@ -0,0 +1,26 @@
+import * as React from 'react';
+
+export function Svg(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+ );
+}
+
+export function ChevronDown(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+
+
+ );
+}
diff --git a/storybook/data.ts b/storybook/data.ts
new file mode 100644
index 0000000000..e659a3014c
--- /dev/null
+++ b/storybook/data.ts
@@ -0,0 +1,185 @@
+export type ColourOption = {
+ readonly value: string;
+ readonly label: string;
+ readonly color: string;
+ readonly isFixed?: boolean;
+ readonly isDisabled?: boolean;
+};
+
+export const colourOptions: readonly ColourOption[] = [
+ { value: 'ocean', label: 'Ocean', color: '#00B8D9', isFixed: true },
+ { value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true },
+ { value: 'purple', label: 'Purple', color: '#5243AA' },
+ { value: 'red', label: 'Red', color: '#FF5630', isFixed: true },
+ { value: 'orange', label: 'Orange', color: '#FF8B00' },
+ { value: 'yellow', label: 'Yellow', color: '#FFC400' },
+ { value: 'green', label: 'Green', color: '#36B37E' },
+ { value: 'forest', label: 'Forest', color: '#00875A' },
+ { value: 'slate', label: 'Slate', color: '#253858' },
+ { value: 'silver', label: 'Silver', color: '#666666' },
+];
+
+export type FlavourOption = {
+ readonly value: string;
+ readonly label: string;
+ readonly rating: string;
+};
+
+export const flavourOptions: readonly FlavourOption[] = [
+ { value: 'vanilla', label: 'Vanilla', rating: 'safe' },
+ { value: 'chocolate', label: 'Chocolate', rating: 'good' },
+ { value: 'strawberry', label: 'Strawberry', rating: 'wild' },
+ { value: 'salted-caramel', label: 'Salted Caramel', rating: 'crazy' },
+];
+
+export type StateOption = {
+ readonly value: string;
+ readonly label: string;
+};
+
+export const stateOptions: readonly StateOption[] = [
+ { value: 'AL', label: 'Alabama' },
+ { value: 'AK', label: 'Alaska' },
+ { value: 'AS', label: 'American Samoa' },
+ { value: 'AZ', label: 'Arizona' },
+ { value: 'AR', label: 'Arkansas' },
+ { value: 'CA', label: 'California' },
+ { value: 'CO', label: 'Colorado' },
+ { value: 'CT', label: 'Connecticut' },
+ { value: 'DE', label: 'Delaware' },
+ { value: 'DC', label: 'District Of Columbia' },
+ { value: 'FM', label: 'Federated States Of Micronesia' },
+ { value: 'FL', label: 'Florida' },
+ { value: 'GA', label: 'Georgia' },
+ { value: 'GU', label: 'Guam' },
+ { value: 'HI', label: 'Hawaii' },
+ { value: 'ID', label: 'Idaho' },
+ { value: 'IL', label: 'Illinois' },
+ { value: 'IN', label: 'Indiana' },
+ { value: 'IA', label: 'Iowa' },
+ { value: 'KS', label: 'Kansas' },
+ { value: 'KY', label: 'Kentucky' },
+ { value: 'LA', label: 'Louisiana' },
+ { value: 'ME', label: 'Maine' },
+ { value: 'MH', label: 'Marshall Islands' },
+ { value: 'MD', label: 'Maryland' },
+ { value: 'MA', label: 'Massachusetts' },
+ { value: 'MI', label: 'Michigan' },
+ { value: 'MN', label: 'Minnesota' },
+ { value: 'MS', label: 'Mississippi' },
+ { value: 'MO', label: 'Missouri' },
+ { value: 'MT', label: 'Montana' },
+ { value: 'NE', label: 'Nebraska' },
+ { value: 'NV', label: 'Nevada' },
+ { value: 'NH', label: 'New Hampshire' },
+ { value: 'NJ', label: 'New Jersey' },
+ { value: 'NM', label: 'New Mexico' },
+ { value: 'NY', label: 'New York' },
+ { value: 'NC', label: 'North Carolina' },
+ { value: 'ND', label: 'North Dakota' },
+ { value: 'MP', label: 'Northern Mariana Islands' },
+ { value: 'OH', label: 'Ohio' },
+ { value: 'OK', label: 'Oklahoma' },
+ { value: 'OR', label: 'Oregon' },
+ { value: 'PW', label: 'Palau' },
+ { value: 'PA', label: 'Pennsylvania' },
+ { value: 'PR', label: 'Puerto Rico' },
+ { value: 'RI', label: 'Rhode Island' },
+ { value: 'SC', label: 'South Carolina' },
+ { value: 'SD', label: 'South Dakota' },
+ { value: 'TN', label: 'Tennessee' },
+ { value: 'TX', label: 'Texas' },
+ { value: 'UT', label: 'Utah' },
+ { value: 'VT', label: 'Vermont' },
+ { value: 'VI', label: 'Virgin Islands' },
+ { value: 'VA', label: 'Virginia' },
+ { value: 'WA', label: 'Washington' },
+ { value: 'WV', label: 'West Virginia' },
+ { value: 'WI', label: 'Wisconsin' },
+ { value: 'WY', label: 'Wyoming' },
+];
+
+export const optionLength = [
+ { value: 1, label: 'general' },
+ {
+ value: 2,
+ label:
+ 'Evil is the moment when I lack the strength to be true to the Good that compels me.',
+ },
+ {
+ value: 3,
+ label:
+ "It is now an easy matter to spell out the ethic of a truth: 'Do all that you can to persevere in that which exceeds your perseverance. Persevere in the interruption. Seize in your being that which has seized and broken you.",
+ },
+];
+
+export const dogOptions = [
+ { id: 1, label: 'Chihuahua' },
+ { id: 2, label: 'Bulldog' },
+ { id: 3, label: 'Dachshund' },
+ { id: 4, label: 'Akita' },
+];
+
+export type GroupedOption = {
+ readonly label: string;
+ readonly options: readonly ColourOption[] | readonly FlavourOption[];
+};
+
+export const groupedOptions: readonly GroupedOption[] = [
+ {
+ label: 'Colours',
+ options: colourOptions,
+ },
+ {
+ label: 'Flavours',
+ options: flavourOptions,
+ },
+];
+
+export type PersonOption = {
+ readonly id: number;
+ readonly name: string;
+ readonly online: boolean;
+};
+
+export const people: readonly PersonOption[] = [
+ { id: 1, name: 'Carla Conroy', online: true },
+ { id: 2, name: 'Beverly Wehner', online: false },
+ { id: 3, name: 'Clifton Schimmel', online: true },
+ { id: 4, name: 'Charles Greenfelder', online: true },
+ { id: 5, name: 'Nadine Hoeger', online: false },
+ { id: 6, name: 'Freddie Klocko', online: false },
+ { id: 7, name: 'Della Crona', online: false },
+ { id: 8, name: 'Leigh Herzog', online: false },
+ { id: 9, name: 'Winston Schultz', online: true },
+ { id: 10, name: 'Andrew Ryan', online: true },
+];
+
+export type NumberOption = {
+ readonly label: string;
+ readonly value: string;
+};
+
+export const numbers: NumberOption[] = [
+ { label: 'One', value: 'one' },
+ { label: 'Two', value: 'two' },
+ { label: 'Three', value: 'three' },
+];
+
+export const EMOJIS = ['👍', '🤙', '👏', '👌', '🙌', '✌️', '🖖', '👐'];
+
+export const defaultArgs = {
+ defaultMenuIsOpen: false,
+ defaultValue: undefined,
+ inputId: 'react-select-id',
+ isClearable: true,
+ isDisabled: false,
+ isLoading: false,
+ isMulti: false,
+ isRtl: false,
+ isSearchable: true,
+ menuPlacement: 'bottom',
+ menuPortalTarget: undefined,
+ options: colourOptions,
+ placeholder: 'Select...',
+} as const;
diff --git a/storybook/package.json b/storybook/package.json
new file mode 100644
index 0000000000..c88262f093
--- /dev/null
+++ b/storybook/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "storybook",
+ "version": "0.0.0",
+ "private": true,
+ "license": "MIT",
+ "scripts": {
+ "build": "build-storybook",
+ "dev": "start-storybook -p 6006"
+ },
+ "dependencies": {
+ "@atlaskit/button": "^15.1.4",
+ "@atlaskit/icon": "^11.0.1",
+ "@atlaskit/modal-dialog": "^11.2.5",
+ "@atlaskit/tooltip": "^17.1.2",
+ "@babel/core": "^7.19.6",
+ "@babel/preset-env": "^7.19.4",
+ "@babel/preset-typescript": "^7.18.6",
+ "@emotion/babel-plugin": "^11.10.2",
+ "@emotion/babel-preset-css-prop": "^11.10.0",
+ "@emotion/react": "^11.8.1",
+ "babel-loader": "^8.2.5",
+ "chroma-js": "^2.4.2",
+ "chrono-node": "^2.1.11",
+ "classnames": "^2.3.2",
+ "moment": "^2.29.4",
+ "react": "^16.13.0",
+ "react-dom": "^16.13.0",
+ "react-select": "^5.5.9",
+ "remeda": "^1.1.0",
+ "webpack": "^4.30.0"
+ },
+ "devDependencies": {
+ "@storybook/addon-a11y": "^6.5.13",
+ "@storybook/addon-essentials": "^6.5.13",
+ "@storybook/addon-postcss": "^2.0.0",
+ "@storybook/builder-webpack4": "^6.5.13",
+ "@storybook/manager-webpack4": "^6.5.13",
+ "@storybook/react": "^6.5.13",
+ "autoprefixer": "^10.4.12",
+ "postcss": "^8.4.18",
+ "tailwindcss": "^3.2.1",
+ "typescript": "^4.1.3"
+ }
+}
diff --git a/storybook/postcss.config.js b/storybook/postcss.config.js
new file mode 100644
index 0000000000..3ea9307f40
--- /dev/null
+++ b/storybook/postcss.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ plugins: [require('tailwindcss'), require('autoprefixer')],
+};
diff --git a/storybook/stories/AccessingInternalsViaRef.stories.tsx b/storybook/stories/AccessingInternalsViaRef.stories.tsx
new file mode 100644
index 0000000000..aa9c298c03
--- /dev/null
+++ b/storybook/stories/AccessingInternalsViaRef.stories.tsx
@@ -0,0 +1,108 @@
+import Button from '@atlaskit/button/standard-button';
+import type { ComponentMeta } from '@storybook/react';
+import React, { useRef } from 'react';
+import Select, { SelectInstance } from 'react-select';
+import AsyncSelect from 'react-select/async';
+import CreatableSelect from 'react-select/creatable';
+
+import { Field, Inline, Stack } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AccessingInternalsViaRef',
+ component: Select,
+ argTypes: {},
+} as ComponentMeta;
+
+export function AccessingInternalsViaRef() {
+ const selectRef = useRef | null>(null);
+ const asyncRef = useRef | null>(null);
+ const creatableRef = useRef | null>(null);
+
+ // Focus handlers
+ const focus = () => {
+ selectRef.current?.focus();
+ };
+ const focusAsync = () => {
+ asyncRef.current?.focus();
+ };
+ const focusCreatable = () => {
+ creatableRef.current?.focus();
+ };
+
+ // Blur handlers
+ const blur = () => {
+ selectRef.current?.blur();
+ };
+ const blurAsync = () => {
+ asyncRef.current?.blur();
+ };
+ const blurCreatable = () => {
+ creatableRef.current?.blur();
+ };
+
+ return (
+
+
+
+
+
+
+ Focus
+ Blur
+
+
+
+ {/* Async Select */}
+
+
+
+
+
+ Focus
+ Blur
+
+
+
+ {/* Creatable */}
+
+
+
+
+
+ Focus
+ Blur
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function promiseOptions(inputValue: string) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+}
diff --git a/storybook/stories/AnimatedMulti.stories.tsx b/storybook/stories/AnimatedMulti.stories.tsx
new file mode 100644
index 0000000000..aebef29fae
--- /dev/null
+++ b/storybook/stories/AnimatedMulti.stories.tsx
@@ -0,0 +1,36 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import * as React from 'react';
+import Select from 'react-select';
+import makeAnimated from 'react-select/animated';
+
+import { Field } from '../components';
+import { colourOptions, defaultArgs } from '../data';
+
+export default {
+ title: 'Select/AnimatedMulti',
+ component: Select,
+} as ComponentMeta;
+
+const animatedComponents = makeAnimated();
+
+const Template: ComponentStory = ({
+ inputId = 'react-select',
+ ...props
+}) => {
+ return (
+
+
+
+ );
+};
+
+export const AnimatedMulti = Template.bind({});
+AnimatedMulti.args = {
+ ...defaultArgs,
+ defaultValue: [colourOptions[0], colourOptions[1], colourOptions[2]],
+ isMulti: true,
+};
diff --git a/storybook/stories/AsyncCallbacks.stories.tsx b/storybook/stories/AsyncCallbacks.stories.tsx
new file mode 100644
index 0000000000..28f7055968
--- /dev/null
+++ b/storybook/stories/AsyncCallbacks.stories.tsx
@@ -0,0 +1,43 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import AsyncSelect from 'react-select/async';
+
+import { Field } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AsyncCallbacks',
+ component: AsyncSelect,
+} as ComponentMeta;
+
+export function AsyncCallbacks() {
+ return (
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function loadOptions(
+ inputValue: string,
+ callback: (options: ColourOption[]) => void
+) {
+ setTimeout(() => {
+ callback(filterColors(inputValue));
+ }, 1000);
+}
diff --git a/storybook/stories/AsyncCreatable.stories.tsx b/storybook/stories/AsyncCreatable.stories.tsx
new file mode 100644
index 0000000000..01540cec63
--- /dev/null
+++ b/storybook/stories/AsyncCreatable.stories.tsx
@@ -0,0 +1,42 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import AsyncCreatableSelect from 'react-select/async-creatable';
+
+import { Field } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AsyncCreatable',
+ component: AsyncCreatableSelect,
+} as ComponentMeta;
+
+export function AsyncCreatable() {
+ return (
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function promiseOptions(inputValue: string) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+}
diff --git a/storybook/stories/AsyncMulti.stories.tsx b/storybook/stories/AsyncMulti.stories.tsx
new file mode 100644
index 0000000000..92d915b392
--- /dev/null
+++ b/storybook/stories/AsyncMulti.stories.tsx
@@ -0,0 +1,43 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import AsyncSelect from 'react-select/async';
+
+import { Field } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AsyncMulti',
+ component: AsyncSelect,
+} as ComponentMeta;
+
+export function AsyncMulti() {
+ return (
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function promiseOptions(inputValue: string) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+}
diff --git a/storybook/stories/AsyncPromises.stories.tsx b/storybook/stories/AsyncPromises.stories.tsx
new file mode 100644
index 0000000000..30c0ce727e
--- /dev/null
+++ b/storybook/stories/AsyncPromises.stories.tsx
@@ -0,0 +1,43 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import AsyncSelect from 'react-select/async';
+
+import { Field } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AsyncPromises',
+ component: AsyncSelect,
+ argTypes: {},
+} as ComponentMeta;
+
+export function AsyncPromises() {
+ return (
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function promiseOptions(inputValue: string) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+}
diff --git a/storybook/stories/AsyncSelectWithDefaultOptions.stories.tsx b/storybook/stories/AsyncSelectWithDefaultOptions.stories.tsx
new file mode 100644
index 0000000000..8473f467af
--- /dev/null
+++ b/storybook/stories/AsyncSelectWithDefaultOptions.stories.tsx
@@ -0,0 +1,46 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import AsyncSelect from 'react-select/async';
+import { Field } from '../components';
+
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/AsyncSelectWithDefaultOptions',
+ component: AsyncSelect,
+ argTypes: {},
+} as ComponentMeta;
+
+export function AsyncSelectWithDefaultOptions() {
+ return (
+
+
+
+ );
+}
+
+// =============================================================================
+// Utils
+// =============================================================================
+
+function filterColors(inputValue: string) {
+ return colourOptions.filter((i) =>
+ i.label.toLowerCase().includes(inputValue.toLowerCase())
+ );
+}
+
+function promiseOptions(inputValue: string) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(filterColors(inputValue));
+ }, 1000);
+ });
+}
diff --git a/storybook/stories/BasicGrouped.stories.tsx b/storybook/stories/BasicGrouped.stories.tsx
new file mode 100644
index 0000000000..0f9feb1d01
--- /dev/null
+++ b/storybook/stories/BasicGrouped.stories.tsx
@@ -0,0 +1,60 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import Select from 'react-select';
+
+import { Field } from '../components';
+import {
+ ColourOption,
+ colourOptions,
+ FlavourOption,
+ GroupedOption,
+ groupedOptions,
+} from '../data';
+
+export default {
+ title: 'Select/BasicGrouped',
+ component: Select,
+} as ComponentMeta;
+
+export function BasicGrouped() {
+ return (
+
+
+ inputId="basic-grouped-id"
+ defaultValue={colourOptions[1]}
+ options={groupedOptions}
+ formatGroupLabel={FormatGroupLabel}
+ />
+
+ );
+}
+
+function FormatGroupLabel({ label, options }: GroupedOption) {
+ return (
+
+ {label}
+
+ {options.length}
+
+
+ );
+}
diff --git a/storybook/stories/BasicMulti.stories.tsx b/storybook/stories/BasicMulti.stories.tsx
new file mode 100644
index 0000000000..233f06a2da
--- /dev/null
+++ b/storybook/stories/BasicMulti.stories.tsx
@@ -0,0 +1,30 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import * as React from 'react';
+import Select from 'react-select';
+
+import { Field } from '../components';
+import { colourOptions, defaultArgs } from '../data';
+
+export default {
+ title: 'Select/BasicMulti',
+ component: Select,
+ argTypes: {},
+} as ComponentMeta;
+
+const Template: ComponentStory = ({
+ inputId = 'react-select',
+ ...props
+}) => {
+ return (
+
+
+
+ );
+};
+
+export const BasicMulti = Template.bind({});
+BasicMulti.args = {
+ ...defaultArgs,
+ defaultValue: [colourOptions[0], colourOptions[1], colourOptions[2]],
+ isMulti: true,
+};
diff --git a/storybook/stories/BasicSingle.stories.tsx b/storybook/stories/BasicSingle.stories.tsx
new file mode 100644
index 0000000000..10fc70ec9c
--- /dev/null
+++ b/storybook/stories/BasicSingle.stories.tsx
@@ -0,0 +1,44 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import * as React from 'react';
+import Select from 'react-select';
+
+import { Field } from '../components';
+import { defaultArgs } from '../data';
+
+/**
+ * More on default export:
+ * @see https://storybook.js.org/docs/react/writing-stories/introduction#default-export
+ */
+export default {
+ title: 'Select/BasicSingle',
+ component: Select,
+ /**
+ * More on argTypes:
+ * @see https://storybook.js.org/docs/react/api/argtypes
+ */
+ argTypes: {},
+} as ComponentMeta;
+
+/**
+ * More on component templates:
+ * @see https://storybook.js.org/docs/react/writing-stories/introduction#using-args
+ */
+const Template: ComponentStory = ({
+ inputId = 'react-select',
+ ...props
+}) => {
+ return (
+
+
+
+ );
+};
+
+export const BasicSingle = Template.bind({});
+/**
+ * More on args:
+ * @see https://storybook.js.org/docs/react/writing-stories/args
+ */
+BasicSingle.args = {
+ ...defaultArgs,
+};
diff --git a/storybook/stories/ClassNamesWithTailwind.stories.tsx b/storybook/stories/ClassNamesWithTailwind.stories.tsx
new file mode 100644
index 0000000000..1d0072ef13
--- /dev/null
+++ b/storybook/stories/ClassNamesWithTailwind.stories.tsx
@@ -0,0 +1,67 @@
+import '../styles/tailwind.css';
+
+import createCache from '@emotion/cache';
+import { CacheProvider } from '@emotion/react';
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import classNames from 'classnames';
+import * as React from 'react';
+import Select from 'react-select';
+
+import { Field } from '../components/field';
+import { defaultArgs } from '../data';
+
+export default {
+ title: 'Select/ClassNamesWithTailwind',
+ component: Select,
+ argTypes: {},
+} as ComponentMeta;
+
+// This ensures that Emotion's styles are inserted before Tailwind's styles so that Tailwind classes have precedence over Emotion
+const EmotionCacheProvider = ({ children }: { children: React.ReactNode }) => {
+ const cache = React.useMemo(
+ () =>
+ createCache({
+ key: 'with-tailwind',
+ insertionPoint: document.querySelector('title')!,
+ }),
+ []
+ );
+
+ return {children} ;
+};
+
+const Template: ComponentStory = ({
+ inputId = 'react-select',
+ ...props
+}) => {
+ return (
+
+
+
+ classNames(
+ !isDisabled && isFocused && 'border-purple-800',
+ isFocused && 'shadow-[0_0_0_1px] shadow-purple-800',
+ isFocused && 'hover:border-purple-800'
+ ),
+ option: ({ isDisabled, isFocused, isSelected }) =>
+ classNames(
+ isSelected && 'bg-purple-800',
+ !isSelected && isFocused && 'bg-purple-300',
+ !isDisabled && isSelected && 'active:bg-purple-800',
+ !isDisabled && !isSelected && 'active:bg-purple-500'
+ ),
+ }}
+ />
+
+
+ );
+};
+
+export const ClassNamesWithTailwind = Template.bind({});
+ClassNamesWithTailwind.args = {
+ ...defaultArgs,
+};
diff --git a/storybook/stories/ControlledMenu.stories.tsx b/storybook/stories/ControlledMenu.stories.tsx
new file mode 100644
index 0000000000..dc52ca6822
--- /dev/null
+++ b/storybook/stories/ControlledMenu.stories.tsx
@@ -0,0 +1,56 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import Select, { SelectInstance, StylesConfig } from 'react-select';
+
+import { Field, Inline, Stack } from '../components';
+import { ColourOption, colourOptions } from '../data';
+
+export default {
+ title: 'Select/ControlledMenu',
+ component: Select,
+} as ComponentMeta;
+
+export function ControlledMenu() {
+ const inputRef = React.useRef>(null);
+ const [menuIsOpen, setMenuIsOpen] = React.useState(false);
+
+ function toggleMenuIsOpen() {
+ setMenuIsOpen((value) => !value);
+ const selectEl = inputRef.current;
+ if (!selectEl) return;
+ if (menuIsOpen) selectEl.blur();
+ else selectEl.focus();
+ }
+
+ return (
+
+
+
+ Click to toggle menu
+
+
+
+
+
+ );
+}
+
+// =============================================================================
+// Styles
+// =============================================================================
+
+const styles: StylesConfig = {
+ menu: (base) => ({ ...base, position: 'relative' }),
+};
diff --git a/storybook/stories/Creatable.stories.tsx b/storybook/stories/Creatable.stories.tsx
new file mode 100644
index 0000000000..9fd3634a74
--- /dev/null
+++ b/storybook/stories/Creatable.stories.tsx
@@ -0,0 +1,78 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import * as React from 'react';
+import type { SelectInstance } from 'react-select';
+import CreatableSelect from 'react-select/creatable';
+
+import { Field } from '../components';
+import { defaultArgs } from '../data';
+
+export default {
+ title: 'Select/Creatable',
+ component: CreatableSelect,
+} as ComponentMeta;
+
+type Option = {
+ label: string;
+ value: string;
+};
+
+function createOption(label: string): Option {
+ return {
+ label,
+ value: label.toLowerCase(),
+ };
+}
+
+const defaultOptions: Option[] = [
+ createOption('One'),
+ createOption('Two'),
+ createOption('Three'),
+];
+
+const Template: ComponentStory = ({
+ inputId = 'react-select',
+ ...props
+}) => {
+ const creatableRef = React.useRef | null>(null);
+ const [isLoading, setIsLoading] = React.useState(false);
+ const [options, setOptions] = React.useState(props.options as Option[]);
+ const [value, setValue] = React.useState();
+
+ /** Uses a setTimeout to simulate making a network request. */
+ function handleCreate(inputValue: string) {
+ setIsLoading(true);
+ setTimeout(() => {
+ const newOption = createOption(inputValue);
+ setOptions((prev) => [...prev, newOption]);
+ setValue(newOption);
+ setIsLoading(false);
+ creatableRef.current?.focus();
+ }, 1000);
+ }
+
+ return (
+
+
+
+ );
+};
+
+export const Creatable = Template.bind({});
+Creatable.args = {
+ ...defaultArgs,
+ options: defaultOptions,
+ isClearable: true,
+};
diff --git a/storybook/stories/CreatableAdvanced.stories.tsx b/storybook/stories/CreatableAdvanced.stories.tsx
new file mode 100644
index 0000000000..09e3144c39
--- /dev/null
+++ b/storybook/stories/CreatableAdvanced.stories.tsx
@@ -0,0 +1,52 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import CreatableSelect from 'react-select/creatable';
+
+import { Field } from '../components';
+import { NumberOption, numbers } from '../data';
+
+export default {
+ title: 'Select/CreatableAdvanced',
+ component: CreatableSelect,
+} as ComponentMeta;
+
+export function CreatableAdvanced() {
+ const [isLoading, setIsLoading] = React.useState(false);
+ const [options, setOptions] = React.useState(numbers);
+ const [value, setValue] = React.useState(null);
+
+ function handleCreate(inputValue: string) {
+ setIsLoading(true);
+ setTimeout(() => {
+ const newOption = {
+ label: inputValue,
+ value: slugify(inputValue),
+ };
+ setIsLoading(false);
+ setOptions((prev) => [...prev, newOption]);
+ setValue(newOption);
+ }, 1000);
+ }
+
+ return (
+
+ setValue(newValue)}
+ onCreateOption={handleCreate}
+ options={options}
+ value={value}
+ />
+
+ );
+}
+
+function slugify(text: string) {
+ return text
+ .toLowerCase()
+ .replace(/[^a-z0-9 -]/g, '')
+ .replace(/\s+/g, '-')
+ .replace(/-+/g, '-');
+}
diff --git a/storybook/stories/CreatableInputOnly.stories.tsx b/storybook/stories/CreatableInputOnly.stories.tsx
new file mode 100644
index 0000000000..3f27200578
--- /dev/null
+++ b/storybook/stories/CreatableInputOnly.stories.tsx
@@ -0,0 +1,46 @@
+import type { ComponentMeta } from '@storybook/react';
+import * as React from 'react';
+import CreatableSelect from 'react-select/creatable';
+import { Field } from '../components';
+
+export default {
+ title: 'Select/CreatableInputOnly',
+ component: CreatableSelect,
+} as ComponentMeta;
+
+export function CreatableInputOnly() {
+ const [inputValue, setInputValue] = React.useState('');
+ const [value, setValue] = React.useState([]);
+
+ function handleKeyDown(event: React.KeyboardEvent