fix(chat): stop scroll twitch and message skipping with expanded tools

Gate passive auto-follow on active (working/settling) state so idle layout
churn from virtualizer re-measurement no longer re-pins the viewport to the
bottom. Render default-open tool bodies synchronously on mount so the
virtualizer measures the real row height up front instead of growing a frame
later and lurching scroll past several messages.
This commit is contained in:
Bohdan Triapitsyn
2026-06-28 12:01:26 +03:00
parent b72230bc24
commit b2598fa45e
2 changed files with 89 additions and 18 deletions
@@ -226,14 +226,30 @@ const scheduleDeferredToolBodyMount = (fn: () => void) => {
};
const useDeferredExpandedContent = (isExpanded: boolean) => {
const [shouldRender, setShouldRender] = React.useState(false);
// If the tool is expanded when the row first mounts (e.g. "show tools open
// by default", or scrolling a default-open tool back into a virtualized
// view), render the body SYNCHRONOUSLY so the virtualizer measures the real
// height immediately. Deferring it would let the row mount short and grow a
// frame later, which makes the virtualizer compensate scroll and lurch the
// viewport past several messages on slow scroll. Only defer LATER
// user-initiated expansions, where instant single-item feedback isn't worth
// blocking the click on a heavy body render.
const [shouldRender, setShouldRender] = React.useState(isExpanded);
const mountedRef = React.useRef(false);
React.useEffect(() => {
if (!isExpanded) {
mountedRef.current = true;
setShouldRender(false);
return;
}
if (!mountedRef.current) {
mountedRef.current = true;
setShouldRender(true);
return;
}
return scheduleDeferredToolBodyMount(() => {
setShouldRender(true);
});