fix: keep the final chat turn active near the bottom

Aligns the scroll spy with the chat pinned zone at the bottom
Keeps the active rail state on the latest turn before its DOM is measurable
Adds coverage for the bottom spacer behavior
This commit is contained in:
Bohdan Triapitsyn
2026-07-29 17:39:05 +03:00
parent 0f830f8804
commit 84f651d9c8
3 changed files with 65 additions and 6 deletions
@@ -313,6 +313,20 @@ export const useChatTimelineController = ({
setActiveTurnId(null);
}, [sessionId]);
React.useLayoutEffect(() => {
if (!isPinned) {
return;
}
const latestTurnId = turnWindowModel.turnIds[turnWindowModel.turnIds.length - 1];
if (!latestTurnId) {
return;
}
// A sent prompt updates the timeline model before its new DOM node is
// measurable by the scroll spy. While pinned, the latest turn is
// authoritative and keeps the rail in sync for that interval.
setActiveTurnId((current) => current === latestTurnId ? current : latestTurnId);
}, [isPinned, turnWindowModel.turnIds]);
const resolvePendingRenderWaiters = React.useCallback(() => {
const resolvers = pendingRenderResolversRef.current;
if (resolvers.length === 0) {