UNPKG

@wordpress/components

Version:
243 lines (197 loc) 7.37 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _element = require("@wordpress/element"); var _classnames = _interopRequireDefault(require("classnames")); var _lodash = require("lodash"); var _i18n = require("@wordpress/i18n"); var _compose = require("@wordpress/compose"); var _keycodes = require("@wordpress/keycodes"); var _a11y = require("@wordpress/a11y"); var _icons = require("@wordpress/icons"); var _tokenInput = _interopRequireDefault(require("../form-token-field/token-input")); var _suggestionsList = _interopRequireDefault(require("../form-token-field/suggestions-list")); var _baseControl = _interopRequireDefault(require("../base-control")); var _button = _interopRequireDefault(require("../button")); var _flex = require("../flex"); var _withFocusOutside = _interopRequireDefault(require("../higher-order/with-focus-outside")); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const DetectOutside = (0, _withFocusOutside.default)(class extends _element.Component { handleFocusOutside(event) { this.props.onFocusOutside(event); } render() { return this.props.children; } }); function ComboboxControl({ value, label, options, onChange, onFilterValueChange = _lodash.noop, hideLabelFromVision, help, allowReset = true, className, messages = { selected: (0, _i18n.__)('Item selected.') } }) { var _currentOption$label; const instanceId = (0, _compose.useInstanceId)(ComboboxControl); const [selectedSuggestion, setSelectedSuggestion] = (0, _element.useState)(null); const [isExpanded, setIsExpanded] = (0, _element.useState)(false); const [inputValue, setInputValue] = (0, _element.useState)(''); const inputContainer = (0, _element.useRef)(); const currentOption = options.find(option => option.value === value); const currentLabel = (_currentOption$label = currentOption === null || currentOption === void 0 ? void 0 : currentOption.label) !== null && _currentOption$label !== void 0 ? _currentOption$label : ''; const matchingSuggestions = (0, _element.useMemo)(() => { const startsWithMatch = []; const containsMatch = []; const match = (0, _lodash.deburr)(inputValue.toLocaleLowerCase()); options.forEach(option => { const index = (0, _lodash.deburr)(option.label).toLocaleLowerCase().indexOf(match); if (index === 0) { startsWithMatch.push(option); } else if (index > 0) { containsMatch.push(option); } }); return startsWithMatch.concat(containsMatch); }, [inputValue, options, value]); const onSuggestionSelected = newSelectedSuggestion => { onChange(newSelectedSuggestion.value); (0, _a11y.speak)(messages.selected, 'assertive'); setSelectedSuggestion(newSelectedSuggestion); setInputValue(''); setIsExpanded(false); }; const handleArrowNavigation = (offset = 1) => { const index = matchingSuggestions.indexOf(selectedSuggestion); let nextIndex = index + offset; if (nextIndex < 0) { nextIndex = matchingSuggestions.length - 1; } else if (nextIndex >= matchingSuggestions.length) { nextIndex = 0; } setSelectedSuggestion(matchingSuggestions[nextIndex]); setIsExpanded(true); }; const onKeyDown = event => { let preventDefault = false; switch (event.keyCode) { case _keycodes.ENTER: if (selectedSuggestion) { onSuggestionSelected(selectedSuggestion); preventDefault = true; } break; case _keycodes.UP: handleArrowNavigation(-1); preventDefault = true; break; case _keycodes.DOWN: handleArrowNavigation(1); preventDefault = true; break; case _keycodes.ESCAPE: setIsExpanded(false); setSelectedSuggestion(null); preventDefault = true; event.stopPropagation(); break; default: break; } if (preventDefault) { event.preventDefault(); } }; const onFocus = () => { setIsExpanded(true); onFilterValueChange(''); setInputValue(''); }; const onFocusOutside = () => { setIsExpanded(false); }; const onInputChange = event => { const text = event.value; setInputValue(text); onFilterValueChange(text); setIsExpanded(true); }; const handleOnReset = () => { onChange(null); inputContainer.current.input.focus(); }; // Announcements (0, _element.useEffect)(() => { const hasMatchingSuggestions = matchingSuggestions.length > 0; if (isExpanded) { const message = hasMatchingSuggestions ? (0, _i18n.sprintf)( /* translators: %d: number of results. */ (0, _i18n._n)('%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', matchingSuggestions.length), matchingSuggestions.length) : (0, _i18n.__)('No results.'); (0, _a11y.speak)(message, 'polite'); } }, [matchingSuggestions, isExpanded]); // Disable reason: There is no appropriate role which describes the // input container intended accessible usability. // TODO: Refactor click detection to use blur to stop propagation. /* eslint-disable jsx-a11y/no-static-element-interactions */ return (0, _element.createElement)(DetectOutside, { onFocusOutside: onFocusOutside }, (0, _element.createElement)(_baseControl.default, { className: (0, _classnames.default)(className, 'components-combobox-control'), tabIndex: "-1", label: label, id: `components-form-token-input-${instanceId}`, hideLabelFromVision: hideLabelFromVision, help: help }, (0, _element.createElement)("div", { className: "components-combobox-control__suggestions-container", tabIndex: "-1", onKeyDown: onKeyDown }, (0, _element.createElement)(_flex.Flex, null, (0, _element.createElement)(_flex.FlexBlock, null, (0, _element.createElement)(_tokenInput.default, { className: "components-combobox-control__input", instanceId: instanceId, ref: inputContainer, value: isExpanded ? inputValue : currentLabel, "aria-label": currentLabel ? `${currentLabel}, ${label}` : null, onFocus: onFocus, isExpanded: isExpanded, selectedSuggestionIndex: matchingSuggestions.indexOf(selectedSuggestion), onChange: onInputChange })), allowReset && (0, _element.createElement)(_flex.FlexItem, null, (0, _element.createElement)(_button.default, { className: "components-combobox-control__reset", icon: _icons.closeSmall, disabled: !value, onClick: handleOnReset, label: (0, _i18n.__)('Reset') }))), isExpanded && (0, _element.createElement)(_suggestionsList.default, { instanceId: instanceId, match: { label: inputValue }, displayTransform: suggestion => suggestion.label, suggestions: matchingSuggestions, selectedIndex: matchingSuggestions.indexOf(selectedSuggestion), onHover: setSelectedSuggestion, onSelect: onSuggestionSelected, scrollIntoView: true })))); /* eslint-enable jsx-a11y/no-static-element-interactions */ } var _default = ComboboxControl; exports.default = _default; //# sourceMappingURL=index.js.map