373 lines
12 KiB
JavaScript
373 lines
12 KiB
JavaScript
'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; }
|
|
|
|
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,
|
|
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,
|
|
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, 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;
|
|
|
|
var _props4 = this.props,
|
|
newOptionCreator = _props4.newOptionCreator,
|
|
shouldKeyDownEventCreateNewOption = _props4.shouldKeyDownEventCreateNewOption,
|
|
refProp = _props4.ref,
|
|
restProps = _objectWithoutProperties(_props4, ['newOptionCreator', 'shouldKeyDownEventCreateNewOption', '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);
|
|
|
|
;
|
|
|
|
function defaultChildren(props) {
|
|
return _react2.default.createElement(_Select2.default, props);
|
|
};
|
|
|
|
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(_ref4) {
|
|
var label = _ref4.label;
|
|
|
|
return !!label;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
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;
|
|
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; |