From 3f4b3119fd95ebe271fa3137f5cf612ccddf6051 Mon Sep 17 00:00:00 2001 From: Riyadh Date: Wed, 20 May 2026 18:29:39 +0000 Subject: [PATCH] Adjust dialog positioning to better handle keyboard interactions on mobile Modify dialog component to use window.innerWidth for width and position fixed, ensuring consistent display across iOS PWA environments by anchoring to the layout viewport. --- artifacts/tx-os/src/components/ui/dialog.tsx | 29 ++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/artifacts/tx-os/src/components/ui/dialog.tsx b/artifacts/tx-os/src/components/ui/dialog.tsx index 23e33173..55d88347 100644 --- a/artifacts/tx-os/src/components/ui/dialog.tsx +++ b/artifacts/tx-os/src/components/ui/dialog.tsx @@ -32,7 +32,7 @@ const DialogContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, style, ...props }, ref) => { - const { keyboardInset, width, height, offsetTop, offsetLeft } = useVisualViewport() + const { keyboardInset, height, offsetTop } = useVisualViewport() // Only react when an on-screen keyboard is actually present. iOS Safari // and Android Chrome both report a non-trivial bottom inset (>= ~150px) // when their software keyboard opens; tiny insets from browser chrome @@ -60,17 +60,24 @@ const DialogContent = React.forwardRef< // dialog's internal `flex flex-col` (header / scrollable middle // / sticky footer) then keeps Save/Cancel pinned above the // keyboard and the rest of the form scrolls inside. - // Use the visualViewport rectangle directly. position:fixed on - // iOS Safari is measured against the LAYOUT viewport, which - // diverges from the visual viewport when the soft keyboard is - // open AND when Safari pinch/auto-zooms a focused input. So we - // must explicitly set top/left/width to the visual viewport's - // offsetTop/offsetLeft/width and zero out the centering - // translates the base className applies. + // `position: fixed` on iOS is anchored to the LAYOUT viewport, + // which stays at `window.innerWidth` even while the visual + // viewport shrinks (keyboard, pinch-zoom, etc). If we set + // width/left from `visualViewport.width/offsetLeft` the dialog + // ends up rendered at a fraction of the screen — a narrow + // strip pinned to one corner — because those values describe + // the *visible* rectangle in layout pixels, not the dialog's + // own container. + // + // Pin horizontally to the layout viewport (0 / 100vw) so the + // dialog always spans the full width the iframe sees, and pin + // vertically to the visual viewport so it sits just above the + // keyboard. `maxHeight` uses `vv.height` so the dialog's + // internal scroll keeps the footer above the keyboard. top: `${offsetTop}px`, - left: `${offsetLeft}px`, - right: "auto", - width: `${width}px`, + left: 0, + right: 0, + width: "100vw", maxWidth: "none", maxHeight: `${height - 8}px`, transform: "none",