Skip to content

fix(scroll): keep sent messages stuck to the bottom on WebKit#769

Merged
mremond merged 1 commit into
mainfrom
claude/youthful-gagarin-ecf2ac
Jun 30, 2026
Merged

fix(scroll): keep sent messages stuck to the bottom on WebKit#769
mremond merged 1 commit into
mainfrom
claude/youthful-gagarin-ecf2ac

Conversation

@mremond

@mremond mremond commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

Sending a message did not stick to the bottom on WebKit (Safari + Tauri): the just-sent message stayed below the fold instead of scrolling into view.

Fix

Gate the pin on intent, not position. The pin-to-bottom loop now yields only to a genuine user takeover (wheel / FAB, via userScrollIntentAtRef) and otherwise keeps converging on real geometry until the bottom is reached or its frame budget ends, re-deriving isAtBottom from real geometry when the budget ends. It no longer reads the corrupted position flag, so it is robust to any pattern of WebKit growth-settle scroll events rather than to the specific cases patched before.

Trade-off: within the ~1s pin window after a send, a non-wheel scroll-up (touch, arrow keys, dragging the scrollbar thumb) is pulled back to the bottom. On desktop Safari/Tauri (trackpad/wheel) this is not reached, and it matches the intended "send reveals your message" behaviour.

Adds a scroll-invariant modelling the two-event growth settle that the single-event #760 test does not cover (RED before the fix, GREEN after), passing on chromium and webkit.

The pin-to-bottom loop bailed on a position-derived `isAtBottomRef`, which WebKit
corrupts: a tall just-sent row grows after paint and the engine fires extra scroll
events during the pin. handleScroll's height-unchanged discriminator only catches
the first one (it advances prevScrollHeightRef on every event), so a growth that
settles across two scroll events slips through, flips isAtBottom false, and the pin
bails — stranding the message below the fold. That is the recurring send-stick bug
(#673/#683/#724/#760 each patched one variant of the same position-inference leak).

The pin now yields only to genuine user intent (wheel/FAB, via userScrollIntentAtRef)
and otherwise keeps converging on real geometry until the bottom is reached or its
frame budget ends, re-deriving isAtBottom from real geometry on exit. It no longer
reads the corrupted position flag, so it is robust to any pattern of WebKit
growth-settle scroll events rather than to the specific cases patched before.

Adds a scroll-invariant modelling the two-event growth settle the single-event #760
test does not cover (RED before, GREEN after), passing on chromium and webkit.
@mremond mremond added this to the 0.17.0 milestone Jun 30, 2026
@mremond mremond merged commit 332856a into main Jun 30, 2026
3 checks passed
@mremond mremond deleted the claude/youthful-gagarin-ecf2ac branch June 30, 2026 06:49
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