diff options
| author | adamelmore <[email protected]> | 2026-01-23 23:18:54 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-24 07:00:41 -0600 |
| commit | da8f3e92a7bbc3b288f89f6b535b72b94c1d1c19 (patch) | |
| tree | aca02084c140751929532c2bb86caa847997f63c /packages/ui | |
| parent | 04b511e1fe135b70256c6aa4f41b81ce2571276c (diff) | |
| download | opencode-da8f3e92a7bbc3b288f89f6b535b72b94c1d1c19.tar.gz opencode-da8f3e92a7bbc3b288f89f6b535b72b94c1d1c19.zip | |
perf(app): better session stream rendering
Diffstat (limited to 'packages/ui')
| -rw-r--r-- | packages/ui/src/components/session-turn.tsx | 16 | ||||
| -rw-r--r-- | packages/ui/src/hooks/create-auto-scroll.tsx | 11 |
2 files changed, 18 insertions, 9 deletions
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index ca63d17ab..fe53c0939 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -457,9 +457,16 @@ export function SessionTurn( }) createEffect(() => { - const timer = setInterval(() => { + const update = () => { setStore("duration", duration()) - }, 1000) + } + + update() + + // Only keep ticking while the active (in-progress) turn is running. + if (!working()) return + + const timer = setInterval(update, 1000) onCleanup(() => clearInterval(timer)) }) @@ -495,6 +502,11 @@ export function SessionTurn( } }) + onCleanup(() => { + if (!statusTimeout) return + clearTimeout(statusTimeout) + }) + return ( <div data-component="session-turn" class={props.classes?.root} ref={setRootRef}> <div diff --git a/packages/ui/src/hooks/create-auto-scroll.tsx b/packages/ui/src/hooks/create-auto-scroll.tsx index 26cd06e88..c8c380cb8 100644 --- a/packages/ui/src/hooks/create-auto-scroll.tsx +++ b/packages/ui/src/hooks/create-auto-scroll.tsx @@ -15,7 +15,6 @@ export function createAutoScroll(options: AutoScrollOptions) { let settleTimer: ReturnType<typeof setTimeout> | undefined let autoTimer: ReturnType<typeof setTimeout> | undefined let cleanup: (() => void) | undefined - let resizeFrame: number | undefined let auto: { top: number; time: number } | undefined const threshold = () => options.bottomThreshold ?? 10 @@ -152,11 +151,10 @@ export function createAutoScroll(options: AutoScrollOptions) { () => { if (!active()) return if (store.userScrolled) return - if (resizeFrame !== undefined) return - resizeFrame = requestAnimationFrame(() => { - resizeFrame = undefined - scrollToBottom(false) - }) + // ResizeObserver fires after layout, before paint. + // Keep the bottom locked in the same frame to avoid visible + // "jump up then catch up" artifacts while streaming content. + scrollToBottom(false) }, ) @@ -190,7 +188,6 @@ export function createAutoScroll(options: AutoScrollOptions) { onCleanup(() => { if (settleTimer) clearTimeout(settleTimer) if (autoTimer) clearTimeout(autoTimer) - if (resizeFrame !== undefined) cancelAnimationFrame(resizeFrame) if (cleanup) cleanup() }) |
