Re-fit once the chat height has finished moving

The transcript animates, so a page measuring it one frame later sized itself from a box caught
mid-collapse and left a dead strip the height the chat was shrinking from.
This commit is contained in:
Gmer4Lfe
2026-08-09 13:57:06 -04:00
parent 4b6c5fe1cc
commit c135d46cbc
+27 -4
View File
@@ -956,12 +956,31 @@ vv_ai_profiles_script();
// panel is pinned at the bottom and the views above it are sized from what is left, so without
// this the chat grows downward off the end of the panel and takes its own composer with it —
// which is precisely what it did.
function toggleBig() { big = !big; applyHeights(); scroll(); onResize(big); }
// Announced twice: now, so a page that lays out around this tracks the change as it happens,
// and again once it has finished.
//
// The transcript animates its height — see the transition on .vv-ai-chat — so a page that
// measures the moment we change it reads a box that is still moving. The Scheduler sizes the
// view above from the panel's measured height, and re-measuring one frame after a collapse
// read a dock caught part of the way down: the view came out short by roughly the height the
// chat was shrinking from, leaving a dead strip under the content that nothing filled. It only
// ever showed on collapse, because on expand the same error sizes the view too large and flex
// quietly shrinks it back.
let settle = null;
function announceResize() {
onResize(big);
clearTimeout(settle);
// Comfortably past the 140ms transition. A timer rather than transitionend, which does not
// fire at all when the computed height happens not to change.
settle = setTimeout(() => onResize(big), 220);
}
function toggleBig() { big = !big; applyHeights(); scroll(); announceResize(); }
// Only meaningful while expanded, and the button is only reachable then. The shortcut has to
// check for itself rather than silently changing a size nobody can see.
function toggleSize() {
if (!big) return;
large = !large; applyHeights(); scroll(); onResize(big);
large = !large; applyHeights(); scroll(); announceResize();
}
if (growBtn) growBtn.addEventListener('click', toggleBig);
@@ -990,8 +1009,10 @@ vv_ai_profiles_script();
applyKeys(open);
scroll();
// The total is meant to hold, but the floor above can break that on a small placement, so
// the page is told either way rather than being left to find out by clipping.
onResize(big);
// the page is told either way rather than being left to find out by clipping. Through the
// same settle as the size controls: the list appears at once but the transcript animates
// to its new height, so an immediate measurement is of a box still moving.
announceResize();
});
}
@@ -1121,6 +1142,8 @@ vv_ai_profiles_script();
},
teardown() {
clearInterval(pendingTimer);
// Would otherwise fire a re-layout at a page whose instance no longer exists.
clearTimeout(settle);
window.removeEventListener('error', onErr);
window.removeEventListener('unhandledrejection', onRej);
document.removeEventListener('click', onDocClick);