import { useEffect, useRef, type ReactNode } from "react"; export interface ContextMenuItem { icon?: ReactNode; label: string; onClick: () => void; disabled?: boolean; } export interface ContextMenuProps { x: number; y: number; header?: ReactNode; items: ContextMenuItem[]; onClose: () => void; } export default function ContextMenu({ x, y, header, items, onClose }: ContextMenuProps) { const menuRef = useRef(null); useEffect(() => { function handleClickOutside(e: MouseEvent) { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose(); } } function handleEscape(e: KeyboardEvent) { if (e.key === "Escape") onClose(); } document.addEventListener("mousedown", handleClickOutside); document.addEventListener("keydown", handleEscape); return () => { document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("keydown", handleEscape); }; }, [onClose]); useEffect(() => { if (!menuRef.current) return; const rect = menuRef.current.getBoundingClientRect(); if (rect.right > window.innerWidth) { menuRef.current.style.left = `${x - rect.width}px`; } if (rect.bottom > window.innerHeight) { menuRef.current.style.top = `${y - rect.height}px`; } }, [x, y]); return (
{header && (
{header}
)} {items.map((item, i) => ( ))}
); }