import { watch, onMounted, onBeforeUnmount, toValue } from 'vue' import type { Ref, WritableComputedRef } from 'vue' /** * Intercepts the mobile hardware back button when a detail panel is open, * closing the panel instead of navigating away from the page. * * Strategy: when the panel opens on mobile, push a history entry with the * same URL. When the user presses back, popstate fires and we close the * panel. When the user closes via the X button, we programmatically pop * the entry we pushed so the stack stays clean. */ export function useDetailHistory( isOpen: WritableComputedRef | Ref, isMobile: Ref ) { let pushed = false let fromPopState = false let suppressNext = false function handlePopState() { if (suppressNext) { suppressNext = false return } if (pushed && toValue(isMobile)) { fromPopState = true pushed = false isOpen.value = false } } watch(isOpen, (open, wasOpen) => { if (!toValue(isMobile)) return if (open && !wasOpen) { history.pushState({ detailPanel: true }, '') pushed = true } else if (!open && wasOpen) { if (fromPopState) { // Back button closed the panel — state already popped by the browser. fromPopState = false } else if (pushed) { // X button (or any programmatic close) — pop the entry we pushed. pushed = false suppressNext = true history.go(-1) } } }) if (import.meta.client) { onMounted(() => window.addEventListener('popstate', handlePopState)) onBeforeUnmount(() => window.removeEventListener('popstate', handlePopState)) } }