Conversation
Tapping the composer on iOS could leave the page scrolled so the composer sat at the top of the screen with the chat scrolled away entirely. Two defects in trackVisualViewport conspired: - 'near bottom' was sampled at the kbd-open TRANSITION — after Safari's focus-reveal scrolling had already mangled both the window scroll and the .chat-scroll position — so the restore-to-bottom usually never fired and the chat stayed wherever Safari dumped it. - everything was single-shot per viewport event, while iOS fires focus-reveal scrolls, visualViewport resizes and pans in device-dependent order, sometimes without any event we listen to. A stale --vv-top/--vvh/window scroll never self-healed. Now the chat anchor (pinned-to-bottom, or the reader's scroll position) is captured at composer focusin — before the keyboard opens — and a short rAF settle loop (~900ms) re-asserts the anchored state, window scroll and viewport CSS vars until iOS stops fighting. The user's own touch ends enforcement immediately. jsdom tests cover the anchor capture, reader-position restore, and touch-cancels-enforcement; manual iOS repro notes in the PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
On iOS, tapping the composer can scroll the page so the composer sits at the very top of the screen and the chat is scrolled away (screenshot in the session-debug brief).
Root cause
Two defects in
trackVisualViewport(plugins/web-ui/src/viewport.ts):.chat-scrollonly ran at the kbd-open transition, samplingscrollTopafter Safari's focus-reveal scrolling had already moved both the window and the chat container. The check usually read false → no restore → the chat stayed wherever Safari dumped it.visualViewportresizes and pans in device-dependent order — sometimes panning the visual viewport without any event we listen to, andwindow.scrollTo(0,0)cannot undo a pure visual-viewport pan. A stale--vv-top/--vvh/window-scroll combination (layout translated while the viewport isn't panned, or vice versa) renders exactly the reported state: composer strip at the top, blank page below, chat off-screen — and nothing ever self-heals.Fix
focusin— before the keyboard opens: either pinned to bottom (was within 160px) or the reader's exact scroll position.window.scrollTo(0,0), and fresh--vvh/--vv-topevery frame until iOS stops fighting — covering the event orders that fire nothing we can hook.touchstartends enforcement immediately, so we never fight a real scroll gesture.Tests
plugins/web-ui/test/viewport.test.ts(jsdom + fakevisualViewport, deterministic rAF queue):scrollTopbefore the resize lands → chat re-pinned to bottom;Typecheck (app/server/test tsconfigs) and web-ui suite pass: 1023/1023.
Manual iOS repro notes (no jsdom for real viewport races)
Draft from the session-debug fork sweep (fork 3); do not merge without review.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.