From 8c102cddd0c4b9e6e4bf994f44eeed179554e4e4 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Tue, 25 Aug 2026 17:25:06 +0300 Subject: [PATCH] fix(chat): teleport the send anchor when sent away from the live edge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sending from mid-history positioned the new turn with an animated scrollToIndex; over a long distance the smooth scroll gets cancelled by rows mounting and measuring along the way — a weak scroll attempt that dies partway, leaving the reader where they were. Park instantly when the viewport was not at the end at send time; the short smooth park remains for sends from the live edge. --- packages/ui/src/hooks/useChatTimelineScroll.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/hooks/useChatTimelineScroll.ts b/packages/ui/src/hooks/useChatTimelineScroll.ts index 5e4dd1d8..36d774f6 100644 --- a/packages/ui/src/hooks/useChatTimelineScroll.ts +++ b/packages/ui/src/hooks/useChatTimelineScroll.ts @@ -289,7 +289,15 @@ export const useChatTimelineScroll = ({ // Sending arms the anchor. The message id is not known here (the optimistic // row is created by the store), so the next new user message id claims it. + // Whether the send-time anchor positioning may animate. Sending from the + // live edge parks the new message with a short smooth scroll; sending + // from mid-history teleports — a long smooth scroll through the + // virtualized timeline gets cancelled by rows mounting and measuring + // along the way and dies partway there. + const anchorPositionInstantRef = React.useRef(false); + const scrollToBottomOnSend = React.useCallback(() => { + anchorPositionInstantRef.current = !isAtEndRef.current; isAtEndRef.current = true; setUserOwnsScroll(false); modeRef.current = 'anchoring-new-turn'; @@ -418,7 +426,7 @@ export const useChatTimelineScroll = ({ void list.scrollToIndex({ index: anchorIndex, - animated: true, + animated: !anchorPositionInstantRef.current, viewPosition: 0, viewOffset: CHAT_LIST_ANCHOR_OFFSET, });