From aae1f6ecf273adbaf29e8510a89737f7c5537ef4 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith Date: Mon, 30 Mar 2026 15:11:53 +0000 Subject: [PATCH] Fix user menu clipping at scaled UI (110%+) Menu primitive uses position:fixed inside a CSS-transformed container (#surfaceInner scale). getBoundingClientRect() returns scaled coords but fixed positioning uses the transform container's coordinate space. Divide anchor rect and viewport dimensions by sw.shell.getScale() to convert to the correct coordinate space. Menu now positions and clamps correctly at any UI scale setting. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/js/sw/primitives/menu.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/js/sw/primitives/menu.js b/src/js/sw/primitives/menu.js index b939c46..b7cba2f 100644 --- a/src/js/sw/primitives/menu.js +++ b/src/js/sw/primitives/menu.js @@ -17,13 +17,20 @@ export function Menu({ items = [], anchor, open, direction = 'down-right', onSel const selectableItems = items.filter(i => !i.divider && !i.disabled); // Position relative to anchor + // When the surface uses CSS transform: scale(), getBoundingClientRect() + // returns scaled coordinates but position:fixed uses viewport coordinates. + // Dividing by the scale factor converts back to true viewport pixels. useEffect(() => { if (!open || !anchor) return; - const rect = typeof anchor.getBoundingClientRect === 'function' + const scale = window.sw?.shell?.getScale?.() || 1; + const raw = typeof anchor.getBoundingClientRect === 'function' ? anchor.getBoundingClientRect() : anchor; - const vw = window.innerWidth; - const vh = window.innerHeight; + const rect = scale !== 1 + ? { top: raw.top / scale, bottom: raw.bottom / scale, left: raw.left / scale, right: raw.right / scale } + : raw; + const vw = window.innerWidth / scale; + const vh = window.innerHeight / scale; let top, left; const [vDir, hDir] = direction.split('-');