Download frontend/src/ui/lib/useBackToClose.ts from ruslanmv/HomePilot: direct link, hf CLI and curl.
- Browser
- Download file 2.2 kB
-
https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/src/ui/lib/useBackToClose.ts
- Command line
-
hf download hf://spaces/ruslanmv/HomePilot/frontend/src/ui/lib/useBackToClose.ts
-
curl -L -o useBackToClose.ts https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/src/ui/lib/useBackToClose.ts
2.2 kB
| /** | |
| * useBackToClose β the phone's Back gesture closes the open layer (drawer, | |
| * full-screen settings) instead of leaving HomePilot. | |
| * | |
| * While `open`, one history entry is added for the layer. Back pops it and | |
| * `onClose` runs; closing the layer any other way removes the entry again. | |
| * Layers stack: each records its depth, and Back only closes layers above the | |
| * entry it lands on β so Back from Settings opened over the drawer closes | |
| * Settings and leaves the drawer open. | |
| * | |
| * If the owner declines to close (e.g. "Discard unsaved changes?" β Cancel), | |
| * the entry is restored so the next Back is caught again. | |
| */ | |
| import { useEffect, useRef } from 'react' | |
| type LayerState = { hpLayer?: number } | |
| function depthOf(state: unknown): number { | |
| const d = (state as LayerState | null)?.hpLayer | |
| return typeof d === 'number' ? d : 0 | |
| } | |
| export function useBackToClose(open: boolean, onClose: () => void): void { | |
| const closeRef = useRef(onClose) | |
| closeRef.current = onClose | |
| useEffect(() => { | |
| if (!open || typeof window === 'undefined' || !window.history?.pushState) return | |
| let alive = true | |
| let pushed = false | |
| let depth = 0 | |
| const push = () => { | |
| depth = depthOf(window.history.state) + 1 | |
| window.history.pushState({ ...(window.history.state || {}), hpLayer: depth }, '') | |
| pushed = true | |
| } | |
| // Deferred one tick so React StrictMode's mount β unmount β mount in | |
| // development doesn't leave a stray entry behind. | |
| const startTimer = window.setTimeout(() => { | |
| if (alive) push() | |
| }, 0) | |
| const onPop = (e: PopStateEvent) => { | |
| if (!pushed || depthOf(e.state) >= depth) return | |
| pushed = false | |
| closeRef.current() | |
| // Still open after asking to close β the owner kept it; catch the next Back too. | |
| window.setTimeout(() => { | |
| if (alive && !pushed) push() | |
| }, 0) | |
| } | |
| window.addEventListener('popstate', onPop) | |
| return () => { | |
| alive = false | |
| window.clearTimeout(startTimer) | |
| window.removeEventListener('popstate', onPop) | |
| if (pushed && depthOf(window.history.state) === depth) window.history.back() | |
| } | |
| }, [open]) | |
| } | |
| export default useBackToClose | |