diff --git a/frontend/src/components/ContextMenu.tsx b/frontend/src/components/ContextMenu.tsx index eef2217c..3713ffe6 100644 --- a/frontend/src/components/ContextMenu.tsx +++ b/frontend/src/components/ContextMenu.tsx @@ -30,7 +30,17 @@ export default function ContextMenu({ offset = { x: 0, y: 8 }, }: ContextMenuProps) { const menuRef = useRef(null); - + useEffect(() => { + if (isOpen && menuRef.current) { + const positionStyle = getMenuPosition(); + if (menuRef.current) { + Object.assign(menuRef.current.style, { + top: positionStyle.top, + left: positionStyle.left, + }); + } + } + }, [isOpen]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -61,20 +71,45 @@ export default function ContextMenu({ let top = rect.bottom + scrollY + offset.y; let left = rect.right + scrollX + offset.x; + // Get menu dimensions (need ref to be available) + const menuWidth = menuRef.current?.offsetWidth || 144; // Default min-width + const menuHeight = menuRef.current?.offsetHeight || 0; + + // Get viewport dimensions + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Adjust position based on specified position switch (position) { case 'bottom-left': left = rect.left + scrollX - offset.x; break; case 'top-right': - top = rect.top + scrollY - offset.y; + top = rect.top + scrollY - offset.y - menuHeight; break; case 'top-left': - top = rect.top + scrollY - offset.y; + top = rect.top + scrollY - offset.y - menuHeight; left = rect.left + scrollX - offset.x; break; // bottom-right is default } + if (left + menuWidth > viewportWidth) { + left = Math.max(5, viewportWidth - menuWidth - 5); + } + + if (left < 5) { + left = 5; + } + + if (top + menuHeight > viewportHeight + scrollY) { + top = rect.top + scrollY - menuHeight - offset.y; + } + + if (top < scrollY + 5) { + top = rect.bottom + scrollY + offset.y; + } + return { position: 'fixed', top: `${top}px`,