fix(dashboard): re-snapshot keyboard metrics on focusin and page restore

Switching away from the chat view and back left the hook with stale
metrics — keyboardOpen was false at remount even though the system
keyboard was still visible, so the .chat-thread transform never
re-applied and the message list anchored too high. focusin and
synchronous reads also captured offsetTop mid-transition.

Adds a tail of delayed re-reads (50ms, 200ms, 500ms) on focusin,
visibilitychange, and pageshow so iOS has time to settle before the
final snapshot is taken.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-06 21:16:30 -07:00
parent a0fa7f7bc8
commit 94c93abf68

View File

@@ -157,17 +157,35 @@ export function useMobileKeyboard(
setKeyboardOpen(metrics.open);
};
update();
// Re-snapshot once iOS has settled. focusin/page-restore frequently
// fire while the visualViewport is still mid-transition; the
// synchronous read captures stale offsetTop and the chat-thread
// anchors wrong. A short tail of updates catches the settled value.
const updateWithTail = () => {
update();
window.setTimeout(update, 50);
window.setTimeout(update, 200);
window.setTimeout(update, 500);
};
updateWithTail();
vv.addEventListener("resize", update);
vv.addEventListener("scroll", updateScrollOnly);
document.addEventListener("focusin", update);
document.addEventListener("focusin", updateWithTail);
document.addEventListener("focusout", update);
// When the user navigates back to this view, force a fresh snapshot
// — without it the hook initializes with stale metrics (keyboard up
// from before, but our state thinks it's closed).
document.addEventListener("visibilitychange", updateWithTail);
window.addEventListener("pageshow", updateWithTail);
return () => {
vv.removeEventListener("resize", update);
vv.removeEventListener("scroll", updateScrollOnly);
document.removeEventListener("focusin", update);
document.removeEventListener("focusin", updateWithTail);
document.removeEventListener("focusout", update);
document.removeEventListener("visibilitychange", updateWithTail);
window.removeEventListener("pageshow", updateWithTail);
setKeyboardOverlap(0);
setViewportHeight(null);
setViewportOffsetTop(0);