@wordpress/components
Version:
UI components for WordPress.
243 lines (197 loc) • 7.37 kB
JavaScript
;
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