Files
fusion/docs/solutions/ui-bugs/quick-chat-mobile-keyboard-board-shift.md
gsxdsm 2e3b965909 FN-6757: smooth mobile Quick Chat keyboard resizing
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
2026-06-20 00:41:36 -07:00

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.
Opening Quick Chat on mobile focuses the composer and raises the soft keyboard
The board underneath shifts upward because App-level keyboard logic removes footer/mobile-nav padding
After dismissing the keyboard or closing Quick Chat, the board can remain shifted with a bottom gap
overlay_keyboard_state_leaked_to_board_layout code_fix medium
packages/dashboard/app/App.tsx
packages/dashboard/app/components/QuickChatFAB.tsx
packages/dashboard/app/hooks/useMobileScrollLock.ts
FN-6329
quick-chat
mobile-keyboard
visualviewport
overlay-layout
footer-padding

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 overlayOpen input and suppress only footerHidden when anyModalOpen || overlayOpen is true.
  • Preserve navKeyboardOpen and footerKeyboardOpen semantics so mobile nav/footer keyboard classes continue to reflect keyboard state where needed.
  • In App.tsx, pass overlayOpen: isMobile && quickChatOpen so 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.

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 footerHidden false 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.