From 955b2cc81201adb1492cc239b120f99fd96f3806 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Tue, 25 Aug 2026 01:35:45 +0300 Subject: [PATCH] fix(chat): anchored-scroll behavior parity with the reference model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six reported defects, one root theme — our port diverged from the reference semantics: - a user gesture no longer collapses the reserved anchored end space (that snap-to-bottom was the 'anchoring vanishes on a micro-scroll'); it only disarms the follow/anchor machinery, and anchor remeasures after the user takes over can no longer re-position the viewport - the anchor arms synchronously BEFORE the send reaches the store, and the claim compares against the arm-time baseline — arming a frame after the optimistic row committed is why anchoring 'rarely worked' and sending from mid-history did nothing - gestures are selective (wheel up, touch/pointer away from the end, PageUp/Home/ArrowUp), so scrolling toward the end or clicking a row at the live edge no longer kills follow - 'at end' is a tight 40px band against the full content length instead of the list's half-viewport isNearEnd, so the scroll-to-bottom pill appears when the viewport actually leaves the end - reaching the end re-arms follow without knocking an anchored turn out of its mode, and the overlay scrollbar suppression follows scroll ownership rather than the anchor's mere existence - the status/working row moved out of the list footer to a fixed spot above the composer: inside the list it walked down with every streamed line, and its unmount was part of the end-of-stream jerk --- .../ui/src/components/chat/ChatContainer.tsx | 11 ++- packages/ui/src/components/chat/ChatInput.tsx | 13 +-- .../scroll/timelineScrollAnchoring.test.ts | 10 +- .../lib/scroll/timelineScrollAnchoring.ts | 36 ++++++-- .../ui/src/hooks/useChatTimelineScroll.ts | 92 +++++++++++++++---- 5 files changed, 120 insertions(+), 42 deletions(-) diff --git a/packages/ui/src/components/chat/ChatContainer.tsx b/packages/ui/src/components/chat/ChatContainer.tsx index 9174668b..260328c9 100644 --- a/packages/ui/src/components/chat/ChatContainer.tsx +++ b/packages/ui/src/components/chat/ChatContainer.tsx @@ -361,10 +361,6 @@ const ChatViewport = React.memo(({ -
- -
-