@wordpress/components
Version:
UI components for WordPress.
151 lines (150 loc) • 5.09 kB
JavaScript
// 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