Smooth Quick Chat mobile panel height changes while keeping viewport sampling synchronous.\n\n- Add Android resize-content detection that toggles height easing only for coarse keyboard viewport samples.\n- Clear smoothing and viewport CSS variables on blur, unmount, and suppressed shrink paths.\n- Cover Android smoothing, iOS offsetTop refocus, Latest gate, and streaming state with Quick Chat regression tests.\n- Document the mobile keyboard smoothing behavior and add a published package changeset.\n\nFiles changed:\n .changeset/smooth-mobile-quick-chat-keyboard.md | 5 +\n docs/dashboard-guide.md | 1 +\n .../quick-chat-mobile-keyboard-board-shift.md | 2 +\n packages/dashboard/app/components/QuickChatFAB.css | 8 ++\n packages/dashboard/app/components/QuickChatFAB.tsx | 17 +++\n .../app/components/__tests__/QuickChatFAB.test.tsx | 141 +++++++++++++++++++++\n 6 files changed, 174 insertions(+) Fusion-Task-Id: FN-6757 Fusion-Task-Lineage: d301aee8-ef76-4d70-a4cd-91641bb05259
4.5 KiB
title, date, category, module, problem_type, component, applies_when, symptoms, root_cause, resolution_type, severity, related_components, tags
| title | date | category | module | problem_type | component | applies_when | symptoms | root_cause | resolution_type | severity | related_components | tags | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Quick Chat mobile keyboard board shift | 2026-06-12 | ui-bugs | packages/dashboard/app/utils/mobileBarKeyboardFlags | ui_bug | frontend_mobile_layout | A fullscreen mobile overlay owns its own soft-keyboard and visual-viewport handling while the dashboard board remains mounted underneath. |
|
overlay_keyboard_state_leaked_to_board_layout | code_fix | medium |
|
|
Quick Chat mobile keyboard board shift
Problem
Quick Chat's mobile UI is a fullscreen fixed sheet that covers the board and manages its own keyboard viewport with --vv-height and --vv-offset-top. App-level mobile keyboard logic did not know that sheet was open, so the Quick Chat composer keyboard was treated like an inline board keyboard.
On iOS, computeMobileBarKeyboardFlags returned footerHidden: true whenever isMobile, keyboardOpen, and !anyModalOpen were true. App.tsx mapped that to mobileKeyboardOpen, which removed project-content--with-footer / project-content--with-mobile-nav and hid the footer. Because Quick Chat is not part of modalManager.anyModalOpen, the board behind the sheet shifted up and could remain offset after iOS keyboard dismissal lag.
Solution
Model fullscreen mobile overlays as explicit board-layout suppressors in computeMobileBarKeyboardFlags.
- Keep existing modal suppression intact.
- Add an
overlayOpeninput and suppress onlyfooterHiddenwhenanyModalOpen || overlayOpenis true. - Preserve
navKeyboardOpenandfooterKeyboardOpensemantics so mobile nav/footer keyboard classes continue to reflect keyboard state where needed. - In
App.tsx, passoverlayOpen: isMobile && quickChatOpenso only Quick Chat's mobile fullscreen sheet suppresses board layout. Desktop Quick Chat remains unaffected.
This keeps the board's footer/mobile-nav padding classes present for the entire time Quick Chat is open. The board therefore never shifts in response to the Quick Chat keyboard, leaving nothing to snap back after the overlay closes.
Related viewport-smoothing pitfall
FN-6498 found a separate Quick Chat viewport-tracking jank source inside QuickChatFAB.tsx: mobile visualViewport resize and scroll events can report the same { height, offsetTop } sample during one keyboard animation tick, especially on Android Chrome with interactive-widget=resizes-content. The sheet should still own --vv-height / --vv-offset-top, but same-sample writes are deduped so the overlay does not add redundant style/layout invalidation while the board-shift suppression described above keeps the board underneath stable.
FN-6757 extends that mitigation for Android Chrome's distinct resize-content samples. When visualViewport.height shrinks below the stable layout viewport and offsetTop stays 0, Quick Chat adds a height-only smoothing class so the fullscreen sheet eases through the keyboard animation instead of visibly stepping through every browser sample. The actual --vv-height writes remain synchronous and deduped, so the final sample is authoritative and FN-6503's Android focusin tail can still converge on late keyboard geometry. Non-zero offsetTop samples (the iOS keyboard path) do not enable smoothing because the sheet's translateY alignment must track the visual viewport immediately.
Regression coverage
Cover the invariant at the pure helper seam:
- iOS + mobile + keyboard + no overlay still hides the footer for inline board keyboards.
- iOS + mobile + keyboard + modal keeps the footer visible.
- iOS + mobile + keyboard + fullscreen overlay keeps the footer visible.
- Android + mobile + keyboard + fullscreen overlay keeps
footerHiddenfalse while preserving nav keyboard state. - Non-mobile remains all-false.
Prefer this narrow helper coverage over mock-heavy App rendering unless a future regression needs DOM-level evidence. computeMobileBarKeyboardFlags has a single production caller in App.tsx, making the seam small and reliable.