import React, { useEffect, useRef, useState } from 'react'; import { useUIStore } from '../../stores/uiStore'; interface ContextMenuItem { label: string; onClick: () => void; danger?: boolean; icon?: React.ReactNode; } interface ContextMenuProps { items: ContextMenuItem[]; children: React.ReactNode; } export function ContextMenu({ items, children }: ContextMenuProps) { const [isOpen, setIsOpen] = useState(false); const [position, setPosition] = useState({ x: 0, y: 0 }); const menuRef = useRef(null); const isMobile = useUIStore((s) => s.isMobile); const handleContextMenu = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); setPosition({ x: e.clientX, y: e.clientY }); setIsOpen(true); }; useEffect(() => { const handleClick = () => setIsOpen(false); const handleScroll = () => setIsOpen(false); if (isOpen) { document.addEventListener('click', handleClick); document.addEventListener('scroll', handleScroll, true); return () => { document.removeEventListener('click', handleClick); document.removeEventListener('scroll', handleScroll, true); }; } }, [isOpen]); // Adjust position to keep menu in viewport useEffect(() => { if (isOpen && menuRef.current) { const rect = menuRef.current.getBoundingClientRect(); const newPosition = { ...position }; if (rect.right > window.innerWidth) { newPosition.x = window.innerWidth - rect.width - 8; } if (rect.bottom > window.innerHeight) { newPosition.y = window.innerHeight - rect.height - 8; } if (newPosition.x < 8) newPosition.x = 8; if (newPosition.y < 8) newPosition.y = 8; if (newPosition.x !== position.x || newPosition.y !== position.y) { setPosition(newPosition); } } }, [isOpen, position]); return ( <>
{children}
{isOpen && isMobile && ( <> {/* Backdrop */}
setIsOpen(false)} /> {/* Bottom sheet menu */}
{items.map((item, i) => ( ))}
)} {isOpen && !isMobile && (
{items.map((item, i) => ( ))}
)} ); }