diff options
Diffstat (limited to 'frontend/src/components/document/ContextMenu.tsx')
| -rw-r--r-- | frontend/src/components/document/ContextMenu.tsx | 98 |
1 files changed, 0 insertions, 98 deletions
diff --git a/frontend/src/components/document/ContextMenu.tsx b/frontend/src/components/document/ContextMenu.tsx deleted file mode 100644 index 5aed940..0000000 --- a/frontend/src/components/document/ContextMenu.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { useCallback, useEffect, useRef } from 'react'; -import './ContextMenu.css'; - -export interface ContextMenuAction { - label: string; - icon: string; - disabled?: boolean; - onClick: () => void; -} - -export interface ContextMenuProps { - x: number; - y: number; - actions: ContextMenuAction[]; - dividerAfter?: number[]; - onClose: () => void; -} - -export default function ContextMenu({ - x, - y, - actions, - dividerAfter = [], - onClose, -}: ContextMenuProps) { - const menuRef = useRef<HTMLDivElement>(null); - - // Adjust position so menu stays within viewport - const adjustedPosition = useCallback(() => { - const el = menuRef.current; - if (!el) return { left: x, top: y }; - const rect = el.getBoundingClientRect(); - const left = x + rect.width > window.innerWidth ? x - rect.width : x; - const top = y + rect.height > window.innerHeight ? y - rect.height : y; - return { left: Math.max(0, left), top: Math.max(0, top) }; - }, [x, y]); - - // Close on click outside - useEffect(() => { - const handler = (e: MouseEvent) => { - if (menuRef.current && !menuRef.current.contains(e.target as Node)) { - onClose(); - } - }; - // Use capture so we catch clicks before any other handler - document.addEventListener('mousedown', handler, true); - return () => document.removeEventListener('mousedown', handler, true); - }, [onClose]); - - // Close on Escape - useEffect(() => { - const handler = (e: KeyboardEvent) => { - if (e.key === 'Escape') onClose(); - }; - document.addEventListener('keydown', handler); - return () => document.removeEventListener('keydown', handler); - }, [onClose]); - - // After mount, adjust position - useEffect(() => { - const el = menuRef.current; - if (!el) return; - const pos = adjustedPosition(); - el.style.left = `${pos.left}px`; - el.style.top = `${pos.top}px`; - }, [adjustedPosition]); - - const dividerSet = new Set(dividerAfter); - - return ( - <div - ref={menuRef} - className="ctx-menu" - style={{ left: x, top: y }} - role="menu" - > - {actions.map((action, i) => ( - <div key={i}> - <button - className={`ctx-menu-item ${action.disabled ? 'ctx-menu-item-disabled' : ''}`} - role="menuitem" - disabled={action.disabled} - onClick={() => { - if (!action.disabled) { - action.onClick(); - onClose(); - } - }} - > - <span className="ctx-menu-icon">{action.icon}</span> - <span className="ctx-menu-label">{action.label}</span> - </button> - {dividerSet.has(i) && <div className="ctx-menu-divider" />} - </div> - ))} - </div> - ); -} |
