mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-18 14:52:04 +00:00
During a token stream $messages is replaced ~30x/s. Subscribing the whole chat view to it re-rendered the composer, runtime boundary, and every message on every delta. - Derive coarse facts (empty thread? tail is user?) via nanostores `computed` atoms so per-token flushes don't re-render their consumers. - Move the $messages subscription + runtime wiring into a dedicated ChatRuntimeBoundary; the composer reads $messages imperatively. - Drive message rows off stable useAuiState selectors and a lazy getMessageText getter instead of eagerly materialized text. - Feed ResizeObserver entry sizes into measureClamp / FadeText and dedupe the style writes, killing the read-write-read reflow cascade.
47 lines
1 KiB
TypeScript
47 lines
1 KiB
TypeScript
import { type RefObject, useLayoutEffect, useRef } from 'react'
|
|
|
|
/**
|
|
* Observe element resizes. The callback receives the ResizeObserver entries
|
|
* (empty on the initial synchronous call and in non-RO environments) so
|
|
* callers can read the observed size off the entry instead of forcing a
|
|
* fresh layout read.
|
|
*/
|
|
export function useResizeObserver(
|
|
onResize: (entries: readonly ResizeObserverEntry[]) => void,
|
|
...refs: readonly RefObject<Element | null>[]
|
|
) {
|
|
const refsRef = useRef(refs)
|
|
refsRef.current = refs
|
|
|
|
useLayoutEffect(() => {
|
|
if (typeof ResizeObserver === 'undefined') {
|
|
onResize([])
|
|
|
|
return
|
|
}
|
|
|
|
const observer = new ResizeObserver(entries => onResize(entries))
|
|
let observed = false
|
|
|
|
for (const ref of refsRef.current) {
|
|
const element = ref.current
|
|
|
|
if (!element) {
|
|
continue
|
|
}
|
|
|
|
observer.observe(element)
|
|
observed = true
|
|
}
|
|
|
|
if (!observed) {
|
|
observer.disconnect()
|
|
|
|
return
|
|
}
|
|
|
|
onResize([])
|
|
|
|
return () => observer.disconnect()
|
|
}, [onResize])
|
|
}
|