UNPKG

react-select-v1

Version:

A Select control built with and for ReactJS

372 lines (287 loc) 12.4 kB
'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 _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _defaultFilterOptions = require('./utils/defaultFilterOptions'); var _defaultFilterOptions2 = _interopRequireDefault(_defaultFilterOptions); var _defaultMenuRenderer = require('./utils/defaultMenuRenderer'); var _defaultMenuRenderer2 = _interopRequireDefault(_defaultMenuRenderer); var _Select = require('./Select'); var _Select2 = _interopRequireDefault(_Select); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var 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; } _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; if (isValidNewOption({ label: this.inputValue })) { var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); var _isOptionUnique = this.isOptionUnique({ option: option, options: options }); // 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, promptTextCreator = _props2.promptTextCreator; // TRICKY Check currently selected options as well. // Don't display a create-prompt for a value that's selected. // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array. var excludeOptions = (arguments.length <= 2 ? undefined : arguments[2]) || []; var filteredOptions = filterOptions.apply(undefined, arguments) || []; if (isValidNewOption({ label: this.inputValue })) { var _newOptionCreator = this.props.newOptionCreator; var option = _newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); // TRICKY Compare to all options (not just filtered options) in case option has already been selected). // For multi-selects, this would remove it from the filtered list. var _isOptionUnique2 = this.isOptionUnique({ option: option, options: excludeOptions.concat(filteredOptions) }); if (_isOptionUnique2) { var prompt = promptTextCreator(this.inputValue); this._createPlaceholderOption = _newOptionCreator({ label: prompt, labelKey: this.labelKey, valueKey: this.valueKey }); filteredOptions.unshift(this._createPlaceholderOption); } } return filteredOptions; } }, { key: 'isOptionUnique', value: function isOptionUnique(_ref) { var option = _ref.option, options = _ref.options; var isOptionUnique = this.props.isOptionUnique; options = options || this.props.options; return isOptionUnique({ labelKey: this.labelKey, option: option, options: options, valueKey: this.valueKey }); } }, { key: 'menuRenderer', value: function menuRenderer(params) { var menuRenderer = this.props.menuRenderer; return menuRenderer(_extends({}, params, { onSelect: this.onOptionSelect, selectValue: this.onOptionSelect })); } }, { key: 'onInputChange', value: function onInputChange(input) { var onInputChange = this.props.onInputChange; // This value may be needed in between Select mounts (when this.select is null) this.inputValue = input; if (onInputChange) { this.inputValue = onInputChange(input); } return this.inputValue; } }, { 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) { 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; var _props4 = this.props, refProp = _props4.ref, restProps = _objectWithoutProperties(_props4, ['ref']); var children = this.props.children; // We can't use destructuring default values to set the children, // because it won't apply work if `children` is null. A falsy check is // more reliable in real world use-cases. if (!children) { children = defaultChildren; } var props = _extends({}, restProps, { allowCreate: true, filterOptions: this.filterOptions, menuRenderer: this.menuRenderer, onInputChange: this.onInputChange, onInputKeyDown: this.onInputKeyDown, ref: function ref(_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; } if (refProp) { refProp(_ref2); } } }); return children(props); } }]); return CreatableSelect; }(_react2.default.Component); var defaultChildren = function defaultChildren(props) { return _react2.default.createElement(_Select2.default, props); }; var isOptionUnique = function isOptionUnique(_ref3) { var option = _ref3.option, options = _ref3.options, labelKey = _ref3.labelKey, valueKey = _ref3.valueKey; if (!options || !options.length) { return true; } return options.filter(function (existingOption) { return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey]; }).length === 0; }; var isValidNewOption = function isValidNewOption(_ref4) { var label = _ref4.label; return !!label; }; var newOptionCreator = 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'; return option; }; var promptTextCreator = function promptTextCreator(label) { return 'Create option "' + label + '"'; }; var shouldKeyDownEventCreateNewOption = function shouldKeyDownEventCreateNewOption(_ref6) { var keyCode = _ref6.keyCode; switch (keyCode) { case 9: // TAB case 13: // ENTER case 188: // COMMA return true; default: return false; } }; // Default prop methods CreatableSelect.isOptionUnique = isOptionUnique; CreatableSelect.isValidNewOption = isValidNewOption; CreatableSelect.newOptionCreator = newOptionCreator; CreatableSelect.promptTextCreator = promptTextCreator; CreatableSelect.shouldKeyDownEventCreateNewOption = shouldKeyDownEventCreateNewOption; CreatableSelect.defaultProps = { 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: _propTypes2.default.func, // See Select.propTypes.filterOptions 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: _propTypes2.default.func, // Determines if the current input text represents a valid option. // ({ label: string }): boolean isValidNewOption: _propTypes2.default.func, // See Select.propTypes.menuRenderer menuRenderer: _propTypes2.default.any, // Factory to create new option. // ({ label: string, labelKey: string, valueKey: string }): Object newOptionCreator: _propTypes2.default.func, // input change handler: function (inputValue) {} onInputChange: _propTypes2.default.func, // input keyDown handler: function (event) {} onInputKeyDown: _propTypes2.default.func, // new option click handler: function (option) {} onNewOptionClick: _propTypes2.default.func, // See Select.propTypes.options options: _propTypes2.default.array, // Creates prompt/placeholder option text. // (filterText: string): string promptTextCreator: _propTypes2.default.func, ref: _propTypes2.default.func, // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. shouldKeyDownEventCreateNewOption: _propTypes2.default.func }; exports.default = CreatableSelect;