UNPKG

@1771technologies/lytenyte-pro

Version:

Blazingly fast headless React data grid with 100s of features.

71 lines (70 loc) 3.26 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { forwardRef, useEffect, useRef, useState } from "react"; import { useSubmenuContext } from "./submenu-context.js"; import { getNearestMatching, getTabbables } from "@1771technologies/lytenyte-shared"; import { handleVerticalNavigation } from "../item/handle-vertical-navigation.js"; import { useCombinedRefs } from "@1771technologies/lytenyte-core/internal"; function SubmenuTriggerImpl({ disabled, ...props }, ref) { const [active, setActive] = useState(false); const sub = useSubmenuContext(); const [triggerEl, setTriggerEl] = useState(null); const combined = useCombinedRefs(setTriggerEl, ref); const blurRef = useRef(null); useEffect(() => { if (!triggerEl || !sub) return; const controller = new AbortController(); const signal = controller.signal; triggerEl.addEventListener("ln-activate-mouse", () => { triggerEl.focus(); sub.onOpenChange(true); if (blurRef.current) clearTimeout(blurRef.current); }, { signal }); triggerEl.addEventListener("ln-deactivate-mouse", () => { blurRef.current = setTimeout(() => { triggerEl.blur(); }, 100); }, { signal }); return () => controller.abort(); }, [sub, triggerEl]); if (!sub) return null; return (_jsx("div", { ...props, tabIndex: 0, "data-ln-open": sub.open, "data-ln-menu-item": true, "data-ln-subtrigger": true, "data-ln-active": active, "data-ln-disabled": disabled ? true : undefined, inert: disabled ? true : undefined, ref: combined, onFocus: (ev) => { props.onFocus?.(ev); if (ev.isPropagationStopped()) return; setActive(true); }, onBlur: (ev) => { props.onBlur?.(ev); if (ev.isPropagationStopped()) return; setActive(false); const triggerRoot = getNearestMatching(triggerEl, (el) => el.getAttribute("data-ln-submenu-root") === "true"); if (!triggerRoot || triggerRoot.contains(ev.relatedTarget)) return; sub.onOpenChange(false); }, onKeyDown: (ev) => { if (ev.key === "ArrowUp" || ev.key === "ArrowDown") { handleVerticalNavigation(ev); return; } if (ev.key === "ArrowRight") { ev.stopPropagation(); ev.preventDefault(); sub.onOpenChange(true); const el = ev.currentTarget; setTimeout(() => { const submenu = getNearestMatching(el, (el) => { return el.getAttribute("data-ln-submenu-root") === "true"; }); const menu = submenu?.querySelector('[data-ln-menu="true"][data-ln-submenu="true"]'); if (!menu) return; const first = getTabbables(menu).filter((x) => x.getAttribute("data-ln-menu-item") === "true")[0]; first?.focus(); }, 20); } } })); } export const SubmenuTrigger = forwardRef(SubmenuTriggerImpl);