UNPKG

suomifi-ui-components

Version:
596 lines (590 loc) 26.7 kB
'use strict'; var tslib = require('tslib'); var React = require('react'); var styled = require('styled-components'); var classnames = require('classnames'); require('../../../../reset/HtmlA/HtmlA.js'); require('../../../../reset/HtmlButton/HtmlButton.js'); var HtmlDiv = require('../../../../reset/HtmlDiv/HtmlDiv.js'); require('../../../../reset/HtmlFieldSet/HtmlFieldSet.js'); require('../../../../reset/HtmlH/HtmlH.js'); require('../../../../reset/HtmlInput/HtmlInput.js'); require('../../../../reset/HtmlLabel/HtmlLabel.js'); require('../../../../reset/HtmlLegend/HtmlLegend.js'); require('../../../../reset/HtmlLi/HtmlLi.js'); require('../../../../reset/HtmlNav/HtmlNav.js'); require('../../../../reset/HtmlOl/HtmlOl.js'); require('../../../../reset/HtmlSpan/HtmlSpan.js'); require('../../../../reset/HtmlTextarea/HtmlTextarea.js'); require('../../../../reset/HtmlUl/HtmlUl.js'); require('../../../../reset/HtmlTable/HtmlTable.js'); require('../../../../reset/HtmlTable/HtmlTableCaption.js'); require('../../../../reset/HtmlTable/HtmlTableHeader.js'); require('../../../../reset/HtmlTable/HtmlTableRow.js'); require('../../../../reset/HtmlTable/HtmlTableBody.js'); require('../../../../reset/HtmlTable/HtmlTableHeaderCell.js'); require('../../../../reset/HtmlTable/HtmlTableCell.js'); var common = require('../../../../utils/common/common.js'); var AutoId = require('../../../utils/AutoId/AutoId.js'); var Debounce = require('../../../utils/Debounce/Debounce.js'); var Popover = require('../../../Popover/Popover.js'); var SuomifiThemeProvider = require('../../../theme/SuomifiThemeProvider/SuomifiThemeProvider.js'); require('../../../theme/SuomifiTheme/SuomifiTheme.js'); var SpacingProvider = require('../../../theme/SpacingProvider/SpacingProvider.js'); var spacing = require('../../../theme/utils/spacing.js'); var FilterInput = require('../../FilterInput/FilterInput.js'); var LoadingSpinner = require('../../../LoadingSpinner/LoadingSpinner.js'); var VisuallyHidden = require('../../../VisuallyHidden/VisuallyHidden.js'); var InputClearButton = require('../../InputClearButton/InputClearButton.js'); var SelectItemList = require('../BaseSelect/SelectItemList/SelectItemList.js'); var SelectItem = require('../BaseSelect/SelectItem/SelectItem.js'); var SelectEmptyItem = require('../BaseSelect/SelectEmptyItem/SelectEmptyItem.js'); var InputToggleButton = require('../../InputToggleButton/InputToggleButton.js'); var SingleSelect_baseStyles = require('./SingleSelect.baseStyles.js'); var SelectItemAddition = require('../BaseSelect/SelectItemAddition/SelectItemAddition.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); var classnames__default = /*#__PURE__*/_interopDefault(classnames); var baseClassName = 'fi-single-select'; var singleSelectClassNames = { valueSelected: "".concat(baseClassName, "--value-selected"), clearButtonWrapper: "".concat(baseClassName, "_clear-button_wrapper"), open: "".concat(baseClassName, "--open"), error: "".concat(baseClassName, "--error"), queryHighlight: "".concat(baseClassName, "-item--query_highlight"), fullWidth: "".concat(baseClassName, "--full-width") }; var BaseSingleSelect = function (_super) { tslib.__extends(BaseSingleSelect, _super); function BaseSingleSelect(props) { var _this = this; var _a, _b; _this = _super.call(this, props) || this; _this.preventShowPopoverOnInputFocus = false; _this.state = { filterInputValue: ((_a = _this.props.selectedItem) === null || _a === void 0 ? void 0 : _a.labelText) ? _this.props.selectedItem.labelText : ((_b = _this.props.defaultSelectedItem) === null || _b === void 0 ? void 0 : _b.labelText) || '', filteredItems: _this.props.items, filterMode: false, showPopover: false, focusedDescendantId: null, selectedItem: _this.props.selectedItem ? _this.props.selectedItem : _this.props.defaultSelectedItem || null, initialItems: _this.props.items, computedItems: _this.props.items, popoverPlacement: 'bottom' }; _this.filter = function (data, query) { return data.labelText.toLowerCase().includes(query.toLowerCase()); }; _this.handleBlur = function () { if (!!_this.props.onBlur) { _this.props.onBlur(); } var ownerDocument = common.getOwnerDocument(_this.popoverListRef); if (!ownerDocument) { return; } requestAnimationFrame(function () { var _a, _b; var focusInPopover = (_a = _this.popoverListRef.current) === null || _a === void 0 ? void 0 : _a.contains(ownerDocument.activeElement); var focusInToggleButton = (_b = _this.toggleButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(ownerDocument.activeElement); var focusInInput = ownerDocument.activeElement === _this.filterInputRef.current; var focusInSingleSelect = focusInPopover || focusInInput || focusInToggleButton; if (!focusInSingleSelect) { _this.setState(function (prevState) { var _a; return { filterInputValue: ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.labelText) || '', filterMode: false, showPopover: focusInSingleSelect, focusedDescendantId: null }; }); } }); }; _this.handleOnChange = function (value) { _this.setState(function (prevState) { var _a; var newValue = prevState.filterMode || !prevState.selectedItem ? value : value.replace(new RegExp("^".concat(common.escapeStringRegexp(((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.labelText) || ''))), ''); return { filterInputValue: newValue, showPopover: true, filterMode: true }; }); }; _this.focusToInputAndSelectText = function () { if (!!_this.filterInputRef && _this.filterInputRef.current) { _this.filterInputRef.current.focus(); setTimeout(function () { var _a; return (_a = _this.filterInputRef.current) === null || _a === void 0 ? void 0 : _a.select(); }, 100); } }; _this.focusToInputAndCloseMenu = function () { _this.focusToInputAndSelectText(); _this.setState(function (prevState) { var _a; return { showPopover: false, filterMode: false, focusedDescendantId: null, filterInputValue: ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.labelText) || '' }; }); }; _this.handleItemSelection = function (item) { if (item !== null && item.disabled) return; var _a = _this.props, onItemSelect = _a.onItemSelect, onItemSelectionChange = _a.onItemSelectionChange, controlledItem = _a.selectedItem; if (!controlledItem) { var userAddedSelectedItem = []; if (item !== null) { var itemIsFromPropItems = _this.props.items.some(function (propItem) { return propItem.uniqueItemId === item.uniqueItemId; }); if (!itemIsFromPropItems) { userAddedSelectedItem.push(item); } } _this.setState({ selectedItem: item || null, filterInputValue: (item === null || item === void 0 ? void 0 : item.labelText) || '', focusedDescendantId: null, computedItems: _this.props.items.concat(userAddedSelectedItem) }); } else { _this.setState(function (prevState) { var _a; return { filterInputValue: ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.labelText) || '' }; }); } if (!!onItemSelect) { onItemSelect((item === null || item === void 0 ? void 0 : item.uniqueItemId) || null); } if (!!onItemSelectionChange) { onItemSelectionChange(item); } _this.focusToInputAndCloseMenu(); }; _this.handleKeyDown = function (event) { var _a = _this.state, filteredItems = _a.filteredItems, focusedDescendantId = _a.focusedDescendantId, filterMode = _a.filterMode, filterInputValue = _a.filterInputValue; var popoverItems = !!filterMode ? filteredItems : _this.state.computedItems; var index = !!focusedDescendantId ? popoverItems.findIndex(function (_a) { var uniqueItemId = _a.uniqueItemId; return uniqueItemId === focusedDescendantId; }) : null; var getNextIndex = function getNextIndex() { return index !== null ? (index + 1) % popoverItems.length : 0; }; var getPreviousIndex = function getPreviousIndex() { return index !== null && index !== -1 ? (index - 1 + popoverItems.length) % popoverItems.length : popoverItems.length - 1; }; var getNextItem = function getNextItem() { return popoverItems[getNextIndex()]; }; var getPreviousItem = function getPreviousItem() { return popoverItems[getPreviousIndex()]; }; switch (event.key) { case 'ArrowDown': { event.preventDefault(); if (!_this.state.showPopover) { _this.setState({ showPopover: true }); } var nextItem = _this.props.allowItemAddition && (index === popoverItems.length - 1 || popoverItems.length === 0) && filterInputValue !== '' && !_this.inputValueInItems() ? { uniqueItemId: filterInputValue.toLowerCase(), labelText: filterInputValue } : getNextItem(); if (nextItem) { _this.setState({ focusedDescendantId: nextItem.uniqueItemId }); } break; } case 'ArrowUp': { event.preventDefault(); if (!_this.state.showPopover) { _this.setState({ showPopover: true }); } var previousItem = _this.props.allowItemAddition && (index === null || index === 0) && filterInputValue !== '' && !_this.inputValueInItems() ? { uniqueItemId: filterInputValue.toLowerCase(), labelText: filterInputValue } : getPreviousItem(); if (previousItem) { _this.setState({ focusedDescendantId: previousItem.uniqueItemId }); } break; } case 'Enter': { event.preventDefault(); if (focusedDescendantId) { var focusedItem = popoverItems.find(function (_a) { var uniqueItemId = _a.uniqueItemId; return uniqueItemId === focusedDescendantId; }); if (focusedItem) { _this.handleItemSelection(focusedItem); } else { var userAddedItem = { uniqueItemId: filterInputValue.toLowerCase(), labelText: filterInputValue }; _this.handleItemSelection(userAddedItem); } } break; } case 'Escape': { if (_this.state.showPopover) { event.stopPropagation(); } _this.focusToInputAndCloseMenu(); break; } } }; _this.inputValueInItems = function () { return !!_this.state.computedItems.find(function (ci) { return ci.uniqueItemId === _this.state.filterInputValue.toLowerCase() || ci.labelText.toLowerCase() === _this.state.filterInputValue.toLowerCase(); }); }; _this.updatePopoverPlacement = function (placement) { if (!placement) return; if (placement !== _this.state.popoverPlacement) { requestAnimationFrame(function () { _this.setState({ popoverPlacement: placement }); }); } }; _this.popoverListRef = /*#__PURE__*/React__default.default.createRef(); if (_this.props.forwardedRef) { _this.filterInputRef = _this.props.forwardedRef; } else { _this.filterInputRef = /*#__PURE__*/React__default.default.createRef(); } _this.toggleButtonRef = /*#__PURE__*/React__default.default.createRef(); _this.clearButtonRef = /*#__PURE__*/React__default.default.createRef(); return _this; } BaseSingleSelect.getDerivedStateFromProps = function (nextProps, prevState) { var _a; var propItems = nextProps.items, selectedItem = nextProps.selectedItem; var selectedItemChanged = 'selectedItem' in nextProps && (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.uniqueItemId) !== ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.uniqueItemId); if (selectedItemChanged || propItems !== prevState.initialItems) { var resolvedSelectedItem = 'selectedItem' in nextProps ? selectedItem : propItems.find(function (item) { var _a; return item.uniqueItemId === ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.uniqueItemId); }); var resolvedInputValue = prevState.filterInputValue; if (selectedItemChanged) { resolvedInputValue = selectedItem ? selectedItem.labelText || prevState.filterInputValue : ''; } else { var matchingItem = propItems.find(function (item) { var _a; return item.uniqueItemId === ((_a = prevState.selectedItem) === null || _a === void 0 ? void 0 : _a.uniqueItemId); }); if (matchingItem) { resolvedInputValue = matchingItem.labelText && !prevState.filterMode ? matchingItem.labelText : prevState.filterInputValue; } } return { selectedItem: resolvedSelectedItem, filteredItems: propItems, filterInputValue: resolvedInputValue, filterMode: prevState.filterMode, initialItems: propItems }; } return null; }; BaseSingleSelect.prototype.componentDidUpdate = function (prevProps) { if (JSON.stringify(this.props.items) !== JSON.stringify(prevProps.items)) { this.setState({ computedItems: this.props.items }); } if (this.props.selectedItem === undefined && prevProps.selectedItem !== undefined) { this.setState({ selectedItem: null, filterInputValue: '' }); } }; BaseSingleSelect.prototype.isOutsideClick = function (event) { return !!this.toggleButtonRef && this.toggleButtonRef.current.contains(event.target); }; BaseSingleSelect.prototype.render = function () { var _a; var _this = this; var _b = this.state, filteredItems = _b.filteredItems, filterMode = _b.filterMode, showPopover = _b.showPopover, focusedDescendantId = _b.focusedDescendantId, filterInputValue = _b.filterInputValue, selectedItem = _b.selectedItem, computedItems = _b.computedItems; var _c = this.props, id = _c.id, className = _c.className; _c.theme; var labelText = _c.labelText, optionalText = _c.optionalText, hintText = _c.hintText; _c.onItemSelectionChange; var visualPlaceholder = _c.visualPlaceholder, noItemsText = _c.noItemsText; _c.defaultSelectedItem; var propOnChange = _c.onChange, onChangeWithoutDebounce = _c.onChangeWithoutDebounce; _c.onBlur; var debounce = _c.debounce, loading = _c.loading, loadingText = _c.loadingText, status = _c.status, statusText = _c.statusText; _c.selectedItem; var clearButtonLabel = _c.clearButtonLabel, ariaOptionsAvailableText = _c.ariaOptionsAvailableText, ariaOptionsAvailableTextFunction = _c.ariaOptionsAvailableTextFunction; _c.onItemSelect; var disabled = _c.disabled, allowItemAddition = _c.allowItemAddition, itemAdditionHelpText = _c.itemAdditionHelpText, tooltipComponent = _c.tooltipComponent; _c.items; _c.forwardedRef; var listProps = _c.listProps, popoverClassName = _c.popoverClassName, style = _c.style, fullWidth = _c.fullWidth, rest = tslib.__rest(_c, ["id", "className", "theme", "labelText", "optionalText", "hintText", "onItemSelectionChange", "visualPlaceholder", "noItemsText", "defaultSelectedItem", "onChange", "onChangeWithoutDebounce", "onBlur", "debounce", "loading", "loadingText", "status", "statusText", "selectedItem", "clearButtonLabel", "ariaOptionsAvailableText", "ariaOptionsAvailableTextFunction", "onItemSelect", "disabled", "allowItemAddition", "itemAdditionHelpText", "tooltipComponent", "items", "forwardedRef", "listProps", "popoverClassName", "style", "fullWidth"]); var _d = spacing.separateMarginProps(rest), passProps = _d[1]; var ariaActiveDescendant = focusedDescendantId ? "".concat(id, "-").concat(focusedDescendantId) : ''; var popoverItemListId = "".concat(id, "-popover"); var popoverItems = filterMode ? filteredItems : computedItems; return /*#__PURE__*/React__default.default.createElement(HtmlDiv.HtmlDiv, tslib.__assign({}, passProps, { className: classnames__default.default(baseClassName, className, (_a = {}, _a[singleSelectClassNames.valueSelected] = !!selectedItem, _a[singleSelectClassNames.open] = showPopover, _a[singleSelectClassNames.error] = status === 'error', _a[singleSelectClassNames.fullWidth] = fullWidth, _a)), style: style }), /*#__PURE__*/React__default.default.createElement(Debounce.Debounce, { waitFor: debounce }, function (debouncer) { return /*#__PURE__*/React__default.default.createElement(FilterInput.FilterInput, { inputElementContainerProps: { role: 'combobox', 'aria-haspopup': 'listbox', 'aria-owns': popoverItemListId, 'aria-expanded': showPopover }, "aria-activedescendant": ariaActiveDescendant, id: id, "aria-controls": popoverItemListId, labelText: labelText, optionalText: optionalText, hintText: hintText, items: computedItems, onFilter: function onFilter(filtered) { if (_this.state.filterMode) { _this.setState(function (prevState) { var newFocusedDescendandId = prevState.focusedDescendantId; if (!filtered.some(function (f) { return f.uniqueItemId === newFocusedDescendandId; })) { newFocusedDescendandId = null; } return { filteredItems: filtered, focusedDescendantId: newFocusedDescendandId }; }); } }, filterFunc: _this.filter, forwardedRef: _this.filterInputRef, onFocus: function onFocus() { if (!_this.preventShowPopoverOnInputFocus) { _this.setState({ showPopover: true }); } _this.preventShowPopoverOnInputFocus = false; }, onClick: function onClick() { _this.focusToInputAndSelectText(); _this.setState({ showPopover: true }); }, onKeyDown: _this.handleKeyDown, onBlur: _this.handleBlur, value: filterInputValue, onChange: function onChange(value) { if (propOnChange) { debouncer(propOnChange, value); } if (onChangeWithoutDebounce) { onChangeWithoutDebounce(value); } _this.handleOnChange(value); }, visualPlaceholder: !selectedItem ? visualPlaceholder : '', status: status, statusText: statusText, disabled: disabled, tooltipComponent: tooltipComponent, "data-floating-ui-placement": _this.state.popoverPlacement }, !!selectedItem && ( /*#__PURE__*/React__default.default.createElement(HtmlDiv.HtmlDiv, { className: singleSelectClassNames.clearButtonWrapper }, /*#__PURE__*/React__default.default.createElement(InputClearButton.InputClearButton, { forwardedRef: _this.clearButtonRef, onClick: function onClick() { return _this.handleItemSelection(null); }, onBlur: _this.handleBlur, label: clearButtonLabel, disabled: disabled }))), /*#__PURE__*/React__default.default.createElement(InputToggleButton.InputToggleButton, { open: showPopover, ref: _this.toggleButtonRef, onClick: function onClick(event) { event.preventDefault(); _this.setState(function (prevState) { return { showPopover: !prevState.showPopover }; }); _this.preventShowPopoverOnInputFocus = true; _this.focusToInputAndSelectText(); }, "aria-hidden": true, tabIndex: -1, disabled: disabled })); }), showPopover && ( /*#__PURE__*/React__default.default.createElement(Popover.Popover, { sourceRef: this.filterInputRef, matchWidth: true, onKeyDown: this.handleKeyDown, onClickOutside: function onClickOutside(event) { if (!_this.isOutsideClick(event)) { _this.setState({ showPopover: false }); } }, className: popoverClassName }, /*#__PURE__*/React__default.default.createElement(Popover.PopoverConsumer, null, function (consumer) { _this.updatePopoverPlacement(consumer === null || consumer === void 0 ? void 0 : consumer.popoverPlacement); return /*#__PURE__*/React__default.default.createElement(SelectItemList.SelectItemList, tslib.__assign({ id: popoverItemListId, ref: _this.popoverListRef, focusedDescendantId: ariaActiveDescendant, popoverPlacement: consumer === null || consumer === void 0 ? void 0 : consumer.popoverPlacement }, listProps), /*#__PURE__*/React__default.default.createElement(React__default.default.Fragment, null, popoverItems.length > 0 && !loading && popoverItems.map(function (item) { var _a; var isCurrentlySelected = item.uniqueItemId === focusedDescendantId; return /*#__PURE__*/React__default.default.createElement(SelectItem.SelectItem, tslib.__assign({ hasKeyboardFocus: isCurrentlySelected, key: "".concat(item.uniqueItemId, "_").concat(item.uniqueItemId === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.uniqueItemId)), id: "".concat(id, "-").concat(item.uniqueItemId), checked: item.uniqueItemId === (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.uniqueItemId), disabled: item.disabled, onClick: function onClick() { _this.handleItemSelection(item); }, hightlightQuery: filterMode ? (_a = _this.filterInputRef.current) === null || _a === void 0 ? void 0 : _a.value : '' }, item.listItemProps), item.labelText); }), popoverItems.length === 0 && !allowItemAddition && !loading && ( /*#__PURE__*/React__default.default.createElement(SelectEmptyItem.SelectEmptyItem, null, noItemsText)), loading && ( /*#__PURE__*/React__default.default.createElement(SelectEmptyItem.SelectEmptyItem, { className: "loading" }, /*#__PURE__*/React__default.default.createElement(LoadingSpinner.LoadingSpinner, { status: "loading", variant: "small", textAlign: "right", text: loadingText }))), filterInputValue !== '' && !_this.inputValueInItems() && allowItemAddition && !loading && ( /*#__PURE__*/React__default.default.createElement(SelectItemAddition.SelectItemAddition, { hintText: itemAdditionHelpText, hasKeyboardFocus: filterInputValue === focusedDescendantId, id: "".concat(id, "-").concat(filterInputValue.toLowerCase()), onClick: function onClick() { var item = { labelText: filterInputValue, uniqueItemId: filterInputValue.toLowerCase() }; _this.handleItemSelection(item); } }, filterInputValue)))); }))), /*#__PURE__*/React__default.default.createElement(VisuallyHidden.VisuallyHidden, { "aria-live": "polite", "aria-atomic": "true" }, this.state.filterMode && !loading ? ariaOptionsAvailableTextFunction ? ariaOptionsAvailableTextFunction(popoverItems.length) : "".concat(popoverItems.length, " ").concat(ariaOptionsAvailableText) : ''), /*#__PURE__*/React__default.default.createElement(VisuallyHidden.VisuallyHidden, { "aria-live": "polite", "aria-atomic": "true", id: "".concat(id, "-loading-announce") }, loading ? loadingText : '')); }; return BaseSingleSelect; }(React.Component); var StyledSingleSelect = styled.styled(function (_a) { _a.globalMargins; var passProps = tslib.__rest(_a, ["globalMargins"]); return /*#__PURE__*/React__default.default.createElement(BaseSingleSelect, tslib.__assign({}, passProps)); }).withConfig({ componentId: "sc-t1n3a2-0" })(templateObject_1 || (templateObject_1 = tslib.__makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (_a) { var theme = _a.theme, globalMargins = _a.globalMargins, rest = tslib.__rest(_a, ["theme", "globalMargins"]); var _b = spacing.separateMarginProps(rest), marginProps = _b[0]; var cleanedGlobalMargins = common.filterDuplicateKeys(globalMargins.singleSelect, marginProps); return SingleSelect_baseStyles.baseStyles(theme, cleanedGlobalMargins, marginProps); }); function SingleSelectInner(props, ref) { var propId = props.id, passProps = tslib.__rest(props, ["id"]); return /*#__PURE__*/React__default.default.createElement(SpacingProvider.SpacingConsumer, null, function (_a) { var margins = _a.margins; return /*#__PURE__*/React__default.default.createElement(SuomifiThemeProvider.SuomifiThemeConsumer, null, function (_a) { var suomifiTheme = _a.suomifiTheme; return /*#__PURE__*/React__default.default.createElement(AutoId.AutoId, { id: propId }, function (id) { return /*#__PURE__*/React__default.default.createElement(StyledSingleSelect, tslib.__assign({ theme: suomifiTheme, id: id, globalMargins: margins, forwardedRef: ref }, passProps)); }); }); }); } var SingleSelect = /*#__PURE__*/React.forwardRef(SingleSelectInner); SingleSelect.displayName = 'SingleSelect'; var templateObject_1; exports.SingleSelect = SingleSelect; //# sourceMappingURL=SingleSelect.js.map