Repository: JedWatson/react-select
Branch: master
Commit: 052e864b4990
Files: 302
Total size: 885.2 KB
Directory structure:
gitextract_m207rt_u/
├── .browserslistrc
├── .changeset/
│ ├── README.md
│ ├── config.json
│ └── getChangelogEntry.js
├── .circleci/
│ └── config.yml
├── .codesandbox/
│ └── ci.json
├── .coveralls.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── config.yml
│ ├── dependabot.yml
│ └── workflows/
│ └── release.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── cypress/
│ ├── fixtures/
│ │ └── selectors.json
│ ├── integration/
│ │ ├── multi-select.spec.ts
│ │ └── single-select.spec.ts
│ └── tsconfig.json
├── cypress.json
├── docs/
│ ├── App/
│ │ ├── Footer.tsx
│ │ ├── GitHubButton.tsx
│ │ ├── Header.tsx
│ │ ├── PageNav.tsx
│ │ ├── ScrollSpy.tsx
│ │ ├── Section.tsx
│ │ ├── Sticky.tsx
│ │ ├── TwitterButton.tsx
│ │ ├── components.tsx
│ │ ├── index.tsx
│ │ └── routes.ts
│ ├── CHANGELOG.md
│ ├── ExampleWrapper.tsx
│ ├── NoMatch.tsx
│ ├── PropTypes/
│ │ ├── Async.ts
│ │ ├── Creatable.ts
│ │ ├── Select.ts
│ │ ├── components/
│ │ │ ├── ClearIndicator.ts
│ │ │ ├── Control.ts
│ │ │ ├── DropdownIndicator.ts
│ │ │ ├── Group.ts
│ │ │ ├── IndicatorsContainer.ts
│ │ │ ├── IndicatorsSeparator.ts
│ │ │ ├── Input.ts
│ │ │ ├── LoadingIndicator.ts
│ │ │ ├── LoadingMessage.ts
│ │ │ ├── Menu.ts
│ │ │ ├── MenuList.ts
│ │ │ ├── MultiValue.ts
│ │ │ ├── MultiValueContainer.ts
│ │ │ ├── MultiValueLabel.ts
│ │ │ ├── MultiValueRemove.ts
│ │ │ ├── NoOptionsMessage.ts
│ │ │ ├── Option.ts
│ │ │ ├── Placeholder.ts
│ │ │ ├── SelectContainer.ts
│ │ │ ├── SingleValue.ts
│ │ │ └── ValueContainer.ts
│ │ └── stateManager.ts
│ ├── Svg.tsx
│ ├── Table.tsx
│ ├── Tests.tsx
│ ├── _redirects
│ ├── data.ts
│ ├── examples/
│ │ ├── AccessingInternals.tsx
│ │ ├── AnimatedMulti.tsx
│ │ ├── AsyncCallbacks.tsx
│ │ ├── AsyncCreatable.tsx
│ │ ├── AsyncMulti.tsx
│ │ ├── AsyncPromises.tsx
│ │ ├── BasicGrouped.tsx
│ │ ├── BasicMulti.tsx
│ │ ├── BasicSingle.tsx
│ │ ├── ControlledMenu.tsx
│ │ ├── CreatableAdvanced.tsx
│ │ ├── CreatableInputOnly.tsx
│ │ ├── CreatableMulti.tsx
│ │ ├── CreatableSingle.tsx
│ │ ├── CreateFilter.tsx
│ │ ├── CustomAriaLive.tsx
│ │ ├── CustomClearIndicator.tsx
│ │ ├── CustomControl.tsx
│ │ ├── CustomDropdownIndicator.tsx
│ │ ├── CustomFilterOptions.tsx
│ │ ├── CustomGetOptionLabel.tsx
│ │ ├── CustomGetOptionValue.tsx
│ │ ├── CustomGroup.tsx
│ │ ├── CustomGroupHeading.tsx
│ │ ├── CustomIndicatorSeparator.tsx
│ │ ├── CustomIndicatorsContainer.tsx
│ │ ├── CustomInput.tsx
│ │ ├── CustomIsOptionDisabled.tsx
│ │ ├── CustomLoadingIndicator.tsx
│ │ ├── CustomLoadingMessage.tsx
│ │ ├── CustomMenu.tsx
│ │ ├── CustomMenuList.tsx
│ │ ├── CustomMultiValueContainer.tsx
│ │ ├── CustomMultiValueLabel.tsx
│ │ ├── CustomMultiValueRemove.tsx
│ │ ├── CustomNoOptionsMessage.tsx
│ │ ├── CustomOption.tsx
│ │ ├── CustomPlaceholder.tsx
│ │ ├── CustomSelectContainer.tsx
│ │ ├── CustomSelectProps.tsx
│ │ ├── CustomSingleValue.tsx
│ │ ├── CustomValueContainer.tsx
│ │ ├── DefaultOptions.tsx
│ │ ├── Experimental.tsx
│ │ ├── FixedOptions.tsx
│ │ ├── MenuBuffer.tsx
│ │ ├── MenuPortal.tsx
│ │ ├── MultiSelectSort.tsx
│ │ ├── OnSelectResetsInput.tsx
│ │ ├── Popout.tsx
│ │ ├── StyleCompositionExample.tsx
│ │ ├── StyledMulti.tsx
│ │ ├── StyledSingle.tsx
│ │ ├── Theme.tsx
│ │ └── index.tsx
│ ├── generate-magical-types/
│ │ ├── generate/
│ │ │ └── package.json
│ │ ├── package.json
│ │ ├── serialize/
│ │ │ └── package.json
│ │ └── src/
│ │ ├── generate.ts
│ │ ├── serialize.ts
│ │ └── types.ts
│ ├── index.css
│ ├── index.html
│ ├── index.tsx
│ ├── isArray.ts
│ ├── markdown/
│ │ ├── renderer.tsx
│ │ └── store.ts
│ ├── package.json
│ ├── pages/
│ │ ├── advanced/
│ │ │ └── index.tsx
│ │ ├── async/
│ │ │ └── index.tsx
│ │ ├── components/
│ │ │ └── index.tsx
│ │ ├── creatable/
│ │ │ └── index.tsx
│ │ ├── home/
│ │ │ └── index.tsx
│ │ ├── props/
│ │ │ └── index.tsx
│ │ ├── styles/
│ │ │ └── index.tsx
│ │ ├── typescript/
│ │ │ └── index.tsx
│ │ ├── upgrade/
│ │ │ └── index.tsx
│ │ └── upgrade-to-v2/
│ │ ├── index.tsx
│ │ └── props.tsx
│ ├── styled-components.tsx
│ ├── tsconfig.json
│ ├── utils.ts
│ └── webpack.config.ts
├── netlify.toml
├── package.json
├── packages/
│ └── react-select/
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── animated/
│ │ └── package.json
│ ├── async/
│ │ └── package.json
│ ├── async-creatable/
│ │ └── package.json
│ ├── base/
│ │ └── package.json
│ ├── creatable/
│ │ └── package.json
│ ├── package.json
│ ├── src/
│ │ ├── Async.tsx
│ │ ├── AsyncCreatable.tsx
│ │ ├── Creatable.tsx
│ │ ├── NonceProvider.tsx
│ │ ├── Select.tsx
│ │ ├── __tests__/
│ │ │ ├── Async.test.tsx
│ │ │ ├── AsyncCreatable.test.tsx
│ │ │ ├── Creatable.test.tsx
│ │ │ ├── Select.test.tsx
│ │ │ ├── StateManaged.test.tsx
│ │ │ ├── __snapshots__/
│ │ │ │ ├── Async.test.tsx.snap
│ │ │ │ ├── AsyncCreatable.test.tsx.snap
│ │ │ │ ├── Creatable.test.tsx.snap
│ │ │ │ ├── Select.test.tsx.snap
│ │ │ │ └── StateManaged.test.tsx.snap
│ │ │ ├── constants.ts
│ │ │ └── tsconfig.json
│ │ ├── accessibility/
│ │ │ ├── helpers.ts
│ │ │ └── index.ts
│ │ ├── animated/
│ │ │ ├── Input.tsx
│ │ │ ├── MultiValue.tsx
│ │ │ ├── Placeholder.tsx
│ │ │ ├── SingleValue.tsx
│ │ │ ├── ValueContainer.tsx
│ │ │ ├── index.ts
│ │ │ └── transitions.tsx
│ │ ├── async/
│ │ │ └── index.ts
│ │ ├── async-creatable/
│ │ │ └── index.ts
│ │ ├── base/
│ │ │ └── index.ts
│ │ ├── builtins.ts
│ │ ├── components/
│ │ │ ├── Control.tsx
│ │ │ ├── Group.tsx
│ │ │ ├── Input.tsx
│ │ │ ├── LiveRegion.tsx
│ │ │ ├── Menu.tsx
│ │ │ ├── MultiValue.tsx
│ │ │ ├── Option.tsx
│ │ │ ├── Placeholder.tsx
│ │ │ ├── SingleValue.tsx
│ │ │ ├── containers.tsx
│ │ │ ├── index.ts
│ │ │ └── indicators.tsx
│ │ ├── creatable/
│ │ │ └── index.ts
│ │ ├── diacritics.ts
│ │ ├── filters.ts
│ │ ├── index.ts
│ │ ├── internal/
│ │ │ ├── A11yText.tsx
│ │ │ ├── DummyInput.tsx
│ │ │ ├── RequiredInput.tsx
│ │ │ ├── ScrollManager.tsx
│ │ │ ├── index.ts
│ │ │ ├── useScrollCapture.ts
│ │ │ └── useScrollLock.ts
│ │ ├── stateManager.tsx
│ │ ├── styles.ts
│ │ ├── theme.ts
│ │ ├── types.ts
│ │ ├── useAsync.ts
│ │ ├── useCreatable.ts
│ │ ├── useStateManager.ts
│ │ └── utils.ts
│ └── tsconfig.json
├── storybook/
│ ├── .gitignore
│ ├── .storybook/
│ │ ├── .babelrc
│ │ ├── main.ts
│ │ └── preview.tsx
│ ├── components/
│ │ ├── field.tsx
│ │ ├── index.ts
│ │ ├── inline.tsx
│ │ ├── stack.tsx
│ │ └── svg.tsx
│ ├── data.ts
│ ├── package.json
│ ├── postcss.config.js
│ ├── stories/
│ │ ├── AccessingInternalsViaRef.stories.tsx
│ │ ├── AnimatedMulti.stories.tsx
│ │ ├── AsyncCallbacks.stories.tsx
│ │ ├── AsyncCreatable.stories.tsx
│ │ ├── AsyncMulti.stories.tsx
│ │ ├── AsyncPromises.stories.tsx
│ │ ├── AsyncSelectWithDefaultOptions.stories.tsx
│ │ ├── BasicGrouped.stories.tsx
│ │ ├── BasicMulti.stories.tsx
│ │ ├── BasicSingle.stories.tsx
│ │ ├── ClassNamesWithTailwind.stories.tsx
│ │ ├── ControlledMenu.stories.tsx
│ │ ├── Creatable.stories.tsx
│ │ ├── CreatableAdvanced.stories.tsx
│ │ ├── CreatableInputOnly.stories.tsx
│ │ ├── CreateFilter.stories.tsx
│ │ ├── CustomAriaLive.stories.tsx
│ │ ├── CustomClearIndicator.stories.tsx
│ │ ├── CustomControl.stories.tsx
│ │ ├── CustomDropdownIndicator.stories.tsx
│ │ ├── CustomFilterOptions.stories.tsx
│ │ ├── CustomFormatOptionLabel.stories.tsx
│ │ ├── CustomGetOptionLabel.stories.tsx
│ │ ├── CustomGetOptionValue.stories.tsx
│ │ ├── CustomGroup.stories.tsx
│ │ ├── CustomGroupHeading.stories.tsx
│ │ ├── CustomIndicatorSeparator.stories.tsx
│ │ ├── CustomIndicatorsContainer.stories.tsx
│ │ ├── CustomInput.stories.tsx
│ │ ├── CustomIsOptionDisabled.stories.tsx
│ │ ├── CustomLoadingIndicator.stories.tsx
│ │ ├── CustomLoadingMessage.stories.tsx
│ │ ├── CustomMenu.stories.tsx
│ │ ├── CustomMenuList.stories.tsx
│ │ ├── CustomMultiValueContainer.stories.tsx
│ │ ├── CustomMultiValueLabel.stories.tsx
│ │ ├── CustomMultiValueRemove.stories.tsx
│ │ ├── CustomNoOptionsMessage.stories.tsx
│ │ ├── CustomOption.stories.tsx
│ │ ├── CustomPlaceholder.stories.tsx
│ │ ├── CustomSelectContainer.stories.tsx
│ │ ├── CustomSelectProps.stories.tsx
│ │ ├── CustomSingleValue.stories.tsx
│ │ ├── CustomValueContainer.stories.tsx
│ │ ├── ExperimentalDatePicker.stories.tsx
│ │ ├── FixedOptions.stories.tsx
│ │ ├── Grouped.stories.tsx
│ │ ├── MenuBuffer.stories.tsx
│ │ ├── MenuPortal.stories.tsx
│ │ ├── MultiSelectSort.stories.tsx
│ │ ├── OnSelectKeepsInput.stories.tsx
│ │ ├── Popout.stories.tsx
│ │ ├── StyleCompositionExample.stories.tsx
│ │ ├── StyledMulti.stories.tsx
│ │ ├── StyledSingle.stories.tsx
│ │ ├── Tailwind.stories.tsx
│ │ ├── Theme.stories.tsx
│ │ └── UnstyledWithTailwind.stories.tsx
│ ├── styles/
│ │ └── tailwind.css
│ └── tailwind.config.js
├── test-setup.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .browserslistrc
================================================
> 0.25%
ie 11
not op_mini all
================================================
FILE: .changeset/README.md
================================================
# 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.
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@0.2.1/schema.json",
"changelog": "./getChangelogEntry",
"commit": false,
"linked": [],
"access": "public"
}
================================================
FILE: .changeset/getChangelogEntry.js
================================================
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,
};
================================================
FILE: .circleci/config.yml
================================================
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
================================================
FILE: .codesandbox/ci.json
================================================
{
"buildCommand": "build",
"packages": ["packages/*"],
"sandboxes": ["nfmxw"],
"node": "20"
}
================================================
FILE: .coveralls.yml
================================================
service-name: travis-ci
repo_token: itdMRdBNgDK8Gb5nIA63zVMEryaxTQxkR
================================================
FILE: .editorconfig
================================================
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[.circleci/config.yml]
indent_size = 4
================================================
FILE: .eslintignore
================================================
coverage/*
cypress/plugins/*
cypress/support/*
**/dist/*
lib/*
node_modules/*
**/node_modules/*
================================================
FILE: .eslintrc.js
================================================
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',
},
},
};
================================================
FILE: .github/CONTRIBUTING.md
================================================
# 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
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
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.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
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
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
ignore:
- dependency-name: '*'
update-types:
['version-update:semver-minor', 'version-update:semver-patch']
================================================
FILE: .github/workflows/release.yml
================================================
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 }}
================================================
FILE: .gitignore
================================================
# Build
lib
dist
docs/dist
.env
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Coverage tools
lib-cov
coverage
.nyc_output
# Cypress
cypress/videos
cypress/screenshots
cypress/support
cypress/plugins
# Dependency directory
node_modules
bower_components
# Publish directory
.publish
# Editor artefacts
.idea
# Other
.DS_Store
.env
package-lock.json
# Notes
.NOTES.md
magical-types
================================================
FILE: .nvmrc
================================================
22
================================================
FILE: .prettierignore
================================================
coverage/*
cypress/plugins/*
cypress/support/*
**/dist/*
lib/*
node_modules/*
**/node_modules/*
**/magical-types/*
================================================
FILE: .prettierrc.js
================================================
module.exports = {
singleQuote: true,
trailingComma: 'es5',
overrides: [
{
files: '.changeset/pre.json',
options: { parser: 'json-stringify' },
},
],
};
================================================
FILE: CONTRIBUTING.md
================================================
# 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 (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.
================================================
FILE: LICENSE
================================================
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.
================================================
FILE: README.md
================================================
[](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.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.
`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.
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.
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:
```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.
================================================
FILE: babel.config.js
================================================
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',
],
};
================================================
FILE: cypress/fixtures/selectors.json
================================================
{
"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"
}
================================================
FILE: cypress/integration/multi-select.spec.ts
================================================
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');
});
});
}
});
================================================
FILE: cypress/integration/single-select.spec.ts
================================================
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');
});
});
}
});
================================================
FILE: cypress/tsconfig.json
================================================
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"noEmit": true,
"strict": true,
"types": ["cypress"],
"esModuleInterop": true,
"resolveJsonModule": true
}
}
================================================
FILE: cypress.json
================================================
{
"baseUrl": "http://localhost:8000/cypress-tests",
"video": false
}
================================================
FILE: docs/App/Footer.tsx
================================================
/** @jsx jsx */
import { jsx } from '@emotion/react';
// const smallDevice = '@media (max-width: 769px)';
const largeDevice = '@media (min-width: 770px)';
const Wrapper = (props: JSX.IntrinsicElements['div']) => (
);
const Container = (props: JSX.IntrinsicElements['div']) => (
);
const A = (props: JSX.IntrinsicElements['a']) => (
);
export default function Footer() {
return (