├── .babelrc ├── .coveralls.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .nvmrc ├── .nycrc ├── .sweet-changelogs.js ├── .travis.yml ├── CONTRIBUTING.md ├── HISTORY.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── react-select-plus.css ├── react-select-plus.es.js ├── react-select-plus.js ├── react-select-plus.min.css └── react-select-plus.min.js ├── examples ├── dist │ ├── .gitignore │ ├── app.js │ ├── bundle.js │ ├── common.js │ ├── example.css │ ├── index.html │ ├── standalone.html │ └── standalone.js └── src │ ├── .gitignore │ ├── .npmignore │ ├── app.js │ ├── components │ ├── BooleanSelect.js │ ├── Cities.js │ ├── Contributors.js │ ├── Creatable.js │ ├── CustomComponents.js │ ├── CustomRender.js │ ├── GithubUsers.js │ ├── GroupedOptionsField.js │ ├── Multiselect.js │ ├── NumericSelect.js │ ├── States.js │ └── Virtualized.js │ ├── data │ ├── cities.js │ ├── contributors.js │ ├── states.js │ └── users.js │ ├── example.less │ ├── favicon.ico │ ├── index.html │ └── standalone.html ├── less ├── control.less ├── default.less ├── menu.less ├── mixins.less ├── multi.less ├── select.less └── spinner.less ├── lib ├── Async.js ├── AsyncCreatable.js ├── Creatable.js ├── Dropdown.js ├── Option.js ├── OptionGroup.js ├── Select.js ├── Value.js ├── index.js └── utils │ ├── blockEvent.js │ ├── defaultArrowRenderer.js │ ├── defaultClearRenderer.js │ ├── defaultFilterOptions.js │ ├── defaultMenuRenderer.js │ ├── stripDiacritics.js │ └── trim.js ├── package-lock.json ├── package-scripts.js ├── package.json ├── rollup.config.js ├── scss ├── components.scss ├── control.scss ├── default.scss ├── menu.scss ├── mixins.scss ├── multi.scss ├── select.scss └── spinner.scss ├── src ├── Async.js ├── AsyncCreatable.js ├── Creatable.js ├── Dropdown.js ├── Option.js ├── OptionGroup.js ├── Select.js ├── Value.js ├── index.js ├── index.umd.js └── utils │ ├── blockEvent.js │ ├── defaultArrowRenderer.js │ ├── defaultClearRenderer.js │ ├── defaultFilterOptions.js │ ├── defaultMenuRenderer.js │ ├── stripDiacritics.js │ └── trim.js ├── test ├── Async-test.js ├── AsyncCreatable-test.js ├── Creatable-test.js ├── Option-test.js ├── Select-test.js └── Value-test.js ├── testHelpers ├── jsdomHelper.js └── nodeListType.js ├── wallaby.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node-modules/**", "src/index.umd.js"], 3 | "presets": [ "env", "stage-0", "react"], 4 | "env": { 5 | "test": { 6 | "plugins": ["istanbul"], 7 | }, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service-name: travis-ci 2 | repo_token: itdMRdBNgDK8Gb5nIA63zVMEryaxTQxkR 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | indent_style = tab 11 | translate_tabs_to_spaces = false 12 | 13 | [*.json] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.yml] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib/* 2 | dist/* 3 | coverage/* 4 | examples/dist/* 5 | node_modules/* 6 | bower_components/* 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | ecmaVersion: 6, 4 | sourceType: 'module', 5 | ecmaFeatures: { 6 | experimentalObjectRestSpread: true, 7 | jsx: true, 8 | }, 9 | }, 10 | env: { 11 | browser: true, 12 | es6: true, 13 | node: true, 14 | }, 15 | plugins: ['react'], 16 | rules: { 17 | 'curly': [2, 'multi-line'], 18 | 'jsx-quotes': 1, 19 | 'no-shadow': 0, 20 | 'no-trailing-spaces': 0, 21 | 'no-underscore-dangle': 0, 22 | 'no-unused-expressions': 0, 23 | 'object-curly-spacing': [1, 'always'], 24 | 'quotes': [2, 'single', 'avoid-escape'], 25 | 'react/jsx-boolean-value': 1, 26 | 'react/jsx-no-undef': 1, 27 | 'react/jsx-uses-react': 1, 28 | 'react/jsx-uses-vars': 1, 29 | 'react/jsx-wrap-multilines': 1, 30 | 'react/no-did-mount-set-state': 1, 31 | 'react/no-did-update-set-state': 1, 32 | 'react/no-unknown-property': 1, 33 | 'react/prop-types': 1, 34 | 'react/react-in-jsx-scope': 1, 35 | 'react/self-closing-comp': 1, 36 | 'react/sort-comp': 1, 37 | 'react/sort-prop-types': 1, 38 | 'semi': 2, 39 | 'strict': 0, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/* binary 2 | examples/dist/* binary 3 | lib/* binary 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage tools 11 | lib-cov 12 | coverage 13 | .nyc_output 14 | 15 | # Dependency directory 16 | node_modules 17 | bower_components 18 | 19 | # Publish directory 20 | .publish 21 | 22 | # Editor artifacts 23 | .idea 24 | 25 | # Other 26 | .DS_Store 27 | .env 28 | yarn.lock 29 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8.4.0 2 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": [ 3 | "lcov", 4 | "text-summary" 5 | ], 6 | "require": [ 7 | "babel-register" 8 | ], 9 | "sourceMap": false, 10 | "instrument": false, 11 | "report-dir": "./coverage" 12 | } 13 | -------------------------------------------------------------------------------- /.sweet-changelogs.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | filename: 'HISTORY.md', 3 | message: ({ pr, user }) => 4 | `* ${pr.title}, thanks [${user.name || 5 | user.login}](${user.url}) - [see PR](${pr.url})`, 6 | }; 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "v4" 5 | script: 6 | - npm run lint 7 | - npm run test 8 | - npm run coveralls 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in React-Select. All forms of contribution are 4 | welcome, from issue reports to PRs and documentation / write-ups. 5 | 6 | * We use node.js v4+ for development and testing. Due to incompatibilities with 7 | JSDOM and older versions of node.js, you'll need to use node 4 and above to run the 8 | tests. If you can't install node v4 or above as your "default" node installation, you 9 | could try using [nvm](https://github.com/creationix/nvm) to install multiple 10 | versions concurrently. 11 | * If you're upgrading your node.js 0.x environment, it's sometimes necessary 12 | to remove the node_modules directory under react-select, and run npm install 13 | again, in order to ensure all the correct dependencies for the new version 14 | of node.js (as a minimum, you'll need to remove the `jsdom` module, and 15 | reinstall that). 16 | 17 | Before you open a PR: 18 | 19 | * If you're planning to add or change a major feature in a PR, please ensure 20 | the change is aligned with the project roadmap by opening an issue first, 21 | especially if you're going to spend a lot of time on it. 22 | * In development, run `npm start` to build (+watch) the project source, and run 23 | the [development server](http://localhost:8000). 24 | * Please ensure all the examples work correctly after your change. If you're 25 | adding a major new use-case, add a new example demonstrating its use. 26 | * Please **do not** commit the build files. Make sure **only** your changes to 27 | `/src/`, `/less/` and `/examples/src` are included in your PR. 28 | * Be careful to follow the code style of the project. Run `npm run lint` after 29 | your changes and ensure you do not introduce any new errors or warnings. 30 | 31 | * Ensure that your effort is aligned with the project's roadmap by talking to 32 | the maintainers, especially if you are going to spend a lot of time on it. 33 | * Make sure there's an issue open for any work you take on and intend to submit 34 | as a pull request - it helps core members review your concept and direction 35 | early and is a good way to discuss what you're planning to do. 36 | * If you open an issue and are interested in working on a fix, please let us 37 | know. We'll help you get started, rather than adding it to the queue. 38 | * Make sure you do not add regressions by running `npm test`. 39 | * Where possible, include tests with your changes, either that demonstrates the 40 | bug, or tests the new functionality. If you're not sure how to test your 41 | changes, feel free to ping @bruderstein 42 | * Run `npm run cover` to check that the coverage hasn't dropped, and look at the 43 | report (under the generated `coverage` directory) to check that your changes are 44 | covered 45 | * Please [follow our established coding conventions](https://github.com/keystonejs/keystone/wiki/Coding-Standards) 46 | (with regards to formatting, etc) 47 | * You can also run `npm run lint` - our linter is a WIP 48 | but please ensure there are not more violations than before your changes. 49 | * All new features and changes need documentation. We have three translations, 50 | please read our [Documentation Guidelines](https://github.com/keystonejs/keystone/wiki/Documentation-Translation-Guidelines). 51 | 52 | * _Make sure you revert your build before submitting a PR_ to reduce the chance 53 | of conflicts. `npm run build` is run after PRs are merged and before any 54 | releases are made. 55 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Thanks for using react-select! 2 | 3 | Before creating an issue... 4 | 5 | # Are you asking a question? 6 | Please don't file GitHub issues to ask questions. Use Stack Overflow with a [#react-select](http://stackoverflow.com/questions/tagged/react-select) tag 7 | 8 | 9 | # Are you reporting a bug or runtime error? 10 | Please include a test case that demonstrates the issue you're reporting! 11 | This is very helpful to maintainers in order to help us see the issue you're seeing. 12 | 13 | Here is a Plunker you can fork that has react-select loaded and supports JSX syntax: 14 | https://plnkr.co/edit/dHygFMWWqVwaRAfpEmbn?p=preview 15 | 16 | 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. 17 | 18 | 19 | # Are you making a feature request? 20 | Provide as much information as possible about your requested feature. Here are a few questions you may consider answering: 21 | 22 | * What's your use case? (Tell us about your application and what problem you're trying to solve.) 23 | * What interface do you have in mind? (What new properties or methods do you think might be helpful?) 24 | * Can you point to similar functionality with any existing libraries or components? (Working demos can be helpful.) 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 HubSpot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-select-plus", 3 | "main": [ 4 | "dist/react-select-plus.min.js", 5 | "dist/react-select-plus.min.css" 6 | ], 7 | "version": "1.2.0", 8 | "homepage": "https://github.com/HubSpot/react-select-plus", 9 | "authors": [ 10 | "Trevor Burnham" 11 | ], 12 | "description": "A Select control built with and for ReactJS", 13 | "moduleType": ["amd", "globals", "node"], 14 | "dependencies": { 15 | "classnames": "^2.2.0", 16 | "react-input-autosize": "^2.0.1" 17 | }, 18 | "keywords": [ 19 | "react", 20 | "react-component", 21 | "select", 22 | "multiselect", 23 | "combobox", 24 | "input", 25 | "form", 26 | "ui" 27 | ], 28 | "license": "MIT", 29 | "ignore": [ 30 | ".editorconfig", 31 | ".gitignore", 32 | "package.json", 33 | "src", 34 | "node_modules", 35 | "example", 36 | "test" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /dist/react-select-plus.min.css: -------------------------------------------------------------------------------- 1 | .Select{position:relative}.Select input::-webkit-contacts-auto-fill-button,.Select input::-webkit-credentials-auto-fill-button{display:none!important}.Select input::-ms-clear{display:none!important}.Select input::-ms-reveal{display:none!important}.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-arrow-zone{cursor:default;pointer-events:none;opacity:.35}.Select.is-disabled>.Select-control{background-color:#f9f9f9}.Select.is-disabled>.Select-control:hover{box-shadow:none}.Select.is-open>.Select-control{border-bottom-right-radius:0;border-bottom-left-radius:0;background:#fff;border-color:#b3b3b3 #ccc #d9d9d9}.Select.is-open>.Select-control .Select-arrow{top:-2px;border-color:transparent transparent #999;border-width:0 5px 5px}.Select.is-searchable.is-open>.Select-control{cursor:text}.Select.is-searchable.is-focused:not(.is-open)>.Select-control{cursor:text}.Select.is-focused>.Select-control{background:#fff}.Select.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);background:#fff}.Select.has-value.is-clearable.Select--single>.Select-control .Select-value{padding-right:42px}.Select.has-value.Select--single>.Select-control .Select-value .Select-value-label,.Select.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value .Select-value-label{color:#333}.Select.has-value.Select--single>.Select-control .Select-value a.Select-value-label,.Select.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label{cursor:pointer;text-decoration:none}.Select.has-value.Select--single>.Select-control .Select-value a.Select-value-label:focus,.Select.has-value.Select--single>.Select-control .Select-value a.Select-value-label:hover,.Select.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label:focus,.Select.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label:hover{color:#007eff;outline:0;text-decoration:underline}.Select.has-value.Select--single>.Select-control .Select-value a.Select-value-label:focus,.Select.has-value.is-pseudo-focused.Select--single>.Select-control .Select-value a.Select-value-label:focus{background:#fff}.Select.has-value.is-pseudo-focused .Select-input{opacity:0}.Select .Select-arrow-zone:hover>.Select-arrow,.Select.is-open .Select-arrow{border-top-color:#666}.Select.Select--rtl{direction:rtl;text-align:right}.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:0;overflow:hidden;position:relative;width:100%}.Select-control:hover{box-shadow:0 1px 0 rgba(0,0,0,.06)}.Select-control .Select-input:focus{outline:0;background:#fff}.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}.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:0;line-height:17px;padding:8px 0 12px;-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:0}.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 .4s infinite linear;-o-animation:Select-animation-spin .4s infinite linear;animation:Select-animation-spin .4s 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 .2s;-o-animation:Select-animation-fadeIn .2s;animation:Select-animation-fadeIn .2s;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--rtl .Select-arrow-zone{padding-right:0;padding-left: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}.Select-control>:last-child{padding-right:5px}.Select--multi .Select-multi-value-wrapper{display:inline-block}.Select .Select-aria-only{position:absolute;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,.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-group-label{box-sizing:border-box;background-color:#fff;color:#666;font-weight:700;cursor:default;display:block;padding:8px 10px}.Select-option-group-label~.Select-option,.Select-option-group-label~.Select-option-group{padding-left:20px}.Select-option{box-sizing:border-box;background-color:#fff;color:#666;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;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{box-sizing:border-box;color:#999;cursor:default;display:block;padding:8px 10px}.Select--multi .Select-input{vertical-align:middle;margin-left:10px;padding:0}.Select--multi.Select--rtl .Select-input{margin-left:0;margin-right:10px}.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.Select--rtl .Select-value{margin-left:0;margin-right:5px}.Select--multi.Select--rtl .Select-value-icon{border-right:none;border-left:1px solid #c2e0ff;border-left:1px solid 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)}} -------------------------------------------------------------------------------- /examples/dist/.gitignore: -------------------------------------------------------------------------------- 1 | ## This file is here to ensure it is included in the gh-pages branch, 2 | ## when `gulp deploy` is used to push updates to the demo site. 3 | 4 | # Dependency directory 5 | node_modules 6 | -------------------------------------------------------------------------------- /examples/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React-Select-Plus Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 |
27 |
28 | Code and Docs on GitHub 29 | 30 | Star 31 | 32 |
33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 |
41 |
42 | 47 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /examples/dist/standalone.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React-Select Example 4 | 5 | 6 | 7 |
8 |

React Select

9 |

Standalone bulid

10 |
For usage without babel / browserify / webpack
11 |
12 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 48 | 49 | -------------------------------------------------------------------------------- /examples/src/.gitignore: -------------------------------------------------------------------------------- 1 | ## This file is here to ensure it is included in the gh-pages branch, 2 | ## when `gulp deploy` is used to push updates to the demo site. 3 | 4 | # Dependency directory 5 | node_modules 6 | -------------------------------------------------------------------------------- /examples/src/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HubSpot/react-select-plus/8ae7465fc9b6b9600a01e4e23de97f2d403fd139/examples/src/.npmignore -------------------------------------------------------------------------------- /examples/src/app.js: -------------------------------------------------------------------------------- 1 | /* eslint react/prop-types: 0 */ 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import Select from 'react-select-plus'; 6 | import './example.less'; 7 | 8 | import Creatable from './components/Creatable'; 9 | import Contributors from './components/Contributors'; 10 | import GithubUsers from './components/GithubUsers'; 11 | import CustomComponents from './components/CustomComponents'; 12 | import CustomRender from './components/CustomRender'; 13 | import GroupedOptionsField from './components/GroupedOptionsField'; 14 | import Multiselect from './components/Multiselect'; 15 | import NumericSelect from './components/NumericSelect'; 16 | import BooleanSelect from './components/BooleanSelect'; 17 | import Virtualized from './components/Virtualized'; 18 | import States from './components/States'; 19 | 20 | ReactDOM.render( 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 36 |
, 37 | document.getElementById('example') 38 | ); 39 | -------------------------------------------------------------------------------- /examples/src/components/BooleanSelect.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | var ValuesAsBooleansField = createClass({ 7 | displayName: 'ValuesAsBooleansField', 8 | propTypes: { 9 | label: PropTypes.string 10 | }, 11 | getInitialState () { 12 | return { 13 | options: [ 14 | { value: true, label: 'Yes' }, 15 | { value: false, label: 'No' } 16 | ], 17 | value: null 18 | }; 19 | }, 20 | onChange(value) { 21 | this.setState({ value }); 22 | console.log('Boolean Select value changed to', value); 23 | }, 24 | render () { 25 | return ( 26 |
27 |

{this.props.label} (Source)

28 | 110 |
111 | ); 112 | } 113 | }); 114 | 115 | 116 | module.exports = CitiesField; 117 | -------------------------------------------------------------------------------- /examples/src/components/Contributors.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | const CONTRIBUTORS = require('../data/contributors'); 7 | const MAX_CONTRIBUTORS = 6; 8 | const ASYNC_DELAY = 500; 9 | 10 | const Contributors = createClass({ 11 | displayName: 'Contributors', 12 | propTypes: { 13 | label: PropTypes.string, 14 | }, 15 | getInitialState () { 16 | return { 17 | multi: true, 18 | value: [CONTRIBUTORS[0]], 19 | }; 20 | }, 21 | onChange (value) { 22 | this.setState({ 23 | value: value, 24 | }); 25 | }, 26 | switchToMulti () { 27 | this.setState({ 28 | multi: true, 29 | value: [this.state.value], 30 | }); 31 | }, 32 | switchToSingle () { 33 | this.setState({ 34 | multi: false, 35 | value: this.state.value[0], 36 | }); 37 | }, 38 | getContributors (input, callback) { 39 | input = input.toLowerCase(); 40 | var options = CONTRIBUTORS.filter(i => { 41 | return i.github.substr(0, input.length) === input; 42 | }); 43 | var data = { 44 | options: options.slice(0, MAX_CONTRIBUTORS), 45 | complete: options.length <= MAX_CONTRIBUTORS, 46 | }; 47 | setTimeout(function() { 48 | callback(null, data); 49 | }, ASYNC_DELAY); 50 | }, 51 | gotoContributor (value, event) { 52 | window.open('https://github.com/' + value.github); 53 | }, 54 | render () { 55 | return ( 56 |
57 |

{this.props.label} (Source)

58 | 59 |
60 | 64 | 68 |
69 |
This example implements custom label and value properties, async options and opens the github profiles in a new window when values are clicked
70 |
71 | ); 72 | } 73 | }); 74 | 75 | module.exports = Contributors; 76 | -------------------------------------------------------------------------------- /examples/src/components/Creatable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | var CreatableDemo = createClass({ 7 | displayName: 'CreatableDemo', 8 | propTypes: { 9 | hint: PropTypes.string, 10 | label: PropTypes.string 11 | }, 12 | getInitialState () { 13 | return { 14 | multi: true, 15 | multiValue: [], 16 | options: [ 17 | { value: 'R', label: 'Red' }, 18 | { value: 'G', label: 'Green' }, 19 | { value: 'B', label: 'Blue' } 20 | ], 21 | value: undefined 22 | }; 23 | }, 24 | handleOnChange (value) { 25 | const { multi } = this.state; 26 | if (multi) { 27 | this.setState({ multiValue: value }); 28 | } else { 29 | this.setState({ value }); 30 | } 31 | }, 32 | render () { 33 | const { multi, multiValue, options, value } = this.state; 34 | return ( 35 |
36 |

{this.props.label} (Source)

37 | 43 |
{this.props.hint}
44 |
45 | 54 | 63 |
64 |
65 | ); 66 | } 67 | }); 68 | 69 | module.exports = CreatableDemo; 70 | -------------------------------------------------------------------------------- /examples/src/components/CustomComponents.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | import Gravatar from 'react-gravatar'; 6 | 7 | const USERS = require('../data/users'); 8 | const GRAVATAR_SIZE = 15; 9 | 10 | const stringOrNode = PropTypes.oneOfType([ 11 | PropTypes.string, 12 | PropTypes.node, 13 | ]); 14 | 15 | const GravatarOption = createClass({ 16 | propTypes: { 17 | children: PropTypes.node, 18 | className: PropTypes.string, 19 | isDisabled: PropTypes.bool, 20 | isFocused: PropTypes.bool, 21 | isSelected: PropTypes.bool, 22 | onFocus: PropTypes.func, 23 | onSelect: PropTypes.func, 24 | option: PropTypes.object.isRequired, 25 | }, 26 | handleMouseDown (event) { 27 | event.preventDefault(); 28 | event.stopPropagation(); 29 | this.props.onSelect(this.props.option, event); 30 | }, 31 | handleMouseEnter (event) { 32 | this.props.onFocus(this.props.option, event); 33 | }, 34 | handleMouseMove (event) { 35 | if (this.props.isFocused) return; 36 | this.props.onFocus(this.props.option, event); 37 | }, 38 | render () { 39 | let gravatarStyle = { 40 | borderRadius: 3, 41 | display: 'inline-block', 42 | marginRight: 10, 43 | position: 'relative', 44 | top: -2, 45 | verticalAlign: 'middle', 46 | }; 47 | return ( 48 |
53 | 54 | {this.props.children} 55 |
56 | ); 57 | } 58 | }); 59 | 60 | const GravatarValue = createClass({ 61 | propTypes: { 62 | children: PropTypes.node, 63 | placeholder: stringOrNode, 64 | value: PropTypes.object 65 | }, 66 | render () { 67 | var gravatarStyle = { 68 | borderRadius: 3, 69 | display: 'inline-block', 70 | marginRight: 10, 71 | position: 'relative', 72 | top: -2, 73 | verticalAlign: 'middle', 74 | }; 75 | return ( 76 |
77 | 78 | 79 | {this.props.children} 80 | 81 |
82 | ); 83 | } 84 | }); 85 | 86 | const UsersField = createClass({ 87 | propTypes: { 88 | hint: PropTypes.string, 89 | label: PropTypes.string, 90 | }, 91 | getInitialState () { 92 | return {}; 93 | }, 94 | setValue (value) { 95 | this.setState({ value }); 96 | }, 97 | render () { 98 | var placeholder = ☺ Select User; 99 | 100 | return ( 101 |
102 |

{this.props.label} (Source)

103 | this._inputValue = inputValue} 46 | options={options} 47 | optionRenderer={this.renderOption} 48 | onChange={this.setValue} 49 | value={this.state.value} 50 | valueRenderer={this.renderValue} 51 | /> 52 |
This demonstrates custom render methods and links in disabled options
53 |
54 | ); 55 | } 56 | }); 57 | module.exports = DisabledUpsellOptions; 58 | -------------------------------------------------------------------------------- /examples/src/components/GithubUsers.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | import fetch from 'isomorphic-fetch'; 6 | 7 | 8 | const GithubUsers = createClass({ 9 | displayName: 'GithubUsers', 10 | propTypes: { 11 | label: PropTypes.string, 12 | }, 13 | getInitialState () { 14 | return { 15 | backspaceRemoves: true, 16 | multi: true, 17 | creatable: false, 18 | }; 19 | }, 20 | onChange (value) { 21 | this.setState({ 22 | value: value, 23 | }); 24 | }, 25 | switchToMulti () { 26 | this.setState({ 27 | multi: true, 28 | value: [this.state.value], 29 | }); 30 | }, 31 | switchToSingle () { 32 | this.setState({ 33 | multi: false, 34 | value: this.state.value ? this.state.value[0] : null 35 | }); 36 | }, 37 | getUsers (input) { 38 | if (!input) { 39 | return Promise.resolve({ options: [] }); 40 | } 41 | 42 | return fetch(`https://api.github.com/search/users?q=${input}`) 43 | .then((response) => response.json()) 44 | .then((json) => { 45 | return { options: json.items }; 46 | }); 47 | }, 48 | gotoUser (value, event) { 49 | window.open(value.html_url); 50 | }, 51 | toggleBackspaceRemoves () { 52 | this.setState({ 53 | backspaceRemoves: !this.state.backspaceRemoves 54 | }); 55 | }, 56 | toggleCreatable () { 57 | this.setState({ 58 | creatable: !this.state.creatable 59 | }); 60 | }, 61 | render () { 62 | const AsyncComponent = this.state.creatable 63 | ? Select.AsyncCreatable 64 | : Select.Async; 65 | 66 | return ( 67 |
68 |

{this.props.label} (Source)

69 | 70 |
71 | 75 | 79 |
80 |
81 | 85 | 89 |
90 |
This example uses fetch.js for showing Async options with Promises
91 |
92 | ); 93 | } 94 | }); 95 | 96 | module.exports = GithubUsers; 97 | -------------------------------------------------------------------------------- /examples/src/components/GroupedOptionsField.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | var ops = [{ 7 | label: 'Black', 8 | value: 'black', 9 | }, { 10 | label: 'Primary Colors', 11 | options: [{ 12 | label: 'Yellow', 13 | value: 'yellow' 14 | }, { 15 | label: 'Red', 16 | value: 'red' 17 | }, { 18 | label: 'Blue', 19 | value: 'blue' 20 | }] 21 | }, { 22 | label: 'Secondary Colors', 23 | options: [{ 24 | label: 'Orange', 25 | value: 'orange' 26 | }, { 27 | label: 'Purple', 28 | options: [{ 29 | label: 'Light Purple', 30 | value: 'light_purple' 31 | }, { 32 | label: 'Medium Purple', 33 | value: 'medium_purple' 34 | }, { 35 | label: 'Dark Purple', 36 | value: 'dark_purple' 37 | }] 38 | }, { 39 | label: 'Green', 40 | value: 'green' 41 | }] 42 | }, { 43 | label: 'White', 44 | value: 'white', 45 | }]; 46 | 47 | var GroupedOptionsField = createClass({ 48 | displayName: 'GroupedOptionsField', 49 | propTypes: { 50 | delimiter: PropTypes.string, 51 | label: PropTypes.string, 52 | multi: PropTypes.bool, 53 | }, 54 | 55 | getInitialState () { 56 | return { 57 | value: null, 58 | }; 59 | }, 60 | 61 | onChange(value) { 62 | this.setState({ value }); 63 | console.log('Option Groups Select value changed to', value); 64 | }, 65 | 66 | render () { 67 | return ( 68 |
69 |

{this.props.label}

70 | 66 | 67 |
68 | 72 | 76 | 80 | 84 | 88 |
89 |
90 | ); 91 | } 92 | }); 93 | 94 | module.exports = MultiSelectField; 95 | -------------------------------------------------------------------------------- /examples/src/components/NumericSelect.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | var ValuesAsNumbersField = createClass({ 7 | displayName: 'ValuesAsNumbersField', 8 | propTypes: { 9 | label: PropTypes.string 10 | }, 11 | getInitialState () { 12 | return { 13 | options: [ 14 | { value: 10, label: 'Ten' }, 15 | { value: 11, label: 'Eleven' }, 16 | { value: 12, label: 'Twelve' }, 17 | { value: 23, label: 'Twenty-three' }, 18 | { value: 24, label: 'Twenty-four' } 19 | ], 20 | matchPos: 'any', 21 | matchValue: true, 22 | matchLabel: true, 23 | value: null, 24 | multi: false 25 | }; 26 | }, 27 | onChangeMatchStart(event) { 28 | this.setState({ 29 | matchPos: event.target.checked ? 'start' : 'any' 30 | }); 31 | }, 32 | onChangeMatchValue(event) { 33 | this.setState({ 34 | matchValue: event.target.checked 35 | }); 36 | }, 37 | onChangeMatchLabel(event) { 38 | this.setState({ 39 | matchLabel: event.target.checked 40 | }); 41 | }, 42 | onChange(value) { 43 | this.setState({ value }); 44 | console.log('Numeric Select value changed to', value); 45 | }, 46 | onChangeMulti(event) { 47 | this.setState({ 48 | multi: event.target.checked 49 | }); 50 | }, 51 | render () { 52 | var matchProp = 'any'; 53 | if (this.state.matchLabel && !this.state.matchValue) { 54 | matchProp = 'label'; 55 | } 56 | if (!this.state.matchLabel && this.state.matchValue) { 57 | matchProp = 'value'; 58 | } 59 | return ( 60 |
61 |

{this.props.label} (Source)

62 | 74 | Multi-Select 75 | 76 | 80 | 84 | 88 |
89 |
This example uses simple numeric values
90 | 91 | ); 92 | } 93 | }); 94 | 95 | module.exports = ValuesAsNumbersField; 96 | -------------------------------------------------------------------------------- /examples/src/components/States.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import PropTypes from 'prop-types'; 4 | import Select from 'react-select-plus'; 5 | 6 | const STATES = require('../data/states'); 7 | 8 | var StatesField = createClass({ 9 | displayName: 'StatesField', 10 | propTypes: { 11 | label: PropTypes.string, 12 | searchable: PropTypes.bool, 13 | }, 14 | getDefaultProps () { 15 | return { 16 | label: 'States:', 17 | searchable: true, 18 | }; 19 | }, 20 | getInitialState () { 21 | return { 22 | country: 'AU', 23 | disabled: false, 24 | searchable: this.props.searchable, 25 | selectValue: 'new-south-wales', 26 | clearable: true, 27 | rtl: false, 28 | }; 29 | }, 30 | clearValue (e) { 31 | this.select.setInputValue(''); 32 | }, 33 | switchCountry (e) { 34 | var newCountry = e.target.value; 35 | this.setState({ 36 | country: newCountry, 37 | selectValue: null, 38 | }); 39 | }, 40 | updateValue (newValue) { 41 | this.setState({ 42 | selectValue: newValue, 43 | }); 44 | }, 45 | focusStateSelect () { 46 | this.refs.stateSelect.focus(); 47 | }, 48 | toggleCheckbox (e) { 49 | let newState = {}; 50 | newState[e.target.name] = e.target.checked; 51 | this.setState(newState); 52 | }, 53 | render () { 54 | var options = STATES[this.state.country]; 55 | return ( 56 |
57 |

{this.props.label} (Source)

58 | 82 | Searchable 83 | 84 | 88 | 92 | 96 |
97 |
98 | 102 | 106 |
107 | 108 | ); 109 | } 110 | }); 111 | 112 | 113 | module.exports = StatesField; 114 | -------------------------------------------------------------------------------- /examples/src/components/Virtualized.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import createClass from 'create-react-class'; 3 | import VirtualizedSelect from 'react-virtualized-select'; 4 | 5 | const DATA = require('../data/cities'); 6 | 7 | var CitiesField = createClass({ 8 | displayName: 'CitiesField', 9 | getInitialState () { 10 | return {}; 11 | }, 12 | updateValue (newValue) { 13 | this.setState({ 14 | selectValue: newValue 15 | }); 16 | }, 17 | render () { 18 | var options = DATA.CITIES; 19 | return ( 20 |
21 |

Cities (Large Dataset) (Source)

22 | 33 |
34 | Uses react-virtualized and react-virtualized-select to display a list of the world's 1,000 largest cities. 35 |
36 |
37 | ); 38 | } 39 | }); 40 | 41 | 42 | module.exports = CitiesField; 43 | -------------------------------------------------------------------------------- /examples/src/data/contributors.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { github: 'jedwatson', name: 'Jed Watson' }, 3 | { github: 'bruderstein', name: 'Dave Brotherstone' }, 4 | { github: 'jossmac', name: 'Joss Mackison' }, 5 | { github: 'jniechcial', name: 'Jakub Niechciał' }, 6 | { github: 'craigdallimore', name: 'Craig Dallimore' }, 7 | { github: 'julen', name: 'Julen Ruiz Aizpuru' }, 8 | { github: 'dcousens', name: 'Daniel Cousens' }, 9 | { github: 'jgautsch', name: 'Jon Gautsch' }, 10 | { github: 'dmitry-smirnov', name: 'Dmitry Smirnov' }, 11 | { github: 'trevorburnham', name: 'Trevor Burnham' }, 12 | ]; 13 | -------------------------------------------------------------------------------- /examples/src/data/states.js: -------------------------------------------------------------------------------- 1 | exports.AU = [ 2 | { value: 'australian-capital-territory', label: 'Australian Capital Territory', className: 'State-ACT' }, 3 | { value: 'new-south-wales', label: 'New South Wales', className: 'State-NSW' }, 4 | { value: 'victoria', label: 'Victoria', className: 'State-Vic' }, 5 | { value: 'queensland', label: 'Queensland', className: 'State-Qld' }, 6 | { value: 'western-australia', label: 'Western Australia', className: 'State-WA' }, 7 | { value: 'south-australia', label: 'South Australia', className: 'State-SA' }, 8 | { value: 'tasmania', label: 'Tasmania', className: 'State-Tas' }, 9 | { value: 'northern-territory', label: 'Northern Territory', className: 'State-NT' }, 10 | ]; 11 | 12 | exports.US = [ 13 | { value: 'AL', label: 'Alabama', disabled: true }, 14 | { value: 'AK', label: 'Alaska' }, 15 | { value: 'AS', label: 'American Samoa' }, 16 | { value: 'AZ', label: 'Arizona' }, 17 | { value: 'AR', label: 'Arkansas' }, 18 | { value: 'CA', label: 'California' }, 19 | { value: 'CO', label: 'Colorado' }, 20 | { value: 'CT', label: 'Connecticut' }, 21 | { value: 'DE', label: 'Delaware' }, 22 | { value: 'DC', label: 'District Of Columbia' }, 23 | { value: 'FM', label: 'Federated States Of Micronesia' }, 24 | { value: 'FL', label: 'Florida' }, 25 | { value: 'GA', label: 'Georgia' }, 26 | { value: 'GU', label: 'Guam' }, 27 | { value: 'HI', label: 'Hawaii' }, 28 | { value: 'ID', label: 'Idaho' }, 29 | { value: 'IL', label: 'Illinois' }, 30 | { value: 'IN', label: 'Indiana' }, 31 | { value: 'IA', label: 'Iowa' }, 32 | { value: 'KS', label: 'Kansas' }, 33 | { value: 'KY', label: 'Kentucky' }, 34 | { value: 'LA', label: 'Louisiana' }, 35 | { value: 'ME', label: 'Maine' }, 36 | { value: 'MH', label: 'Marshall Islands' }, 37 | { value: 'MD', label: 'Maryland' }, 38 | { value: 'MA', label: 'Massachusetts' }, 39 | { value: 'MI', label: 'Michigan' }, 40 | { value: 'MN', label: 'Minnesota' }, 41 | { value: 'MS', label: 'Mississippi' }, 42 | { value: 'MO', label: 'Missouri' }, 43 | { value: 'MT', label: 'Montana' }, 44 | { value: 'NE', label: 'Nebraska' }, 45 | { value: 'NV', label: 'Nevada' }, 46 | { value: 'NH', label: 'New Hampshire' }, 47 | { value: 'NJ', label: 'New Jersey' }, 48 | { value: 'NM', label: 'New Mexico' }, 49 | { value: 'NY', label: 'New York' }, 50 | { value: 'NC', label: 'North Carolina' }, 51 | { value: 'ND', label: 'North Dakota' }, 52 | { value: 'MP', label: 'Northern Mariana Islands' }, 53 | { value: 'OH', label: 'Ohio' }, 54 | { value: 'OK', label: 'Oklahoma' }, 55 | { value: 'OR', label: 'Oregon' }, 56 | { value: 'PW', label: 'Palau' }, 57 | { value: 'PA', label: 'Pennsylvania' }, 58 | { value: 'PR', label: 'Puerto Rico' }, 59 | { value: 'RI', label: 'Rhode Island' }, 60 | { value: 'SC', label: 'South Carolina' }, 61 | { value: 'SD', label: 'South Dakota' }, 62 | { value: 'TN', label: 'Tennessee' }, 63 | { value: 'TX', label: 'Texas' }, 64 | { value: 'UT', label: 'Utah' }, 65 | { value: 'VT', label: 'Vermont' }, 66 | { value: 'VI', label: 'Virgin Islands' }, 67 | { value: 'VA', label: 'Virginia' }, 68 | { value: 'WA', label: 'Washington' }, 69 | { value: 'WV', label: 'West Virginia' }, 70 | { value: 'WI', label: 'Wisconsin' }, 71 | { value: 'WY', label: 'Wyoming' }, 72 | ]; 73 | -------------------------------------------------------------------------------- /examples/src/data/users.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { value: 'John Smith', label: 'John Smith', email: 'john@smith.com' }, 3 | { value: 'Merry Jane', label: 'Merry Jane', email: 'merry@jane.com' }, 4 | { value: 'Stan Hoper', label: 'Stan Hoper', email: 'stan@hoper.com' } 5 | ]; 6 | -------------------------------------------------------------------------------- /examples/src/example.less: -------------------------------------------------------------------------------- 1 | // 2 | // Common Example Styles 3 | // ------------------------------ 4 | 5 | 6 | 7 | 8 | // import select field styles 9 | 10 | @import "../../less/select.less"; 11 | 12 | 13 | 14 | 15 | // Constants 16 | // ------------------------------ 17 | 18 | // example site 19 | 20 | @heading-color: black; 21 | @text-color: #333; 22 | @link-color: #007eff; 23 | @gutter: 30px; 24 | 25 | 26 | 27 | 28 | // Base 29 | // ------------------------------ 30 | 31 | body { 32 | color: @text-color; 33 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif; 34 | font-size: 14px; 35 | line-height: 1.4; 36 | margin: 0; 37 | padding: 0; 38 | } 39 | 40 | a { 41 | color: @link-color; 42 | text-decoration: none; 43 | 44 | &:hover { 45 | text-decoration: underline; 46 | } 47 | } 48 | 49 | .container { 50 | margin-left: auto; 51 | margin-right: auto; 52 | max-width: 400px; 53 | padding: 0 @gutter; 54 | } 55 | 56 | 57 | 58 | 59 | // Headings 60 | // ------------------------------ 61 | 62 | h1, h2, h3, h4, h5, h6, 63 | .h1, .h2, .h3, .h4, .h5, .h6 { 64 | color: @heading-color; 65 | font-weight: 500; 66 | line-height: 1; 67 | margin-bottom: .66em; 68 | margin-top: 0; 69 | } 70 | 71 | h1, .h1 { 72 | font-size: 2.4em; 73 | } 74 | h2, .h2 { 75 | font-size: 2em; 76 | font-weight: 300; 77 | } 78 | h3, .h3 { 79 | font-size: 1.25em; 80 | // text-transform: uppercase; 81 | } 82 | h4, .h4 { 83 | font-size: 1em; 84 | } 85 | h5, .h5 { 86 | font-size: .85em; 87 | } 88 | h6, .h6 { 89 | font-size: .75em; 90 | } 91 | 92 | 93 | 94 | 95 | // Layout 96 | // ------------------------------ 97 | 98 | // common 99 | 100 | .page-body, 101 | .page-footer, 102 | .page-header { 103 | padding: @gutter 0; 104 | } 105 | 106 | // header 107 | 108 | .page-header { 109 | background-color: @link-color; 110 | color: mix(white, @link-color, 75%); 111 | 112 | h1, h2, h3 { 113 | color: white; 114 | } 115 | p { 116 | font-size: 1.2em; 117 | margin: 0; 118 | } 119 | a { 120 | border-bottom: 1px solid fade(white, 30%); 121 | color: white; 122 | text-decoration: none; 123 | 124 | &:hover, 125 | &:focus { 126 | border-bottom-color: white; 127 | outline: none; 128 | text-decoration: none; 129 | } 130 | } 131 | } 132 | 133 | // subheader 134 | 135 | .page-subheader { 136 | background-color: mix(@link-color, white, 10%); 137 | line-height: 20px; 138 | padding: @gutter 0; 139 | } 140 | .page-subheader__button { 141 | float: right; 142 | } 143 | .page-subheader__link { 144 | border-bottom: 1px solid fade(@link-color, 30%); 145 | outline: none; 146 | text-decoration: none; 147 | 148 | &:hover, 149 | &:focus { 150 | border-bottom-color: @link-color; 151 | outline: none; 152 | text-decoration: none; 153 | } 154 | } 155 | 156 | // footer 157 | 158 | .page-footer { 159 | background-color: #fafafa; 160 | // border-top: 1px solid #eee; 161 | color: #999; 162 | padding: @gutter 0; 163 | text-align: center; 164 | 165 | a { 166 | color: black; 167 | } 168 | } 169 | 170 | // layout changes based on screen dimensions 171 | 172 | @media (min-width: 480px) { 173 | .page-body, 174 | .page-header { 175 | padding: (@gutter * 2) 0; 176 | } 177 | .page-header { 178 | font-size: 1.4em; 179 | } 180 | .page-subheader { 181 | font-size: 1.125em; 182 | line-height: 28px; 183 | } 184 | } 185 | 186 | 187 | 188 | 189 | // Form Styles 190 | // ------------------------------ 191 | 192 | .checkbox-list { 193 | margin-top: .5em; 194 | overflow: hidden; 195 | } 196 | .checkbox-list > .checkbox { 197 | clear: left; 198 | float: left; 199 | margin-top: .5em; 200 | } 201 | .checkbox-control { 202 | margin-right: .5em; 203 | position: relative; 204 | top: -1px; 205 | } 206 | .checkbox-label {} 207 | 208 | 209 | 210 | 211 | // Switcher 212 | // ------------------------------ 213 | 214 | .switcher { 215 | color: #999; 216 | cursor: default; 217 | font-size: 12px; 218 | margin: 10px 0; 219 | text-transform: uppercase; 220 | 221 | .link { 222 | color: @link-color; 223 | cursor: pointer; 224 | font-weight: bold; 225 | margin-left: 10px; 226 | 227 | &:hover { 228 | text-decoration: underline; 229 | } 230 | } 231 | .active { 232 | color: #666; 233 | font-weight: bold; 234 | margin-left: 10px; 235 | } 236 | } 237 | 238 | 239 | 240 | 241 | // Miscellaneous 242 | // ------------------------------ 243 | 244 | .section { 245 | margin-bottom: 40px; 246 | } 247 | 248 | .hint { 249 | font-size: .85em; 250 | margin: 15px 0; 251 | color: #666; 252 | } 253 | 254 | .virtual-scroll { 255 | z-index: 1; 256 | } 257 | -------------------------------------------------------------------------------- /examples/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HubSpot/react-select-plus/8ae7465fc9b6b9600a01e4e23de97f2d403fd139/examples/src/favicon.ico -------------------------------------------------------------------------------- /examples/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React-Select-Plus Example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 |
27 |
28 | Code and Docs on GitHub 29 | 30 | Star 31 | 32 |
33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 |
41 |
42 | 47 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/src/standalone.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | react-select umd example 4 | 5 | 6 | 7 |
8 |

React Select

9 |

Standalone (UMD) Bulid

10 |
For usage without browserify / rollup / webpack
11 |
12 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 44 | 45 | -------------------------------------------------------------------------------- /less/control.less: -------------------------------------------------------------------------------- 1 | // 2 | // Control 3 | // ------------------------------ 4 | 5 | // Mixins 6 | 7 | // focused styles 8 | .Select-focus-state(@color) { 9 | border-color: @color; 10 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px fade(@color, 10%); 11 | background: @select-input-bg-focus; 12 | } 13 | // "classic" focused styles: maintain for legacy 14 | .Select-focus-state-classic() { 15 | border-color: @select-input-border-focus lighten(@select-input-border-focus, 5%) lighten(@select-input-border-focus, 5%); 16 | box-shadow: @select-input-box-shadow-focus; 17 | background: @select-input-bg-focus; 18 | } 19 | 20 | // base 21 | 22 | .Select { 23 | position: relative; 24 | 25 | // disable some browser-specific behaviours that break the input 26 | input::-webkit-contacts-auto-fill-button, 27 | input::-webkit-credentials-auto-fill-button { 28 | display: none !important; 29 | } 30 | input::-ms-clear { 31 | display: none !important; 32 | } 33 | input::-ms-reveal { 34 | display: none !important; 35 | } 36 | 37 | // preferred box model 38 | &, 39 | & div, 40 | & input, 41 | & span { 42 | .box-sizing(border-box); 43 | } 44 | 45 | // handle disabled state 46 | &.is-disabled { 47 | .Select-arrow-zone { 48 | cursor: default; 49 | pointer-events: none; 50 | opacity: 0.35; 51 | } 52 | 53 | > .Select-control { 54 | background-color: @select-input-bg-disabled; 55 | &:hover { 56 | box-shadow: none; 57 | } 58 | } 59 | } 60 | 61 | &.is-open > .Select-control { 62 | .border-bottom-radius( 0 ); 63 | background: @select-input-bg; 64 | border-color: darken(@select-input-border-color, 10%) @select-input-border-color lighten(@select-input-border-color, 5%); 65 | 66 | // flip the arrow so its pointing up when the menu is open 67 | .Select-arrow { 68 | top: -2px; 69 | border-color: transparent transparent @select-arrow-color; 70 | border-width: 0 @select-arrow-width @select-arrow-width; 71 | } 72 | } 73 | 74 | &.is-searchable { 75 | &.is-open > .Select-control { 76 | cursor: text; 77 | } 78 | 79 | &.is-focused:not(.is-open) > .Select-control { 80 | cursor: text; 81 | } 82 | } 83 | 84 | &.is-focused > .Select-control { 85 | background: @select-input-bg-focus; 86 | } 87 | 88 | &.is-focused:not(.is-open) > .Select-control { 89 | .Select-focus-state(@select-input-border-focus); 90 | } 91 | 92 | &.has-value.is-clearable.Select--single > .Select-control .Select-value { 93 | padding-right: (@select-clear-width + @select-arrow-width * 5); 94 | } 95 | 96 | &.has-value.Select--single > .Select-control .Select-value, 97 | &.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value { 98 | .Select-value-label { 99 | color: @select-text-color; 100 | } 101 | a.Select-value-label { 102 | cursor: pointer; 103 | text-decoration: none; 104 | 105 | &:hover, 106 | &:focus { 107 | color: @select-link-hover-color; 108 | outline: none; 109 | text-decoration: underline; 110 | } 111 | 112 | &:focus { 113 | background: @select-input-bg-focus; 114 | } 115 | } 116 | } 117 | 118 | // fake-hide the input when the control is pseudo-focused 119 | &.has-value.is-pseudo-focused .Select-input { 120 | opacity: 0; 121 | } 122 | 123 | &.is-open .Select-arrow, 124 | .Select-arrow-zone:hover > .Select-arrow { 125 | border-top-color: @select-arrow-color-hover; 126 | } 127 | &.Select--rtl { 128 | direction: rtl; 129 | text-align: right; 130 | } 131 | } 132 | 133 | // base 134 | 135 | .Select-control { 136 | background-color: @select-input-bg; 137 | border-color: lighten(@select-input-border-color, 5%) @select-input-border-color darken(@select-input-border-color, 10%); 138 | border-radius: @select-input-border-radius; 139 | border: @select-input-border-width solid @select-input-border-color; 140 | color: @select-text-color; 141 | cursor: default; 142 | display: table; 143 | border-spacing: 0; 144 | border-collapse: separate; 145 | height: @select-input-height; 146 | outline: none; 147 | overflow: hidden; 148 | position: relative; 149 | width: 100%; 150 | 151 | &:hover { 152 | box-shadow: @select-input-hover-box-shadow; 153 | } 154 | 155 | .Select-input:focus { 156 | outline: none; 157 | background: @select-input-bg-focus; 158 | } 159 | } 160 | 161 | // placeholder 162 | .Select-placeholder, 163 | .Select--single > .Select-control .Select-value { 164 | bottom: 0; 165 | color: @select-input-placeholder; 166 | left: 0; 167 | line-height: @select-input-internal-height; 168 | padding-left: @select-padding-horizontal; 169 | padding-right: @select-padding-horizontal; 170 | position: absolute; 171 | right: 0; 172 | top: 0; 173 | 174 | // crop text 175 | max-width: 100%; 176 | overflow: hidden; 177 | text-overflow: ellipsis; 178 | white-space: nowrap; 179 | } 180 | 181 | // the element users type in 182 | 183 | .Select-input { 184 | // inherits `display: inline-block` from "react-input-autosize" 185 | height: @select-input-internal-height; 186 | padding-left: @select-padding-horizontal; 187 | padding-right: @select-padding-horizontal; 188 | vertical-align: middle; 189 | 190 | > input { 191 | width: 100%; 192 | background: none transparent; 193 | border: 0 none; 194 | box-shadow: none; 195 | cursor: default; 196 | display: inline-block; 197 | font-family: inherit; 198 | font-size: inherit; 199 | // height: @select-input-internal-height; 200 | margin: 0; 201 | outline: none; 202 | // padding: 0; 203 | line-height: 17px; /* For IE 8 compatibility */ 204 | padding: ((@select-input-internal-height - 14) / 2 - 2) 0 ((@select-input-internal-height - 14) / 2 + 2); /* For IE 8 compatibility */ 205 | -webkit-appearance: none; 206 | 207 | .is-focused & { 208 | cursor: text; 209 | } 210 | } 211 | 212 | } 213 | 214 | // fake-hide the input when the control is pseudo-focused 215 | .has-value.is-pseudo-focused .Select-input { 216 | opacity: 0; 217 | } 218 | 219 | // fake input 220 | .Select-control:not(.is-searchable) > .Select-input { 221 | outline: none; 222 | } 223 | 224 | // loading indicator 225 | .Select-loading-zone { 226 | cursor: pointer; 227 | display: table-cell; 228 | position: relative; 229 | text-align: center; 230 | vertical-align: middle; 231 | width: @select-loading-size; 232 | } 233 | .Select-loading { 234 | .Select-spinner(@select-loading-size, @select-loading-color-bg, @select-loading-color); 235 | vertical-align: middle; 236 | } 237 | 238 | 239 | // the little cross that clears the field 240 | 241 | .Select-clear-zone { 242 | .animation( Select-animation-fadeIn 200ms ); 243 | color: @select-clear-color; 244 | cursor: pointer; 245 | display: table-cell; 246 | position: relative; 247 | text-align: center; 248 | vertical-align: middle; 249 | width: @select-clear-width; 250 | 251 | &:hover { 252 | color: @select-clear-hover-color; 253 | } 254 | } 255 | .Select-clear { 256 | display: inline-block; 257 | font-size: @select-clear-size; 258 | line-height: 1; 259 | } 260 | .Select--multi .Select-clear-zone { 261 | width: @select-clear-width; 262 | } 263 | 264 | 265 | // arrow indicator 266 | 267 | .Select-arrow-zone { 268 | cursor: pointer; 269 | display: table-cell; 270 | position: relative; 271 | text-align: center; 272 | vertical-align: middle; 273 | width: (@select-arrow-width * 5); 274 | padding-right: @select-arrow-width; 275 | 276 | .Select--rtl & { 277 | padding-right: 0; 278 | padding-left: @select-arrow-width; 279 | } 280 | } 281 | 282 | .Select-arrow { 283 | border-color: @select-arrow-color transparent transparent; 284 | border-style: solid; 285 | border-width: @select-arrow-width @select-arrow-width (@select-arrow-width / 2); 286 | display: inline-block; 287 | height: 0; 288 | width: 0; 289 | position: relative; 290 | } 291 | 292 | .Select-control > *:last-child { 293 | padding-right: @select-right-padding; 294 | } 295 | 296 | .Select--multi .Select-multi-value-wrapper { 297 | display: inline-block; 298 | } 299 | .Select .Select-aria-only { 300 | position: absolute; 301 | display: inline-block; 302 | height: 1px; 303 | width: 1px; 304 | margin: -1px; 305 | clip: rect(0,0,0,0); 306 | overflow: hidden; 307 | float: left; 308 | } 309 | 310 | // Animation 311 | // ------------------------------ 312 | 313 | // fade in 314 | 315 | @-webkit-keyframes Select-animation-fadeIn { 316 | from { opacity: 0; } 317 | to { opacity: 1; } 318 | } 319 | @keyframes Select-animation-fadeIn { 320 | from { opacity: 0; } 321 | to { opacity: 1; } 322 | } 323 | -------------------------------------------------------------------------------- /less/default.less: -------------------------------------------------------------------------------- 1 | @import "select.less"; 2 | -------------------------------------------------------------------------------- /less/menu.less: -------------------------------------------------------------------------------- 1 | // 2 | // Select Menu 3 | // ------------------------------ 4 | 5 | 6 | // wrapper around the menu 7 | 8 | .Select-menu-outer { 9 | // Unfortunately, having both border-radius and allows scrolling using overflow defined on the same 10 | // element forces the browser to repaint on scroll. However, if these definitions are split into an 11 | // outer and an inner element, the browser is able to optimize the scrolling behavior and does not 12 | // have to repaint on scroll. 13 | .border-bottom-radius( @select-input-border-radius ); 14 | background-color: @select-input-bg; 15 | border: 1px solid @select-input-border-color; 16 | border-top-color: mix(@select-input-bg, @select-input-border-color, 50%); 17 | box-shadow: @select-menu-box-shadow; 18 | box-sizing: border-box; 19 | margin-top: -1px; 20 | max-height: @select-menu-max-height; 21 | position: absolute; 22 | top: 100%; 23 | width: 100%; 24 | z-index: @select-menu-zindex; 25 | -webkit-overflow-scrolling: touch; 26 | } 27 | 28 | 29 | // wrapper 30 | 31 | .Select-menu { 32 | max-height: (@select-menu-max-height - 2px); 33 | overflow-y: auto; 34 | } 35 | 36 | 37 | // option groups 38 | 39 | .Select-option-group-label { 40 | box-sizing: border-box; 41 | background-color: @select-option-bg; 42 | color: @select-option-color; 43 | font-weight: bold; 44 | cursor: default; 45 | display: block; 46 | padding: @select-padding-vertical @select-padding-horizontal; 47 | } 48 | 49 | .Select-option-group-label ~ .Select-option, 50 | .Select-option-group-label ~ .Select-option-group { 51 | padding-left: @select-padding-horizontal * 2; 52 | } 53 | 54 | 55 | // options 56 | 57 | .Select-option { 58 | box-sizing: border-box; 59 | background-color: @select-option-bg; 60 | color: @select-option-color; 61 | cursor: pointer; 62 | display: block; 63 | padding: @select-padding-vertical @select-padding-horizontal; 64 | 65 | &:last-child { 66 | .border-bottom-radius( @select-input-border-radius ); 67 | } 68 | 69 | &.is-selected { 70 | background-color: @select-option-selected-bg-fb; /* Fallback color for IE 8 */ 71 | background-color: @select-option-selected-bg; 72 | color: @select-option-selected-color; 73 | } 74 | 75 | &.is-focused { 76 | background-color: @select-option-focused-bg-fb; /* Fallback color for IE 8 */ 77 | background-color: @select-option-focused-bg; 78 | color: @select-option-focused-color; 79 | } 80 | 81 | &.is-disabled { 82 | color: @select-option-disabled-color; 83 | cursor: default; 84 | } 85 | 86 | } 87 | 88 | 89 | // no results 90 | 91 | .Select-noresults { 92 | box-sizing: border-box; 93 | color: @select-noresults-color; 94 | cursor: default; 95 | display: block; 96 | padding: @select-padding-vertical @select-padding-horizontal; 97 | } 98 | -------------------------------------------------------------------------------- /less/mixins.less: -------------------------------------------------------------------------------- 1 | // 2 | // Mixins 3 | // ------------------------------ 4 | 5 | 6 | // Utilities 7 | 8 | .size(@width; @height) { 9 | width: @width; 10 | height: @height; 11 | } 12 | .square(@size) { 13 | .size(@size; @size); 14 | } 15 | .border-top-radius(@radius) { 16 | border-top-right-radius: @radius; 17 | border-top-left-radius: @radius; 18 | } 19 | .border-right-radius(@radius) { 20 | border-bottom-right-radius: @radius; 21 | border-top-right-radius: @radius; 22 | } 23 | .border-bottom-radius(@radius) { 24 | border-bottom-right-radius: @radius; 25 | border-bottom-left-radius: @radius; 26 | } 27 | .border-left-radius(@radius) { 28 | border-bottom-left-radius: @radius; 29 | border-top-left-radius: @radius; 30 | } 31 | 32 | 33 | // Vendor Prefixes 34 | 35 | .animation(@animation) { 36 | -webkit-animation: @animation; 37 | -o-animation: @animation; 38 | animation: @animation; 39 | } 40 | .box-sizing(@boxmodel) { 41 | -webkit-box-sizing: @boxmodel; 42 | -moz-box-sizing: @boxmodel; 43 | box-sizing: @boxmodel; 44 | } 45 | .rotate(@degrees) { 46 | -webkit-transform: rotate(@degrees); 47 | -ms-transform: rotate(@degrees); // IE9 only 48 | -o-transform: rotate(@degrees); 49 | transform: rotate(@degrees); 50 | } 51 | .transform(@transform) { 52 | -webkit-transform: @transform; 53 | -moz-transform: @transform; 54 | -ms-transform: @transform; 55 | transform: @transform; 56 | } 57 | -------------------------------------------------------------------------------- /less/multi.less: -------------------------------------------------------------------------------- 1 | // 2 | // Multi-Select 3 | // ------------------------------ 4 | 5 | 6 | // Base 7 | 8 | .Select--multi { 9 | 10 | // add margin to the input element 11 | .Select-input { 12 | vertical-align: middle; 13 | // border: 1px solid transparent; 14 | margin-left: @select-padding-horizontal; 15 | padding: 0; 16 | } 17 | &.Select--rtl .Select-input { 18 | margin-left: 0; 19 | margin-right: @select-padding-horizontal; 20 | } 21 | 22 | // reduce margin once there is value 23 | &.has-value .Select-input { 24 | margin-left: @select-item-gutter; 25 | } 26 | 27 | // Items 28 | .Select-value { 29 | background-color: @select-item-bg-fb; /* Fallback color for IE 8 */ 30 | background-color: @select-item-bg; 31 | border-radius: @select-item-border-radius; 32 | border: 1px solid @select-item-border-color-fb; /* Fallback color for IE 8 */ 33 | border: 1px solid @select-item-border-color; 34 | color: @select-item-color; 35 | display: inline-block; 36 | font-size: @select-item-font-size; 37 | line-height: 1.4; 38 | margin-left: @select-item-gutter; 39 | margin-top: @select-item-gutter; 40 | vertical-align: top; 41 | } 42 | 43 | // common 44 | .Select-value-icon, 45 | .Select-value-label { 46 | display: inline-block; 47 | vertical-align: middle; 48 | } 49 | 50 | // label 51 | .Select-value-label { 52 | .border-right-radius( @select-item-border-radius ); 53 | cursor: default; 54 | padding: @select-item-padding-vertical @select-item-padding-horizontal; 55 | } 56 | a.Select-value-label { 57 | color: @select-item-color; 58 | cursor: pointer; 59 | text-decoration: none; 60 | 61 | &:hover { 62 | text-decoration: underline; 63 | } 64 | } 65 | 66 | // icon 67 | .Select-value-icon { 68 | cursor: pointer; 69 | .border-left-radius( @select-item-border-radius ); 70 | border-right: 1px solid @select-item-border-color-fb; /* Fallback color for IE 8 */ 71 | border-right: 1px solid @select-item-border-color; 72 | 73 | // move the baseline up by 1px 74 | padding: (@select-item-padding-vertical - 1) @select-item-padding-horizontal (@select-item-padding-vertical + 1); 75 | 76 | &:hover, 77 | &:focus { 78 | background-color: @select-item-hover-bg-fb; /* Fallback color for IE 8 */ 79 | background-color: @select-item-hover-bg; 80 | color: @select-item-hover-color; 81 | } 82 | &:active { 83 | background-color: @select-item-border-color-fb; /* Fallback color for IE 8 */ 84 | background-color: @select-item-border-color; 85 | } 86 | } 87 | &.Select--rtl { 88 | .Select-value { 89 | margin-left: 0; 90 | margin-right: @select-item-gutter; 91 | } 92 | .Select-value-icon { 93 | border-right: none; 94 | border-left: 1px solid @select-item-border-color-fb; /* Fallback color for IE 8 */ 95 | border-left: 1px solid @select-item-border-color; 96 | } 97 | } 98 | } 99 | 100 | .Select--multi.is-disabled { 101 | .Select-value { 102 | background-color: @select-item-disabled-bg; 103 | border: 1px solid @select-item-disabled-border-color; 104 | color: @select-item-disabled-color; 105 | } 106 | // icon 107 | .Select-value-icon { 108 | cursor: not-allowed; 109 | border-right: 1px solid @select-item-disabled-border-color; 110 | 111 | &:hover, 112 | &:focus, 113 | &:active { 114 | background-color: @select-item-disabled-bg; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /less/select.less: -------------------------------------------------------------------------------- 1 | /** 2 | * React Select Plus 3 | * ================= 4 | * MIT License: https://github.com/HubSpot/react-select-plus 5 | */ 6 | 7 | // Variables 8 | // ------------------------------ 9 | 10 | // common 11 | @select-primary-color: #007eff; 12 | 13 | // control options 14 | @select-input-bg: #fff; 15 | @select-input-bg-disabled: #f9f9f9; 16 | @select-input-bg-focus: @select-input-bg; 17 | @select-input-border-color: #ccc; 18 | @select-input-border-radius: 4px; 19 | @select-input-border-focus: @select-primary-color; 20 | @select-input-box-shadow-focus: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade(@select-input-border-focus, 50%); 21 | @select-input-border-width: 1px; 22 | @select-input-height: 36px; 23 | @select-input-internal-height: (@select-input-height - (@select-input-border-width * 2)); 24 | @select-input-placeholder: #aaa; 25 | @select-text-color: #333; 26 | @select-link-hover-color: @select-input-border-focus; 27 | @select-input-hover-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); 28 | 29 | @select-padding-vertical: 8px; 30 | @select-padding-horizontal: 10px; 31 | 32 | // menu options 33 | @select-menu-zindex: 1; 34 | @select-menu-max-height: 200px; 35 | @select-menu-box-shadow: @select-input-hover-box-shadow; 36 | 37 | @select-option-color: lighten(@select-text-color, 20%); 38 | @select-option-bg: @select-input-bg; 39 | @select-option-focused-color: @select-text-color; 40 | @select-option-focused-bg: fade(@select-primary-color, 8%); 41 | @select-option-focused-bg-fb: mix(@select-primary-color, @select-option-bg, 8%); // Fallback color for IE 8 42 | @select-option-selected-color: @select-text-color; 43 | @select-option-selected-bg: fade(@select-primary-color, 4%); 44 | @select-option-selected-bg-fb: mix(@select-primary-color, @select-option-bg, 4%); // Fallback color for IE 8 45 | @select-option-disabled-color: lighten(@select-text-color, 60%); 46 | 47 | @select-noresults-color: lighten(@select-text-color, 40%); 48 | 49 | // clear "x" button 50 | @select-clear-size: floor((@select-input-height / 2)); 51 | @select-clear-color: #999; 52 | @select-clear-hover-color: #D0021B; // red 53 | @select-clear-width: (@select-input-internal-height / 2); 54 | 55 | // arrow indicator 56 | @select-arrow-color: #999; 57 | @select-arrow-color-hover: #666; 58 | @select-arrow-width: 5px; 59 | 60 | // loading indicator 61 | @select-loading-size: 16px; 62 | @select-loading-color: @select-text-color; 63 | @select-loading-color-bg: @select-input-border-color; 64 | 65 | @select-right-padding: 5px; 66 | 67 | // multi-select item 68 | @select-item-font-size: .9em; 69 | 70 | @select-item-bg: fade(@select-primary-color, 8%); 71 | @select-item-bg-fb: mix(@select-primary-color, @select-input-bg, 8%); // Fallback color for IE 8 72 | @select-item-color: @select-primary-color; 73 | @select-item-border-color: fade(@select-primary-color, 24%); 74 | @select-item-border-color-fb: mix(@select-primary-color, @select-input-bg, 24%); // Fallback color for IE 8 75 | @select-item-hover-color: darken(@select-item-color, 5%); 76 | @select-item-hover-bg: darken(@select-item-bg, 5%); 77 | @select-item-hover-bg-fb: mix(darken(@select-primary-color, 5%), @select-item-bg-fb, 8%); // Fallback color for IE 8 78 | @select-item-disabled-color: #333; 79 | @select-item-disabled-bg: #fcfcfc; 80 | @select-item-disabled-border-color: darken(@select-item-disabled-bg, 10%); 81 | 82 | @select-item-border-radius: 2px; 83 | @select-item-gutter: 5px; 84 | 85 | @select-item-padding-horizontal: 5px; 86 | @select-item-padding-vertical: 2px; 87 | 88 | // imports 89 | @import "control.less"; 90 | @import "menu.less"; 91 | @import "mixins.less"; 92 | @import "multi.less"; 93 | @import "spinner.less"; 94 | -------------------------------------------------------------------------------- /less/spinner.less: -------------------------------------------------------------------------------- 1 | // 2 | // Spinner 3 | // ------------------------------ 4 | 5 | .Select-spinner(@size, @orbit, @satellite) { 6 | .animation( Select-animation-spin 400ms infinite linear ); 7 | .square(@size); 8 | box-sizing: border-box; 9 | border-radius: 50%; 10 | border: floor((@size / 8)) solid @orbit; 11 | border-right-color: @satellite; 12 | display: inline-block; 13 | position: relative; 14 | 15 | } 16 | 17 | @keyframes Select-animation-spin { 18 | to { transform: rotate(1turn); } 19 | } 20 | @-webkit-keyframes Select-animation-spin { 21 | to { -webkit-transform: rotate(1turn); } 22 | } 23 | -------------------------------------------------------------------------------- /lib/AsyncCreatable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | 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; }; 8 | 9 | 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; }; }(); 10 | 11 | var _propTypes = require('prop-types'); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | var _react = require('react'); 16 | 17 | var _react2 = _interopRequireDefault(_react); 18 | 19 | var _Async = require('./Async'); 20 | 21 | var _Async2 = _interopRequireDefault(_Async); 22 | 23 | var _Creatable = require('./Creatable'); 24 | 25 | var _Creatable2 = _interopRequireDefault(_Creatable); 26 | 27 | var _Select = require('./Select'); 28 | 29 | var _Select2 = _interopRequireDefault(_Select); 30 | 31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 32 | 33 | 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; } 34 | 35 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 36 | 37 | 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; } 38 | 39 | 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; } 40 | 41 | var AsyncCreatableSelect = function (_React$Component) { 42 | _inherits(AsyncCreatableSelect, _React$Component); 43 | 44 | function AsyncCreatableSelect() { 45 | _classCallCheck(this, AsyncCreatableSelect); 46 | 47 | return _possibleConstructorReturn(this, (AsyncCreatableSelect.__proto__ || Object.getPrototypeOf(AsyncCreatableSelect)).apply(this, arguments)); 48 | } 49 | 50 | _createClass(AsyncCreatableSelect, [{ 51 | key: 'focus', 52 | value: function focus() { 53 | this.select.focus(); 54 | } 55 | }, { 56 | key: 'render', 57 | value: function render() { 58 | var _this2 = this; 59 | 60 | return _react2.default.createElement( 61 | _Async2.default, 62 | this.props, 63 | function (_ref) { 64 | var ref = _ref.ref, 65 | asyncProps = _objectWithoutProperties(_ref, ['ref']); 66 | 67 | var asyncRef = ref; 68 | return _react2.default.createElement( 69 | _Creatable2.default, 70 | asyncProps, 71 | function (_ref2) { 72 | var ref = _ref2.ref, 73 | creatableProps = _objectWithoutProperties(_ref2, ['ref']); 74 | 75 | var creatableRef = ref; 76 | return _this2.props.children(_extends({}, creatableProps, { 77 | ref: function ref(select) { 78 | creatableRef(select); 79 | asyncRef(select); 80 | _this2.select = select; 81 | } 82 | })); 83 | } 84 | ); 85 | } 86 | ); 87 | } 88 | }]); 89 | 90 | return AsyncCreatableSelect; 91 | }(_react2.default.Component); 92 | 93 | var defaultChildren = function defaultChildren(props) { 94 | return _react2.default.createElement(_Select2.default, props); 95 | }; 96 | 97 | AsyncCreatableSelect.propTypes = { 98 | children: _propTypes2.default.func.isRequired // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element 99 | }; 100 | 101 | AsyncCreatableSelect.defaultProps = { 102 | children: defaultChildren 103 | }; 104 | 105 | exports.default = AsyncCreatableSelect; -------------------------------------------------------------------------------- /lib/Dropdown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | 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; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _propTypes = require('prop-types'); 14 | 15 | var _propTypes2 = _interopRequireDefault(_propTypes); 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 20 | 21 | 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; } 22 | 23 | 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; } 24 | 25 | var Dropdown = function (_React$Component) { 26 | _inherits(Dropdown, _React$Component); 27 | 28 | function Dropdown() { 29 | _classCallCheck(this, Dropdown); 30 | 31 | return _possibleConstructorReturn(this, (Dropdown.__proto__ || Object.getPrototypeOf(Dropdown)).apply(this, arguments)); 32 | } 33 | 34 | _createClass(Dropdown, [{ 35 | key: 'render', 36 | value: function render() { 37 | // This component adds no markup 38 | return this.props.children; 39 | } 40 | }]); 41 | 42 | return Dropdown; 43 | }(_react2.default.Component); 44 | 45 | ; 46 | 47 | Dropdown.propTypes = { 48 | children: _propTypes2.default.node 49 | }; 50 | 51 | exports.default = Dropdown; -------------------------------------------------------------------------------- /lib/Option.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | 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; }; }(); 8 | 9 | var _classnames = require('classnames'); 10 | 11 | var _classnames2 = _interopRequireDefault(_classnames); 12 | 13 | var _propTypes = require('prop-types'); 14 | 15 | var _propTypes2 = _interopRequireDefault(_propTypes); 16 | 17 | var _react = require('react'); 18 | 19 | var _react2 = _interopRequireDefault(_react); 20 | 21 | var _blockEvent = require('./utils/blockEvent'); 22 | 23 | var _blockEvent2 = _interopRequireDefault(_blockEvent); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 28 | 29 | 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; } 30 | 31 | 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; } 32 | 33 | var Option = function (_React$Component) { 34 | _inherits(Option, _React$Component); 35 | 36 | function Option(props) { 37 | _classCallCheck(this, Option); 38 | 39 | var _this = _possibleConstructorReturn(this, (Option.__proto__ || Object.getPrototypeOf(Option)).call(this, props)); 40 | 41 | _this.handleMouseDown = _this.handleMouseDown.bind(_this); 42 | _this.handleMouseEnter = _this.handleMouseEnter.bind(_this); 43 | _this.handleMouseMove = _this.handleMouseMove.bind(_this); 44 | _this.handleTouchStart = _this.handleTouchStart.bind(_this); 45 | _this.handleTouchEnd = _this.handleTouchEnd.bind(_this); 46 | _this.handleTouchMove = _this.handleTouchMove.bind(_this); 47 | _this.onFocus = _this.onFocus.bind(_this); 48 | return _this; 49 | } 50 | 51 | _createClass(Option, [{ 52 | key: 'handleMouseDown', 53 | value: function handleMouseDown(event) { 54 | event.preventDefault(); 55 | event.stopPropagation(); 56 | this.props.onSelect(this.props.option, event); 57 | } 58 | }, { 59 | key: 'handleMouseEnter', 60 | value: function handleMouseEnter(event) { 61 | this.onFocus(event); 62 | } 63 | }, { 64 | key: 'handleMouseMove', 65 | value: function handleMouseMove(event) { 66 | this.onFocus(event); 67 | } 68 | }, { 69 | key: 'handleTouchEnd', 70 | value: function handleTouchEnd(event) { 71 | // Check if the view is being dragged, In this case 72 | // we don't want to fire the click event (because the user only wants to scroll) 73 | if (this.dragging) return; 74 | 75 | this.handleMouseDown(event); 76 | } 77 | }, { 78 | key: 'handleTouchMove', 79 | value: function handleTouchMove() { 80 | // Set a flag that the view is being dragged 81 | this.dragging = true; 82 | } 83 | }, { 84 | key: 'handleTouchStart', 85 | value: function handleTouchStart() { 86 | // Set a flag that the view is not being dragged 87 | this.dragging = false; 88 | } 89 | }, { 90 | key: 'onFocus', 91 | value: function onFocus(event) { 92 | if (!this.props.isFocused) { 93 | this.props.onFocus(this.props.option, event); 94 | } 95 | } 96 | }, { 97 | key: 'render', 98 | value: function render() { 99 | var _props = this.props, 100 | option = _props.option, 101 | instancePrefix = _props.instancePrefix, 102 | optionIndex = _props.optionIndex; 103 | 104 | var className = (0, _classnames2.default)(this.props.className, option.className); 105 | 106 | return option.disabled ? _react2.default.createElement( 107 | 'div', 108 | { className: className, 109 | onMouseDown: _blockEvent2.default, 110 | onClick: _blockEvent2.default }, 111 | this.props.children 112 | ) : _react2.default.createElement( 113 | 'div', 114 | { className: className, 115 | style: option.style, 116 | role: 'option', 117 | 'aria-label': option.label, 118 | onMouseDown: this.handleMouseDown, 119 | onMouseEnter: this.handleMouseEnter, 120 | onMouseMove: this.handleMouseMove, 121 | onTouchStart: this.handleTouchStart, 122 | onTouchMove: this.handleTouchMove, 123 | onTouchEnd: this.handleTouchEnd, 124 | id: instancePrefix + '-option-' + optionIndex, 125 | title: option.title }, 126 | this.props.children 127 | ); 128 | } 129 | }]); 130 | 131 | return Option; 132 | }(_react2.default.Component); 133 | 134 | Option.propTypes = { 135 | children: _propTypes2.default.node, 136 | className: _propTypes2.default.string, // className (based on mouse position) 137 | instancePrefix: _propTypes2.default.string.isRequired, // unique prefix for the ids (used for aria) 138 | isDisabled: _propTypes2.default.bool, // the option is disabled 139 | isFocused: _propTypes2.default.bool, // the option is focused 140 | isSelected: _propTypes2.default.bool, // the option is selected 141 | onFocus: _propTypes2.default.func, // method to handle mouseEnter on option element 142 | onSelect: _propTypes2.default.func, // method to handle click on option element 143 | onUnfocus: _propTypes2.default.func, // method to handle mouseLeave on option element 144 | option: _propTypes2.default.object.isRequired, // object that is base for that option 145 | optionIndex: _propTypes2.default.number // index of the option, used to generate unique ids for aria 146 | }; 147 | 148 | exports.default = Option; -------------------------------------------------------------------------------- /lib/OptionGroup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | 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; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _propTypes = require('prop-types'); 14 | 15 | var _propTypes2 = _interopRequireDefault(_propTypes); 16 | 17 | var _classnames = require('classnames'); 18 | 19 | var _classnames2 = _interopRequireDefault(_classnames); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 24 | 25 | 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; } 26 | 27 | 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; } 28 | 29 | var OptionGroup = function (_React$Component) { 30 | _inherits(OptionGroup, _React$Component); 31 | 32 | function OptionGroup(props) { 33 | _classCallCheck(this, OptionGroup); 34 | 35 | var _this = _possibleConstructorReturn(this, (OptionGroup.__proto__ || Object.getPrototypeOf(OptionGroup)).call(this, props)); 36 | 37 | _this.handleMouseDown = _this.handleMouseDown.bind(_this); 38 | _this.handleTouchEnd = _this.handleTouchEnd.bind(_this); 39 | _this.handleTouchMove = _this.handleTouchMove.bind(_this); 40 | _this.handleTouchStart = _this.handleTouchStart.bind(_this); 41 | return _this; 42 | } 43 | 44 | _createClass(OptionGroup, [{ 45 | key: 'blockEvent', 46 | value: function blockEvent(event) { 47 | event.preventDefault(); 48 | event.stopPropagation(); 49 | if (event.target.tagName !== 'A' || !('href' in event.target)) { 50 | return; 51 | } 52 | if (event.target.target) { 53 | window.open(event.target.href, event.target.target); 54 | } else { 55 | window.location.href = event.target.href; 56 | } 57 | } 58 | }, { 59 | key: 'handleMouseDown', 60 | value: function handleMouseDown(event) { 61 | event.preventDefault(); 62 | event.stopPropagation(); 63 | } 64 | }, { 65 | key: 'handleTouchEnd', 66 | value: function handleTouchEnd(event) { 67 | // Check if the view is being dragged, In this case 68 | // we don't want to fire the click event (because the user only wants to scroll) 69 | if (this.dragging) return; 70 | 71 | this.handleMouseDown(event); 72 | } 73 | }, { 74 | key: 'handleTouchMove', 75 | value: function handleTouchMove(event) { 76 | // Set a flag that the view is being dragged 77 | this.dragging = true; 78 | } 79 | }, { 80 | key: 'handleTouchStart', 81 | value: function handleTouchStart(event) { 82 | // Set a flag that the view is not being dragged 83 | this.dragging = false; 84 | } 85 | }, { 86 | key: 'render', 87 | value: function render() { 88 | var option = this.props.option; 89 | 90 | var className = (0, _classnames2.default)(this.props.className, option.className); 91 | 92 | return option.disabled ? _react2.default.createElement( 93 | 'div', 94 | { className: className, 95 | onMouseDown: this.blockEvent, 96 | onClick: this.blockEvent }, 97 | this.props.children 98 | ) : _react2.default.createElement( 99 | 'div', 100 | { className: className, 101 | style: option.style, 102 | onMouseDown: this.handleMouseDown, 103 | onMouseEnter: this.handleMouseEnter, 104 | onMouseMove: this.handleMouseMove, 105 | onTouchStart: this.handleTouchStart, 106 | onTouchMove: this.handleTouchMove, 107 | onTouchEnd: this.handleTouchEnd, 108 | title: option.title }, 109 | _react2.default.createElement( 110 | 'div', 111 | { className: 'Select-option-group-label' }, 112 | this.props.label 113 | ), 114 | this.props.children 115 | ); 116 | } 117 | }]); 118 | 119 | return OptionGroup; 120 | }(_react2.default.Component); 121 | 122 | ; 123 | 124 | OptionGroup.propTypes = { 125 | children: _propTypes2.default.any, 126 | className: _propTypes2.default.string, // className (based on mouse position) 127 | label: _propTypes2.default.node, // the heading to show above the child options 128 | option: _propTypes2.default.object.isRequired // object that is base for that option group 129 | }; 130 | 131 | exports.default = OptionGroup; -------------------------------------------------------------------------------- /lib/Value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | 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; }; }(); 8 | 9 | var _classnames = require('classnames'); 10 | 11 | var _classnames2 = _interopRequireDefault(_classnames); 12 | 13 | var _propTypes = require('prop-types'); 14 | 15 | var _propTypes2 = _interopRequireDefault(_propTypes); 16 | 17 | var _react = require('react'); 18 | 19 | var _react2 = _interopRequireDefault(_react); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 24 | 25 | 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; } 26 | 27 | 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; } 28 | 29 | var Value = function (_React$Component) { 30 | _inherits(Value, _React$Component); 31 | 32 | function Value(props) { 33 | _classCallCheck(this, Value); 34 | 35 | var _this = _possibleConstructorReturn(this, (Value.__proto__ || Object.getPrototypeOf(Value)).call(this, props)); 36 | 37 | _this.handleMouseDown = _this.handleMouseDown.bind(_this); 38 | _this.onRemove = _this.onRemove.bind(_this); 39 | _this.handleTouchEndRemove = _this.handleTouchEndRemove.bind(_this); 40 | _this.handleTouchMove = _this.handleTouchMove.bind(_this); 41 | _this.handleTouchStart = _this.handleTouchStart.bind(_this); 42 | return _this; 43 | } 44 | 45 | _createClass(Value, [{ 46 | key: 'handleMouseDown', 47 | value: function handleMouseDown(event) { 48 | if (event.type === 'mousedown' && event.button !== 0) { 49 | return; 50 | } 51 | if (this.props.onClick) { 52 | event.stopPropagation(); 53 | this.props.onClick(this.props.value, event); 54 | return; 55 | } 56 | if (this.props.value.href) { 57 | event.stopPropagation(); 58 | } 59 | } 60 | }, { 61 | key: 'onRemove', 62 | value: function onRemove(event) { 63 | event.preventDefault(); 64 | event.stopPropagation(); 65 | this.props.onRemove(this.props.value); 66 | } 67 | }, { 68 | key: 'handleTouchEndRemove', 69 | value: function handleTouchEndRemove(event) { 70 | // Check if the view is being dragged, In this case 71 | // we don't want to fire the click event (because the user only wants to scroll) 72 | if (this.dragging) return; 73 | 74 | // Fire the mouse events 75 | this.onRemove(event); 76 | } 77 | }, { 78 | key: 'handleTouchMove', 79 | value: function handleTouchMove() { 80 | // Set a flag that the view is being dragged 81 | this.dragging = true; 82 | } 83 | }, { 84 | key: 'handleTouchStart', 85 | value: function handleTouchStart() { 86 | // Set a flag that the view is not being dragged 87 | this.dragging = false; 88 | } 89 | }, { 90 | key: 'renderRemoveIcon', 91 | value: function renderRemoveIcon() { 92 | if (this.props.disabled || !this.props.onRemove) return; 93 | return _react2.default.createElement( 94 | 'span', 95 | { className: 'Select-value-icon', 96 | 'aria-hidden': 'true', 97 | onMouseDown: this.onRemove, 98 | onTouchEnd: this.handleTouchEndRemove, 99 | onTouchStart: this.handleTouchStart, 100 | onTouchMove: this.handleTouchMove }, 101 | '\xD7' 102 | ); 103 | } 104 | }, { 105 | key: 'renderLabel', 106 | value: function renderLabel() { 107 | var className = 'Select-value-label'; 108 | return this.props.onClick || this.props.value.href ? _react2.default.createElement( 109 | 'a', 110 | { className: className, href: this.props.value.href, target: this.props.value.target, onMouseDown: this.handleMouseDown, onTouchEnd: this.handleMouseDown }, 111 | this.props.children 112 | ) : _react2.default.createElement( 113 | 'span', 114 | { className: className, role: 'option', 'aria-selected': 'true', id: this.props.id }, 115 | this.props.children 116 | ); 117 | } 118 | }, { 119 | key: 'render', 120 | value: function render() { 121 | return _react2.default.createElement( 122 | 'div', 123 | { className: (0, _classnames2.default)('Select-value', this.props.value.className), 124 | style: this.props.value.style, 125 | title: this.props.value.title 126 | }, 127 | this.renderRemoveIcon(), 128 | this.renderLabel() 129 | ); 130 | } 131 | }]); 132 | 133 | return Value; 134 | }(_react2.default.Component); 135 | 136 | Value.propTypes = { 137 | children: _propTypes2.default.node, 138 | disabled: _propTypes2.default.bool, // disabled prop passed to ReactSelect 139 | id: _propTypes2.default.string, // Unique id for the value - used for aria 140 | onClick: _propTypes2.default.func, // method to handle click on value label 141 | onRemove: _propTypes2.default.func, // method to handle removal of the value 142 | value: _propTypes2.default.object.isRequired // the option object for this value 143 | }; 144 | 145 | exports.default = Value; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.defaultFilterOptions = exports.defaultClearRenderer = exports.defaultArrowRenderer = exports.defaultMenuRenderer = exports.Option = exports.Value = exports.Creatable = exports.AsyncCreatable = exports.Async = undefined; 7 | 8 | var _Select = require('./Select'); 9 | 10 | var _Select2 = _interopRequireDefault(_Select); 11 | 12 | var _Async = require('./Async'); 13 | 14 | var _Async2 = _interopRequireDefault(_Async); 15 | 16 | var _AsyncCreatable = require('./AsyncCreatable'); 17 | 18 | var _AsyncCreatable2 = _interopRequireDefault(_AsyncCreatable); 19 | 20 | var _Creatable = require('./Creatable'); 21 | 22 | var _Creatable2 = _interopRequireDefault(_Creatable); 23 | 24 | var _Value = require('./Value'); 25 | 26 | var _Value2 = _interopRequireDefault(_Value); 27 | 28 | var _Option = require('./Option'); 29 | 30 | var _Option2 = _interopRequireDefault(_Option); 31 | 32 | var _defaultMenuRenderer = require('./utils/defaultMenuRenderer'); 33 | 34 | var _defaultMenuRenderer2 = _interopRequireDefault(_defaultMenuRenderer); 35 | 36 | var _defaultArrowRenderer = require('./utils/defaultArrowRenderer'); 37 | 38 | var _defaultArrowRenderer2 = _interopRequireDefault(_defaultArrowRenderer); 39 | 40 | var _defaultClearRenderer = require('./utils/defaultClearRenderer'); 41 | 42 | var _defaultClearRenderer2 = _interopRequireDefault(_defaultClearRenderer); 43 | 44 | var _defaultFilterOptions = require('./utils/defaultFilterOptions'); 45 | 46 | var _defaultFilterOptions2 = _interopRequireDefault(_defaultFilterOptions); 47 | 48 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 49 | 50 | _Select2.default.Async = _Async2.default; 51 | _Select2.default.AsyncCreatable = _AsyncCreatable2.default; 52 | _Select2.default.Creatable = _Creatable2.default; 53 | _Select2.default.Value = _Value2.default; 54 | _Select2.default.Option = _Option2.default; 55 | 56 | exports.default = _Select2.default; 57 | exports.Async = _Async2.default; 58 | exports.AsyncCreatable = _AsyncCreatable2.default; 59 | exports.Creatable = _Creatable2.default; 60 | exports.Value = _Value2.default; 61 | exports.Option = _Option2.default; 62 | exports.defaultMenuRenderer = _defaultMenuRenderer2.default; 63 | exports.defaultArrowRenderer = _defaultArrowRenderer2.default; 64 | exports.defaultClearRenderer = _defaultClearRenderer2.default; 65 | exports.defaultFilterOptions = _defaultFilterOptions2.default; -------------------------------------------------------------------------------- /lib/utils/blockEvent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports.default = function (event) { 8 | event.preventDefault(); 9 | event.stopPropagation(); 10 | if (event.target.tagName !== 'A' || !('href' in event.target)) { 11 | return; 12 | } 13 | if (event.target.target) { 14 | window.open(event.target.href, event.target.target); 15 | } else { 16 | window.location.href = event.target.href; 17 | } 18 | }; -------------------------------------------------------------------------------- /lib/utils/defaultArrowRenderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | var _propTypes = require('prop-types'); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var arrowRenderer = function arrowRenderer(_ref) { 18 | var onMouseDown = _ref.onMouseDown; 19 | 20 | return _react2.default.createElement('span', { 21 | className: 'Select-arrow', 22 | onMouseDown: onMouseDown 23 | }); 24 | }; 25 | 26 | arrowRenderer.propTypes = { 27 | onMouseDown: _propTypes2.default.func 28 | }; 29 | 30 | exports.default = arrowRenderer; -------------------------------------------------------------------------------- /lib/utils/defaultClearRenderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _react = require('react'); 8 | 9 | var _react2 = _interopRequireDefault(_react); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var clearRenderer = function clearRenderer() { 14 | return _react2.default.createElement('span', { 15 | className: 'Select-clear', 16 | dangerouslySetInnerHTML: { __html: '×' } 17 | }); 18 | }; 19 | 20 | exports.default = clearRenderer; -------------------------------------------------------------------------------- /lib/utils/defaultFilterOptions.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _stripDiacritics = require('./stripDiacritics'); 8 | 9 | var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics); 10 | 11 | var _trim = require('./trim'); 12 | 13 | var _trim2 = _interopRequireDefault(_trim); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var isValid = function isValid(value) { 18 | return typeof value !== 'undefined' && value !== null && value !== ''; 19 | }; 20 | 21 | var filterOptions = function filterOptions(options, filterValue, excludeOptions, props) { 22 | if (props.ignoreAccents) { 23 | filterValue = (0, _stripDiacritics2.default)(filterValue); 24 | } 25 | 26 | if (props.ignoreCase) { 27 | filterValue = filterValue.toLowerCase(); 28 | } 29 | 30 | if (props.trimFilter) { 31 | filterValue = (0, _trim2.default)(filterValue); 32 | } 33 | 34 | if (excludeOptions) excludeOptions = excludeOptions.map(function (i) { 35 | return i[props.valueKey]; 36 | }); 37 | 38 | return options.filter(function (option) { 39 | if (excludeOptions && excludeOptions.indexOf(option[props.valueKey]) > -1) return false; 40 | if (props.filterOption) return props.filterOption.call(undefined, option, filterValue); 41 | if (!filterValue) return true; 42 | 43 | var value = option[props.valueKey]; 44 | var label = option[props.labelKey]; 45 | var hasValue = isValid(value); 46 | var hasLabel = isValid(label); 47 | 48 | if (!hasValue && !hasLabel) { 49 | return false; 50 | } 51 | 52 | var valueTest = hasValue ? String(value) : null; 53 | var labelTest = hasLabel ? String(label) : null; 54 | 55 | if (props.ignoreAccents) { 56 | if (valueTest && props.matchProp !== 'label') valueTest = (0, _stripDiacritics2.default)(valueTest); 57 | if (labelTest && props.matchProp !== 'value') labelTest = (0, _stripDiacritics2.default)(labelTest); 58 | } 59 | 60 | if (props.ignoreCase) { 61 | if (valueTest && props.matchProp !== 'label') valueTest = valueTest.toLowerCase(); 62 | if (labelTest && props.matchProp !== 'value') labelTest = labelTest.toLowerCase(); 63 | } 64 | 65 | return props.matchPos === 'start' ? valueTest && props.matchProp !== 'label' && valueTest.substr(0, filterValue.length) === filterValue || labelTest && props.matchProp !== 'value' && labelTest.substr(0, filterValue.length) === filterValue : valueTest && props.matchProp !== 'label' && valueTest.indexOf(filterValue) >= 0 || labelTest && props.matchProp !== 'value' && labelTest.indexOf(filterValue) >= 0; 66 | }); 67 | }; 68 | 69 | exports.default = filterOptions; -------------------------------------------------------------------------------- /lib/utils/defaultMenuRenderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _classnames = require('classnames'); 8 | 9 | var _classnames2 = _interopRequireDefault(_classnames); 10 | 11 | var _propTypes = require('prop-types'); 12 | 13 | var _propTypes2 = _interopRequireDefault(_propTypes); 14 | 15 | var _react = require('react'); 16 | 17 | var _react2 = _interopRequireDefault(_react); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | var isGroup = function isGroup(option) { 22 | return option && Array.isArray(option.options); 23 | }; 24 | 25 | var menuRenderer = function menuRenderer(_ref) { 26 | var focusedOption = _ref.focusedOption, 27 | focusOption = _ref.focusOption, 28 | inputValue = _ref.inputValue, 29 | instancePrefix = _ref.instancePrefix, 30 | onFocus = _ref.onFocus, 31 | onOptionRef = _ref.onOptionRef, 32 | onSelect = _ref.onSelect, 33 | optionClassName = _ref.optionClassName, 34 | optionComponent = _ref.optionComponent, 35 | optionGroupComponent = _ref.optionGroupComponent, 36 | optionRenderer = _ref.optionRenderer, 37 | options = _ref.options, 38 | removeValue = _ref.removeValue, 39 | selectValue = _ref.selectValue, 40 | valueArray = _ref.valueArray, 41 | valueKey = _ref.valueKey; 42 | 43 | var OptionGroup = optionGroupComponent; 44 | var Option = optionComponent; 45 | var renderLabel = optionRenderer; 46 | 47 | var renderOptions = function renderOptions(optionsSubset) { 48 | return optionsSubset.map(function (option, i) { 49 | if (isGroup(option)) { 50 | var optionGroupClass = (0, _classnames2.default)({ 51 | 'Select-option-group': true 52 | }); 53 | 54 | return _react2.default.createElement( 55 | OptionGroup, 56 | { 57 | className: optionGroupClass, 58 | key: 'option-group-' + i, 59 | label: renderLabel(option), 60 | option: option, 61 | optionIndex: i 62 | }, 63 | renderOptions(option.options) 64 | ); 65 | } else { 66 | var isSelected = valueArray && valueArray.indexOf(option) > -1; 67 | var isFocused = option === focusedOption; 68 | var optionRef = isFocused ? 'focused' : null; 69 | var optionClass = (0, _classnames2.default)(optionClassName, { 70 | 'Select-option': true, 71 | 'is-selected': isSelected, 72 | 'is-focused': isFocused, 73 | 'is-disabled': option.disabled 74 | }); 75 | 76 | return _react2.default.createElement( 77 | Option, 78 | { 79 | className: optionClass, 80 | focusOption: focusOption, 81 | inputValue: inputValue, 82 | instancePrefix: instancePrefix, 83 | isDisabled: option.disabled, 84 | isFocused: isFocused, 85 | isSelected: isSelected, 86 | key: 'option-' + i + '-' + option[valueKey], 87 | onFocus: onFocus, 88 | onSelect: onSelect, 89 | option: option, 90 | optionIndex: i, 91 | ref: function ref(_ref2) { 92 | onOptionRef(_ref2, isFocused); 93 | }, 94 | removeValue: removeValue, 95 | selectValue: selectValue 96 | }, 97 | renderLabel(option, i) 98 | ); 99 | } 100 | }); 101 | }; 102 | 103 | return renderOptions(options); 104 | }; 105 | 106 | menuRenderer.propTypes = { 107 | focusOption: _propTypes2.default.func, 108 | focusedOption: _propTypes2.default.object, 109 | inputValue: _propTypes2.default.string, 110 | instancePrefix: _propTypes2.default.string, 111 | onFocus: _propTypes2.default.func, 112 | onOptionRef: _propTypes2.default.func, 113 | onSelect: _propTypes2.default.func, 114 | optionClassName: _propTypes2.default.string, 115 | optionComponent: _propTypes2.default.func, 116 | optionRenderer: _propTypes2.default.func, 117 | options: _propTypes2.default.array, 118 | removeValue: _propTypes2.default.func, 119 | selectValue: _propTypes2.default.func, 120 | valueArray: _propTypes2.default.array, 121 | valueKey: _propTypes2.default.string 122 | }; 123 | 124 | exports.default = menuRenderer; -------------------------------------------------------------------------------- /lib/utils/stripDiacritics.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 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 }]; 7 | 8 | var stripDiacritics = function stripDiacritics(str) { 9 | for (var i = 0; i < map.length; i++) { 10 | str = str.replace(map[i].letters, map[i].base); 11 | } 12 | return str; 13 | }; 14 | 15 | exports.default = stripDiacritics; -------------------------------------------------------------------------------- /lib/utils/trim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | var trim = function trim(str) { 7 | return str.replace(/^\s+|\s+$/g, ''); 8 | }; 9 | 10 | exports.default = trim; -------------------------------------------------------------------------------- /package-scripts.js: -------------------------------------------------------------------------------- 1 | const npsUtils = require('nps-utils'); 2 | const path = require('path'); 3 | const series = npsUtils.series; 4 | const rimraf = npsUtils.rimraf; 5 | const concurrent = npsUtils.concurrent; 6 | 7 | module.exports = { 8 | scripts: { 9 | build: { 10 | description: 'clean dist directory and run all builds', 11 | default: series( 12 | rimraf('dist'), 13 | rimraf('lib'), 14 | concurrent.nps('build.css', 'build.cssmin'), 15 | concurrent.nps('build.rollup', 'build.babel') 16 | ), 17 | rollup: 'rollup --config', 18 | babel: 'babel src -d lib', 19 | css: 'lessc less/default.less dist/react-select-plus.css', 20 | cssmin: 'lessc --clean-css less/default.less dist/react-select-plus.min.css', 21 | standalone: series( 22 | 'cp examples/src/standalone.html examples/dist/standalone.html', 23 | 'lessc examples/src/example.less examples/dist/example.css' 24 | ), 25 | }, 26 | publish: { 27 | default: series( 28 | rimraf('examples/dist'), 29 | 'webpack --progress -p', 30 | 'cp examples/src/.gitignore examples/dist/.gitignore', 31 | 'gh-pages -d examples/dist' 32 | ), 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-select-plus", 3 | "version": "1.2.0", 4 | "description": "A fork of react-select with support for option groups", 5 | "main": "lib/index.js", 6 | "jsnext:main": "dist/react-select-plus.es.js", 7 | "module": "dist/react-select-plus.es.js", 8 | "style": "dist/react-select-plus.min.css", 9 | "author": "HubSpot", 10 | "license": "MIT", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/HubSpot/react-select-plus.git" 14 | }, 15 | "dependencies": { 16 | "classnames": "^2.2.4", 17 | "prop-types": "^15.5.8", 18 | "react-input-autosize": "^2.1.2" 19 | }, 20 | "devDependencies": { 21 | "babel-cli": "^6.26.0", 22 | "babel-core": "^6.26.0", 23 | "babel-loader": "^7.1.1", 24 | "babel-plugin-external-helpers": "^6.22.0", 25 | "babel-plugin-istanbul": "^4.1.4", 26 | "babel-plugin-transform-react-remove-prop-types": "^0.4.8", 27 | "babel-preset-env": "^1.6.1", 28 | "babel-preset-react": "^6.24.1", 29 | "babel-preset-stage-0": "^6.24.1", 30 | "babel-register": "^6.26.0", 31 | "chai": "^4.1.2", 32 | "coveralls": "^2.11.12", 33 | "create-react-class": "^15.5.2", 34 | "cross-env": "^5.0.5", 35 | "css-loader": "^0.28.7", 36 | "eslint": "^4.6.1", 37 | "eslint-plugin-react": "^7.3.0", 38 | "extract-text-webpack-plugin": "^3.0.0", 39 | "gh-pages": "^1.1.0", 40 | "html-loader": "^0.5.1", 41 | "html-webpack-plugin": "^2.30.1", 42 | "husky": "^0.14.3", 43 | "isomorphic-fetch": "^2.2.1", 44 | "istanbul": "^0.4.5", 45 | "jsdom": "^9.12.0", 46 | "less": "^2.7.2", 47 | "less-loader": "^4.0.5", 48 | "less-plugin-clean-css": "^1.5.1", 49 | "lint-staged": "^4.3.0", 50 | "mocha": "^3.0.2", 51 | "nps": "^5.7.1", 52 | "nps-utils": "^1.3.0", 53 | "nyc": "^11.1.0", 54 | "react": "^15.5.0", 55 | "react-addons-shallow-compare": "^15.5.0", 56 | "react-dom": "^15.5.0", 57 | "react-gravatar": "^2.4.5", 58 | "react-highlight-words": "^0.8.1", 59 | "react-test-renderer": "^15.6.1", 60 | "react-virtualized": "^9.9.0", 61 | "react-virtualized-select": "^3.1.0", 62 | "rollup": "^0.49.2", 63 | "rollup-plugin-babel": "^3.0.2", 64 | "rollup-plugin-commonjs": "^8.2.0", 65 | "rollup-plugin-node-resolve": "^3.0.0", 66 | "rollup-plugin-uglify": "^2.0.1", 67 | "sinon": "^3.2.1", 68 | "style-loader": "^0.18.2", 69 | "uglify-es": "^3.0.28", 70 | "unexpected": "^10.35.0", 71 | "unexpected-dom": "^4.0.0", 72 | "unexpected-react": "^4.1.0", 73 | "unexpected-sinon": "^10.4.0", 74 | "webpack": "^3.5.5", 75 | "webpack-dev-server": "^2.7.1" 76 | }, 77 | "peerDependencies": { 78 | "react": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0", 79 | "react-dom": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0" 80 | }, 81 | "scripts": { 82 | "build": "nps build", 83 | "cover": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha", 84 | "coveralls": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text mocha && cat coverage/lcov.info | coveralls", 85 | "lint": "eslint .", 86 | "deploy": "cross-env NODE_ENV=production nps publish", 87 | "start": "webpack-dev-server --progress", 88 | "test": "cross-env NODE_ENV=test mocha --compilers js:babel-core/register", 89 | "precommit": "lint-staged && yarn run test" 90 | }, 91 | "files": [ 92 | "dist", 93 | "less", 94 | "lib", 95 | "scss" 96 | ], 97 | "keywords": [ 98 | "combobox", 99 | "form", 100 | "input", 101 | "multiselect", 102 | "react", 103 | "react-component", 104 | "select", 105 | "ui" 106 | ], 107 | "lint-staged": { 108 | "*.js": "eslint" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import resolve from 'rollup-plugin-node-resolve'; 3 | import uglify from 'rollup-plugin-uglify'; 4 | import { minify } from 'uglify-es'; 5 | 6 | const name = 'Select'; 7 | const path = 'dist/react-select-plus'; 8 | const globals = { 9 | classnames: 'classNames', 10 | 'prop-types': 'PropTypes', 11 | 'react-dom': 'ReactDOM', 12 | 'react-input-autosize': 'AutosizeInput', 13 | react: 'React', 14 | }; 15 | const external = Object.keys(globals); 16 | const babelOptions = (production) => { 17 | let result = { 18 | babelrc: false, 19 | presets: [['env', { modules: false }], 'stage-0', 'react'], 20 | plugins: ['external-helpers'], 21 | }; 22 | if (production) { 23 | result.plugins.push('transform-react-remove-prop-types'); 24 | }; 25 | return result; 26 | }; 27 | 28 | export default [ 29 | { 30 | input: 'src/index.js', 31 | output: { 32 | file: path + '.es.js', 33 | format: 'es', 34 | }, 35 | external: external, 36 | plugins: [babel(babelOptions(false))], 37 | }, 38 | { 39 | input: 'src/index.umd.js', 40 | output: { 41 | name: name, 42 | file: path + '.js', 43 | format: 'umd', 44 | }, 45 | globals: globals, 46 | external: external, 47 | plugins: [babel(babelOptions(false)), resolve()], 48 | }, 49 | { 50 | input: 'src/index.umd.js', 51 | output: { 52 | name: name, 53 | file: path + '.min.js', 54 | format: 'umd', 55 | }, 56 | globals: globals, 57 | external: external, 58 | plugins: [babel(babelOptions(true)), resolve(), uglify({}, minify)], 59 | }, 60 | ]; 61 | -------------------------------------------------------------------------------- /scss/components.scss: -------------------------------------------------------------------------------- 1 | @import "control"; 2 | @import "menu"; 3 | @import "mixins"; 4 | @import "multi"; 5 | @import "spinner"; 6 | -------------------------------------------------------------------------------- /scss/control.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Control 3 | // ------------------------------ 4 | 5 | @import 'spinner'; 6 | @import 'mixins'; 7 | 8 | .Select { 9 | position: relative; 10 | 11 | // disable some browser-specific behaviours that break the input 12 | input::-webkit-contacts-auto-fill-button, 13 | input::-webkit-credentials-auto-fill-button { 14 | display: none !important; 15 | } 16 | input::-ms-clear { 17 | display: none !important; 18 | } 19 | input::-ms-reveal { 20 | display: none !important; 21 | } 22 | 23 | // preferred box model 24 | &, 25 | & div, 26 | & input, 27 | & span { 28 | @include box-sizing(border-box); 29 | } 30 | 31 | // handle disabled state 32 | &.is-disabled { 33 | .Select-arrow-zone { 34 | cursor: default; 35 | pointer-events: none; 36 | } 37 | 38 | > .Select-control { 39 | background-color: $select-input-bg-disabled; 40 | &:hover { 41 | box-shadow: none; 42 | } 43 | } 44 | } 45 | 46 | &.is-searchable { 47 | &.is-open > .Select-control { 48 | cursor: text; 49 | } 50 | 51 | &.is-focused:not(.is-open) > .Select-control { 52 | cursor: text; 53 | } 54 | } 55 | 56 | &.is-open > .Select-control { 57 | @include border-bottom-radius( 0 ); 58 | background: $select-input-bg; 59 | border-color: darken($select-input-border-color, 10%) $select-input-border-color lighten($select-input-border-color, 5%); 60 | 61 | // flip the arrow so its pointing up when the menu is open 62 | .Select-arrow { 63 | top: -2px; 64 | border-color: transparent transparent $select-arrow-color; 65 | border-width: 0 $select-arrow-width $select-arrow-width; 66 | } 67 | } 68 | 69 | &.is-focused > .Select-control { 70 | background: $select-input-bg-focus; 71 | } 72 | 73 | &.is-focused:not(.is-open) > .Select-control { 74 | border-color: $select-input-border-focus lighten($select-input-border-focus, 5%) lighten($select-input-border-focus, 5%); 75 | box-shadow: $select-input-box-shadow-focus; 76 | } 77 | 78 | 79 | &.has-value.is-clearable.Select--single > .Select-control .Select-value { 80 | padding-right: ($select-clear-width + $select-arrow-width * 5); 81 | } 82 | 83 | &.has-value.Select--single > .Select-control .Select-value, 84 | &.has-value.is-pseudo-focused.Select--single > .Select-control .Select-value { 85 | .Select-value-label { 86 | color: $select-text-color; 87 | } 88 | a.Select-value-label { 89 | cursor: pointer; 90 | text-decoration: none; 91 | 92 | &:hover, 93 | &:focus { 94 | color: $select-link-hover-color; 95 | outline: none; 96 | text-decoration: underline; 97 | } 98 | 99 | &:focus { 100 | background: $select-input-bg-focus; 101 | } 102 | } 103 | } 104 | 105 | // fake-hide the input when the control is pseudo-focused 106 | &.has-value.is-pseudo-focused .Select-input { 107 | opacity: 0; 108 | } 109 | 110 | &.is-open .Select-arrow, 111 | .Select-arrow-zone:hover > .Select-arrow { 112 | border-top-color: $select-arrow-color-hover; 113 | } 114 | &.Select--rtl { 115 | direction: rtl; 116 | text-align: right; 117 | } 118 | } 119 | 120 | // base 121 | 122 | .Select-control { 123 | background-color: $select-input-bg; 124 | border-color: lighten($select-input-border-color, 5%) $select-input-border-color darken($select-input-border-color, 10%); 125 | border-radius: $select-input-border-radius; 126 | border: $select-input-border-width solid $select-input-border-color; 127 | color: $select-text-color; 128 | cursor: default; 129 | display: table; 130 | border-spacing: 0; 131 | border-collapse: separate; 132 | height: $select-input-height; 133 | outline: none; 134 | overflow: hidden; 135 | position: relative; 136 | width: 100%; 137 | 138 | &:hover { 139 | box-shadow: $select-input-hover-box-shadow; 140 | } 141 | 142 | .Select-input:focus { 143 | outline: none; 144 | background: $select-input-bg-focus; 145 | } 146 | } 147 | 148 | // placeholder 149 | .Select-placeholder, 150 | .Select--single > .Select-control .Select-value { 151 | bottom: 0; 152 | color: $select-input-placeholder; 153 | left: 0; 154 | line-height: $select-input-internal-height; 155 | padding-left: $select-padding-horizontal; 156 | padding-right: $select-padding-horizontal; 157 | position: absolute; 158 | right: 0; 159 | top: 0; 160 | 161 | // crop text 162 | max-width: 100%; 163 | overflow: hidden; 164 | text-overflow: ellipsis; 165 | white-space: nowrap; 166 | } 167 | 168 | 169 | // the element users type in 170 | 171 | .Select-input { 172 | // inherits `display: inline-block` from "react-input-autosize" 173 | height: $select-input-internal-height; 174 | padding-left: $select-padding-horizontal; 175 | padding-right: $select-padding-horizontal; 176 | vertical-align: middle; 177 | 178 | > input { 179 | background: none transparent; 180 | border: 0 none; 181 | box-shadow: none; 182 | cursor: default; 183 | display: inline-block; 184 | font-family: inherit; 185 | font-size: inherit; 186 | // height: $select-input-internal-height; 187 | margin: 0; 188 | outline: none; 189 | // padding: 0; 190 | line-height: 17px; /* For IE 8 compatibility */ 191 | padding: (($select-input-internal-height - 14) / 2 - 2) 0 (($select-input-internal-height - 14) / 2 + 2); /* For IE 8 compatibility */ 192 | -webkit-appearance: none; 193 | 194 | .is-focused & { 195 | cursor: text; 196 | } 197 | } 198 | 199 | } 200 | 201 | // fake input 202 | .Select-control:not(.is-searchable) > .Select-input { 203 | outline: none; 204 | } 205 | 206 | // loading indicator 207 | .Select-loading-zone { 208 | cursor: pointer; 209 | display: table-cell; 210 | position: relative; 211 | text-align: center; 212 | vertical-align: middle; 213 | width: $select-loading-size; 214 | } 215 | .Select-loading { 216 | @include Select-spinner($select-loading-size, $select-loading-color-bg, $select-loading-color); 217 | vertical-align: middle; 218 | } 219 | 220 | 221 | // the little cross that clears the field 222 | 223 | .Select-clear-zone { 224 | @include animation( Select-animation-fadeIn 200ms ); 225 | color: $select-clear-color; 226 | cursor: pointer; 227 | display: table-cell; 228 | position: relative; 229 | text-align: center; 230 | vertical-align: middle; 231 | width: $select-clear-width; 232 | 233 | &:hover { 234 | color: $select-clear-hover-color; 235 | } 236 | } 237 | .Select-clear { 238 | display: inline-block; 239 | font-size: $select-clear-size; 240 | line-height: 1; 241 | } 242 | .Select--multi .Select-clear-zone { 243 | width: $select-clear-width; 244 | } 245 | 246 | .Select--multi .Select-multi-value-wrapper { 247 | display: inline-block; 248 | } 249 | .Select .Select-aria-only { 250 | position: absolute; 251 | display: inline-block; 252 | height: 1px; 253 | width: 1px; 254 | margin: -1px; 255 | clip: rect(0,0,0,0); 256 | overflow: hidden; 257 | float: left; 258 | } 259 | 260 | 261 | // arrow indicator 262 | 263 | .Select-arrow-zone { 264 | cursor: pointer; 265 | display: table-cell; 266 | position: relative; 267 | text-align: center; 268 | vertical-align: middle; 269 | width: ($select-arrow-width * 5); 270 | padding-right: $select-arrow-width; 271 | 272 | .Select--rtl & { 273 | padding-right: 0; 274 | padding-left: $select-arrow-width; 275 | } 276 | } 277 | 278 | .Select-arrow { 279 | border-color: $select-arrow-color transparent transparent; 280 | border-style: solid; 281 | border-width: $select-arrow-width $select-arrow-width ($select-arrow-width / 2); 282 | display: inline-block; 283 | height: 0; 284 | width: 0; 285 | position: relative; 286 | } 287 | 288 | 289 | 290 | 291 | // Animation 292 | // ------------------------------ 293 | 294 | // fade in 295 | 296 | @-webkit-keyframes Select-animation-fadeIn { 297 | from { opacity: 0; } 298 | to { opacity: 1; } 299 | } 300 | @keyframes Select-animation-fadeIn { 301 | from { opacity: 0; } 302 | to { opacity: 1; } 303 | } 304 | -------------------------------------------------------------------------------- /scss/default.scss: -------------------------------------------------------------------------------- 1 | @import "select"; 2 | @import "control"; 3 | @import "menu"; 4 | @import "mixins"; 5 | @import "multi"; 6 | @import "spinner"; 7 | -------------------------------------------------------------------------------- /scss/menu.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Select Menu 3 | // ------------------------------ 4 | 5 | 6 | // wrapper around the menu 7 | 8 | .Select-menu-outer { 9 | // Unfortunately, having both border-radius and allows scrolling using overflow defined on the same 10 | // element forces the browser to repaint on scroll. However, if these definitions are split into an 11 | // outer and an inner element, the browser is able to optimize the scrolling behavior and does not 12 | // have to repaint on scroll. 13 | @include border-bottom-radius( $select-input-border-radius ); 14 | background-color: $select-input-bg; 15 | border: 1px solid $select-input-border-color; 16 | border-top-color: mix($select-input-bg, $select-input-border-color, 50%); 17 | box-shadow: $select-menu-box-shadow; 18 | box-sizing: border-box; 19 | margin-top: -1px; 20 | max-height: $select-menu-max-height; 21 | position: absolute; 22 | top: 100%; 23 | width: 100%; 24 | z-index: $select-menu-zindex; 25 | -webkit-overflow-scrolling: touch; 26 | } 27 | 28 | 29 | // wrapper 30 | 31 | .Select-menu { 32 | max-height: ($select-menu-max-height - 2px); 33 | overflow-y: auto; 34 | } 35 | 36 | 37 | // options 38 | 39 | .Select-option { 40 | box-sizing: border-box; 41 | background-color: $select-option-bg; 42 | color: $select-option-color; 43 | cursor: pointer; 44 | display: block; 45 | padding: $select-padding-vertical $select-padding-horizontal; 46 | 47 | &:last-child { 48 | @include border-bottom-radius( $select-input-border-radius ); 49 | } 50 | 51 | &.is-selected { 52 | background-color: $select-option-selected-bg; 53 | color: $select-option-selected-color; 54 | } 55 | 56 | &.is-focused { 57 | background-color: $select-option-focused-bg; 58 | color: $select-option-focused-color; 59 | } 60 | 61 | &.is-disabled { 62 | color: $select-option-disabled-color; 63 | cursor: default; 64 | } 65 | 66 | } 67 | 68 | 69 | // no results 70 | 71 | .Select-noresults { 72 | box-sizing: border-box; 73 | color: $select-noresults-color; 74 | cursor: default; 75 | display: block; 76 | padding: $select-padding-vertical $select-padding-horizontal; 77 | } 78 | -------------------------------------------------------------------------------- /scss/mixins.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Mixins 3 | // ------------------------------ 4 | 5 | 6 | // Utilities 7 | 8 | @mixin size($width, $height) 9 | { 10 | width: $width; 11 | height: $height; 12 | } 13 | @mixin square($size) 14 | { 15 | @include size($size, $size); 16 | } 17 | @mixin border-top-radius($radius) 18 | { 19 | border-top-right-radius: $radius; 20 | border-top-left-radius: $radius; 21 | } 22 | @mixin border-right-radius($radius) 23 | { 24 | border-bottom-right-radius: $radius; 25 | border-top-right-radius: $radius; 26 | } 27 | @mixin border-bottom-radius($radius) 28 | { 29 | border-bottom-right-radius: $radius; 30 | border-bottom-left-radius: $radius; 31 | } 32 | @mixin border-left-radius($radius) 33 | { 34 | border-bottom-left-radius: $radius; 35 | border-top-left-radius: $radius; 36 | } 37 | 38 | 39 | // Vendor Prefixes 40 | 41 | @mixin animation($animation) 42 | { 43 | -webkit-animation: $animation; 44 | -o-animation: $animation; 45 | animation: $animation; 46 | } 47 | @mixin box-sizing($boxmodel) 48 | { 49 | -webkit-box-sizing: $boxmodel; 50 | -moz-box-sizing: $boxmodel; 51 | box-sizing: $boxmodel; 52 | } 53 | -------------------------------------------------------------------------------- /scss/multi.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Multi-Select 3 | // ------------------------------ 4 | 5 | 6 | // Base 7 | 8 | .Select--multi { 9 | 10 | // add margin to the input element 11 | .Select-input { 12 | vertical-align: middle; 13 | // border: 1px solid transparent; 14 | margin-left: $select-padding-horizontal; 15 | padding: 0; 16 | } 17 | &.Select--rtl .Select-input { 18 | margin-left: 0; 19 | margin-right: $select-padding-horizontal; 20 | } 21 | 22 | // reduce margin once there is value 23 | &.has-value .Select-input { 24 | margin-left: $select-item-gutter; 25 | } 26 | 27 | // Items 28 | .Select-value { 29 | background-color: $select-item-bg; 30 | border-radius: $select-item-border-radius; 31 | border: 1px solid $select-item-border-color; 32 | color: $select-item-color; 33 | display: inline-block; 34 | font-size: $select-item-font-size; 35 | margin-left: $select-item-gutter; 36 | margin-top: $select-item-gutter; 37 | vertical-align: top; 38 | } 39 | 40 | // common 41 | .Select-value-icon, 42 | .Select-value-label { 43 | display: inline-block; 44 | vertical-align: middle; 45 | } 46 | 47 | // label 48 | .Select-value-label { 49 | @include border-right-radius( $select-item-border-radius ); 50 | cursor: default; 51 | padding: $select-item-padding-vertical $select-item-padding-horizontal; 52 | } 53 | a.Select-value-label { 54 | color: $select-item-color; 55 | cursor: pointer; 56 | text-decoration: none; 57 | 58 | &:hover { 59 | text-decoration: underline; 60 | } 61 | } 62 | 63 | // icon 64 | .Select-value-icon { 65 | cursor: pointer; 66 | @include border-left-radius( $select-item-border-radius ); 67 | border-right: 1px solid $select-item-border-color; 68 | 69 | // move the baseline up by 1px 70 | padding: ($select-item-padding-vertical - 1) $select-item-padding-horizontal ($select-item-padding-vertical + 1); 71 | 72 | &:hover, 73 | &:focus { 74 | background-color: $select-item-hover-bg; 75 | color: $select-item-hover-color; 76 | } 77 | &:active { 78 | background-color: $select-item-border-color; 79 | } 80 | } 81 | 82 | &.Select--rtl { 83 | .Select-value { 84 | margin-left: 0; 85 | margin-right: $select-item-gutter; 86 | } 87 | .Select-value-icon { 88 | border-right: none; 89 | border-left: 1px solid $select-item-border-color; 90 | } 91 | } 92 | } 93 | 94 | .Select--multi.is-disabled { 95 | .Select-value { 96 | background-color: $select-item-disabled-bg; 97 | border: 1px solid $select-item-disabled-border-color; 98 | color: $select-item-disabled-color; 99 | } 100 | // icon 101 | .Select-value-icon { 102 | cursor: not-allowed; 103 | border-right: 1px solid $select-item-disabled-border-color; 104 | 105 | &:hover, 106 | &:focus, 107 | &:active { 108 | background-color: $select-item-disabled-bg; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /scss/select.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * React Select Plus 3 | * ================= 4 | * MIT License: https://github.com/HubSpot/react-select-plus 5 | */ 6 | 7 | // Variables 8 | // ------------------------------ 9 | 10 | // control options 11 | $select-input-bg: #fff !default; 12 | $select-input-bg-disabled: #f9f9f9 !default; 13 | $select-input-bg-focus: $select-input-bg !default; 14 | $select-input-border-color: #ccc !default; 15 | $select-input-border-radius: 4px !default; 16 | $select-input-border-focus: #08c !default; // blue 17 | $select-input-box-shadow-focus: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade($select-input-border-focus, 50%) !default; 18 | $select-input-border-width: 1px !default; 19 | $select-input-height: 36px !default; 20 | $select-input-internal-height: ($select-input-height - ($select-input-border-width * 2)) !default; 21 | $select-input-placeholder: #aaa !default; 22 | $select-text-color: #333 !default; 23 | $select-link-hover-color: $select-input-border-focus !default; 24 | $select-input-hover-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06) !default; 25 | 26 | $select-padding-vertical: 8px !default; 27 | $select-padding-horizontal: 10px !default; 28 | 29 | // menu options 30 | $select-menu-zindex: 1000 !default; 31 | $select-menu-max-height: 200px !default; 32 | $select-menu-box-shadow: $select-input-hover-box-shadow !default; 33 | 34 | $select-option-color: lighten($select-text-color, 20%) !default; 35 | $select-option-bg: $select-input-bg !default; 36 | $select-option-focused-color: $select-text-color !default; 37 | $select-option-focused-bg: #f2f9fc !default; // pale blue 38 | $select-option-selected-color: $select-text-color !default; 39 | $select-option-selected-bg: #f5faff !default; // lightest blue 40 | $select-option-disabled-color: lighten($select-text-color, 60%) !default; 41 | 42 | $select-noresults-color: lighten($select-text-color, 40%) !default; 43 | 44 | // clear "x" button 45 | $select-clear-size: floor(($select-input-height / 2)) !default; 46 | $select-clear-color: #999 !default; 47 | $select-clear-hover-color: #D0021B !default; // red 48 | $select-clear-width: ($select-input-internal-height / 2) !default; 49 | 50 | // arrow indicator 51 | $select-arrow-color: #999 !default; 52 | $select-arrow-color-hover: #666 !default; 53 | $select-arrow-width: 5px !default; 54 | 55 | // loading indicator 56 | $select-loading-size: 16px !default; 57 | $select-loading-color: $select-text-color !default; 58 | $select-loading-color-bg: $select-input-border-color !default; 59 | 60 | // multi-select item 61 | $select-item-border-radius: 2px !default; 62 | $select-item-gutter: 5px !default; 63 | $select-item-padding-vertical: 2px !default; 64 | $select-item-padding-horizontal: 5px !default; 65 | $select-item-font-size: .9em !default; 66 | $select-item-color: #08c !default; // pale blue 67 | $select-item-bg: #f2f9fc !default; 68 | $select-item-border-color: darken($select-item-bg, 10%) !default; 69 | $select-item-hover-color: darken($select-item-color, 5%) !default; // pale blue 70 | $select-item-hover-bg: darken($select-item-bg, 5%) !default; 71 | $select-item-disabled-color: #333 !default; 72 | $select-item-disabled-bg: #fcfcfc !default; 73 | $select-item-disabled-border-color: darken($select-item-disabled-bg, 10%) !default; 74 | -------------------------------------------------------------------------------- /scss/spinner.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Spinner 3 | // ------------------------------ 4 | @import 'mixins'; 5 | 6 | @mixin Select-spinner($size, $orbit, $satellite) 7 | { 8 | @include animation( Select-animation-spin 400ms infinite linear ); 9 | @include square($size); 10 | box-sizing: border-box; 11 | border-radius: 50%; 12 | border: floor(($size / 8)) solid $orbit; 13 | border-right-color: $satellite; 14 | display: inline-block; 15 | position: relative; 16 | 17 | } 18 | 19 | @keyframes Select-animation-spin { 20 | to { transform: rotate(1turn); } 21 | } 22 | @-webkit-keyframes Select-animation-spin { 23 | to { -webkit-transform: rotate(1turn); } 24 | } 25 | -------------------------------------------------------------------------------- /src/Async.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Component } from 'react'; 3 | import Select from './Select'; 4 | 5 | import stripDiacritics from './utils/stripDiacritics'; 6 | 7 | const propTypes = { 8 | autoload: PropTypes.bool.isRequired, // automatically call the `loadOptions` prop on-mount; defaults to true 9 | cache: PropTypes.any, // object to use to cache results; set to null/false to disable caching 10 | children: PropTypes.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element 11 | ignoreAccents: PropTypes.bool, // strip diacritics when filtering; defaults to true 12 | ignoreCase: PropTypes.bool, // perform case-insensitive filtering; defaults to true 13 | loadOptions: PropTypes.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise 14 | loadingPlaceholder: PropTypes.oneOfType([ // replaces the placeholder while options are loading 15 | PropTypes.string, 16 | PropTypes.node 17 | ]), 18 | multi: PropTypes.bool, // multi-value input 19 | noResultsText: PropTypes.oneOfType([ // field noResultsText, displayed when no options come back from the server 20 | PropTypes.string, 21 | PropTypes.node 22 | ]), 23 | onChange: PropTypes.func, // onChange handler: function (newValue) {} 24 | onInputChange: PropTypes.func, // optional for keeping track of what is being typed 25 | options: PropTypes.array.isRequired, // array of options 26 | placeholder: PropTypes.oneOfType([ // field placeholder, displayed when there's no value (shared with Select) 27 | PropTypes.string, 28 | PropTypes.node 29 | ]), 30 | searchPromptText: PropTypes.oneOfType([ // label to prompt for search input 31 | PropTypes.string, 32 | PropTypes.node 33 | ]), 34 | value: PropTypes.any, // initial field value 35 | }; 36 | 37 | const defaultCache = {}; 38 | 39 | const defaultChildren = props => ; 39 | 40 | AsyncCreatableSelect.propTypes = { 41 | children: PropTypes.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element 42 | }; 43 | 44 | AsyncCreatableSelect.defaultProps = { 45 | children: defaultChildren, 46 | }; 47 | 48 | export default AsyncCreatableSelect; 49 | -------------------------------------------------------------------------------- /src/Creatable.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | import defaultFilterOptions from './utils/defaultFilterOptions'; 5 | import defaultMenuRenderer from './utils/defaultMenuRenderer'; 6 | import Select from './Select'; 7 | 8 | class CreatableSelect extends React.Component { 9 | constructor (props, context) { 10 | super(props, context); 11 | 12 | this.filterOptions = this.filterOptions.bind(this); 13 | this.menuRenderer = this.menuRenderer.bind(this); 14 | this.onInputKeyDown = this.onInputKeyDown.bind(this); 15 | this.onInputChange = this.onInputChange.bind(this); 16 | this.onOptionSelect = this.onOptionSelect.bind(this); 17 | } 18 | 19 | createNewOption () { 20 | const { 21 | isValidNewOption, 22 | newOptionCreator, 23 | onNewOptionClick, 24 | options = [], 25 | } = this.props; 26 | 27 | if (isValidNewOption({ label: this.inputValue })) { 28 | const option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); 29 | const isOptionUnique = this.isOptionUnique({ option, options }); 30 | 31 | // Don't add the same option twice. 32 | if (isOptionUnique) { 33 | if (onNewOptionClick) { 34 | onNewOptionClick(option); 35 | } else { 36 | options.unshift(option); 37 | 38 | this.select.selectValue(option); 39 | } 40 | } 41 | } 42 | } 43 | 44 | filterOptions (...params) { 45 | const { filterOptions, isValidNewOption, promptTextCreator } = this.props; 46 | 47 | // TRICKY Check currently selected options as well. 48 | // Don't display a create-prompt for a value that's selected. 49 | // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array. 50 | const excludeOptions = params[2] || []; 51 | 52 | const filteredOptions = filterOptions(...params) || []; 53 | 54 | if (isValidNewOption({ label: this.inputValue })) { 55 | const { newOptionCreator } = this.props; 56 | 57 | const option = newOptionCreator({ 58 | label: this.inputValue, 59 | labelKey: this.labelKey, 60 | valueKey: this.valueKey 61 | }); 62 | 63 | // TRICKY Compare to all options (not just filtered options) in case option has already been selected). 64 | // For multi-selects, this would remove it from the filtered list. 65 | const isOptionUnique = this.isOptionUnique({ 66 | option, 67 | options: excludeOptions.concat(filteredOptions) 68 | }); 69 | 70 | if (isOptionUnique) { 71 | const prompt = promptTextCreator(this.inputValue); 72 | 73 | this._createPlaceholderOption = newOptionCreator({ 74 | label: prompt, 75 | labelKey: this.labelKey, 76 | valueKey: this.valueKey 77 | }); 78 | 79 | filteredOptions.unshift(this._createPlaceholderOption); 80 | } 81 | } 82 | 83 | return filteredOptions; 84 | } 85 | 86 | isOptionUnique ({ 87 | option, 88 | options 89 | }) { 90 | const { isOptionUnique } = this.props; 91 | 92 | options = options || this.select.filterFlatOptions(); 93 | 94 | return isOptionUnique({ 95 | labelKey: this.labelKey, 96 | option, 97 | options, 98 | valueKey: this.valueKey 99 | }); 100 | } 101 | 102 | menuRenderer (params) { 103 | const { menuRenderer } = this.props; 104 | 105 | return menuRenderer({ 106 | ...params, 107 | onSelect: this.onOptionSelect, 108 | selectValue: this.onOptionSelect 109 | }); 110 | } 111 | 112 | onInputChange (input) { 113 | const { onInputChange } = this.props; 114 | 115 | // This value may be needed in between Select mounts (when this.select is null) 116 | this.inputValue = input; 117 | 118 | if (onInputChange) { 119 | this.inputValue = onInputChange(input); 120 | } 121 | 122 | return this.inputValue; 123 | } 124 | 125 | onInputKeyDown (event) { 126 | const { shouldKeyDownEventCreateNewOption, onInputKeyDown } = this.props; 127 | const focusedOption = this.select.getFocusedOption(); 128 | 129 | if ( 130 | focusedOption && 131 | focusedOption === this._createPlaceholderOption && 132 | shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode }) 133 | ) { 134 | this.createNewOption(); 135 | 136 | // Prevent decorated Select from doing anything additional with this keyDown event 137 | event.preventDefault(); 138 | } else if (onInputKeyDown) { 139 | onInputKeyDown(event); 140 | } 141 | } 142 | 143 | onOptionSelect (option) { 144 | if (option === this._createPlaceholderOption) { 145 | this.createNewOption(); 146 | } else { 147 | this.select.selectValue(option); 148 | } 149 | } 150 | 151 | focus () { 152 | this.select.focus(); 153 | } 154 | 155 | render () { 156 | const { 157 | ref: refProp, 158 | ...restProps 159 | } = this.props; 160 | 161 | let { children } = this.props; 162 | 163 | // We can't use destructuring default values to set the children, 164 | // because it won't apply work if `children` is null. A falsy check is 165 | // more reliable in real world use-cases. 166 | if (!children) { 167 | children = defaultChildren; 168 | } 169 | 170 | const props = { 171 | ...restProps, 172 | allowCreate: true, 173 | filterOptions: this.filterOptions, 174 | menuRenderer: this.menuRenderer, 175 | onInputChange: this.onInputChange, 176 | onInputKeyDown: this.onInputKeyDown, 177 | ref: (ref) => { 178 | this.select = ref; 179 | 180 | // These values may be needed in between Select mounts (when this.select is null) 181 | if (ref) { 182 | this.labelKey = ref.props.labelKey; 183 | this.valueKey = ref.props.valueKey; 184 | } 185 | if (refProp) { 186 | refProp(ref); 187 | } 188 | } 189 | }; 190 | 191 | return children(props); 192 | } 193 | } 194 | 195 | const defaultChildren = props =>