Skip to content

Commit 2fd8e9a

Browse files
mikewolfdclaude
andcommitted
fix(studio): clamp context menu to viewport using actual rendered dimensions
Adds a useLayoutEffect that measures the context menu after render and adjusts position if it overflows the viewport. The existing hardcoded MENU_HEIGHT estimate was insufficient for shorter menus near the edge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5baf2da commit 2fd8e9a

1 file changed

Lines changed: 12 additions & 1 deletion

File tree

packages/formspec-studio/src/workspaces/editor/EditorCanvas.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @filedesc Main editor canvas with drag-and-drop, page tabs, context menu, and item palette. */
2-
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
2+
import { useState, useEffect, useLayoutEffect, useRef, useCallback, useMemo } from 'react';
33
import { DragDropProvider, DragOverlay } from '@dnd-kit/react';
44
import { PointerSensor, KeyboardSensor, PointerActivationConstraints } from '@dnd-kit/dom';
55
import { useDefinition } from '../../state/useDefinition';
@@ -260,6 +260,17 @@ export function EditorCanvas() {
260260
};
261261
}, [contextMenu]);
262262

263+
// Clamp context menu to viewport using actual rendered dimensions
264+
useLayoutEffect(() => {
265+
const el = contextMenuRef.current;
266+
if (!contextMenu || !el) return;
267+
const rect = el.getBoundingClientRect();
268+
const vw = window.innerWidth;
269+
const vh = window.innerHeight;
270+
if (rect.right > vw) el.style.left = `${Math.max(0, vw - rect.width)}px`;
271+
if (rect.bottom > vh) el.style.top = `${Math.max(0, vh - rect.height)}px`;
272+
}, [contextMenu]);
273+
263274
// Escape to deselect (only when context menu is not open)
264275
useEffect(() => {
265276
if (contextMenu) return; // context menu's own Escape handler takes priority

0 commit comments

Comments
 (0)