import { useEffect, useRef, useCallback } from 'react' import { cn } from '@/lib/utils' export interface ContextMenuPosition { x: number y: number } export interface ContextMenuItem { id: string label: string icon?: React.ReactNode onClick: () => void variant?: 'default' | 'danger' separator?: boolean } interface ContextMenuProps { position: ContextMenuPosition items: ContextMenuItem[] onClose: () => void } export function ContextMenu({ position, items, onClose }: ContextMenuProps) { const menuRef = useRef(null) const handleClickOutside = useCallback( (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose() } }, [onClose] ) const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }, [onClose] ) useEffect(() => { document.addEventListener('mousedown', handleClickOutside) document.addEventListener('keydown', handleKeyDown) return () => { document.removeEventListener('mousedown', handleClickOutside) document.removeEventListener('keydown', handleKeyDown) } }, [handleClickOutside, handleKeyDown]) // Adjust position to stay within viewport useEffect(() => { if (!menuRef.current) return const rect = menuRef.current.getBoundingClientRect() const el = menuRef.current if (position.x + rect.width > window.innerWidth) { el.style.left = `${position.x - rect.width}px` } if (position.y + rect.height > window.innerHeight) { el.style.top = `${position.y - rect.height}px` } }, [position]) return (
{items.map((item) => (
{item.separator && (
)}
))}
) }