summaryrefslogtreecommitdiffhomepage
path: root/packages/ui
diff options
context:
space:
mode:
authoradamelmore <[email protected]>2026-01-23 23:18:54 -0600
committerAdam <[email protected]>2026-01-24 07:00:41 -0600
commitda8f3e92a7bbc3b288f89f6b535b72b94c1d1c19 (patch)
treeaca02084c140751929532c2bb86caa847997f63c /packages/ui
parent04b511e1fe135b70256c6aa4f41b81ce2571276c (diff)
downloadopencode-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.tsx16
-rw-r--r--packages/ui/src/hooks/create-auto-scroll.tsx11
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()
})