UNPKG

@wordpress/components

Version:
137 lines (114 loc) 4.59 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getAutoCompleterUI = getAutoCompleterUI; var _element = require("@wordpress/element"); var _classnames = _interopRequireDefault(require("classnames")); var _richText = require("@wordpress/rich-text"); var _compose = require("@wordpress/compose"); var _getDefaultUseItems = _interopRequireDefault(require("./get-default-use-items")); var _button = _interopRequireDefault(require("../button")); var _popover = _interopRequireDefault(require("../popover")); var _visuallyHidden = require("../visually-hidden"); var _reactDom = require("react-dom"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ function getAutoCompleterUI(autocompleter) { const useItems = autocompleter.useItems ? autocompleter.useItems : (0, _getDefaultUseItems.default)(autocompleter); function AutocompleterUI(_ref) { let { filterValue, instanceId, listBoxId, className, selectedIndex, onChangeOptions, onSelect, onReset, reset, contentRef } = _ref; const [items] = useItems(filterValue); const popoverAnchor = (0, _richText.useAnchor)({ editableContentElement: contentRef.current }); const [needsA11yCompat, setNeedsA11yCompat] = (0, _element.useState)(false); const popoverRef = (0, _element.useRef)(null); const popoverRefs = (0, _compose.useMergeRefs)([popoverRef, (0, _compose.useRefEffect)(node => { if (!contentRef.current) return; // If the popover is rendered in a different document than // the content, we need to duplicate the options list in the // content document so that it's available to the screen // readers, which check the DOM ID based aira-* attributes. setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument); }, [contentRef])]); useOnClickOutside(popoverRef, reset); (0, _element.useLayoutEffect)(() => { onChangeOptions(items); // Temporarily disabling exhaustive-deps to avoid introducing unexpected side effecst. // See https://github.com/WordPress/gutenberg/pull/41820 // eslint-disable-next-line react-hooks/exhaustive-deps }, [items]); if (items.length === 0) { return null; } const ListBox = _ref2 => { let { Component = 'div' } = _ref2; return (0, _element.createElement)(Component, { id: listBoxId, role: "listbox", className: "components-autocomplete__results" }, items.map((option, index) => (0, _element.createElement)(_button.default, { key: option.key, id: `components-autocomplete-item-${instanceId}-${option.key}`, role: "option", "aria-selected": index === selectedIndex, disabled: option.isDisabled, className: (0, _classnames.default)('components-autocomplete__result', className, { 'is-selected': index === selectedIndex }), onClick: () => onSelect(option) }, option.label))); }; return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_popover.default, { focusOnMount: false, onClose: onReset, placement: "top-start", className: "components-autocomplete__popover", anchor: popoverAnchor, ref: popoverRefs }, (0, _element.createElement)(ListBox, null)), contentRef.current && needsA11yCompat && (0, _reactDom.createPortal)((0, _element.createElement)(ListBox, { Component: _visuallyHidden.VisuallyHidden }), contentRef.current.ownerDocument.body)); } return AutocompleterUI; } function useOnClickOutside(ref, handler) { (0, _element.useEffect)(() => { const listener = event => { // Do nothing if clicking ref's element or descendent elements, or if the ref is not referencing an element if (!ref.current || ref.current.contains(event.target)) { return; } handler(event); }; document.addEventListener('mousedown', listener); document.addEventListener('touchstart', listener); return () => { document.removeEventListener('mousedown', listener); document.removeEventListener('touchstart', listener); }; // Disable reason: `ref` is a ref object and should not be included in a // hook's dependency list. // eslint-disable-next-line react-hooks/exhaustive-deps }, [handler]); } //# sourceMappingURL=autocompleter-ui.js.map