import { useEffect, useRef, useState, type ReactNode, } from "react"; import { cn } from "../../lib/cn"; import { Button, type ButtonTone } from "../button"; export type MenuItem = { disabled?: boolean; label: string; leadingIcon?: ReactNode; onSelect?: () => void; tone?: "default" | "destructive"; }; export function Menu({ className, items, }: { className?: string; items: MenuItem[]; }) { return (
{items.map((item) => ( ))}
); } export function DropdownMenu({ align = "left", className, items, label, tone = "secondary", }: { align?: "center" | "left" | "right"; className?: string; items: MenuItem[]; label: string; tone?: Exclude; }) { const containerRef = useRef(null); const [open, setOpen] = useState(false); const menuPlacement = align === "center" ? "left-1/2 -translate-x-1/2" : align === "right" ? "right-0" : "left-0"; useEffect(() => { function handlePointerDown(event: PointerEvent) { if (!containerRef.current?.contains(event.target as Node)) { setOpen(false); } } function handleEscape(event: KeyboardEvent) { if (event.key === "Escape") { setOpen(false); } } window.addEventListener("pointerdown", handlePointerDown); window.addEventListener("keydown", handleEscape); return () => { window.removeEventListener("pointerdown", handlePointerDown); window.removeEventListener("keydown", handleEscape); }; }, []); return (
({ ...item, onSelect: () => { item.onSelect?.(); setOpen(false); }, }))} />
); }