fix(canvas): prevent horizontal overflow on mobile

- Add overflow:hidden on html element for canvas-layout pages
- Bottom toolbar: constrain to viewport with right:8px, horizontal
  scroll for overflow buttons, flex-shrink:0 on items
- Context menu: clamp position to viewport bounds
- Modal panels: use min() for min-width to respect small screens

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-21 18:17:27 -07:00
parent 823d2c4110
commit 36e76449fa
2 changed files with 21 additions and 5 deletions

View File

@ -1789,16 +1789,25 @@
padding: 4px 6px;
gap: 1px;
left: 56px; /* offset right of side toolbar */
transform: translateX(0);
right: 8px;
transform: none;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
#bottom-toolbar::-webkit-scrollbar { display: none; }
#bottom-toolbar .tool-btn {
width: 36px;
height: 36px;
flex-shrink: 0;
}
#bottom-toolbar .tool-sep {
margin: 0 2px;
flex-shrink: 0;
}
/* Corner tools: horizontal on mobile, tucked bottom-right */
@ -4488,7 +4497,7 @@
overlay.style.cssText = "position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.3);display:flex;align-items:center;justify-content:center;";
const panel = document.createElement("div");
panel.style.cssText = "background:white;border-radius:12px;padding:16px;box-shadow:0 8px 32px rgba(0,0,0,0.2);min-width:340px;max-width:500px;font-family:system-ui;";
panel.style.cssText = "background:white;border-radius:12px;padding:16px;box-shadow:0 8px 32px rgba(0,0,0,0.2);min-width:min(340px,calc(100vw - 32px));max-width:min(500px,calc(100vw - 32px));font-family:system-ui;";
let selectedSrc = srcPorts[0]?.name || "";
let selectedTgt = tgtPorts[0]?.name || "";
@ -5287,9 +5296,13 @@
}
shapeContextMenu.innerHTML = html;
shapeContextMenu.style.left = e.clientX + 'px';
shapeContextMenu.style.top = e.clientY + 'px';
shapeContextMenu.classList.add("open");
// Clamp position to viewport so menu doesn't overflow
const menuRect = shapeContextMenu.getBoundingClientRect();
const maxLeft = window.innerWidth - menuRect.width - 8;
const maxTop = window.innerHeight - menuRect.height - 8;
shapeContextMenu.style.left = Math.min(e.clientX, maxLeft) + 'px';
shapeContextMenu.style.top = Math.min(e.clientY, maxTop) + 'px';
// Asynchronously populate the copy submenu
if (isAuthenticated && state === 'present') {
@ -5513,7 +5526,7 @@
overlay.style.cssText = "position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.3);display:flex;align-items:center;justify-content:center;";
const panel = document.createElement("div");
panel.style.cssText = "background:white;border-radius:12px;padding:16px;box-shadow:0 8px 32px rgba(0,0,0,0.2);min-width:320px;font-family:system-ui;";
panel.style.cssText = "background:white;border-radius:12px;padding:16px;box-shadow:0 8px 32px rgba(0,0,0,0.2);min-width:min(320px,calc(100vw - 32px));max-width:calc(100vw - 32px);font-family:system-ui;";
panel.innerHTML = `
<div style="font-size:14px;font-weight:600;margin-bottom:12px;color:#1e293b;">Data Transform</div>
<div style="margin-bottom:8px;">

View File

@ -408,10 +408,13 @@ body.rstack-sidebar-open #toolbar {
}
/* Canvas on mobile: header/tab-row are sticky (in-flow), so body must
become a flex column to prevent the 100vh #app from overflowing. */
html:has(#app.canvas-layout),
body:has(#app.canvas-layout) {
height: 100dvh;
overflow: hidden;
overscroll-behavior: none;
}
body:has(#app.canvas-layout) {
display: flex;
flex-direction: column;
}