From 9cfeb4d74aa8a53c90e52ace027254f388fe2b6e Mon Sep 17 00:00:00 2001 From: Jed Watson Date: Mon, 11 Sep 2017 15:06:02 +1000 Subject: [PATCH] Updating build --- dist/react-select.js | 2 +- examples/dist/standalone.html | 2 +- lib/Async.js | 349 +++-- lib/AsyncCreatable.js | 114 +- lib/Creatable.js | 432 +++--- lib/Option.js | 239 ++-- lib/Select.js | 2138 ++++++++++++++++------------- lib/Value.js | 218 +-- lib/index.js | 40 +- lib/utils/defaultArrowRenderer.js | 26 +- lib/utils/defaultClearRenderer.js | 17 +- lib/utils/defaultFilterOptions.js | 30 +- lib/utils/defaultMenuRenderer.js | 69 +- lib/utils/stripDiacritics.js | 8 +- 14 files changed, 2114 insertions(+), 1570 deletions(-) diff --git a/dist/react-select.js b/dist/react-select.js index 20821719ac..5f7aa4b443 100644 --- a/dist/react-select.js +++ b/dist/react-select.js @@ -597,7 +597,7 @@ Value.propTypes = { }; /*! - Copyright (c) 2016 Jed Watson. + Copyright (c) 2017 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/react-select */ diff --git a/examples/dist/standalone.html b/examples/dist/standalone.html index 993547cedb..b0aab42feb 100644 --- a/examples/dist/standalone.html +++ b/examples/dist/standalone.html @@ -10,7 +10,7 @@

Standalone bulid

For usage without babel / browserify / webpack
diff --git a/lib/Async.js b/lib/Async.js index 8da06a8c4c..bb62e264bb 100644 --- a/lib/Async.js +++ b/lib/Async.js @@ -1,34 +1,62 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import Select from './Select'; -import stripDiacritics from './utils/stripDiacritics'; -const propTypes = { - autoload: PropTypes.bool.isRequired, // automatically call the `loadOptions` prop on-mount; defaults to true - cache: PropTypes.any, // object to use to cache results; set to null/false to disable caching - children: PropTypes.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element - ignoreAccents: PropTypes.bool, // strip diacritics when filtering; defaults to true - ignoreCase: PropTypes.bool, // perform case-insensitive filtering; defaults to true - loadOptions: PropTypes.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise - loadingPlaceholder: PropTypes.oneOfType([// replaces the placeholder while options are loading - PropTypes.string, PropTypes.node]), - multi: PropTypes.bool, // multi-value input - noResultsText: PropTypes.oneOfType([// field noResultsText, displayed when no options come back from the server - PropTypes.string, PropTypes.node]), - onChange: PropTypes.func, // onChange handler: function (newValue) {} - onInputChange: PropTypes.func, // optional for keeping track of what is being typed - options: PropTypes.array.isRequired, // array of options - placeholder: PropTypes.oneOfType([// field placeholder, displayed when there's no value (shared with Select) - PropTypes.string, PropTypes.node]), - searchPromptText: PropTypes.oneOfType([// label to prompt for search input - PropTypes.string, PropTypes.node]), - value: PropTypes.any // initial field value +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _Select = require('./Select'); + +var _Select2 = _interopRequireDefault(_Select); + +var _stripDiacritics = require('./utils/stripDiacritics'); + +var _stripDiacritics2 = _interopRequireDefault(_stripDiacritics); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var propTypes = { + autoload: _propTypes2.default.bool.isRequired, // automatically call the `loadOptions` prop on-mount; defaults to true + cache: _propTypes2.default.any, // object to use to cache results; set to null/false to disable caching + children: _propTypes2.default.func.isRequired, // Child function responsible for creating the inner Select component; (props: Object): PropTypes.element + ignoreAccents: _propTypes2.default.bool, // strip diacritics when filtering; defaults to true + ignoreCase: _propTypes2.default.bool, // perform case-insensitive filtering; defaults to true + loadOptions: _propTypes2.default.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise + loadingPlaceholder: _propTypes2.default.oneOfType([// replaces the placeholder while options are loading + _propTypes2.default.string, _propTypes2.default.node]), + multi: _propTypes2.default.bool, // multi-value input + noResultsText: _propTypes2.default.oneOfType([// field noResultsText, displayed when no options come back from the server + _propTypes2.default.string, _propTypes2.default.node]), + onChange: _propTypes2.default.func, // onChange handler: function (newValue) {} + onInputChange: _propTypes2.default.func, // optional for keeping track of what is being typed + options: _propTypes2.default.array.isRequired, // array of options + placeholder: _propTypes2.default.oneOfType([// field placeholder, displayed when there's no value (shared with Select) + _propTypes2.default.string, _propTypes2.default.node]), + searchPromptText: _propTypes2.default.oneOfType([// label to prompt for search input + _propTypes2.default.string, _propTypes2.default.node]), + value: _propTypes2.default.any // initial field value }; -const defaultCache = {}; +var defaultCache = {}; -const defaultProps = { +var defaultProps = { autoload: true, cache: defaultCache, children: defaultChildren, @@ -39,159 +67,206 @@ const defaultProps = { searchPromptText: 'Type to search' }; -export default class Async extends Component { - constructor(props, context) { - super(props, context); +var Async = function (_Component) { + _inherits(Async, _Component); + + function Async(props, context) { + _classCallCheck(this, Async); - this._cache = props.cache === defaultCache ? {} : props.cache; + var _this = _possibleConstructorReturn(this, (Async.__proto__ || Object.getPrototypeOf(Async)).call(this, props, context)); - this.state = { + _this._cache = props.cache === defaultCache ? {} : props.cache; + + _this.state = { isLoading: false, options: props.options }; - this._onInputChange = this._onInputChange.bind(this); + _this._onInputChange = _this._onInputChange.bind(_this); + return _this; } - componentDidMount() { - const { autoload } = this.props; + _createClass(Async, [{ + key: 'componentDidMount', + value: function componentDidMount() { + var autoload = this.props.autoload; - if (autoload) { - this.loadOptions(''); - } - } - componentWillReceiveProps(nextProps) { - if (nextProps.options !== this.props.options) { - this.setState({ - options: nextProps.options - }); + if (autoload) { + this.loadOptions(''); + } } - } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + if (nextProps.options !== this.props.options) { + this.setState({ + options: nextProps.options + }); + } + } + }, { + key: 'clearOptions', + value: function clearOptions() { + this.setState({ options: [] }); + } + }, { + key: 'loadOptions', + value: function loadOptions(inputValue) { + var _this2 = this; - clearOptions() { - this.setState({ options: [] }); - } + var loadOptions = this.props.loadOptions; - loadOptions(inputValue) { - const { loadOptions } = this.props; - const cache = this._cache; + var cache = this._cache; - if (cache && cache.hasOwnProperty(inputValue)) { - this.setState({ - options: cache[inputValue] - }); + if (cache && cache.hasOwnProperty(inputValue)) { + this.setState({ + options: cache[inputValue] + }); - return; - } + return; + } - const callback = (error, data) => { - if (callback === this._callback) { - this._callback = null; + var callback = function callback(error, data) { + if (callback === _this2._callback) { + _this2._callback = null; - const options = data && data.options || []; + var options = data && data.options || []; - if (cache) { - cache[inputValue] = options; + if (cache) { + cache[inputValue] = options; + } + + _this2.setState({ + isLoading: false, + options: options + }); } + }; - this.setState({ - isLoading: false, - options + // Ignore all but the most recent request + this._callback = callback; + + var promise = loadOptions(inputValue, callback); + if (promise) { + promise.then(function (data) { + return callback(null, data); + }, function (error) { + return callback(error); }); } - }; - // Ignore all but the most recent request - this._callback = callback; - - const promise = loadOptions(inputValue, callback); - if (promise) { - promise.then(data => callback(null, data), error => callback(error)); + if (this._callback && !this.state.isLoading) { + this.setState({ + isLoading: true + }); + } } + }, { + key: '_onInputChange', + value: function _onInputChange(inputValue) { + var _props = this.props, + ignoreAccents = _props.ignoreAccents, + ignoreCase = _props.ignoreCase, + onInputChange = _props.onInputChange; + + var transformedInputValue = inputValue; + + if (ignoreAccents) { + transformedInputValue = (0, _stripDiacritics2.default)(transformedInputValue); + } - if (this._callback && !this.state.isLoading) { - this.setState({ - isLoading: true - }); - } - } + if (ignoreCase) { + transformedInputValue = transformedInputValue.toLowerCase(); + } - _onInputChange(inputValue) { - const { ignoreAccents, ignoreCase, onInputChange } = this.props; - let transformedInputValue = inputValue; + if (onInputChange) { + onInputChange(transformedInputValue); + } - if (ignoreAccents) { - transformedInputValue = stripDiacritics(transformedInputValue); - } + this.loadOptions(transformedInputValue); - if (ignoreCase) { - transformedInputValue = transformedInputValue.toLowerCase(); + // Return the original input value to avoid modifying the user's view of the input while typing. + return inputValue; } - - if (onInputChange) { - onInputChange(transformedInputValue); + }, { + key: 'inputValue', + value: function inputValue() { + if (this.select) { + return this.select.state.inputValue; + } + return ''; } + }, { + key: 'noResultsText', + value: function noResultsText() { + var _props2 = this.props, + loadingPlaceholder = _props2.loadingPlaceholder, + noResultsText = _props2.noResultsText, + searchPromptText = _props2.searchPromptText; + var isLoading = this.state.isLoading; - this.loadOptions(transformedInputValue); - // Return the original input value to avoid modifying the user's view of the input while typing. - return inputValue; - } + var inputValue = this.inputValue(); - inputValue() { - if (this.select) { - return this.select.state.inputValue; + if (isLoading) { + return loadingPlaceholder; + } + if (inputValue && noResultsText) { + return noResultsText; + } + return searchPromptText; } - return ''; - } - - noResultsText() { - const { loadingPlaceholder, noResultsText, searchPromptText } = this.props; - const { isLoading } = this.state; - - const inputValue = this.inputValue(); - - if (isLoading) { - return loadingPlaceholder; + }, { + key: 'focus', + value: function focus() { + this.select.focus(); } - if (inputValue && noResultsText) { - return noResultsText; + }, { + key: 'render', + value: function render() { + var _this3 = this; + + var _props3 = this.props, + children = _props3.children, + loadingPlaceholder = _props3.loadingPlaceholder, + placeholder = _props3.placeholder; + var _state = this.state, + isLoading = _state.isLoading, + options = _state.options; + + + var props = { + noResultsText: this.noResultsText(), + placeholder: isLoading ? loadingPlaceholder : placeholder, + options: isLoading && loadingPlaceholder ? [] : options, + ref: function ref(_ref) { + return _this3.select = _ref; + }, + onChange: function onChange(newValues) { + if (_this3.props.multi && _this3.props.value && newValues.length > _this3.props.value.length) { + _this3.clearOptions(); + } + _this3.props.onChange(newValues); + } + }; + + return children(_extends({}, this.props, props, { + isLoading: isLoading, + onInputChange: this._onInputChange + })); } - return searchPromptText; - } + }]); - focus() { - this.select.focus(); - } + return Async; +}(_react.Component); - render() { - const { children, loadingPlaceholder, placeholder } = this.props; - const { isLoading, options } = this.state; - - const props = { - noResultsText: this.noResultsText(), - placeholder: isLoading ? loadingPlaceholder : placeholder, - options: isLoading && loadingPlaceholder ? [] : options, - ref: ref => this.select = ref, - onChange: newValues => { - if (this.props.multi && this.props.value && newValues.length > this.props.value.length) { - this.clearOptions(); - } - this.props.onChange(newValues); - } - }; +exports.default = Async; - return children(_extends({}, this.props, props, { - isLoading, - onInputChange: this._onInputChange - })); - } -} Async.propTypes = propTypes; Async.defaultProps = defaultProps; function defaultChildren(props) { - return React.createElement(Select, props); + return _react2.default.createElement(_Select2.default, props); } \ No newline at end of file diff --git a/lib/AsyncCreatable.js b/lib/AsyncCreatable.js index 7b0dee90fe..0367e758f6 100644 --- a/lib/AsyncCreatable.js +++ b/lib/AsyncCreatable.js @@ -1,45 +1,95 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -import React from 'react'; -import Select from './Select'; -import Async from './Async'; -import Creatable from './Creatable'; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _Select = require('./Select'); + +var _Select2 = _interopRequireDefault(_Select); + +var _Async = require('./Async'); + +var _Async2 = _interopRequireDefault(_Async); + +var _Creatable = require('./Creatable'); + +var _Creatable2 = _interopRequireDefault(_Creatable); -function reduce(obj, props = {}) { - return Object.keys(obj).reduce((props, key) => { - const value = obj[key]; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function reduce(obj) { + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + return Object.keys(obj).reduce(function (props, key) { + var value = obj[key]; if (value !== undefined) props[key] = value; return props; }, props); } -class AsyncCreatableSelect extends React.Component { +var AsyncCreatableSelect = function (_React$Component) { + _inherits(AsyncCreatableSelect, _React$Component); - focus() { - this.select.focus(); + function AsyncCreatableSelect() { + _classCallCheck(this, AsyncCreatableSelect); + + return _possibleConstructorReturn(this, (AsyncCreatableSelect.__proto__ || Object.getPrototypeOf(AsyncCreatableSelect)).apply(this, arguments)); } - render() { - return React.createElement( - Async, - this.props, - asyncProps => React.createElement( - Creatable, + _createClass(AsyncCreatableSelect, [{ + key: 'focus', + value: function focus() { + this.select.focus(); + } + }, { + key: 'render', + value: function render() { + var _this2 = this; + + return _react2.default.createElement( + _Async2.default, this.props, - creatableProps => React.createElement(Select, _extends({}, reduce(asyncProps, reduce(creatableProps, {})), { - onInputChange: input => { - creatableProps.onInputChange(input); - return asyncProps.onInputChange(input); - }, - ref: ref => { - this.select = ref; - creatableProps.ref(ref); - asyncProps.ref(ref); - } - })) - ) - ); - } -}; + function (asyncProps) { + return _react2.default.createElement( + _Creatable2.default, + _this2.props, + function (creatableProps) { + return _react2.default.createElement(_Select2.default, _extends({}, reduce(asyncProps, reduce(creatableProps, {})), { + onInputChange: function onInputChange(input) { + creatableProps.onInputChange(input); + return asyncProps.onInputChange(input); + }, + ref: function ref(_ref) { + _this2.select = _ref; + creatableProps.ref(_ref); + asyncProps.ref(_ref); + } + })); + } + ); + } + ); + } + }]); + + return AsyncCreatableSelect; +}(_react2.default.Component); + +; -export default AsyncCreatableSelect; \ No newline at end of file +exports.default = AsyncCreatableSelect; \ No newline at end of file diff --git a/lib/Creatable.js b/lib/Creatable.js index 5b56983646..6d0badcf5b 100644 --- a/lib/Creatable.js +++ b/lib/Creatable.js @@ -1,206 +1,282 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _Select = require('./Select'); + +var _Select2 = _interopRequireDefault(_Select); + +var _defaultFilterOptions = require('./utils/defaultFilterOptions'); + +var _defaultFilterOptions2 = _interopRequireDefault(_defaultFilterOptions); + +var _defaultMenuRenderer = require('./utils/defaultMenuRenderer'); + +var _defaultMenuRenderer2 = _interopRequireDefault(_defaultMenuRenderer); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } -import React from 'react'; -import PropTypes from 'prop-types'; -import Select from './Select'; -import defaultFilterOptions from './utils/defaultFilterOptions'; -import defaultMenuRenderer from './utils/defaultMenuRenderer'; - -class CreatableSelect extends React.Component { - constructor(props, context) { - super(props, context); - - this.filterOptions = this.filterOptions.bind(this); - this.menuRenderer = this.menuRenderer.bind(this); - this.onInputKeyDown = this.onInputKeyDown.bind(this); - this.onInputChange = this.onInputChange.bind(this); - this.onOptionSelect = this.onOptionSelect.bind(this); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var CreatableSelect = function (_React$Component) { + _inherits(CreatableSelect, _React$Component); + + function CreatableSelect(props, context) { + _classCallCheck(this, CreatableSelect); + + var _this = _possibleConstructorReturn(this, (CreatableSelect.__proto__ || Object.getPrototypeOf(CreatableSelect)).call(this, props, context)); + + _this.filterOptions = _this.filterOptions.bind(_this); + _this.menuRenderer = _this.menuRenderer.bind(_this); + _this.onInputKeyDown = _this.onInputKeyDown.bind(_this); + _this.onInputChange = _this.onInputChange.bind(_this); + _this.onOptionSelect = _this.onOptionSelect.bind(_this); + return _this; } - createNewOption() { - const { - isValidNewOption, - newOptionCreator, - onNewOptionClick, - options = [], - shouldKeyDownEventCreateNewOption - } = this.props; - - if (isValidNewOption({ label: this.inputValue })) { - const option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); - const isOptionUnique = this.isOptionUnique({ option }); - - // Don't add the same option twice. - if (isOptionUnique) { - if (onNewOptionClick) { - onNewOptionClick(option); - } else { - options.unshift(option); - - this.select.selectValue(option); + _createClass(CreatableSelect, [{ + key: 'createNewOption', + value: function createNewOption() { + var _props = this.props, + isValidNewOption = _props.isValidNewOption, + newOptionCreator = _props.newOptionCreator, + onNewOptionClick = _props.onNewOptionClick, + _props$options = _props.options, + options = _props$options === undefined ? [] : _props$options, + shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption; + + + if (isValidNewOption({ label: this.inputValue })) { + var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); + var _isOptionUnique = this.isOptionUnique({ option: option }); + + // Don't add the same option twice. + if (_isOptionUnique) { + if (onNewOptionClick) { + onNewOptionClick(option); + } else { + options.unshift(option); + + this.select.selectValue(option); + } } } } - } + }, { + key: 'filterOptions', + value: function filterOptions() { + var _props2 = this.props, + filterOptions = _props2.filterOptions, + isValidNewOption = _props2.isValidNewOption, + options = _props2.options, + promptTextCreator = _props2.promptTextCreator; - filterOptions(...params) { - const { filterOptions, isValidNewOption, options, promptTextCreator } = this.props; + // TRICKY Check currently selected options as well. + // Don't display a create-prompt for a value that's selected. + // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array. - // TRICKY Check currently selected options as well. - // Don't display a create-prompt for a value that's selected. - // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array. - const excludeOptions = params[2] || []; + var excludeOptions = (arguments.length <= 2 ? undefined : arguments[2]) || []; - const filteredOptions = filterOptions(...params) || []; - - if (isValidNewOption({ label: this.inputValue })) { - const { newOptionCreator } = this.props; - - const option = newOptionCreator({ - label: this.inputValue, - labelKey: this.labelKey, - valueKey: this.valueKey - }); + var filteredOptions = filterOptions.apply(undefined, arguments) || []; - // TRICKY Compare to all options (not just filtered options) in case option has already been selected). - // For multi-selects, this would remove it from the filtered list. - const isOptionUnique = this.isOptionUnique({ - option, - options: excludeOptions.concat(filteredOptions) - }); + if (isValidNewOption({ label: this.inputValue })) { + var _newOptionCreator = this.props.newOptionCreator; - if (isOptionUnique) { - const prompt = promptTextCreator(this.inputValue); - this._createPlaceholderOption = newOptionCreator({ - label: prompt, + var option = _newOptionCreator({ + label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); - filteredOptions.unshift(this._createPlaceholderOption); + // TRICKY Compare to all options (not just filtered options) in case option has already been selected). + // For multi-selects, this would remove it from the filtered list. + var _isOptionUnique2 = this.isOptionUnique({ + option: option, + options: excludeOptions.concat(filteredOptions) + }); + + if (_isOptionUnique2) { + var prompt = promptTextCreator(this.inputValue); + + this._createPlaceholderOption = _newOptionCreator({ + label: prompt, + labelKey: this.labelKey, + valueKey: this.valueKey + }); + + filteredOptions.unshift(this._createPlaceholderOption); + } } + + return filteredOptions; } + }, { + key: 'isOptionUnique', + value: function isOptionUnique(_ref) { + var option = _ref.option, + options = _ref.options; + var isOptionUnique = this.props.isOptionUnique; - return filteredOptions; - } - isOptionUnique({ - option, - options - }) { - const { isOptionUnique } = this.props; + options = options || this.select.filterOptions(); - options = options || this.select.filterOptions(); + return isOptionUnique({ + labelKey: this.labelKey, + option: option, + options: options, + valueKey: this.valueKey + }); + } + }, { + key: 'menuRenderer', + value: function menuRenderer(params) { + var menuRenderer = this.props.menuRenderer; - return isOptionUnique({ - labelKey: this.labelKey, - option, - options, - valueKey: this.valueKey - }); - } - menuRenderer(params) { - const { menuRenderer } = this.props; + return menuRenderer(_extends({}, params, { + onSelect: this.onOptionSelect, + selectValue: this.onOptionSelect + })); + } + }, { + key: 'onInputChange', + value: function onInputChange(input) { + var onInputChange = this.props.onInputChange; - return menuRenderer(_extends({}, params, { - onSelect: this.onOptionSelect, - selectValue: this.onOptionSelect - })); - } - onInputChange(input) { - const { onInputChange } = this.props; + if (onInputChange) { + onInputChange(input); + } - if (onInputChange) { - onInputChange(input); + // This value may be needed in between Select mounts (when this.select is null) + this.inputValue = input; } + }, { + key: 'onInputKeyDown', + value: function onInputKeyDown(event) { + var _props3 = this.props, + shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption, + onInputKeyDown = _props3.onInputKeyDown; + + var focusedOption = this.select.getFocusedOption(); + + if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) { + this.createNewOption(); + + // Prevent decorated Select from doing anything additional with this keyDown event + event.preventDefault(); + } else if (onInputKeyDown) { + onInputKeyDown(event); + } + } + }, { + key: 'onOptionSelect', + value: function onOptionSelect(option, event) { + if (option === this._createPlaceholderOption) { + this.createNewOption(); + } else { + this.select.selectValue(option); + } + } + }, { + key: 'focus', + value: function focus() { + this.select.focus(); + } + }, { + key: 'render', + value: function render() { + var _this2 = this; - // This value may be needed in between Select mounts (when this.select is null) - this.inputValue = input; - } - - onInputKeyDown(event) { - const { shouldKeyDownEventCreateNewOption, onInputKeyDown } = this.props; - const focusedOption = this.select.getFocusedOption(); + var _props4 = this.props, + newOptionCreator = _props4.newOptionCreator, + shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption, + restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']); - if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) { - this.createNewOption(); + var children = this.props.children; - // Prevent decorated Select from doing anything additional with this keyDown event - event.preventDefault(); - } else if (onInputKeyDown) { - onInputKeyDown(event); - } - } + // We can't use destructuring default values to set the children, + // because it won't apply work if `children` is null. A falsy check is + // more reliable in real world use-cases. - onOptionSelect(option, event) { - if (option === this._createPlaceholderOption) { - this.createNewOption(); - } else { - this.select.selectValue(option); - } - } + if (!children) { + children = defaultChildren; + } - focus() { - this.select.focus(); - } + var props = _extends({}, restProps, { + allowCreate: true, + filterOptions: this.filterOptions, + menuRenderer: this.menuRenderer, + onInputChange: this.onInputChange, + onInputKeyDown: this.onInputKeyDown, + ref: function ref(_ref2) { + _this2.select = _ref2; + + // These values may be needed in between Select mounts (when this.select is null) + if (_ref2) { + _this2.labelKey = _ref2.props.labelKey; + _this2.valueKey = _ref2.props.valueKey; + } + } + }); - render() { - const _props = this.props, - { - newOptionCreator, - shouldKeyDownEventCreateNewOption - } = _props, - restProps = _objectWithoutProperties(_props, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']); - - let { children } = this.props; - - // We can't use destructuring default values to set the children, - // because it won't apply work if `children` is null. A falsy check is - // more reliable in real world use-cases. - if (!children) { - children = defaultChildren; + return children(props); } + }]); - const props = _extends({}, restProps, { - allowCreate: true, - filterOptions: this.filterOptions, - menuRenderer: this.menuRenderer, - onInputChange: this.onInputChange, - onInputKeyDown: this.onInputKeyDown, - ref: ref => { - this.select = ref; - - // These values may be needed in between Select mounts (when this.select is null) - if (ref) { - this.labelKey = ref.props.labelKey; - this.valueKey = ref.props.valueKey; - } - } - }); + return CreatableSelect; +}(_react2.default.Component); - return children(props); - } -}; +; function defaultChildren(props) { - return React.createElement(Select, props); + return _react2.default.createElement(_Select2.default, props); }; -function isOptionUnique({ option, options, labelKey, valueKey }) { - return options.filter(existingOption => existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey]).length === 0; +function isOptionUnique(_ref3) { + var option = _ref3.option, + options = _ref3.options, + labelKey = _ref3.labelKey, + valueKey = _ref3.valueKey; + + return options.filter(function (existingOption) { + return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey]; + }).length === 0; }; -function isValidNewOption({ label }) { +function isValidNewOption(_ref4) { + var label = _ref4.label; + return !!label; }; -function newOptionCreator({ label, labelKey, valueKey }) { - const option = {}; +function newOptionCreator(_ref5) { + var label = _ref5.label, + labelKey = _ref5.labelKey, + valueKey = _ref5.valueKey; + + var option = {}; option[valueKey] = label; option[labelKey] = label; option.className = 'Select-create-option-placeholder'; @@ -208,10 +284,12 @@ function newOptionCreator({ label, labelKey, valueKey }) { }; function promptTextCreator(label) { - return `Create option "${label}"`; + return 'Create option "' + label + '"'; } -function shouldKeyDownEventCreateNewOption({ keyCode }) { +function shouldKeyDownEventCreateNewOption(_ref6) { + var keyCode = _ref6.keyCode; + switch (keyCode) { case 9: // TAB case 13: // ENTER @@ -231,58 +309,58 @@ CreatableSelect.promptTextCreator = promptTextCreator; CreatableSelect.shouldKeyDownEventCreateNewOption = shouldKeyDownEventCreateNewOption; CreatableSelect.defaultProps = { - filterOptions: defaultFilterOptions, - isOptionUnique, - isValidNewOption, - menuRenderer: defaultMenuRenderer, - newOptionCreator, - promptTextCreator, - shouldKeyDownEventCreateNewOption + filterOptions: _defaultFilterOptions2.default, + isOptionUnique: isOptionUnique, + isValidNewOption: isValidNewOption, + menuRenderer: _defaultMenuRenderer2.default, + newOptionCreator: newOptionCreator, + promptTextCreator: promptTextCreator, + shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption }; CreatableSelect.propTypes = { // Child function responsible for creating the inner Select component // This component can be used to compose HOCs (eg Creatable and Async) // (props: Object): PropTypes.element - children: PropTypes.func, + children: _propTypes2.default.func, // See Select.propTypes.filterOptions - filterOptions: PropTypes.any, + filterOptions: _propTypes2.default.any, // Searches for any matching option within the set of options. // This function prevents duplicate options from being created. // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean - isOptionUnique: PropTypes.func, + isOptionUnique: _propTypes2.default.func, // Determines if the current input text represents a valid option. // ({ label: string }): boolean - isValidNewOption: PropTypes.func, + isValidNewOption: _propTypes2.default.func, // See Select.propTypes.menuRenderer - menuRenderer: PropTypes.any, + menuRenderer: _propTypes2.default.any, // Factory to create new option. // ({ label: string, labelKey: string, valueKey: string }): Object - newOptionCreator: PropTypes.func, + newOptionCreator: _propTypes2.default.func, // input change handler: function (inputValue) {} - onInputChange: PropTypes.func, + onInputChange: _propTypes2.default.func, // input keyDown handler: function (event) {} - onInputKeyDown: PropTypes.func, + onInputKeyDown: _propTypes2.default.func, // new option click handler: function (option) {} - onNewOptionClick: PropTypes.func, + onNewOptionClick: _propTypes2.default.func, // See Select.propTypes.options - options: PropTypes.array, + options: _propTypes2.default.array, // Creates prompt/placeholder option text. // (filterText: string): string - promptTextCreator: PropTypes.func, + promptTextCreator: _propTypes2.default.func, // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. - shouldKeyDownEventCreateNewOption: PropTypes.func + shouldKeyDownEventCreateNewOption: _propTypes2.default.func }; -export default CreatableSelect; \ No newline at end of file +exports.default = CreatableSelect; \ No newline at end of file diff --git a/lib/Option.js b/lib/Option.js index c59bd1cd18..71784feb51 100644 --- a/lib/Option.js +++ b/lib/Option.js @@ -1,112 +1,159 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; - -class Option extends React.Component { - - constructor(props) { - super(props); - - this.handleMouseDown = this.handleMouseDown.bind(this); - this.handleMouseEnter = this.handleMouseEnter.bind(this); - this.handleMouseMove = this.handleMouseMove.bind(this); - this.handleTouchStart = this.handleTouchStart.bind(this); - this.handleTouchEnd = this.handleTouchEnd.bind(this); - this.handleTouchMove = this.handleTouchMove.bind(this); - this.onFocus = this.onFocus.bind(this); - } +'use strict'; - blockEvent(event) { - event.preventDefault(); - event.stopPropagation(); - if (event.target.tagName !== 'A' || !('href' in event.target)) { - return; - } - if (event.target.target) { - window.open(event.target.href, event.target.target); - } else { - window.location.href = event.target.href; - } - } +Object.defineProperty(exports, "__esModule", { + value: true +}); - handleMouseDown(event) { - event.preventDefault(); - event.stopPropagation(); - this.props.onSelect(this.props.option, event); - } +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; }; }(); - handleMouseEnter(event) { - this.onFocus(event); - } +var _react = require('react'); - handleMouseMove(event) { - this.onFocus(event); - } +var _react2 = _interopRequireDefault(_react); - handleTouchEnd(event) { - // Check if the view is being dragged, In this case - // we don't want to fire the click event (because the user only wants to scroll) - if (this.dragging) return; +var _propTypes = require('prop-types'); - this.handleMouseDown(event); - } +var _propTypes2 = _interopRequireDefault(_propTypes); - handleTouchMove(event) { - // Set a flag that the view is being dragged - this.dragging = true; - } +var _classnames = require('classnames'); + +var _classnames2 = _interopRequireDefault(_classnames); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Option = function (_React$Component) { + _inherits(Option, _React$Component); - handleTouchStart(event) { - // Set a flag that the view is not being dragged - this.dragging = false; + function Option(props) { + _classCallCheck(this, Option); + + var _this = _possibleConstructorReturn(this, (Option.__proto__ || Object.getPrototypeOf(Option)).call(this, props)); + + _this.handleMouseDown = _this.handleMouseDown.bind(_this); + _this.handleMouseEnter = _this.handleMouseEnter.bind(_this); + _this.handleMouseMove = _this.handleMouseMove.bind(_this); + _this.handleTouchStart = _this.handleTouchStart.bind(_this); + _this.handleTouchEnd = _this.handleTouchEnd.bind(_this); + _this.handleTouchMove = _this.handleTouchMove.bind(_this); + _this.onFocus = _this.onFocus.bind(_this); + return _this; } - onFocus(event) { - if (!this.props.isFocused) { - this.props.onFocus(this.props.option, event); + _createClass(Option, [{ + key: 'blockEvent', + value: function blockEvent(event) { + event.preventDefault(); + event.stopPropagation(); + if (event.target.tagName !== 'A' || !('href' in event.target)) { + return; + } + if (event.target.target) { + window.open(event.target.href, event.target.target); + } else { + window.location.href = event.target.href; + } } - } + }, { + key: 'handleMouseDown', + value: function handleMouseDown(event) { + event.preventDefault(); + event.stopPropagation(); + this.props.onSelect(this.props.option, event); + } + }, { + key: 'handleMouseEnter', + value: function handleMouseEnter(event) { + this.onFocus(event); + } + }, { + key: 'handleMouseMove', + value: function handleMouseMove(event) { + this.onFocus(event); + } + }, { + key: 'handleTouchEnd', + value: function handleTouchEnd(event) { + // Check if the view is being dragged, In this case + // we don't want to fire the click event (because the user only wants to scroll) + if (this.dragging) return; + + this.handleMouseDown(event); + } + }, { + key: 'handleTouchMove', + value: function handleTouchMove(event) { + // Set a flag that the view is being dragged + this.dragging = true; + } + }, { + key: 'handleTouchStart', + value: function handleTouchStart(event) { + // Set a flag that the view is not being dragged + this.dragging = false; + } + }, { + key: 'onFocus', + value: function onFocus(event) { + if (!this.props.isFocused) { + this.props.onFocus(this.props.option, event); + } + } + }, { + key: 'render', + value: function render() { + var _props = this.props, + option = _props.option, + instancePrefix = _props.instancePrefix, + optionIndex = _props.optionIndex; + + var className = (0, _classnames2.default)(this.props.className, option.className); + + return option.disabled ? _react2.default.createElement( + 'div', + { className: className, + onMouseDown: this.blockEvent, + onClick: this.blockEvent }, + this.props.children + ) : _react2.default.createElement( + 'div', + { className: className, + style: option.style, + role: 'option', + onMouseDown: this.handleMouseDown, + onMouseEnter: this.handleMouseEnter, + onMouseMove: this.handleMouseMove, + onTouchStart: this.handleTouchStart, + onTouchMove: this.handleTouchMove, + onTouchEnd: this.handleTouchEnd, + id: instancePrefix + '-option-' + optionIndex, + title: option.title }, + this.props.children + ); + } + }]); - render() { - var { option, instancePrefix, optionIndex } = this.props; - var className = classNames(this.props.className, option.className); - - return option.disabled ? React.createElement( - 'div', - { className: className, - onMouseDown: this.blockEvent, - onClick: this.blockEvent }, - this.props.children - ) : React.createElement( - 'div', - { className: className, - style: option.style, - role: 'option', - onMouseDown: this.handleMouseDown, - onMouseEnter: this.handleMouseEnter, - onMouseMove: this.handleMouseMove, - onTouchStart: this.handleTouchStart, - onTouchMove: this.handleTouchMove, - onTouchEnd: this.handleTouchEnd, - id: instancePrefix + '-option-' + optionIndex, - title: option.title }, - this.props.children - ); - } -}; + return Option; +}(_react2.default.Component); + +; Option.propTypes = { - children: PropTypes.node, - className: PropTypes.string, // className (based on mouse position) - instancePrefix: PropTypes.string.isRequired, // unique prefix for the ids (used for aria) - isDisabled: PropTypes.bool, // the option is disabled - isFocused: PropTypes.bool, // the option is focused - isSelected: PropTypes.bool, // the option is selected - onFocus: PropTypes.func, // method to handle mouseEnter on option element - onSelect: PropTypes.func, // method to handle click on option element - onUnfocus: PropTypes.func, // method to handle mouseLeave on option element - option: PropTypes.object.isRequired, // object that is base for that option - optionIndex: PropTypes.number // index of the option, used to generate unique ids for aria + children: _propTypes2.default.node, + className: _propTypes2.default.string, // className (based on mouse position) + instancePrefix: _propTypes2.default.string.isRequired, // unique prefix for the ids (used for aria) + isDisabled: _propTypes2.default.bool, // the option is disabled + isFocused: _propTypes2.default.bool, // the option is focused + isSelected: _propTypes2.default.bool, // the option is selected + onFocus: _propTypes2.default.func, // method to handle mouseEnter on option element + onSelect: _propTypes2.default.func, // method to handle click on option element + onUnfocus: _propTypes2.default.func, // method to handle mouseLeave on option element + option: _propTypes2.default.object.isRequired, // object that is base for that option + optionIndex: _propTypes2.default.number // index of the option, used to generate unique ids for aria }; -export default Option; \ No newline at end of file +exports.default = Option; \ No newline at end of file diff --git a/lib/Select.js b/lib/Select.js index 3240a3a0ad..abe7a24419 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -1,28 +1,78 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*! + Copyright (c) 2017 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/react-select + */ + + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _reactDom = require('react-dom'); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +var _reactInputAutosize = require('react-input-autosize'); + +var _reactInputAutosize2 = _interopRequireDefault(_reactInputAutosize); + +var _classnames = require('classnames'); + +var _classnames2 = _interopRequireDefault(_classnames); + +var _defaultArrowRenderer = require('./utils/defaultArrowRenderer'); + +var _defaultArrowRenderer2 = _interopRequireDefault(_defaultArrowRenderer); + +var _defaultFilterOptions = require('./utils/defaultFilterOptions'); + +var _defaultFilterOptions2 = _interopRequireDefault(_defaultFilterOptions); + +var _defaultMenuRenderer = require('./utils/defaultMenuRenderer'); + +var _defaultMenuRenderer2 = _interopRequireDefault(_defaultMenuRenderer); + +var _defaultClearRenderer = require('./utils/defaultClearRenderer'); + +var _defaultClearRenderer2 = _interopRequireDefault(_defaultClearRenderer); + +var _Option = require('./Option'); + +var _Option2 = _interopRequireDefault(_Option); + +var _Value = require('./Value'); + +var _Value2 = _interopRequireDefault(_Value); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } -/*! - Copyright (c) 2016 Jed Watson. - Licensed under the MIT License (MIT), see - http://jedwatson.github.io/react-select -*/ -import React from 'react'; -import PropTypes from 'prop-types'; -import ReactDOM from 'react-dom'; -import AutosizeInput from 'react-input-autosize'; -import classNames from 'classnames'; - -import defaultArrowRenderer from './utils/defaultArrowRenderer'; -import defaultFilterOptions from './utils/defaultFilterOptions'; -import defaultMenuRenderer from './utils/defaultMenuRenderer'; -import defaultClearRenderer from './utils/defaultClearRenderer'; - -import Option from './Option'; -import Value from './Value'; +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function stringifyValue(value) { - const valueType = typeof value; + var valueType = typeof value === 'undefined' ? 'undefined' : _typeof(value); if (valueType === 'string') { return value; } else if (valueType === 'object') { @@ -34,1109 +84,1229 @@ function stringifyValue(value) { } } -const stringOrNode = PropTypes.oneOfType([PropTypes.string, PropTypes.node]); - -let instanceId = 1; - -class Select extends React.Component { - - constructor(props) { - super(props); - - this.handleTouchOutside = this.handleTouchOutside.bind(this); - this.handleTouchMove = this.handleTouchMove.bind(this); - this.handleTouchStart = this.handleTouchStart.bind(this); - this.handleTouchEnd = this.handleTouchEnd.bind(this); - this.handleTouchEndClearValue = this.handleTouchEndClearValue.bind(this); - this.handleMouseDown = this.handleMouseDown.bind(this); - this.handleMouseDownOnArrow = this.handleMouseDownOnArrow.bind(this); - this.handleMouseDownOnMenu = this.handleMouseDownOnMenu.bind(this); - this.handleInputFocus = this.handleInputFocus.bind(this); - this.handleInputBlur = this.handleInputBlur.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - this.handleInputValueChange = this.handleInputValueChange.bind(this); - this.handleKeyDown = this.handleKeyDown.bind(this); - this.handleValueClick = this.handleValueClick.bind(this); - this.handleMenuScroll = this.handleMenuScroll.bind(this); - this.handleRequired = this.handleRequired.bind(this); - this.getOptionLabel = this.getOptionLabel.bind(this); - this.onOptionRef = this.onOptionRef.bind(this); - this.clearValue = this.clearValue.bind(this); - this.removeValue = this.removeValue.bind(this); - this.selectValue = this.selectValue.bind(this); - this.focusOption = this.focusOption.bind(this); - - this.state = { +var stringOrNode = _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.node]); + +var instanceId = 1; + +var Select = function (_React$Component) { + _inherits(Select, _React$Component); + + function Select(props) { + _classCallCheck(this, Select); + + var _this = _possibleConstructorReturn(this, (Select.__proto__ || Object.getPrototypeOf(Select)).call(this, props)); + + _this.handleTouchOutside = _this.handleTouchOutside.bind(_this); + _this.handleTouchMove = _this.handleTouchMove.bind(_this); + _this.handleTouchStart = _this.handleTouchStart.bind(_this); + _this.handleTouchEnd = _this.handleTouchEnd.bind(_this); + _this.handleTouchEndClearValue = _this.handleTouchEndClearValue.bind(_this); + _this.handleMouseDown = _this.handleMouseDown.bind(_this); + _this.handleMouseDownOnArrow = _this.handleMouseDownOnArrow.bind(_this); + _this.handleMouseDownOnMenu = _this.handleMouseDownOnMenu.bind(_this); + _this.handleInputFocus = _this.handleInputFocus.bind(_this); + _this.handleInputBlur = _this.handleInputBlur.bind(_this); + _this.handleInputChange = _this.handleInputChange.bind(_this); + _this.handleInputValueChange = _this.handleInputValueChange.bind(_this); + _this.handleKeyDown = _this.handleKeyDown.bind(_this); + _this.handleValueClick = _this.handleValueClick.bind(_this); + _this.handleMenuScroll = _this.handleMenuScroll.bind(_this); + _this.handleRequired = _this.handleRequired.bind(_this); + _this.getOptionLabel = _this.getOptionLabel.bind(_this); + _this.onOptionRef = _this.onOptionRef.bind(_this); + _this.clearValue = _this.clearValue.bind(_this); + _this.removeValue = _this.removeValue.bind(_this); + _this.selectValue = _this.selectValue.bind(_this); + _this.focusOption = _this.focusOption.bind(_this); + + _this.state = { inputValue: '', isFocused: false, isOpen: false, isPseudoFocused: false, required: false }; + return _this; } - componentWillMount() { - this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-'; - const valueArray = this.getValueArray(this.props.value); - - if (this.props.required) { - this.setState({ - required: this.handleRequired(valueArray[0], this.props.multi) - }); - } - } - - componentDidMount() { - if (this.props.autofocus) { - this.focus(); - } - } - - componentWillReceiveProps(nextProps) { - const valueArray = this.getValueArray(nextProps.value, nextProps); - - if (nextProps.required) { - this.setState({ - required: this.handleRequired(valueArray[0], nextProps.multi) - }); - } else if (this.props.required) { - // Used to be required but it's not any more - this.setState({ required: false }); - } - } - - componentWillUpdate(nextProps, nextState) { - if (nextState.isOpen !== this.state.isOpen) { - this.toggleTouchOutsideEvent(nextState.isOpen); - const handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose; - handler && handler(); - } - } - - componentDidUpdate(prevProps, prevState) { - // focus to the selected option - if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) { - let focusedOptionNode = ReactDOM.findDOMNode(this.focused); - let menuNode = ReactDOM.findDOMNode(this.menu); - menuNode.scrollTop = focusedOptionNode.offsetTop; - this.hasScrolledToOption = true; - } else if (!this.state.isOpen) { - this.hasScrolledToOption = false; - } + _createClass(Select, [{ + key: 'componentWillMount', + value: function componentWillMount() { + this._instancePrefix = 'react-select-' + (this.props.instanceId || ++instanceId) + '-'; + var valueArray = this.getValueArray(this.props.value); - if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) { - this._scrollToFocusedOptionOnUpdate = false; - var focusedDOM = ReactDOM.findDOMNode(this.focused); - var menuDOM = ReactDOM.findDOMNode(this.menu); - var focusedRect = focusedDOM.getBoundingClientRect(); - var menuRect = menuDOM.getBoundingClientRect(); - if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) { - menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight; + if (this.props.required) { + this.setState({ + required: this.handleRequired(valueArray[0], this.props.multi) + }); } } - if (this.props.scrollMenuIntoView && this.menuContainer) { - var menuContainerRect = this.menuContainer.getBoundingClientRect(); - if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) { - window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight); + }, { + key: 'componentDidMount', + value: function componentDidMount() { + if (this.props.autofocus) { + this.focus(); } } - if (prevProps.disabled !== this.props.disabled) { - this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state - this.closeMenu(); + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + var valueArray = this.getValueArray(nextProps.value, nextProps); + + if (nextProps.required) { + this.setState({ + required: this.handleRequired(valueArray[0], nextProps.multi) + }); + } else if (this.props.required) { + // Used to be required but it's not any more + this.setState({ required: false }); + } } - } - - componentWillUnmount() { - if (!document.removeEventListener && document.detachEvent) { - document.detachEvent('ontouchstart', this.handleTouchOutside); - } else { - document.removeEventListener('touchstart', this.handleTouchOutside); + }, { + key: 'componentWillUpdate', + value: function componentWillUpdate(nextProps, nextState) { + if (nextState.isOpen !== this.state.isOpen) { + this.toggleTouchOutsideEvent(nextState.isOpen); + var handler = nextState.isOpen ? nextProps.onOpen : nextProps.onClose; + handler && handler(); + } } - } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate(prevProps, prevState) { + // focus to the selected option + if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) { + var focusedOptionNode = _reactDom2.default.findDOMNode(this.focused); + var menuNode = _reactDom2.default.findDOMNode(this.menu); + menuNode.scrollTop = focusedOptionNode.offsetTop; + this.hasScrolledToOption = true; + } else if (!this.state.isOpen) { + this.hasScrolledToOption = false; + } - toggleTouchOutsideEvent(enabled) { - if (enabled) { - if (!document.addEventListener && document.attachEvent) { - document.attachEvent('ontouchstart', this.handleTouchOutside); - } else { - document.addEventListener('touchstart', this.handleTouchOutside); + if (this._scrollToFocusedOptionOnUpdate && this.focused && this.menu) { + this._scrollToFocusedOptionOnUpdate = false; + var focusedDOM = _reactDom2.default.findDOMNode(this.focused); + var menuDOM = _reactDom2.default.findDOMNode(this.menu); + var focusedRect = focusedDOM.getBoundingClientRect(); + var menuRect = menuDOM.getBoundingClientRect(); + if (focusedRect.bottom > menuRect.bottom || focusedRect.top < menuRect.top) { + menuDOM.scrollTop = focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight; + } + } + if (this.props.scrollMenuIntoView && this.menuContainer) { + var menuContainerRect = this.menuContainer.getBoundingClientRect(); + if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) { + window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight); + } + } + if (prevProps.disabled !== this.props.disabled) { + this.setState({ isFocused: false }); // eslint-disable-line react/no-did-update-set-state + this.closeMenu(); } - } else { + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { if (!document.removeEventListener && document.detachEvent) { document.detachEvent('ontouchstart', this.handleTouchOutside); } else { document.removeEventListener('touchstart', this.handleTouchOutside); } } - } - - handleTouchOutside(event) { - // handle touch outside on ios to dismiss menu - if (this.wrapper && !this.wrapper.contains(event.target)) { - this.closeMenu(); + }, { + key: 'toggleTouchOutsideEvent', + value: function toggleTouchOutsideEvent(enabled) { + if (enabled) { + if (!document.addEventListener && document.attachEvent) { + document.attachEvent('ontouchstart', this.handleTouchOutside); + } else { + document.addEventListener('touchstart', this.handleTouchOutside); + } + } else { + if (!document.removeEventListener && document.detachEvent) { + document.detachEvent('ontouchstart', this.handleTouchOutside); + } else { + document.removeEventListener('touchstart', this.handleTouchOutside); + } + } } - } - - focus() { - if (!this.input) return; - this.input.focus(); - } - - blurInput() { - if (!this.input) return; - this.input.blur(); - } - - handleTouchMove(event) { - // Set a flag that the view is being dragged - this.dragging = true; - } + }, { + key: 'handleTouchOutside', + value: function handleTouchOutside(event) { + // handle touch outside on ios to dismiss menu + if (this.wrapper && !this.wrapper.contains(event.target)) { + this.closeMenu(); + } + } + }, { + key: 'focus', + value: function focus() { + if (!this.input) return; + this.input.focus(); + } + }, { + key: 'blurInput', + value: function blurInput() { + if (!this.input) return; + this.input.blur(); + } + }, { + key: 'handleTouchMove', + value: function handleTouchMove(event) { + // Set a flag that the view is being dragged + this.dragging = true; + } + }, { + key: 'handleTouchStart', + value: function handleTouchStart(event) { + // Set a flag that the view is not being dragged + this.dragging = false; + } + }, { + key: 'handleTouchEnd', + value: function handleTouchEnd(event) { + // Check if the view is being dragged, In this case + // we don't want to fire the click event (because the user only wants to scroll) + if (this.dragging) return; + + // Fire the mouse events + this.handleMouseDown(event); + } + }, { + key: 'handleTouchEndClearValue', + value: function handleTouchEndClearValue(event) { + // Check if the view is being dragged, In this case + // we don't want to fire the click event (because the user only wants to scroll) + if (this.dragging) return; + + // Clear the value + this.clearValue(event); + } + }, { + key: 'handleMouseDown', + value: function handleMouseDown(event) { + // if the event was triggered by a mousedown and not the primary + // button, or if the component is disabled, ignore it. + if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { + return; + } - handleTouchStart(event) { - // Set a flag that the view is not being dragged - this.dragging = false; - } + if (event.target.tagName === 'INPUT') { + return; + } - handleTouchEnd(event) { - // Check if the view is being dragged, In this case - // we don't want to fire the click event (because the user only wants to scroll) - if (this.dragging) return; + // prevent default event handlers + event.stopPropagation(); + event.preventDefault(); + + // for the non-searchable select, toggle the menu + if (!this.props.searchable) { + // TODO: This code means that if a select is searchable, onClick the options menu will not appear, only on subsequent click will it open. + this.focus(); + return this.setState({ + isOpen: !this.state.isOpen + }); + } - // Fire the mouse events - this.handleMouseDown(event); - } + if (this.state.isFocused) { + // On iOS, we can get into a state where we think the input is focused but it isn't really, + // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event. + // Call focus() again here to be safe. + this.focus(); - handleTouchEndClearValue(event) { - // Check if the view is being dragged, In this case - // we don't want to fire the click event (because the user only wants to scroll) - if (this.dragging) return; + var input = this.input; + if (typeof input.getInput === 'function') { + // Get the actual DOM input if the ref is an component + input = input.getInput(); + } - // Clear the value - this.clearValue(event); - } + // clears the value so that the cursor will be at the end of input when the component re-renders + input.value = ''; - handleMouseDown(event) { - // if the event was triggered by a mousedown and not the primary - // button, or if the component is disabled, ignore it. - if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { - return; + // if the input is focused, ensure the menu is open + this.setState({ + isOpen: true, + isPseudoFocused: false + }); + } else { + // otherwise, focus the input and open the menu + this._openAfterFocus = this.props.openAfterFocus; + this.focus(); + } } - - if (event.target.tagName === 'INPUT') { - return; + }, { + key: 'handleMouseDownOnArrow', + value: function handleMouseDownOnArrow(event) { + // if the event was triggered by a mousedown and not the primary + // button, or if the component is disabled, ignore it. + if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { + return; + } + // If the menu isn't open, let the event bubble to the main handleMouseDown + if (!this.state.isOpen) { + return; + } + // prevent default event handlers + event.stopPropagation(); + event.preventDefault(); + // close the menu + this.closeMenu(); } + }, { + key: 'handleMouseDownOnMenu', + value: function handleMouseDownOnMenu(event) { + // if the event was triggered by a mousedown and not the primary + // button, or if the component is disabled, ignore it. + if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { + return; + } + event.stopPropagation(); + event.preventDefault(); - // prevent default event handlers - event.stopPropagation(); - event.preventDefault(); - - // for the non-searchable select, toggle the menu - if (!this.props.searchable) { - // TODO: This code means that if a select is searchable, onClick the options menu will not appear, only on subsequent click will it open. + this._openAfterFocus = true; this.focus(); - return this.setState({ - isOpen: !this.state.isOpen - }); } - - if (this.state.isFocused) { - // On iOS, we can get into a state where we think the input is focused but it isn't really, - // since iOS ignores programmatic calls to input.focus() that weren't triggered by a click event. - // Call focus() again here to be safe. - this.focus(); - - let input = this.input; - if (typeof input.getInput === 'function') { - // Get the actual DOM input if the ref is an component - input = input.getInput(); + }, { + key: 'closeMenu', + value: function closeMenu() { + if (this.props.onCloseResetsInput) { + this.setState({ + isOpen: false, + isPseudoFocused: this.state.isFocused && !this.props.multi, + inputValue: this.handleInputValueChange('') + }); + } else { + this.setState({ + isOpen: false, + isPseudoFocused: this.state.isFocused && !this.props.multi + }); + } + this.hasScrolledToOption = false; + } + }, { + key: 'handleInputFocus', + value: function handleInputFocus(event) { + if (this.props.disabled) return; + var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus; + if (this.props.onFocus) { + this.props.onFocus(event); } - - // clears the value so that the cursor will be at the end of input when the component re-renders - input.value = ''; - - // if the input is focused, ensure the menu is open this.setState({ - isOpen: true, - isPseudoFocused: false + isFocused: true, + isOpen: isOpen }); - } else { - // otherwise, focus the input and open the menu - this._openAfterFocus = this.props.openAfterFocus; - this.focus(); - } - } - - handleMouseDownOnArrow(event) { - // if the event was triggered by a mousedown and not the primary - // button, or if the component is disabled, ignore it. - if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { - return; - } - // If the menu isn't open, let the event bubble to the main handleMouseDown - if (!this.state.isOpen) { - return; + this._openAfterFocus = false; } - // prevent default event handlers - event.stopPropagation(); - event.preventDefault(); - // close the menu - this.closeMenu(); - } + }, { + key: 'handleInputBlur', + value: function handleInputBlur(event) { + // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts. + if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) { + this.focus(); + return; + } - handleMouseDownOnMenu(event) { - // if the event was triggered by a mousedown and not the primary - // button, or if the component is disabled, ignore it. - if (this.props.disabled || event.type === 'mousedown' && event.button !== 0) { - return; + if (this.props.onBlur) { + this.props.onBlur(event); + } + var onBlurredState = { + isFocused: false, + isOpen: false, + isPseudoFocused: false + }; + if (this.props.onBlurResetsInput) { + onBlurredState.inputValue = this.handleInputValueChange(''); + } + this.setState(onBlurredState); } - event.stopPropagation(); - event.preventDefault(); + }, { + key: 'handleInputChange', + value: function handleInputChange(event) { + var newInputValue = event.target.value; - this._openAfterFocus = true; - this.focus(); - } + if (this.state.inputValue !== event.target.value) { + newInputValue = this.handleInputValueChange(newInputValue); + } - closeMenu() { - if (this.props.onCloseResetsInput) { this.setState({ - isOpen: false, - isPseudoFocused: this.state.isFocused && !this.props.multi, - inputValue: this.handleInputValueChange('') - }); - } else { - this.setState({ - isOpen: false, - isPseudoFocused: this.state.isFocused && !this.props.multi + isOpen: true, + isPseudoFocused: false, + inputValue: newInputValue }); } - this.hasScrolledToOption = false; - } - - handleInputFocus(event) { - if (this.props.disabled) return; - var isOpen = this.state.isOpen || this._openAfterFocus || this.props.openOnFocus; - if (this.props.onFocus) { - this.props.onFocus(event); + }, { + key: 'handleInputValueChange', + value: function handleInputValueChange(newValue) { + if (this.props.onInputChange) { + var nextState = this.props.onInputChange(newValue); + // Note: != used deliberately here to catch undefined and null + if (nextState != null && (typeof nextState === 'undefined' ? 'undefined' : _typeof(nextState)) !== 'object') { + newValue = '' + nextState; + } + } + return newValue; } - this.setState({ - isFocused: true, - isOpen: isOpen - }); - this._openAfterFocus = false; - } + }, { + key: 'handleKeyDown', + value: function handleKeyDown(event) { + if (this.props.disabled) return; + + if (typeof this.props.onInputKeyDown === 'function') { + this.props.onInputKeyDown(event); + if (event.defaultPrevented) { + return; + } + } - handleInputBlur(event) { - // The check for menu.contains(activeElement) is necessary to prevent IE11's scrollbar from closing the menu in certain contexts. - if (this.menu && (this.menu === document.activeElement || this.menu.contains(document.activeElement))) { - this.focus(); - return; + switch (event.keyCode) { + case 8: + // backspace + if (!this.state.inputValue && this.props.backspaceRemoves) { + event.preventDefault(); + this.popValue(); + } + return; + case 9: + // tab + if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) { + return; + } + this.selectFocusedOption(); + return; + case 13: + // enter + if (!this.state.isOpen) return; + event.stopPropagation(); + this.selectFocusedOption(); + break; + case 27: + // escape + if (this.state.isOpen) { + this.closeMenu(); + event.stopPropagation(); + } else if (this.props.clearable && this.props.escapeClearsValue) { + this.clearValue(event); + event.stopPropagation(); + } + break; + case 38: + // up + this.focusPreviousOption(); + break; + case 40: + // down + this.focusNextOption(); + break; + case 33: + // page up + this.focusPageUpOption(); + break; + case 34: + // page down + this.focusPageDownOption(); + break; + case 35: + // end key + if (event.shiftKey) { + return; + } + this.focusEndOption(); + break; + case 36: + // home key + if (event.shiftKey) { + return; + } + this.focusStartOption(); + break; + case 46: + // backspace + if (!this.state.inputValue && this.props.deleteRemoves) { + event.preventDefault(); + this.popValue(); + } + return; + default: + return; + } + event.preventDefault(); } - - if (this.props.onBlur) { - this.props.onBlur(event); + }, { + key: 'handleValueClick', + value: function handleValueClick(option, event) { + if (!this.props.onValueClick) return; + this.props.onValueClick(option, event); } - var onBlurredState = { - isFocused: false, - isOpen: false, - isPseudoFocused: false - }; - if (this.props.onBlurResetsInput) { - onBlurredState.inputValue = this.handleInputValueChange(''); + }, { + key: 'handleMenuScroll', + value: function handleMenuScroll(event) { + if (!this.props.onMenuScrollToBottom) return; + var target = event.target; + + if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) { + this.props.onMenuScrollToBottom(); + } } - this.setState(onBlurredState); - } - - handleInputChange(event) { - let newInputValue = event.target.value; - - if (this.state.inputValue !== event.target.value) { - newInputValue = this.handleInputValueChange(newInputValue); + }, { + key: 'handleRequired', + value: function handleRequired(value, multi) { + if (!value) return true; + return multi ? value.length === 0 : Object.keys(value).length === 0; + } + }, { + key: 'getOptionLabel', + value: function getOptionLabel(op) { + return op[this.props.labelKey]; } - this.setState({ - isOpen: true, - isPseudoFocused: false, - inputValue: newInputValue - }); - } - - handleInputValueChange(newValue) { - if (this.props.onInputChange) { - let nextState = this.props.onInputChange(newValue); - // Note: != used deliberately here to catch undefined and null - if (nextState != null && typeof nextState !== 'object') { - newValue = '' + nextState; + /** + * Turns a value into an array from the given options + * @param {String|Number|Array} value - the value of the select input + * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration + * @returns {Array} the value of the select represented in an array + */ + + }, { + key: 'getValueArray', + value: function getValueArray(value, nextProps) { + var _this2 = this; + + /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */ + var props = (typeof nextProps === 'undefined' ? 'undefined' : _typeof(nextProps)) === 'object' ? nextProps : this.props; + if (props.multi) { + if (typeof value === 'string') value = value.split(props.delimiter); + if (!Array.isArray(value)) { + if (value === null || value === undefined) return []; + value = [value]; + } + return value.map(function (value) { + return _this2.expandValue(value, props); + }).filter(function (i) { + return i; + }); } + var expandedValue = this.expandValue(value, props); + return expandedValue ? [expandedValue] : []; } - return newValue; - } - - handleKeyDown(event) { - if (this.props.disabled) return; - if (typeof this.props.onInputKeyDown === 'function') { - this.props.onInputKeyDown(event); - if (event.defaultPrevented) { - return; + /** + * Retrieve a value from the given options and valueKey + * @param {String|Number|Array} value - the selected value(s) + * @param {Object} props - the Select component's props (or nextProps) + */ + + }, { + key: 'expandValue', + value: function expandValue(value, props) { + var valueType = typeof value === 'undefined' ? 'undefined' : _typeof(value); + if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value; + var options = props.options, + valueKey = props.valueKey; + + if (!options) return; + for (var i = 0; i < options.length; i++) { + if (options[i][valueKey] === value) return options[i]; } } + }, { + key: 'setValue', + value: function setValue(value) { + var _this3 = this; - switch (event.keyCode) { - case 8: - // backspace - if (!this.state.inputValue && this.props.backspaceRemoves) { - event.preventDefault(); - this.popValue(); - } - return; - case 9: - // tab - if (event.shiftKey || !this.state.isOpen || !this.props.tabSelectsValue) { - return; - } - this.selectFocusedOption(); - return; - case 13: - // enter - if (!this.state.isOpen) return; - event.stopPropagation(); - this.selectFocusedOption(); - break; - case 27: - // escape - if (this.state.isOpen) { - this.closeMenu(); - event.stopPropagation(); - } else if (this.props.clearable && this.props.escapeClearsValue) { - this.clearValue(event); - event.stopPropagation(); - } - break; - case 38: - // up - this.focusPreviousOption(); - break; - case 40: - // down - this.focusNextOption(); - break; - case 33: - // page up - this.focusPageUpOption(); - break; - case 34: - // page down - this.focusPageDownOption(); - break; - case 35: - // end key - if (event.shiftKey) { - return; - } - this.focusEndOption(); - break; - case 36: - // home key - if (event.shiftKey) { - return; - } - this.focusStartOption(); - break; - case 46: - // backspace - if (!this.state.inputValue && this.props.deleteRemoves) { - event.preventDefault(); - this.popValue(); - } - return; - default: - return; + if (this.props.autoBlur) { + this.blurInput(); + } + if (!this.props.onChange) return; + if (this.props.required) { + var required = this.handleRequired(value, this.props.multi); + this.setState({ required: required }); + } + if (this.props.simpleValue && value) { + value = this.props.multi ? value.map(function (i) { + return i[_this3.props.valueKey]; + }).join(this.props.delimiter) : value[this.props.valueKey]; + } + this.props.onChange(value); } - event.preventDefault(); - } - - handleValueClick(option, event) { - if (!this.props.onValueClick) return; - this.props.onValueClick(option, event); - } + }, { + key: 'selectValue', + value: function selectValue(value) { + var _this4 = this; - handleMenuScroll(event) { - if (!this.props.onMenuScrollToBottom) return; - let { target } = event; - if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) { - this.props.onMenuScrollToBottom(); + //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise) + this.hasScrolledToOption = false; + if (this.props.multi) { + var updatedValue = this.props.onSelectResetsInput ? '' : this.state.inputValue; + this.setState({ + inputValue: this.handleInputValueChange(updatedValue), + focusedIndex: null + }, function () { + _this4.addValue(value); + }); + } else { + this.setState({ + isOpen: false, + inputValue: this.handleInputValueChange(''), + isPseudoFocused: this.state.isFocused + }, function () { + _this4.setValue(value); + }); + } } - } - - handleRequired(value, multi) { - if (!value) return true; - return multi ? value.length === 0 : Object.keys(value).length === 0; - } - - getOptionLabel(op) { - return op[this.props.labelKey]; - } - - /** - * Turns a value into an array from the given options - * @param {String|Number|Array} value - the value of the select input - * @param {Object} nextProps - optionally specify the nextProps so the returned array uses the latest configuration - * @returns {Array} the value of the select represented in an array - */ - getValueArray(value, nextProps) { - /** support optionally passing in the `nextProps` so `componentWillReceiveProps` updates will function as expected */ - const props = typeof nextProps === 'object' ? nextProps : this.props; - if (props.multi) { - if (typeof value === 'string') value = value.split(props.delimiter); - if (!Array.isArray(value)) { - if (value === null || value === undefined) return []; - value = [value]; + }, { + key: 'addValue', + value: function addValue(value) { + var valueArray = this.getValueArray(this.props.value); + var visibleOptions = this._visibleOptions.filter(function (val) { + return !val.disabled; + }); + var lastValueIndex = visibleOptions.indexOf(value); + this.setValue(valueArray.concat(value)); + if (visibleOptions.length - 1 === lastValueIndex) { + // the last option was selected; focus the second-last one + this.focusOption(visibleOptions[lastValueIndex - 1]); + } else if (visibleOptions.length > lastValueIndex) { + // focus the option below the selected one + this.focusOption(visibleOptions[lastValueIndex + 1]); } - return value.map(value => this.expandValue(value, props)).filter(i => i); } - var expandedValue = this.expandValue(value, props); - return expandedValue ? [expandedValue] : []; - } - - /** - * Retrieve a value from the given options and valueKey - * @param {String|Number|Array} value - the selected value(s) - * @param {Object} props - the Select component's props (or nextProps) - */ - expandValue(value, props) { - const valueType = typeof value; - if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') return value; - let { options, valueKey } = props; - if (!options) return; - for (var i = 0; i < options.length; i++) { - if (options[i][valueKey] === value) return options[i]; + }, { + key: 'popValue', + value: function popValue() { + var valueArray = this.getValueArray(this.props.value); + if (!valueArray.length) return; + if (valueArray[valueArray.length - 1].clearableValue === false) return; + this.setValue(this.props.multi ? valueArray.slice(0, valueArray.length - 1) : null); } - } - - setValue(value) { - if (this.props.autoBlur) { - this.blurInput(); + }, { + key: 'removeValue', + value: function removeValue(value) { + var valueArray = this.getValueArray(this.props.value); + this.setValue(valueArray.filter(function (i) { + return i !== value; + })); + this.focus(); } - if (!this.props.onChange) return; - if (this.props.required) { - const required = this.handleRequired(value, this.props.multi); - this.setState({ required }); + }, { + key: 'clearValue', + value: function clearValue(event) { + // if the event was triggered by a mousedown and not the primary + // button, ignore it. + if (event && event.type === 'mousedown' && event.button !== 0) { + return; + } + event.stopPropagation(); + event.preventDefault(); + this.setValue(this.getResetValue()); + this.setState({ + isOpen: false, + inputValue: this.handleInputValueChange('') + }, this.focus); } - if (this.props.simpleValue && value) { - value = this.props.multi ? value.map(i => i[this.props.valueKey]).join(this.props.delimiter) : value[this.props.valueKey]; + }, { + key: 'getResetValue', + value: function getResetValue() { + if (this.props.resetValue !== undefined) { + return this.props.resetValue; + } else if (this.props.multi) { + return []; + } else { + return null; + } } - this.props.onChange(value); - } - - selectValue(value) { - //NOTE: update value in the callback to make sure the input value is empty so that there are no styling issues (Chrome had issue otherwise) - this.hasScrolledToOption = false; - if (this.props.multi) { - const updatedValue = this.props.onSelectResetsInput ? '' : this.state.inputValue; - this.setState({ - inputValue: this.handleInputValueChange(updatedValue), - focusedIndex: null - }, () => { - this.addValue(value); - }); - } else { + }, { + key: 'focusOption', + value: function focusOption(option) { this.setState({ - isOpen: false, - inputValue: this.handleInputValueChange(''), - isPseudoFocused: this.state.isFocused - }, () => { - this.setValue(value); + focusedOption: option }); } - } - - addValue(value) { - var valueArray = this.getValueArray(this.props.value); - const visibleOptions = this._visibleOptions.filter(val => !val.disabled); - const lastValueIndex = visibleOptions.indexOf(value); - this.setValue(valueArray.concat(value)); - if (visibleOptions.length - 1 === lastValueIndex) { - // the last option was selected; focus the second-last one - this.focusOption(visibleOptions[lastValueIndex - 1]); - } else if (visibleOptions.length > lastValueIndex) { - // focus the option below the selected one - this.focusOption(visibleOptions[lastValueIndex + 1]); + }, { + key: 'focusNextOption', + value: function focusNextOption() { + this.focusAdjacentOption('next'); } - } - - popValue() { - var valueArray = this.getValueArray(this.props.value); - if (!valueArray.length) return; - if (valueArray[valueArray.length - 1].clearableValue === false) return; - this.setValue(this.props.multi ? valueArray.slice(0, valueArray.length - 1) : null); - } - - removeValue(value) { - var valueArray = this.getValueArray(this.props.value); - this.setValue(valueArray.filter(i => i !== value)); - this.focus(); - } - - clearValue(event) { - // if the event was triggered by a mousedown and not the primary - // button, ignore it. - if (event && event.type === 'mousedown' && event.button !== 0) { - return; + }, { + key: 'focusPreviousOption', + value: function focusPreviousOption() { + this.focusAdjacentOption('previous'); } - event.stopPropagation(); - event.preventDefault(); - this.setValue(this.getResetValue()); - this.setState({ - isOpen: false, - inputValue: this.handleInputValueChange('') - }, this.focus); - } - - getResetValue() { - if (this.props.resetValue !== undefined) { - return this.props.resetValue; - } else if (this.props.multi) { - return []; - } else { - return null; + }, { + key: 'focusPageUpOption', + value: function focusPageUpOption() { + this.focusAdjacentOption('page_up'); } - } - - focusOption(option) { - this.setState({ - focusedOption: option - }); - } - - focusNextOption() { - this.focusAdjacentOption('next'); - } - - focusPreviousOption() { - this.focusAdjacentOption('previous'); - } - - focusPageUpOption() { - this.focusAdjacentOption('page_up'); - } - - focusPageDownOption() { - this.focusAdjacentOption('page_down'); - } - - focusStartOption() { - this.focusAdjacentOption('start'); - } - - focusEndOption() { - this.focusAdjacentOption('end'); - } - - focusAdjacentOption(dir) { - var options = this._visibleOptions.map((option, index) => ({ option, index })).filter(option => !option.option.disabled); - this._scrollToFocusedOptionOnUpdate = true; - if (!this.state.isOpen) { - this.setState({ - isOpen: true, - inputValue: '', - focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null) - }); - return; + }, { + key: 'focusPageDownOption', + value: function focusPageDownOption() { + this.focusAdjacentOption('page_down'); } - if (!options.length) return; - var focusedIndex = -1; - for (var i = 0; i < options.length; i++) { - if (this._focusedOption === options[i].option) { - focusedIndex = i; - break; - } + }, { + key: 'focusStartOption', + value: function focusStartOption() { + this.focusAdjacentOption('start'); } - if (dir === 'next' && focusedIndex !== -1) { - focusedIndex = (focusedIndex + 1) % options.length; - } else if (dir === 'previous') { - if (focusedIndex > 0) { - focusedIndex = focusedIndex - 1; - } else { - focusedIndex = options.length - 1; + }, { + key: 'focusEndOption', + value: function focusEndOption() { + this.focusAdjacentOption('end'); + } + }, { + key: 'focusAdjacentOption', + value: function focusAdjacentOption(dir) { + var options = this._visibleOptions.map(function (option, index) { + return { option: option, index: index }; + }).filter(function (option) { + return !option.option.disabled; + }); + this._scrollToFocusedOptionOnUpdate = true; + if (!this.state.isOpen) { + this.setState({ + isOpen: true, + inputValue: '', + focusedOption: this._focusedOption || (options.length ? options[dir === 'next' ? 0 : options.length - 1].option : null) + }); + return; } - } else if (dir === 'start') { - focusedIndex = 0; - } else if (dir === 'end') { - focusedIndex = options.length - 1; - } else if (dir === 'page_up') { - var potentialIndex = focusedIndex - this.props.pageSize; - if (potentialIndex < 0) { - focusedIndex = 0; - } else { - focusedIndex = potentialIndex; + if (!options.length) return; + var focusedIndex = -1; + for (var i = 0; i < options.length; i++) { + if (this._focusedOption === options[i].option) { + focusedIndex = i; + break; + } } - } else if (dir === 'page_down') { - var potentialIndex = focusedIndex + this.props.pageSize; - if (potentialIndex > options.length - 1) { + if (dir === 'next' && focusedIndex !== -1) { + focusedIndex = (focusedIndex + 1) % options.length; + } else if (dir === 'previous') { + if (focusedIndex > 0) { + focusedIndex = focusedIndex - 1; + } else { + focusedIndex = options.length - 1; + } + } else if (dir === 'start') { + focusedIndex = 0; + } else if (dir === 'end') { focusedIndex = options.length - 1; - } else { - focusedIndex = potentialIndex; + } else if (dir === 'page_up') { + var potentialIndex = focusedIndex - this.props.pageSize; + if (potentialIndex < 0) { + focusedIndex = 0; + } else { + focusedIndex = potentialIndex; + } + } else if (dir === 'page_down') { + var potentialIndex = focusedIndex + this.props.pageSize; + if (potentialIndex > options.length - 1) { + focusedIndex = options.length - 1; + } else { + focusedIndex = potentialIndex; + } } - } - - if (focusedIndex === -1) { - focusedIndex = 0; - } - this.setState({ - focusedIndex: options[focusedIndex].index, - focusedOption: options[focusedIndex].option - }); - } - - getFocusedOption() { - return this._focusedOption; - } - - getInputValue() { - return this.state.inputValue; - } + if (focusedIndex === -1) { + focusedIndex = 0; + } - selectFocusedOption() { - if (this._focusedOption) { - return this.selectValue(this._focusedOption); + this.setState({ + focusedIndex: options[focusedIndex].index, + focusedOption: options[focusedIndex].option + }); } - } - - renderLoading() { - if (!this.props.isLoading) return; - return React.createElement( - 'span', - { className: 'Select-loading-zone', 'aria-hidden': 'true' }, - React.createElement('span', { className: 'Select-loading' }) - ); - } - - renderValue(valueArray, isOpen) { - let renderLabel = this.props.valueRenderer || this.getOptionLabel; - let ValueComponent = this.props.valueComponent; - if (!valueArray.length) { - return !this.state.inputValue ? React.createElement( - 'div', - { className: 'Select-placeholder' }, - this.props.placeholder - ) : null; + }, { + key: 'getFocusedOption', + value: function getFocusedOption() { + return this._focusedOption; } - let onClick = this.props.onValueClick ? this.handleValueClick : null; - if (this.props.multi) { - return valueArray.map((value, i) => { - return React.createElement( + }, { + key: 'getInputValue', + value: function getInputValue() { + return this.state.inputValue; + } + }, { + key: 'selectFocusedOption', + value: function selectFocusedOption() { + if (this._focusedOption) { + return this.selectValue(this._focusedOption); + } + } + }, { + key: 'renderLoading', + value: function renderLoading() { + if (!this.props.isLoading) return; + return _react2.default.createElement( + 'span', + { className: 'Select-loading-zone', 'aria-hidden': 'true' }, + _react2.default.createElement('span', { className: 'Select-loading' }) + ); + } + }, { + key: 'renderValue', + value: function renderValue(valueArray, isOpen) { + var _this5 = this; + + var renderLabel = this.props.valueRenderer || this.getOptionLabel; + var ValueComponent = this.props.valueComponent; + if (!valueArray.length) { + return !this.state.inputValue ? _react2.default.createElement( + 'div', + { className: 'Select-placeholder' }, + this.props.placeholder + ) : null; + } + var onClick = this.props.onValueClick ? this.handleValueClick : null; + if (this.props.multi) { + return valueArray.map(function (value, i) { + return _react2.default.createElement( + ValueComponent, + { + id: _this5._instancePrefix + '-value-' + i, + instancePrefix: _this5._instancePrefix, + disabled: _this5.props.disabled || value.clearableValue === false, + key: 'value-' + i + '-' + value[_this5.props.valueKey], + onClick: onClick, + onRemove: _this5.removeValue, + value: value + }, + renderLabel(value, i), + _react2.default.createElement( + 'span', + { className: 'Select-aria-only' }, + '\xA0' + ) + ); + }); + } else if (!this.state.inputValue) { + if (isOpen) onClick = null; + return _react2.default.createElement( ValueComponent, { - id: this._instancePrefix + '-value-' + i, + id: this._instancePrefix + '-value-item', + disabled: this.props.disabled, instancePrefix: this._instancePrefix, - disabled: this.props.disabled || value.clearableValue === false, - key: `value-${i}-${value[this.props.valueKey]}`, onClick: onClick, - onRemove: this.removeValue, - value: value + value: valueArray[0] }, - renderLabel(value, i), - React.createElement( - 'span', - { className: 'Select-aria-only' }, - '\xA0' - ) + renderLabel(valueArray[0]) ); - }); - } else if (!this.state.inputValue) { - if (isOpen) onClick = null; - return React.createElement( - ValueComponent, - { - id: this._instancePrefix + '-value-item', - disabled: this.props.disabled, - instancePrefix: this._instancePrefix, - onClick: onClick, - value: valueArray[0] - }, - renderLabel(valueArray[0]) - ); - } - } - - renderInput(valueArray, focusedOptionIndex) { - var className = classNames('Select-input', this.props.inputProps.className); - const isOpen = !!this.state.isOpen; - - const ariaOwns = classNames({ - [this._instancePrefix + '-list']: isOpen, - [this._instancePrefix + '-backspace-remove-message']: this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue - }); - - // TODO: Check how this project includes Object.assign() - const inputProps = Object.assign({}, this.props.inputProps, { - role: 'combobox', - 'aria-expanded': '' + isOpen, - 'aria-owns': ariaOwns, - 'aria-haspopup': '' + isOpen, - 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value', - 'aria-describedby': this.props['aria-describedby'], - 'aria-labelledby': this.props['aria-labelledby'], - 'aria-label': this.props['aria-label'], - className: className, - tabIndex: this.props.tabIndex, - onBlur: this.handleInputBlur, - onChange: this.handleInputChange, - onFocus: this.handleInputFocus, - ref: ref => this.input = ref, - required: this.state.required, - value: this.state.inputValue - }); - - if (this.props.inputRenderer) { - return this.props.inputRenderer(inputProps); + } } + }, { + key: 'renderInput', + value: function renderInput(valueArray, focusedOptionIndex) { + var _classNames, + _this6 = this; - if (this.props.disabled || !this.props.searchable) { - const _props$inputProps = this.props.inputProps, - { inputClassName } = _props$inputProps, - divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']); + var className = (0, _classnames2.default)('Select-input', this.props.inputProps.className); + var isOpen = !!this.state.isOpen; - const ariaOwns = classNames({ - [this._instancePrefix + '-list']: isOpen - }); + var ariaOwns = (0, _classnames2.default)((_classNames = {}, _defineProperty(_classNames, this._instancePrefix + '-list', isOpen), _defineProperty(_classNames, this._instancePrefix + '-backspace-remove-message', this.props.multi && !this.props.disabled && this.state.isFocused && !this.state.inputValue), _classNames)); - return React.createElement('div', _extends({}, divProps, { + // TODO: Check how this project includes Object.assign() + var inputProps = Object.assign({}, this.props.inputProps, { role: 'combobox', - 'aria-expanded': isOpen, + 'aria-expanded': '' + isOpen, 'aria-owns': ariaOwns, + 'aria-haspopup': '' + isOpen, 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value', + 'aria-describedby': this.props['aria-describedby'], + 'aria-labelledby': this.props['aria-labelledby'], + 'aria-label': this.props['aria-label'], className: className, - tabIndex: this.props.tabIndex || 0, + tabIndex: this.props.tabIndex, onBlur: this.handleInputBlur, + onChange: this.handleInputChange, onFocus: this.handleInputFocus, - ref: ref => this.input = ref, - 'aria-readonly': '' + !!this.props.disabled, - style: { border: 0, width: 1, display: 'inline-block' } })); - } - - if (this.props.autosize) { - return React.createElement(AutosizeInput, _extends({}, inputProps, { minWidth: '5' })); - } - return React.createElement( - 'div', - { className: className }, - React.createElement('input', inputProps) - ); - } + ref: function ref(_ref) { + return _this6.input = _ref; + }, + required: this.state.required, + value: this.state.inputValue + }); - renderClear() { - - if (!this.props.clearable || this.props.value === undefined || this.props.value === null || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return; - const clear = this.props.clearRenderer(); - - return React.createElement( - 'span', - { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText, - 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText, - onMouseDown: this.clearValue, - onTouchStart: this.handleTouchStart, - onTouchMove: this.handleTouchMove, - onTouchEnd: this.handleTouchEndClearValue - }, - clear - ); - } + if (this.props.inputRenderer) { + return this.props.inputRenderer(inputProps); + } - renderArrow() { - const onMouseDown = this.handleMouseDownOnArrow; - const isOpen = this.state.isOpen; - const arrow = this.props.arrowRenderer({ onMouseDown, isOpen }); - - return React.createElement( - 'span', - { - className: 'Select-arrow-zone', - onMouseDown: onMouseDown - }, - arrow - ); - } + if (this.props.disabled || !this.props.searchable) { + var _props$inputProps = this.props.inputProps, + inputClassName = _props$inputProps.inputClassName, + divProps = _objectWithoutProperties(_props$inputProps, ['inputClassName']); + + var _ariaOwns = (0, _classnames2.default)(_defineProperty({}, this._instancePrefix + '-list', isOpen)); + + return _react2.default.createElement('div', _extends({}, divProps, { + role: 'combobox', + 'aria-expanded': isOpen, + 'aria-owns': _ariaOwns, + 'aria-activedescendant': isOpen ? this._instancePrefix + '-option-' + focusedOptionIndex : this._instancePrefix + '-value', + className: className, + tabIndex: this.props.tabIndex || 0, + onBlur: this.handleInputBlur, + onFocus: this.handleInputFocus, + ref: function ref(_ref2) { + return _this6.input = _ref2; + }, + 'aria-readonly': '' + !!this.props.disabled, + style: { border: 0, width: 1, display: 'inline-block' } })); + } - filterOptions(excludeOptions) { - var filterValue = this.state.inputValue; - var options = this.props.options || []; - if (this.props.filterOptions) { - // Maintain backwards compatibility with boolean attribute - const filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : defaultFilterOptions; - - return filterOptions(options, filterValue, excludeOptions, { - filterOption: this.props.filterOption, - ignoreAccents: this.props.ignoreAccents, - ignoreCase: this.props.ignoreCase, - labelKey: this.props.labelKey, - matchPos: this.props.matchPos, - matchProp: this.props.matchProp, - valueKey: this.props.valueKey - }); - } else { - return options; + if (this.props.autosize) { + return _react2.default.createElement(_reactInputAutosize2.default, _extends({}, inputProps, { minWidth: '5' })); + } + return _react2.default.createElement( + 'div', + { className: className }, + _react2.default.createElement('input', inputProps) + ); } - } + }, { + key: 'renderClear', + value: function renderClear() { - onOptionRef(ref, isFocused) { - if (isFocused) { - this.focused = ref; - } - } + if (!this.props.clearable || this.props.value === undefined || this.props.value === null || this.props.multi && !this.props.value.length || this.props.disabled || this.props.isLoading) return; + var clear = this.props.clearRenderer(); - renderMenu(options, valueArray, focusedOption) { - if (options && options.length) { - return this.props.menuRenderer({ - focusedOption, - focusOption: this.focusOption, - instancePrefix: this._instancePrefix, - labelKey: this.props.labelKey, - onFocus: this.focusOption, - onSelect: this.selectValue, - optionClassName: this.props.optionClassName, - optionComponent: this.props.optionComponent, - optionRenderer: this.props.optionRenderer || this.getOptionLabel, - options, - selectValue: this.selectValue, - valueArray, - valueKey: this.props.valueKey, - onOptionRef: this.onOptionRef - }); - } else if (this.props.noResultsText) { - return React.createElement( - 'div', - { className: 'Select-noresults' }, - this.props.noResultsText + return _react2.default.createElement( + 'span', + { className: 'Select-clear-zone', title: this.props.multi ? this.props.clearAllText : this.props.clearValueText, + 'aria-label': this.props.multi ? this.props.clearAllText : this.props.clearValueText, + onMouseDown: this.clearValue, + onTouchStart: this.handleTouchStart, + onTouchMove: this.handleTouchMove, + onTouchEnd: this.handleTouchEndClearValue + }, + clear ); - } else { - return null; } - } - - renderHiddenField(valueArray) { - if (!this.props.name) return; - if (this.props.joinValues) { - let value = valueArray.map(i => stringifyValue(i[this.props.valueKey])).join(this.props.delimiter); - return React.createElement('input', { - type: 'hidden', - ref: ref => this.value = ref, - name: this.props.name, - value: value, - disabled: this.props.disabled }); + }, { + key: 'renderArrow', + value: function renderArrow() { + var onMouseDown = this.handleMouseDownOnArrow; + var isOpen = this.state.isOpen; + var arrow = this.props.arrowRenderer({ onMouseDown: onMouseDown, isOpen: isOpen }); + + return _react2.default.createElement( + 'span', + { + className: 'Select-arrow-zone', + onMouseDown: onMouseDown + }, + arrow + ); } - return valueArray.map((item, index) => React.createElement('input', { key: 'hidden.' + index, - type: 'hidden', - ref: 'value' + index, - name: this.props.name, - value: stringifyValue(item[this.props.valueKey]), - disabled: this.props.disabled })); - } - - getFocusableOptionIndex(selectedOption) { - var options = this._visibleOptions; - if (!options.length) return null; - - const valueKey = this.props.valueKey; - let focusedOption = this.state.focusedOption || selectedOption; - if (focusedOption && !focusedOption.disabled) { - let focusedOptionIndex = -1; - options.some((option, index) => { - const isOptionEqual = option[valueKey] === focusedOption[valueKey]; - if (isOptionEqual) { - focusedOptionIndex = index; - } - return isOptionEqual; - }); - if (focusedOptionIndex !== -1) { - return focusedOptionIndex; + }, { + key: 'filterOptions', + value: function filterOptions(excludeOptions) { + var filterValue = this.state.inputValue; + var options = this.props.options || []; + if (this.props.filterOptions) { + // Maintain backwards compatibility with boolean attribute + var filterOptions = typeof this.props.filterOptions === 'function' ? this.props.filterOptions : _defaultFilterOptions2.default; + + return filterOptions(options, filterValue, excludeOptions, { + filterOption: this.props.filterOption, + ignoreAccents: this.props.ignoreAccents, + ignoreCase: this.props.ignoreCase, + labelKey: this.props.labelKey, + matchPos: this.props.matchPos, + matchProp: this.props.matchProp, + valueKey: this.props.valueKey + }); + } else { + return options; } } - - for (var i = 0; i < options.length; i++) { - if (!options[i].disabled) return i; + }, { + key: 'onOptionRef', + value: function onOptionRef(ref, isFocused) { + if (isFocused) { + this.focused = ref; + } } - return null; - } + }, { + key: 'renderMenu', + value: function renderMenu(options, valueArray, focusedOption) { + if (options && options.length) { + return this.props.menuRenderer({ + focusedOption: focusedOption, + focusOption: this.focusOption, + instancePrefix: this._instancePrefix, + labelKey: this.props.labelKey, + onFocus: this.focusOption, + onSelect: this.selectValue, + optionClassName: this.props.optionClassName, + optionComponent: this.props.optionComponent, + optionRenderer: this.props.optionRenderer || this.getOptionLabel, + options: options, + selectValue: this.selectValue, + valueArray: valueArray, + valueKey: this.props.valueKey, + onOptionRef: this.onOptionRef + }); + } else if (this.props.noResultsText) { + return _react2.default.createElement( + 'div', + { className: 'Select-noresults' }, + this.props.noResultsText + ); + } else { + return null; + } + } + }, { + key: 'renderHiddenField', + value: function renderHiddenField(valueArray) { + var _this7 = this; + + if (!this.props.name) return; + if (this.props.joinValues) { + var value = valueArray.map(function (i) { + return stringifyValue(i[_this7.props.valueKey]); + }).join(this.props.delimiter); + return _react2.default.createElement('input', { + type: 'hidden', + ref: function ref(_ref3) { + return _this7.value = _ref3; + }, + name: this.props.name, + value: value, + disabled: this.props.disabled }); + } + return valueArray.map(function (item, index) { + return _react2.default.createElement('input', { key: 'hidden.' + index, + type: 'hidden', + ref: 'value' + index, + name: _this7.props.name, + value: stringifyValue(item[_this7.props.valueKey]), + disabled: _this7.props.disabled }); + }); + } + }, { + key: 'getFocusableOptionIndex', + value: function getFocusableOptionIndex(selectedOption) { + var options = this._visibleOptions; + if (!options.length) return null; + + var valueKey = this.props.valueKey; + var focusedOption = this.state.focusedOption || selectedOption; + if (focusedOption && !focusedOption.disabled) { + var focusedOptionIndex = -1; + options.some(function (option, index) { + var isOptionEqual = option[valueKey] === focusedOption[valueKey]; + if (isOptionEqual) { + focusedOptionIndex = index; + } + return isOptionEqual; + }); + if (focusedOptionIndex !== -1) { + return focusedOptionIndex; + } + } - renderOuter(options, valueArray, focusedOption) { - let menu = this.renderMenu(options, valueArray, focusedOption); - if (!menu) { + for (var i = 0; i < options.length; i++) { + if (!options[i].disabled) return i; + } return null; } + }, { + key: 'renderOuter', + value: function renderOuter(options, valueArray, focusedOption) { + var _this8 = this; + + var menu = this.renderMenu(options, valueArray, focusedOption); + if (!menu) { + return null; + } - return React.createElement( - 'div', - { ref: ref => this.menuContainer = ref, className: 'Select-menu-outer', style: this.props.menuContainerStyle }, - React.createElement( + return _react2.default.createElement( 'div', - { ref: ref => this.menu = ref, role: 'listbox', tabIndex: -1, className: 'Select-menu', id: this._instancePrefix + '-list', - style: this.props.menuStyle, - onScroll: this.handleMenuScroll, - onMouseDown: this.handleMouseDownOnMenu }, - menu - ) - ); - } - - render() { - let valueArray = this.getValueArray(this.props.value); - let options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null); - let isOpen = this.state.isOpen; - if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false; - const focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]); - - let focusedOption = null; - if (focusedOptionIndex !== null) { - focusedOption = this._focusedOption = options[focusedOptionIndex]; - } else { - focusedOption = this._focusedOption = null; - } - let className = classNames('Select', this.props.className, { - 'Select--multi': this.props.multi, - 'Select--single': !this.props.multi, - 'is-clearable': this.props.clearable, - 'is-disabled': this.props.disabled, - 'is-focused': this.state.isFocused, - 'is-loading': this.props.isLoading, - 'is-open': isOpen, - 'is-pseudo-focused': this.state.isPseudoFocused, - 'is-searchable': this.props.searchable, - 'has-value': valueArray.length - }); - - let removeMessage = null; - if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) { - removeMessage = React.createElement( - 'span', - { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' }, - this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey]) + { ref: function ref(_ref5) { + return _this8.menuContainer = _ref5; + }, className: 'Select-menu-outer', style: this.props.menuContainerStyle }, + _react2.default.createElement( + 'div', + { ref: function ref(_ref4) { + return _this8.menu = _ref4; + }, role: 'listbox', tabIndex: -1, className: 'Select-menu', id: this._instancePrefix + '-list', + style: this.props.menuStyle, + onScroll: this.handleMenuScroll, + onMouseDown: this.handleMouseDownOnMenu }, + menu + ) ); } + }, { + key: 'render', + value: function render() { + var _this9 = this; + + var valueArray = this.getValueArray(this.props.value); + var options = this._visibleOptions = this.filterOptions(this.props.multi ? this.getValueArray(this.props.value) : null); + var isOpen = this.state.isOpen; + if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false; + var focusedOptionIndex = this.getFocusableOptionIndex(valueArray[0]); + + var focusedOption = null; + if (focusedOptionIndex !== null) { + focusedOption = this._focusedOption = options[focusedOptionIndex]; + } else { + focusedOption = this._focusedOption = null; + } + var className = (0, _classnames2.default)('Select', this.props.className, { + 'Select--multi': this.props.multi, + 'Select--single': !this.props.multi, + 'is-clearable': this.props.clearable, + 'is-disabled': this.props.disabled, + 'is-focused': this.state.isFocused, + 'is-loading': this.props.isLoading, + 'is-open': isOpen, + 'is-pseudo-focused': this.state.isPseudoFocused, + 'is-searchable': this.props.searchable, + 'has-value': valueArray.length + }); - return React.createElement( - 'div', - { ref: ref => this.wrapper = ref, - className: className, - style: this.props.wrapperStyle }, - this.renderHiddenField(valueArray), - React.createElement( - 'div', - { ref: ref => this.control = ref, - className: 'Select-control', - style: this.props.style, - onKeyDown: this.handleKeyDown, - onMouseDown: this.handleMouseDown, - onTouchEnd: this.handleTouchEnd, - onTouchStart: this.handleTouchStart, - onTouchMove: this.handleTouchMove - }, - React.createElement( + var removeMessage = null; + if (this.props.multi && !this.props.disabled && valueArray.length && !this.state.inputValue && this.state.isFocused && this.props.backspaceRemoves) { + removeMessage = _react2.default.createElement( 'span', - { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' }, - this.renderValue(valueArray, isOpen), - this.renderInput(valueArray, focusedOptionIndex) + { id: this._instancePrefix + '-backspace-remove-message', className: 'Select-aria-only', 'aria-live': 'assertive' }, + this.props.backspaceToRemoveMessage.replace('{label}', valueArray[valueArray.length - 1][this.props.labelKey]) + ); + } + + return _react2.default.createElement( + 'div', + { ref: function ref(_ref7) { + return _this9.wrapper = _ref7; + }, + className: className, + style: this.props.wrapperStyle }, + this.renderHiddenField(valueArray), + _react2.default.createElement( + 'div', + { ref: function ref(_ref6) { + return _this9.control = _ref6; + }, + className: 'Select-control', + style: this.props.style, + onKeyDown: this.handleKeyDown, + onMouseDown: this.handleMouseDown, + onTouchEnd: this.handleTouchEnd, + onTouchStart: this.handleTouchStart, + onTouchMove: this.handleTouchMove + }, + _react2.default.createElement( + 'span', + { className: 'Select-multi-value-wrapper', id: this._instancePrefix + '-value' }, + this.renderValue(valueArray, isOpen), + this.renderInput(valueArray, focusedOptionIndex) + ), + removeMessage, + this.renderLoading(), + this.renderClear(), + this.renderArrow() ), - removeMessage, - this.renderLoading(), - this.renderClear(), - this.renderArrow() - ), - isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null - ); - } -}; + isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null + ); + } + }]); + + return Select; +}(_react2.default.Component); + +; Select.propTypes = { - 'aria-describedby': PropTypes.string, // HTML ID(s) of element(s) that should be used to describe this input (for assistive tech) - 'aria-label': PropTypes.string, // Aria label (for assistive tech) - 'aria-labelledby': PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech) - addLabelText: PropTypes.string, // placeholder displayed when you want to add a label on a multi-value input - arrowRenderer: PropTypes.func, // Create drop-down caret element - autoBlur: PropTypes.bool, // automatically blur the component when an option is selected - autofocus: PropTypes.bool, // autofocus the component on mount - autosize: PropTypes.bool, // whether to enable autosizing or not - backspaceRemoves: PropTypes.bool, // whether backspace removes an item if there is no text input - backspaceToRemoveMessage: PropTypes.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label - className: PropTypes.string, // className for the outer element + 'aria-describedby': _propTypes2.default.string, // HTML ID(s) of element(s) that should be used to describe this input (for assistive tech) + 'aria-label': _propTypes2.default.string, // Aria label (for assistive tech) + 'aria-labelledby': _propTypes2.default.string, // HTML ID of an element that should be used as the label (for assistive tech) + addLabelText: _propTypes2.default.string, // placeholder displayed when you want to add a label on a multi-value input + arrowRenderer: _propTypes2.default.func, // Create drop-down caret element + autoBlur: _propTypes2.default.bool, // automatically blur the component when an option is selected + autofocus: _propTypes2.default.bool, // autofocus the component on mount + autosize: _propTypes2.default.bool, // whether to enable autosizing or not + backspaceRemoves: _propTypes2.default.bool, // whether backspace removes an item if there is no text input + backspaceToRemoveMessage: _propTypes2.default.string, // Message to use for screenreaders to press backspace to remove the current item - {label} is replaced with the item label + className: _propTypes2.default.string, // className for the outer element clearAllText: stringOrNode, // title for the "clear" control when multi: true - clearRenderer: PropTypes.func, // create clearable x element + clearRenderer: _propTypes2.default.func, // create clearable x element clearValueText: stringOrNode, // title for the "clear" control - clearable: PropTypes.bool, // should it be possible to reset value - deleteRemoves: PropTypes.bool, // whether backspace removes an item if there is no text input - delimiter: PropTypes.string, // delimiter to use to join multiple values for the hidden field value - disabled: PropTypes.bool, // whether the Select is disabled or not - escapeClearsValue: PropTypes.bool, // whether escape clears the value when the menu is closed - filterOption: PropTypes.func, // method to filter a single option (option, filterString) - filterOptions: PropTypes.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values]) - ignoreAccents: PropTypes.bool, // whether to strip diacritics when filtering - ignoreCase: PropTypes.bool, // whether to perform case-insensitive filtering - inputProps: PropTypes.object, // custom attributes for the Input - inputRenderer: PropTypes.func, // returns a custom input component - instanceId: PropTypes.string, // set the components instanceId - isLoading: PropTypes.bool, // whether the Select is loading externally or not (such as options being loaded) - joinValues: PropTypes.bool, // joins multiple values into a single form field with the delimiter (legacy mode) - labelKey: PropTypes.string, // path of the label value in option objects - matchPos: PropTypes.string, // (any|start) match the start or entire string when filtering - matchProp: PropTypes.string, // (any|label|value) which option property to filter on - menuBuffer: PropTypes.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu - menuContainerStyle: PropTypes.object, // optional style to apply to the menu container - menuRenderer: PropTypes.func, // renders a custom menu with options - menuStyle: PropTypes.object, // optional style to apply to the menu - multi: PropTypes.bool, // multi-value input - name: PropTypes.string, // generates a hidden tag with this field name for html forms + clearable: _propTypes2.default.bool, // should it be possible to reset value + deleteRemoves: _propTypes2.default.bool, // whether backspace removes an item if there is no text input + delimiter: _propTypes2.default.string, // delimiter to use to join multiple values for the hidden field value + disabled: _propTypes2.default.bool, // whether the Select is disabled or not + escapeClearsValue: _propTypes2.default.bool, // whether escape clears the value when the menu is closed + filterOption: _propTypes2.default.func, // method to filter a single option (option, filterString) + filterOptions: _propTypes2.default.any, // boolean to enable default filtering or function to filter the options array ([options], filterString, [values]) + ignoreAccents: _propTypes2.default.bool, // whether to strip diacritics when filtering + ignoreCase: _propTypes2.default.bool, // whether to perform case-insensitive filtering + inputProps: _propTypes2.default.object, // custom attributes for the Input + inputRenderer: _propTypes2.default.func, // returns a custom input component + instanceId: _propTypes2.default.string, // set the components instanceId + isLoading: _propTypes2.default.bool, // whether the Select is loading externally or not (such as options being loaded) + joinValues: _propTypes2.default.bool, // joins multiple values into a single form field with the delimiter (legacy mode) + labelKey: _propTypes2.default.string, // path of the label value in option objects + matchPos: _propTypes2.default.string, // (any|start) match the start or entire string when filtering + matchProp: _propTypes2.default.string, // (any|label|value) which option property to filter on + menuBuffer: _propTypes2.default.number, // optional buffer (in px) between the bottom of the viewport and the bottom of the menu + menuContainerStyle: _propTypes2.default.object, // optional style to apply to the menu container + menuRenderer: _propTypes2.default.func, // renders a custom menu with options + menuStyle: _propTypes2.default.object, // optional style to apply to the menu + multi: _propTypes2.default.bool, // multi-value input + name: _propTypes2.default.string, // generates a hidden tag with this field name for html forms noResultsText: stringOrNode, // placeholder displayed when there are no matching search results - onBlur: PropTypes.func, // onBlur handler: function (event) {} - onBlurResetsInput: PropTypes.bool, // whether input is cleared on blur - onChange: PropTypes.func, // onChange handler: function (newValue) {} - onClose: PropTypes.func, // fires when the menu is closed - onCloseResetsInput: PropTypes.bool, // whether input is cleared when menu is closed through the arrow - onFocus: PropTypes.func, // onFocus handler: function (event) {} - onInputChange: PropTypes.func, // onInputChange handler: function (inputValue) {} - onInputKeyDown: PropTypes.func, // input keyDown handler: function (event) {} - onMenuScrollToBottom: PropTypes.func, // fires when the menu is scrolled to the bottom; can be used to paginate options - onOpen: PropTypes.func, // fires when the menu is opened - onSelectResetsInput: PropTypes.bool, // whether input is cleared on select (works only for multiselect) - onValueClick: PropTypes.func, // onClick handler for value labels: function (value, event) {} - openAfterFocus: PropTypes.bool, // boolean to enable opening dropdown when focused - openOnFocus: PropTypes.bool, // always open options menu on focus - optionClassName: PropTypes.string, // additional class(es) to apply to the