mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 06:56:35 +00:00
e4ed4bfc7b
On the phone a flick of the sheet's top edge, a tap on the scrim or Escape closed the booking, transport and place forms and threw away whatever had been typed, without a word; the desktop dialogs have asked since #2253. The question moves into a shared hook that DialogShell and MSheet both use, and the three sheets pass their form state to it.
37 lines
1.6 KiB
TypeScript
37 lines
1.6 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
|
const snapshot = (value: unknown): string | null => {
|
|
try { return JSON.stringify(value) ?? null } catch { return null }
|
|
}
|
|
|
|
/**
|
|
* The unsaved-changes question (#2253) for a dialog or a sheet. `guard` is the
|
|
* editor's state, JSON-serialisable; undefined turns the question off. The
|
|
* state at the first key or pointer press (`markStart`) is the starting point,
|
|
* so whatever the editor loaded on open does not count as a change. The ways
|
|
* out a hand takes by accident go through `requestClose`, which asks before
|
|
* throwing away a state that differs from that starting point.
|
|
*/
|
|
export function useDiscardGuard(guard: unknown, onClose: () => void) {
|
|
const baseline = useRef<string | null>(null)
|
|
const guardRef = useRef(guard)
|
|
useEffect(() => { guardRef.current = guard })
|
|
const [asking, setAsking] = useState(false)
|
|
|
|
const markStart = useCallback(() => {
|
|
if (guardRef.current !== undefined && baseline.current === null) baseline.current = snapshot(guardRef.current)
|
|
}, [])
|
|
|
|
const requestClose = useCallback(() => {
|
|
if (guardRef.current !== undefined && baseline.current !== null && snapshot(guardRef.current) !== baseline.current) setAsking(true)
|
|
else onClose()
|
|
}, [onClose])
|
|
|
|
const keepEditing = useCallback(() => setAsking(false), [])
|
|
const discard = useCallback(() => { setAsking(false); onClose() }, [onClose])
|
|
/** Forget the starting point, for a surface that stays mounted between openings. */
|
|
const reset = useCallback(() => { baseline.current = null; setAsking(false) }, [])
|
|
|
|
return { asking, markStart, requestClose, keepEditing, discard, reset }
|
|
}
|