Skip to content

fix(ui): preserve in-flight touch scrolling during chat updates - #94

Open
jmfederico wants to merge 2 commits into
mainfrom
fix/touch-scroll-stall
Open

fix(ui): preserve in-flight touch scrolling during chat updates#94
jmfederico wants to merge 2 commits into
mainfrom
fix/touch-scroll-stall

Conversation

@jmfederico

Copy link
Copy Markdown
Owner

Summary

Fixes chat scrolling on touch devices (iPad) freezing mid-gesture. Programmatic scrollTop writes and DOM repaints cancel in-flight touch/momentum scrolling on iOS; three code paths did this during normal chat use:

  1. Prepend anchor settle loop — wrote scrollTop every frame for 30 frames even when the anchor had not drifted. It now only writes when drift ≥ 0.5px.
  2. Conversation position indicator — repainting the meter mid-gesture cancels the touch scroll (it overlaps the top edge of the scrollport). Index updates are now deferred while a gesture/momentum scroll is in flight and catch up once the scroll settles.
  3. History prepends — applied DOM changes (and their scrollTop corrections) the moment the fetch resolved. The page is still fetched immediately to hide latency, but the merge is held until the scroll is idle, via a new ScrollIdleTracker with a 2.5s max-wait cap so a continuously scrolling user cannot starve it.

Commits

  • fix(ui): preserve in-flight touch scrolling during chat updates — the fix, tests, and changesets.
  • chore(ui): add temporary on-device scroll diagnostics overlayTEMPORARY debug tooling gated behind ?scrolldiag=1 for on-device verification of the stall investigation; to be dropped once the investigation concludes (revert of the single top commit).

Testing

  • 13 new tests: ScrollIdleTracker state machine (fake scheduler), prepend-anchor write suppression, loadEarlierMessages idle-hold incl. the session-switch race, and Lit touch-event wiring on the chat scroller.
  • Full client suite passes (798 tests); typecheck, eslint, and knip clean.

Programmatic scrollTop writes and DOM repaints cancel in-flight
touch/momentum scrolling on iOS, causing the chat to freeze mid-gesture.
Three mechanisms contribute, all addressed:

- The prepend anchor settle loop wrote scrollTop every frame for 30
  frames even when the anchor had not drifted. It now only writes when
  the drift is at least half a pixel.
- The conversation position indicator repainted mid-gesture, cancelling
  touch scrolls because the meter overlaps the top edge of the
  scrollport. Updates are now deferred while a gesture or momentum
  scroll is in flight and committed once the scroll settles.
- History prepends applied their DOM changes (and scrollTop
  corrections) as soon as the fetch resolved. The page is still fetched
  immediately to hide latency, but the merge is held until the chat
  scroll is idle via a new ScrollIdleTracker, with a max-wait cap so a
  continuously scrolling user cannot starve it.
TEMPORARY tooling for the touch-scroll stall investigation, gated
behind ?scrolldiag=1: instruments the chat scroller (scrollTop writes
with stack traces, scroll/touch events, DOM mutations, long tasks) and
renders a timeline overlay with an abrupt-stop detector so an on-device
reproduction can be screenshotted. Remove once the investigation
concludes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant