feat(desktop): follow streaming output at bottom + jump-to-bottom button (#45263)

Strict sticky-bottom autoscroll for the chat thread: while the viewport is
parked at the bottom, the tail follows content growth (streaming tokens, late
measurement, Shiki re-highlight) via a useLayoutEffect keyed on the
virtualizer's own size signal, pinned in the same pre-paint pass as its
scrollToFn so the two never rubber-band. The gate is a single boolean — one
upward pixel (scroll/wheel/touch) disarms follow until the user returns to the
bottom.

Adds a floating jump-to-bottom control that appears once scrolled ~10px away
(above the dim threshold so a sub-pixel settle never flashes it), positioned
above the composer with respect to the status stack, with a subtle
scale + slide in/out animation that honours prefers-reduced-motion. The button
bridges to the virtualizer's re-arm + pin path through a small nanostore
emitter.

Supersedes #43624.
This commit is contained in:
brooklyn!
2026-06-12 23:00:11 +00:00
committed by GitHub
parent 135fe90166
commit bbf020e709
8 changed files with 198 additions and 30 deletions
+1
View File
@@ -1666,6 +1666,7 @@ export const en: Translations = {
stopReading: 'Stop reading',
readAloud: 'Read aloud',
editMessage: 'Edit message',
scrollToBottom: 'Scroll to bottom',
stop: 'Stop',
restorePrevious: 'Restore previous checkpoint',
restoreCheckpoint: 'Restore checkpoint',
+1
View File
@@ -1325,6 +1325,7 @@ export interface Translations {
stopReading: string
readAloud: string
editMessage: string
scrollToBottom: string
stop: string
restorePrevious: string
restoreCheckpoint: string
+1
View File
@@ -1846,6 +1846,7 @@ export const zh: Translations = {
stopReading: '停止朗读',
readAloud: '朗读',
editMessage: '编辑消息',
scrollToBottom: '滚动到底部',
stop: '停止',
restorePrevious: '恢复上一个检查点',
restoreCheckpoint: '恢复检查点',