diff --git a/artifacts/tx-os/src/components/notes/send-note-dialog.tsx b/artifacts/tx-os/src/components/notes/send-note-dialog.tsx index 9738c0ae..cf9d4c05 100644 --- a/artifacts/tx-os/src/components/notes/send-note-dialog.tsx +++ b/artifacts/tx-os/src/components/notes/send-note-dialog.tsx @@ -162,14 +162,31 @@ export function SendNoteDialog({ const dialogStyle: React.CSSProperties | undefined = keyboardActive ? { top: vv.offsetTop + vv.height / 2 - KEYBOARD_PREDICTION_INSET, + left: "50%", transform: "translate(-50%, -50%)", transition: "top 120ms ease", } : keyboardFallback ? { - top: "6vh", + // #634: bind `top` to `visualViewport.offsetTop` so when iPad + // PWA Safari scrolls the layout viewport down behind the + // soft keyboard, our top anchor follows the visible area + // instead of landing above it (which previously hid the + // dialog title + search input). + top: `calc(${vv.offsetTop || 0}px + 6vh)`, + // #634: pin `left: 50%` explicitly. Radix already sets it + // via Tailwind, but the inline `transform` below replaces + // Tailwind's `translate-x-[-50%] translate-y-[-50%]` so we + // also restate the horizontal anchor to defend against any + // animation/RTL interplay that was shifting the box left. + left: "50%", transform: "translate(-50%, 0)", maxHeight: "50dvh", + // #634: allow the dialog itself to scroll when its content + // is taller than the cap — otherwise the header could be + // clipped while only the bottom of the list/buttons stayed + // visible. + overflowY: "auto", transition: "top 120ms ease, transform 120ms ease", } : undefined;