UNPKG

wix-style-react

Version:
357 lines (307 loc) • 12.7 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import _get from "@babel/runtime/helpers/get"; import _inherits from "@babel/runtime/helpers/inherits"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; var _excluded = ["className", "data-ref"], _excluded2 = ["className", "ref"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import InputWithOptions from '../InputWithOptions/InputWithOptions'; import InputWithTags from './InputWithTags'; import last from 'lodash/last'; import difference from 'difference'; import { classes } from './MultiSelect.st.css'; var MultiSelect = /*#__PURE__*/function (_InputWithOptions) { _inherits(MultiSelect, _InputWithOptions); var _super = _createSuper(MultiSelect); function MultiSelect(props) { var _this; _classCallCheck(this, MultiSelect); _this = _super.call(this, props); _this.onKeyDown = _this.onKeyDown.bind(_assertThisInitialized(_this)); _this.onPaste = _this.onPaste.bind(_assertThisInitialized(_this)); _this.state = _objectSpread(_objectSpread({}, _this.state), {}, { pasteDetected: false }); return _this; } _createClass(MultiSelect, [{ key: "hideOptions", value: function hideOptions() { _get(_getPrototypeOf(MultiSelect.prototype), "hideOptions", this).call(this); if (this.props.clearOnBlur) { this.clearInput(); } } }, { key: "onClickOutside", value: function onClickOutside() { if (this.state.showOptions) { this.hideOptions(); } } }, { key: "getUnselectedOptions", value: function getUnselectedOptions() { var optionIds = this.props.options.map(function (option) { return option.id; }); var tagIds = this.props.tags.map(function (tag) { return tag.id; }); var unselectedOptionsIds = difference(optionIds, tagIds); return this.props.options.filter(function (option) { return unselectedOptionsIds.includes(option.id); }); } }, { key: "dropdownAdditionalProps", value: function dropdownAdditionalProps() { return { options: this.getUnselectedOptions().filter(this.props.predicate), closeOnSelect: false, selectedHighlight: false, selectedId: -1 }; } }, { key: "closeOnSelect", value: function closeOnSelect() { return false; } }, { key: "inputAdditionalProps", value: function inputAdditionalProps() { return { readOnly: false, disableEditing: true, inputElement: /*#__PURE__*/React.createElement(InputWithTags, { onReorder: this.props.onReorder, maxNumRows: this.props.maxNumRows, mode: this.props.mode, hideCustomSuffix: this.isDropdownLayoutVisible(), customSuffix: this.props.customSuffix }), onKeyDown: this.onKeyDown, delimiters: this.props.delimiters, onPaste: this.onPaste }; } }, { key: "onPaste", value: function onPaste() { this.setState({ pasteDetected: true }); } }, { key: "_splitByDelimitersAndTrim", value: function _splitByDelimitersAndTrim(value) { var delimitersRegexp = new RegExp(this.props.delimiters.join('|'), 'g'); return value.split(delimitersRegexp).map(function (str) { return str.trim(); }).filter(function (str) { return str; }); } }, { key: "_onChange", value: function _onChange(event) { var _this2 = this; if (this.state.pasteDetected) { var value = event.target.value; this.setState({ pasteDetected: false }, function () { _this2.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(); } } }, { key: "_onSelect", value: function _onSelect(option) { this.onSelect(option); } }, { key: "_onManuallyInput", value: function _onManuallyInput(inputValue, event) { var value = this.props.value; // 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(); } } }, { key: "getManualSubmitKeys", value: function getManualSubmitKeys() { return ['Enter', 'Tab'].concat(this.props.delimiters); } }, { key: "onKeyDown", value: function onKeyDown(event) { var _this$props = this.props, tags = _this$props.tags, value = _this$props.value, onRemoveTag = _this$props.onRemoveTag; if (tags.length > 0 && (event.key === 'Delete' || event.key === 'Backspace') && value.length === 0) { onRemoveTag(last(tags).id); } if (event.key === 'Escape') { this.clearInput(); _get(_getPrototypeOf(MultiSelect.prototype), "hideOptions", this).call(this); } if (this.props.onKeyDown) { this.props.onKeyDown(event); } } }, { key: "optionToTag", value: function optionToTag(_ref) { var id = _ref.id, value = _ref.value, tag = _ref.tag, theme = _ref.theme; return tag ? _objectSpread({ id: id }, tag) : { id: id, label: value, theme: theme }; } }, { key: "onSelect", value: function onSelect(option) { this.clearInput(); var onSelect = this.props.onSelect; if (onSelect) { onSelect(this.props.options.find(function (o) { return o.id === option.id; })); } } }, { key: "submitValue", value: function submitValue(inputValue) { if (!inputValue) { return; } var onManuallyInput = this.props.onManuallyInput; var values = this._splitByDelimitersAndTrim(inputValue); onManuallyInput && values.length && onManuallyInput(values); this.clearInput(); } }, { key: "clearInput", value: function clearInput() { this.input.current && this.input.current.clear(); if (this.props.onChange) { this.props.onChange({ target: { value: '' } }); } } }]); return MultiSelect; }(InputWithOptions); _defineProperty(MultiSelect, "autoSizeInput", function (_ref2) { var className = _ref2.className, dataRef = _ref2['data-ref'], rest = _objectWithoutProperties(_ref2, _excluded); var inputClassName = classNames(className, classes.autoSizeInput); return /*#__PURE__*/React.createElement("input", _extends({}, rest, { ref: dataRef, className: inputClassName })); }); _defineProperty(MultiSelect, "autoSizeInputWithRef", function () { return /*#__PURE__*/React.forwardRef(function (props, ref) { return function (_ref3) { var className = _ref3.className, ref = _ref3.ref, rest = _objectWithoutProperties(_ref3, _excluded2); var inputClassName = classNames(className, classes.autoSizeInput); return /*#__PURE__*/React.createElement("input", _extends({}, rest, { ref: ref, className: inputClassName })); }(_objectSpread(_objectSpread({}, props), {}, { ref: ref })); }); }); MultiSelect.displayName = 'MultiSelect'; MultiSelect.propTypes = { /** Closes list once list item is selected */ closeOnSelect: PropTypes.bool, /** Callback predicate for the filtering options function */ predicate: PropTypes.func, /** Optional list of strings that are selected suggestions. */ tags: PropTypes.array, /** Max number of visible lines */ maxNumRows: PropTypes.number, /** Delimiters that will trigger a Submit action (call to onTagsAdded). By default it is [,] but also enter and tab keys work. */ delimiters: PropTypes.array, /** Passing 'select' will render a readOnly input with menuArrow suffix **/ mode: PropTypes.string, /** The status of the Multiselect */ status: PropTypes.oneOf(['loading', 'warning', 'error']), /** Text to be shown in the status icon tooltip */ statusMessage: PropTypes.string, /** When this callback function is set, tags can be reordered. The expected callback signature is `onReorder({addedIndex: number, removedIndex: number}) => void` **/ onReorder: PropTypes.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.func, /** A callback which is called when options dropdown is shown */ onOptionsShow: PropTypes.func, /** A callback which is called when options dropdown is hidden */ onOptionsHide: PropTypes.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.func, /** Allows adding your own custom Input component instead of the one that is used by default internally. */ customInput: PropTypes.elementType ? PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]) : PropTypes.oneOfType([PropTypes.func]), /** A node to display as input suffix when the dropdown is closed */ customSuffix: PropTypes.node, /** When set to true this component is disabled */ disabled: PropTypes.bool, /** When set to false, the input will not be cleared on blur */ clearOnBlur: PropTypes.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.func }; MultiSelect.defaultProps = _objectSpread(_objectSpread({}, InputWithOptions.defaultProps), {}, { predicate: function predicate() { return true; }, tags: [], delimiters: [','], clearOnBlur: true, customInput: MultiSelect.autoSizeInputWithRef() }); export default MultiSelect;