UNPKG

react-select-plus

Version:

A fork of react-select with support for option groups

320 lines (246 loc) 9.82 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _Select = require('./Select'); var _Select2 = _interopRequireDefault(_Select); var _utilsDefaultFilterOptions = require('./utils/defaultFilterOptions'); var _utilsDefaultFilterOptions2 = _interopRequireDefault(_utilsDefaultFilterOptions); var _utilsDefaultMenuRenderer = require('./utils/defaultMenuRenderer'); var _utilsDefaultMenuRenderer2 = _interopRequireDefault(_utilsDefaultMenuRenderer); var Creatable = _react2['default'].createClass({ displayName: 'CreatableSelect', propTypes: { // Child function responsible for creating the inner Select component // This component can be used to compose HOCs (eg Creatable and Async) // (props: Object): PropTypes.element children: _react2['default'].PropTypes.func, // See Select.propTypes.filterOptions filterOptions: _react2['default'].PropTypes.any, // Searches for any matching option within the set of options. // This function prevents duplicate options from being created. // ({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean isOptionUnique: _react2['default'].PropTypes.func, // Determines if the current input text represents a valid option. // ({ label: string }): boolean isValidNewOption: _react2['default'].PropTypes.func, // See Select.propTypes.menuRenderer menuRenderer: _react2['default'].PropTypes.any, // Factory to create new option. // ({ label: string, labelKey: string, valueKey: string }): Object newOptionCreator: _react2['default'].PropTypes.func, // input change handler: function (inputValue) {} onInputChange: _react2['default'].PropTypes.func, // input keyDown handler: function (event) {} onInputKeyDown: _react2['default'].PropTypes.func, // new option click handler: function (option) {} onNewOptionClick: _react2['default'].PropTypes.func, // See Select.propTypes.options options: _react2['default'].PropTypes.array, // Creates prompt/placeholder option text. // (filterText: string): string promptTextCreator: _react2['default'].PropTypes.func, // Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. shouldKeyDownEventCreateNewOption: _react2['default'].PropTypes.func }, // Default prop methods statics: { isOptionUnique: isOptionUnique, isValidNewOption: isValidNewOption, newOptionCreator: newOptionCreator, promptTextCreator: promptTextCreator, shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption }, getDefaultProps: function getDefaultProps() { return { filterOptions: _utilsDefaultFilterOptions2['default'], isOptionUnique: isOptionUnique, isValidNewOption: isValidNewOption, menuRenderer: _utilsDefaultMenuRenderer2['default'], newOptionCreator: newOptionCreator, promptTextCreator: promptTextCreator, shouldKeyDownEventCreateNewOption: shouldKeyDownEventCreateNewOption }; }, createNewOption: function createNewOption() { var _props = this.props; var isValidNewOption = _props.isValidNewOption; var newOptionCreator = _props.newOptionCreator; var onNewOptionClick = _props.onNewOptionClick; var _props$options = _props.options; var options = _props$options === undefined ? [] : _props$options; var shouldKeyDownEventCreateNewOption = _props.shouldKeyDownEventCreateNewOption; if (isValidNewOption({ label: this.inputValue })) { var option = newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); var _isOptionUnique = this.isOptionUnique({ option: option }); // Don't add the same option twice. if (_isOptionUnique) { if (onNewOptionClick) { onNewOptionClick(option); } else { options.unshift(option); this.select.selectValue(option); } } } }, filterOptions: function filterOptions() { var _props2 = this.props; var filterOptions = _props2.filterOptions; var isValidNewOption = _props2.isValidNewOption; var options = _props2.options; var promptTextCreator = _props2.promptTextCreator; // TRICKY Check currently selected options as well. // Don't display a create-prompt for a value that's selected. // This covers async edge-cases where a newly-created Option isn't yet in the async-loaded array. var excludeOptions = arguments[2] || []; var filteredOptions = filterOptions.apply(undefined, arguments) || []; if (isValidNewOption({ label: this.inputValue })) { var _newOptionCreator = this.props.newOptionCreator; var option = _newOptionCreator({ label: this.inputValue, labelKey: this.labelKey, valueKey: this.valueKey }); // TRICKY Compare to all options (not just filtered options) in case option has already been selected). // For multi-selects, this would remove it from the filtered list. var _isOptionUnique2 = this.isOptionUnique({ option: option, options: excludeOptions.concat(filteredOptions) }); if (_isOptionUnique2) { var _prompt = promptTextCreator(this.inputValue); this._createPlaceholderOption = _newOptionCreator({ label: _prompt, labelKey: this.labelKey, valueKey: this.valueKey }); filteredOptions.unshift(this._createPlaceholderOption); } } return filteredOptions; }, isOptionUnique: function isOptionUnique(_ref2) { var option = _ref2.option; var options = _ref2.options; var isOptionUnique = this.props.isOptionUnique; options = options || this.select.filterFlatOptions(); return isOptionUnique({ labelKey: this.labelKey, option: option, options: options, valueKey: this.valueKey }); }, menuRenderer: function menuRenderer(params) { var menuRenderer = this.props.menuRenderer; return menuRenderer(_extends({}, params, { onSelect: this.onOptionSelect, selectValue: this.onOptionSelect })); }, onInputChange: function onInputChange(input) { var onInputChange = this.props.onInputChange; if (onInputChange) { onInputChange(input); } // This value may be needed in between Select mounts (when this.select is null) this.inputValue = input; }, onInputKeyDown: function onInputKeyDown(event) { var _props3 = this.props; var shouldKeyDownEventCreateNewOption = _props3.shouldKeyDownEventCreateNewOption; var onInputKeyDown = _props3.onInputKeyDown; var focusedOption = this.select.getFocusedOption(); if (focusedOption && focusedOption === this._createPlaceholderOption && shouldKeyDownEventCreateNewOption({ keyCode: event.keyCode })) { this.createNewOption(); // Prevent decorated Select from doing anything additional with this keyDown event event.preventDefault(); } else if (onInputKeyDown) { onInputKeyDown(event); } }, onOptionSelect: function onOptionSelect(option, event) { if (option === this._createPlaceholderOption) { this.createNewOption(); } else { this.select.selectValue(option); } }, focus: function focus() { this.select.focus(); }, render: function render() { var _this = this; var _props4 = this.props; var newOptionCreator = _props4.newOptionCreator; var shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption; var restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption']); var children = this.props.children; // We can't use destructuring default values to set the children, // because it won't apply work if `children` is null. A falsy check is // more reliable in real world use-cases. if (!children) { children = defaultChildren; } var props = _extends({}, restProps, { allowCreate: true, filterOptions: this.filterOptions, menuRenderer: this.menuRenderer, onInputChange: this.onInputChange, onInputKeyDown: this.onInputKeyDown, ref: function ref(_ref) { _this.select = _ref; // These values may be needed in between Select mounts (when this.select is null) if (_ref) { _this.labelKey = _ref.props.labelKey; _this.valueKey = _ref.props.valueKey; } } }); return children(props); } }); function defaultChildren(props) { return _react2['default'].createElement(_Select2['default'], props); }; function isOptionUnique(_ref3) { var option = _ref3.option; var options = _ref3.options; var labelKey = _ref3.labelKey; var valueKey = _ref3.valueKey; return options.filter(function (existingOption) { return existingOption[labelKey] === option[labelKey] || existingOption[valueKey] === option[valueKey]; }).length === 0; }; function isValidNewOption(_ref4) { var label = _ref4.label; return !!label; }; function newOptionCreator(_ref5) { var label = _ref5.label; var labelKey = _ref5.labelKey; var valueKey = _ref5.valueKey; var option = {}; option[valueKey] = label; option[labelKey] = label; option.className = 'Select-create-option-placeholder'; return option; }; function promptTextCreator(label) { return 'Create option "' + label + '"'; } function shouldKeyDownEventCreateNewOption(_ref6) { var keyCode = _ref6.keyCode; switch (keyCode) { case 9: // TAB case 13: // ENTER case 188: // COMMA return true; } return false; }; module.exports = Creatable;