Recover stale iOS document scroll after returning to the Fusion dashboard. - Add an iOS-only restore hook that clears orphaned body offsets and scrolls the document back to the origin when unlocked. - Wire the restore reset from the dashboard app shell for mobile layouts. - Cover visible/page-show restores, platform no-ops, active-lock guards, and orphaned style cleanup. - Document the mobile restore drift solution for future regressions. Files changed: .../mobile-ios-restore-document-scroll-drift.md | 59 ++++++++++ packages/dashboard/app/App.tsx | 4 +- .../hooks/__tests__/useMobileScrollLock.test.ts | 121 ++++++++++++++++++++- .../dashboard/app/hooks/useMobileScrollLock.ts | 61 +++++++++++ 4 files changed, 243 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-6364 Fusion-Task-Lineage: 9243cab8-5fbb-4332-ac4d-aabefde4161c
3.1 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 | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Mobile iOS restore document scroll drift | 2026-06-13 | ui-bugs | packages/dashboard/app/hooks/useMobileScrollLock | ui_bug | frontend_mobile_layout | An iOS Safari/PWA dashboard tab is restored from background or bfcache after the document has stale scroll or orphaned body offset. |
|
ios_restore_left_stale_document_scroll_or_body_offset | code_fix | medium |
|
|
Mobile iOS restore document scroll drift
Problem
On iOS Safari/PWA, switching away from Fusion and returning can leave the layout viewport visually misaligned with the dashboard. The document may retain window.scrollY > 0, or a stale inline body offset from an earlier lock, even though Fusion's base shell uses body { overflow: hidden } and the resting document scroll position should be (0, 0).
The visible symptom is the board/header appearing shifted upward with an empty gap at the bottom after foregrounding the app, including cases where no input is currently focused.
Solution
Keep keyboard metrics recovery and document-scroll recovery as separate concerns:
- FN-6362 resets
useMobileKeyboardmetrics onvisibilitychange/pageshowso--vv-offset-topconsumers stop seeing a stale keyboard-open state. - FN-6364 adds
useMobileViewportRestoreResetinuseMobileScrollLock.tsand wires it once fromApp.tsxfor mobile layouts.
The restore hook only runs on iOS mobile devices. On document.visibilitychange it acts only when document.visibilityState === "visible", and on window.pageshow it handles normal and bfcache restores. If no fullscreen scroll lock or keyboard viewport lock is active, it clears orphaned body fixed-position offset styles and calls window.scrollTo(0, 0) when stale document scroll is present.
Do not run this reset on Android or desktop, and do not run it while useMobileScrollLock or useMobileKeyboardViewportLock is active; live locks own their own restore path.
Regression coverage
Cover the invariant at the useMobileScrollLock hook seam:
- iOS mobile +
visibilitychangeto visible +scrollY > 0callsscrollTo(0, 0). - iOS mobile +
pageshowwithpersisted: falsecallsscrollTo(0, 0). - Android and desktop restore events are no-ops.
visibilitychangeto hidden is a no-op.- Active fullscreen scroll locks and keyboard viewport locks prevent the restore hook from fighting the live lock.
scrollY === 0is idempotent.- Orphaned body
position: fixed/topoffset is cleared only when no lock is active.