UNPKG

@ariakit/react-core

Version:

Ariakit React core

177 lines (174 loc) 5.45 kB
"use client"; import { selectTextField } from "./5VQZOHHZ.js"; import { useCompositeContext } from "./APTFW6PT.js"; import { useStoreState } from "./RTNCFSKZ.js"; import { createElement, createHook, forwardRef } from "./VOQWLFSQ.js"; import { useEvent, useMergeRefs } from "./5GGHRIN3.js"; import { __objRest, __spreadProps, __spreadValues } from "./3YLGPPWQ.js"; // src/composite/composite-container.tsx import { isButton, isTextField } from "@ariakit/core/utils/dom"; import { isFocusEventOutside, isSelfTarget } from "@ariakit/core/utils/events"; import { disableFocusIn, getFirstTabbableIn, restoreFocusIn } from "@ariakit/core/utils/focus"; import { removeUndefinedValues } from "@ariakit/core/utils/misc"; import { useEffect, useRef } from "react"; var TagName = "div"; function getFirstTabbable(container) { restoreFocusIn(container); const tabbable = getFirstTabbableIn(container); disableFocusIn(container); return tabbable; } var useCompositeContainer = createHook(function useCompositeContainer2(_a) { var _b = _a, { store } = _b, props = __objRest(_b, ["store"]); const context = useCompositeContext(); store = store || context; const ref = useRef(null); const isOpenRef = useRef(false); const open = (collapseToEnd = false) => { const container = ref.current; if (!container) return; restoreFocusIn(container); const tabbable = getFirstTabbableIn(container); if (!tabbable) { disableFocusIn(container); return; } isOpenRef.current = true; queueMicrotask(() => { tabbable.focus(); if (isTextField(tabbable) || tabbable.isContentEditable) { selectTextField(tabbable, collapseToEnd); } }); }; const close = () => { const container = ref.current; if (!container) return; isOpenRef.current = false; disableFocusIn(container); }; const renderedItems = useStoreState(store, "renderedItems"); useEffect(() => { const container = ref.current; if (!container) return; const isOpen = isOpenRef.current; if (!isOpen && (renderedItems == null ? void 0 : renderedItems.length)) { disableFocusIn(container); } }, [renderedItems]); const onFocusProp = props.onFocus; const onFocus = useEvent((event) => { onFocusProp == null ? void 0 : onFocusProp(event); if (event.defaultPrevented) return; if (!store) return; const isOpen = isOpenRef.current; if (isSelfTarget(event)) { isOpenRef.current = false; const { baseElement } = store.getState(); const composite = baseElement; const selector = "[data-composite-container]"; const containers = composite == null ? void 0 : composite.querySelectorAll(selector); if (containers) { for (const container of containers) { disableFocusIn(container); } } } else if (!isOpen) { isOpenRef.current = true; restoreFocusIn(event.currentTarget); store == null ? void 0 : store.setState("moves", 0); } }); const onBlurProp = props.onBlur; const onBlur = useEvent((event) => { onBlurProp == null ? void 0 : onBlurProp(event); if (event.defaultPrevented) return; if (isFocusEventOutside(event)) { close(); } }); const onKeyDownProp = props.onKeyDown; const onKeyDown = useEvent((event) => { onKeyDownProp == null ? void 0 : onKeyDownProp(event); if (event.defaultPrevented) return; if (event.altKey) return; if (event.ctrlKey) return; if (event.metaKey) return; if (event.shiftKey) return; const container = event.currentTarget; if (isSelfTarget(event)) { if (event.key.length === 1 && event.key !== " ") { const tabbable = getFirstTabbable(container); if (!tabbable) return; if (isTextField(tabbable) || tabbable.isContentEditable) { event.stopPropagation(); open(); } } else if (event.key === "Delete" || event.key === "Backspace") { const tabbable = getFirstTabbable(container); if (!tabbable) return; if (isTextField(tabbable) || tabbable.isContentEditable) { open(); const onInput = () => queueMicrotask(() => container.focus()); container.addEventListener("input", onInput, { once: true }); } } } else if (event.key === "Escape") { queueMicrotask(() => container.focus()); } else if (event.key === "Enter") { const target = event.target; const isInput = target.tagName === "INPUT" && !isButton(target) || target.tagName === "TEXTAREA"; if (isInput || target.isContentEditable) { event.preventDefault(); queueMicrotask(() => container.focus()); } } }); const onClickProp = props.onClick; const onClick = useEvent((event) => { onClickProp == null ? void 0 : onClickProp(event); if (event.defaultPrevented) return; if (isSelfTarget(event) && !event.detail) { open(true); } }); props = __spreadProps(__spreadValues({ "data-composite-container": "" }, props), { ref: useMergeRefs(ref, props.ref), onFocus, onBlur, onKeyDown, onClick }); return removeUndefinedValues(props); }); var CompositeContainer = forwardRef(function CompositeContainer2(props) { const htmlProps = useCompositeContainer(props); return createElement(TagName, htmlProps); }); export { useCompositeContainer, CompositeContainer };