Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,11 @@ export function useTranscriptScroll({
});
lastScrollTopRef.current = el.scrollTop;
if (transition.releasedFollow) cancelFollowScroll();
// A reader scroll-up takes the viewport back from any held disclosure
// anchor, exactly as a real gesture does in `markScrollGesture`. Without
// this, a held anchor can still be restored by the ResizeObserver during a
// later stream and steal the reader's position.
if (transition.releasedFollow) releaseDisclosureAnchor();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is broader than the stated user-scroll case: releasedFollow can be true for a non-gesture layout clamp, which this handler immediately classifies as layout noise below. Releasing the disclosure anchor here can make the next observer frame lose the held title. The PR's E2E wheel event already bubbles to markScrollGesture, which releases the anchor earlier.

if (gesturing && transition.releasedFollow) {
pinnedRef.current = false;
setShowJump(true);
Expand All @@ -447,7 +452,7 @@ export function useTranscriptScroll({
setShowJump(transition.showJump);
}
rememberReadingPosition();
}, [cancelFollowScroll, reachTop, readingPositionPendingRef, readingWindow, rememberReadingPosition, scheduleFollowScroll]);
}, [cancelFollowScroll, reachTop, readingPositionPendingRef, readingWindow, rememberReadingPosition, releaseDisclosureAnchor, scheduleFollowScroll]);

// Send / retry / regenerate always re-pins follow mode so the new prompt and
// its stream stay in view, even if the user had scrolled up through history.
Expand Down