You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A dialog holding unsaved work should ask before discarding it. Three pieces,
each with one job: `createConfirmHandle()` links a question to its answer,
`useConfirmedClose` guards the close path, and `<AlertDialog.Confirm>` is the
dialog, rendered inside the one it guards so the two share a floating tree —
escape ordering, the stacking styles and the refcounted scroll lock all read
that tree, and a globally mounted confirmation would break every one of them.
`show()` returns a promise resolving to the answer, so a confirmation reads as
`if (await confirm.show({…}))` rather than as a pair of state variables and a
callback. Calling it while one is already showing returns the IN-FLIGHT promise
instead of opening a second: holding Escape against a guarded dialog would
otherwise stack a confirmation per keypress.
The veto is the absence of a commit. `useConfirmedClose` wraps the consumer's
own `onOpenChange`, so it covers every close the dialog owns — Escape, outside
press, `Dialog.CloseButton`, `Dialog.Close`, and the `close` the wrapper hands
its children all funnel through it. A button wired to the consumer's own
`setOpen(false)` never reaches the dialog and so bypasses the question; that is
inherent, and both the hook's JSDoc and the docs page say so.
Two ordering details that are load-bearing. The action settles `true` before
closing, and `settle` is a no-op once a question is answered, so the close that
follows cannot overwrite the answer with `false`. And the hook reads `when` and
`onOpenChange` through a ref, so the callback identity is stable across the
keystrokes of the very form whose dirtiness `when` reports on.
Headless gains `handle.open(payload)` — the programmatic counterpart of a
trigger's payload, which is how the confirmation's own text reaches it. The
root holds it in a ref as well as in state: the registry lookup that runs once
the dialog is open resolves a trigger-less open to `undefined`, and would
otherwise blank the dialog a commit after it was filled.
0 commit comments