UNPKG

wix-style-react

Version:
348 lines (346 loc) • 13.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _InputWithOptions = _interopRequireDefault(require("../InputWithOptions")); var _InputWithTags = _interopRequireDefault(require("./InputWithTags")); var _last = _interopRequireDefault(require("lodash/last")); var _difference = _interopRequireDefault(require("difference")); var _MultiSelectSt = require("./MultiSelect.st.css"); var _excluded = ["className", "data-ref"], _excluded2 = ["className", "ref"]; var _jsxFileName = "/home/builduser/work/a9c1ac8876d5057c/packages/wix-style-react/dist/cjs/MultiSelect/MultiSelect.js", _MultiSelect; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } class MultiSelect extends _InputWithOptions.default { constructor(props) { super(props); this.onKeyDown = this.onKeyDown.bind(this); this.onPaste = this.onPaste.bind(this); this._onBlur = this._onBlur.bind(this); this.state = _objectSpread(_objectSpread({}, this.state), {}, { pasteDetected: false }); } hideOptions() { super.hideOptions(); if (this.props.clearOnBlur) { this.clearInput(); } } rootAdditionalProps() { var { className } = this.props; return { className: (0, _MultiSelectSt.st)(_MultiSelectSt.classes.root, className) }; } onClickOutside() { if (this.state.showOptions) { this.hideOptions(); } } _onBlur(event) { super._onBlur(event); this.props.acceptOnBlur && this.submitValue(this.state.inputValue); } getUnselectedOptions() { var optionIds = this.props.options.map(option => option.id); var tagIds = this.props.tags.map(tag => tag.id); var unselectedOptionsIds = (0, _difference.default)(optionIds, tagIds); return this.props.options.filter(option => unselectedOptionsIds.includes(option.id)); } dropdownAdditionalProps() { var { predicate, emptyStateMessage, fixedFooter } = this.props; var filterFunc = this.state.isEditing ? predicate : () => true; var filtered = this.getUnselectedOptions().filter(filterFunc); var options = filtered; if (emptyStateMessage && filtered.length === 0) { options = [{ id: 'empty-state-message', value: emptyStateMessage, disabled: true }]; } return { options, closeOnSelect: false, selectedHighlight: false, selectedId: -1, fixedFooter }; } closeOnSelect() { return false; } inputAdditionalProps() { return { readOnly: this.props.readOnly, disableEditing: true, inputElement: /*#__PURE__*/_react.default.createElement(_InputWithTags.default, { className: _MultiSelectSt.classes.inputWithTags, onReorder: this.props.onReorder, maxNumRows: this.props.maxNumRows, mode: this.props.mode, hideCustomSuffix: this.isDropdownLayoutVisible(), customSuffix: this.props.customSuffix, border: this.props.border, __self: this, __source: { fileName: _jsxFileName, lineNumber: 89, columnNumber: 9 } }), onKeyDown: this.onKeyDown, delimiters: this.props.delimiters, onPaste: this.onPaste }; } onPaste() { this.setState({ pasteDetected: true }); } _splitByDelimitersAndTrim(value) { var delimitersRegexp = new RegExp(this.props.delimiters.join('|'), 'g'); return value.split(delimitersRegexp).map(str => str.trim()).filter(str => str); } _onChange(event) { if (this.state.pasteDetected) { var value = event.target.value; this.setState({ pasteDetected: false }, () => { this.submitValue(value); }); } else { this.setState({ inputValue: event.target.value }); this.props.onChange && this.props.onChange(event); } // If the input value is not empty, should show the options if (event.target.value.trim()) { this.showOptions(); } } _onSelect(option) { this.onSelect(option); } _onManuallyInput(inputValue, event) { var { value } = this.props; // FIXME: InputWithOptions is not updating it's inputValue state when the `value` prop changes. // So using `value` here, covers for that bug. (This is tested) // BTW: Previously, `value` was used to trigger onSelect, and `inputValue` was used to trigger onManuallyInput. Which is crazy. // So now both of them trigger a submit (onManuallyInput). var _value = value && value.trim() || inputValue && inputValue.trim(); this.submitValue(_value); _value && event.preventDefault(); if (this.closeOnSelect()) { this.hideOptions(); } } getManualSubmitKeys() { return ['Enter', 'Tab'].concat(this.props.delimiters); } onKeyDown(event) { var { tags, value, onRemoveTag } = this.props; if (tags.length > 0 && (event.key === 'Delete' || event.key === 'Backspace') && value && value.length === 0) { onRemoveTag((0, _last.default)(tags).id); } if (event.key === 'Escape') { this.clearInput(); super.hideOptions(); } if (this.props.onKeyDown) { this.props.onKeyDown(event); } } optionToTag(_ref) { var { id, value, tag, theme } = _ref; return tag ? _objectSpread({ id }, tag) : { id, label: value, theme }; } onSelect(option) { this.clearInput(); var { onSelect } = this.props; if (onSelect) { onSelect(this.props.options.find(o => o.id === option.id)); } } submitValue(inputValue) { if (!inputValue) { return; } var { onManuallyInput } = this.props; var values = this._splitByDelimitersAndTrim(inputValue); onManuallyInput && values.length && onManuallyInput(values); this.clearInput(); } clearInput() { this.input.current && this.input.current.clear(); if (this.props.onChange) { this.props.onChange({ target: { value: '' } }); } } } _MultiSelect = MultiSelect; MultiSelect.autoSizeInput = _ref2 => { var { className, 'data-ref': dataRef } = _ref2, rest = (0, _objectWithoutProperties2.default)(_ref2, _excluded); var inputClassName = (0, _classnames.default)(className, _MultiSelectSt.classes.autoSizeInput); return /*#__PURE__*/_react.default.createElement("input", (0, _extends2.default)({}, rest, { ref: dataRef, className: inputClassName, __self: _MultiSelect, __source: { fileName: _jsxFileName, lineNumber: 215, columnNumber: 12 } })); }; MultiSelect.autoSizeInputWithRef = () => /*#__PURE__*/_react.default.forwardRef((props, ref) => (_ref3 => { var { className, ref } = _ref3, rest = (0, _objectWithoutProperties2.default)(_ref3, _excluded2); var inputClassName = (0, _classnames.default)(className, _MultiSelectSt.classes.autoSizeInput); return /*#__PURE__*/_react.default.createElement("input", (0, _extends2.default)({}, rest, { ref: ref, className: inputClassName, __self: _MultiSelect, __source: { fileName: _jsxFileName, lineNumber: 222, columnNumber: 16 } })); })(_objectSpread(_objectSpread({}, props), {}, { ref }))); MultiSelect.displayName = 'MultiSelect'; MultiSelect.propTypes = { /** Associate a control with the regions that it controls.*/ ariaControls: _propTypes.default.string, /** Associate a region with its descriptions. Similar to aria-controls but instead associating descriptions to the region and description identifiers are separated with a space.*/ ariaDescribedby: _propTypes.default.string, /** Define a string that labels the current element in case where a text label is not visible on the screen. */ ariaLabel: _propTypes.default.string, /** Control the border style of input */ border: _propTypes.default.oneOf(['standard', 'round', 'bottomLine', 'none']), /** Closes list once list item is selected */ closeOnSelect: _propTypes.default.bool, /** Allows to pass all common popover props. */ popoverProps: _propTypes.default.shape({ appendTo: _propTypes.default.oneOf(['window', 'scrollParent', 'parent', 'viewport']), maxWidth: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]), minWidth: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]), flip: _propTypes.default.bool, fixed: _propTypes.default.bool, placement: _propTypes.default.oneOf(['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start']), dynamicWidth: _propTypes.default.bool }), /** Callback predicate for the filtering options function */ predicate: _propTypes.default.func, /** Optional list of strings that are selected suggestions. */ tags: _propTypes.default.array, /** Max number of visible lines */ maxNumRows: _propTypes.default.number, /** Delimiters that will trigger a Submit action (call to onTagsAdded). By default it is [,] but also enter and tab keys work. */ delimiters: _propTypes.default.array, /** Defines a message to be displayed instead of options when no options exist or no options pass the predicate filter function. */ emptyStateMessage: _propTypes.default.node, /** Specifies whether there are more items to be loaded. */ hasMore: _propTypes.default.bool, /** Specifies whether lazy loading of the dropdown layout items is enabled. */ infiniteScroll: _propTypes.default.bool, /** Defines a callback function which is called on a request to render more list items. */ loadMore: _propTypes.default.func, /** Passing 'select' will render a readOnly input with menuArrow suffix **/ mode: _propTypes.default.string, /** The status of the Multiselect */ status: _propTypes.default.oneOf(['loading', 'warning', 'error']), /** Text to be shown in the status icon tooltip */ statusMessage: _propTypes.default.string, /** When this callback function is set, tags can be reordered. The expected callback signature is `onReorder({addedIndex: number, removedIndex: number}) => void` **/ onReorder: _propTypes.default.func, /** A callback which is called when the user enters something in the input and then confirms the input with some action like Enter key or Tab. */ onManuallyInput: _propTypes.default.func, /** A callback which is called when options dropdown is shown */ onOptionsShow: _propTypes.default.func, /** A callback which is called when options dropdown is hidden */ onOptionsHide: _propTypes.default.func, /** A callback which is called when the user selects an option from the list. `onSelect(option: Option): void` - Option is the original option from the provided options prop. */ onSelect: _propTypes.default.func, /** A node to display as input suffix when the dropdown is closed */ customSuffix: _propTypes.default.node, /** When set to true this component is disabled */ disabled: _propTypes.default.bool, /** When set to false, the input will not be cleared on blur */ clearOnBlur: _propTypes.default.bool, /** When set to true, the input will be submitted as new tag on blur */ acceptOnBlur: _propTypes.default.bool, /** A callback function to be called when a tag should be removed. The expected callback signature is `onRemoveTag(tagId: number | string) => void.` */ onRemoveTag: _propTypes.default.func, /** Specifies whether input should be read only */ readOnly: _propTypes.default.bool, /** Adds a fixed footer container at the bottom of options list. */ fixedFooter: _propTypes.default.node, /** Sets the default option focus behavior: * - `false` - no initially focused list item * - `true` - focus first selectable option * - any `number/string` specify the id of an option to be focused */ markedOption: _propTypes.default.oneOfType([_propTypes.default.bool, _propTypes.default.string, _propTypes.default.number]) }; MultiSelect.defaultProps = _objectSpread(_objectSpread({}, _InputWithOptions.default.defaultProps), {}, { predicate: () => true, tags: [], delimiters: [','], clearOnBlur: true, customInput: MultiSelect.autoSizeInputWithRef() }); var _default = exports.default = MultiSelect; //# sourceMappingURL=MultiSelect.js.map