import { nextTick } from 'vue' import router from '@/router' let recoveryTimers: ReturnType[] = [] function clearRecoveryTimers() { recoveryTimers.forEach(clearTimeout) recoveryTimers = [] } function blurFocusedField() { const active = document.activeElement if (active instanceof HTMLElement && active !== document.body) { active.blur() } } function clearBodyScrollLock() { document.body.classList.remove('van-overflow-hidden') document.body.style.removeProperty('position') document.body.style.removeProperty('top') document.body.style.removeProperty('left') document.body.style.removeProperty('right') document.body.style.removeProperty('width') document.body.style.removeProperty('height') document.body.style.removeProperty('min-height') document.body.style.removeProperty('overflow') document.body.style.removeProperty('transform') document.documentElement.style.removeProperty('overflow') document.documentElement.style.removeProperty('height') document.documentElement.style.removeProperty('transform') const appRoot = document.getElementById('app') if (appRoot) { appRoot.style.removeProperty('position') appRoot.style.removeProperty('top') appRoot.style.removeProperty('height') appRoot.style.removeProperty('min-height') appRoot.style.removeProperty('overflow') appRoot.style.removeProperty('transform') } } function resetAllScrollPositions() { window.scrollTo(0, 0) document.documentElement.scrollTop = 0 document.body.scrollTop = 0 document .querySelectorAll('.main-with-bottom-chrome-inner, .login-page, .login-page-root') .forEach((node) => { if (node instanceof HTMLElement) { node.scrollTop = 0 } }) } function kickViewportReflow() { window.dispatchEvent(new Event('resize')) if (window.visualViewport) { window.scrollTo(0, 0) } } function runViewportRecovery() { clearBodyScrollLock() resetAllScrollPositions() kickViewportReflow() } function scheduleViewportRecovery() { clearRecoveryTimers() runViewportRecovery() nextTick(() => { requestAnimationFrame(() => { runViewportRecovery() for (const delay of [50, 150, 300, 500]) { recoveryTimers.push(window.setTimeout(runViewportRecovery, delay)) } }) }) } /** Reset scroll offsets after navigation — fixes iOS safe-area drift. */ export function resetMobileAppScroll() { runViewportRecovery() nextTick(() => { requestAnimationFrame(runViewportRecovery) }) } export async function dismissMobileKeyboard() { blurFocusedField() await new Promise((resolve) => window.setTimeout(resolve, 120)) } export async function prepareMobileViewportForAppShell() { blurFocusedField() resetAllScrollPositions() await dismissMobileKeyboard() } /** Full recovery after auth — runs after home shell is mounted. */ export function recoverMobileViewportAfterAuth() { scheduleViewportRecovery() } export const resetMobileAppScrollAfterLogin = recoverMobileViewportAfterAuth export async function completeLoginNavigation() { await prepareMobileViewportForAppShell() await router.push({ name: 'home' }) await router.isReady() recoverMobileViewportAfterAuth() } export function initMobileScrollRestoration() { if (typeof history !== 'undefined' && 'scrollRestoration' in history) { history.scrollRestoration = 'manual' } }