UNPKG

@wordpress/components

Version:
151 lines (150 loc) 5.09 kB
// packages/components/src/autocomplete/autocompleter-ui.tsx import clsx from "clsx"; import { useLayoutEffect, useRef, useEffect, useState } from "@wordpress/element"; import { useAnchor } from "@wordpress/rich-text"; import { useDebounce, useMergeRefs, useRefEffect } from "@wordpress/compose"; import { speak } from "@wordpress/a11y"; import { __, _n, sprintf } from "@wordpress/i18n"; import getDefaultUseItems from "./get-default-use-items"; import Button from "../button"; import Popover from "../popover"; import { VisuallyHidden } from "../visually-hidden"; import { createPortal } from "react-dom"; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; function ListBox({ items, onSelect, selectedIndex, instanceId, listBoxId, className, Component = "div" }) { return /* @__PURE__ */ _jsx(Component, { id: listBoxId, role: "listbox", className: "components-autocomplete__results", children: items.map((option, index) => /* @__PURE__ */ _jsx(Button, { id: `components-autocomplete-item-${instanceId}-${option.key}`, role: "option", __next40pxDefaultSize: true, "aria-selected": index === selectedIndex, accessibleWhenDisabled: true, disabled: option.isDisabled, className: clsx("components-autocomplete__result", className, { // Unused, for backwards compatibility. "is-selected": index === selectedIndex }), variant: index === selectedIndex ? "primary" : void 0, onClick: () => onSelect(option), children: option.label }, option.key)) }); } function getAutoCompleterUI(autocompleter) { var _autocompleter$useIte; const useItems = (_autocompleter$useIte = autocompleter.useItems) !== null && _autocompleter$useIte !== void 0 ? _autocompleter$useIte : getDefaultUseItems(autocompleter); function AutocompleterUI({ filterValue, instanceId, listBoxId, className, selectedIndex, onChangeOptions, onSelect, onReset, reset, contentRef }) { const [items] = useItems(filterValue); const popoverAnchor = useAnchor({ editableContentElement: contentRef.current }); const [needsA11yCompat, setNeedsA11yCompat] = useState(false); const popoverRef = useRef(null); const popoverRefs = useMergeRefs([popoverRef, useRefEffect((node) => { if (!contentRef.current) { return; } setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument); }, [contentRef])]); useOnClickOutside(popoverRef, reset); const debouncedSpeak = useDebounce(speak, 500); function announce(options) { if (!debouncedSpeak) { return; } if (!!options.length) { if (filterValue) { debouncedSpeak(sprintf( /* translators: %d: number of results. */ _n("%d result found, use up and down arrow keys to navigate.", "%d results found, use up and down arrow keys to navigate.", options.length), options.length ), "assertive"); } else { debouncedSpeak(sprintf( /* translators: %d: number of results. */ _n("Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.", "Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.", options.length), options.length ), "assertive"); } } else { debouncedSpeak(__("No results."), "assertive"); } } useLayoutEffect(() => { onChangeOptions(items); announce(items); }, [items]); if (items.length === 0) { return null; } return /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx(Popover, { focusOnMount: false, onClose: onReset, placement: "top-start", className: "components-autocomplete__popover", anchor: popoverAnchor, ref: popoverRefs, children: /* @__PURE__ */ _jsx(ListBox, { items, onSelect, selectedIndex, instanceId, listBoxId, className }) }), contentRef.current && needsA11yCompat && createPortal(/* @__PURE__ */ _jsx(ListBox, { items, onSelect, selectedIndex, instanceId, listBoxId, className, Component: VisuallyHidden }), contentRef.current.ownerDocument.body)] }); } return AutocompleterUI; } function useOnClickOutside(ref, handler) { useEffect(() => { const listener = (event) => { 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); }; }, [handler, ref]); } export { getAutoCompleterUI }; //# sourceMappingURL=autocompleter-ui.js.map