wix-style-react
Version:
wix-style-react
348 lines (346 loc) • 13.7 kB
JavaScript
"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