"use client"; import { type ReactNode, useEffect, useRef, useState } from "react"; import { ChevronDown, type LucideIcon } from "lucide-react"; export type XmindCommand = { label: string; icon?: LucideIcon; shortcut?: string; disabled?: boolean; checked?: boolean; separator?: boolean; run: () => void; }; export function XmindCommandMenu({ label, children, commands, className = "", align = "left" }: { label: string; children: ReactNode; commands: XmindCommand[]; className?: string; align?: "left" | "right"; }) { const [open, setOpen] = useState(false); const host = useRef(null); const trigger = useRef(null); useEffect(() => { if (!open) return; const dismiss = (event: PointerEvent) => { if (!host.current?.contains(event.target as Node)) setOpen(false); }; document.addEventListener("pointerdown", dismiss); return () => document.removeEventListener("pointerdown", dismiss); }, [open]); return (
{open ?
{ if (event.key === "Escape") { event.preventDefault(); event.stopPropagation(); setOpen(false); trigger.current?.focus(); } const items = Array.from(host.current?.querySelectorAll("[role=menuitem]:not(:disabled)") || []); const index = items.indexOf(document.activeElement as HTMLButtonElement); if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) { event.preventDefault(); const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + items.length) % items.length; items[next]?.focus(); } }}> {commands.map(({ label: title, icon: Icon, shortcut, disabled, checked, separator, run }) =>
{separator ?
: null}
)}
: null}
); }