import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks'
import * as ConfirmDialogStories from './ConfirmDialog.stories'

<Meta of={ConfirmDialogStories} />

# ConfirmDialog

A question with two answers, asked before something a person would want
back. Built on DialogShell; the body is plain sentences in `body-2`.

<Canvas of={ConfirmDialogStories.Destructive} />

## When

- Before a deletion, an archive, a handover — anything hard to undo. The
  confirm button is `destructive` when the action is.
- A non-destructive but consequential step confirms with `primary`.

## When not

- Gathering input first → **DialogShell** with a form.
- Telling someone what already happened → **Toast**.
- Guarding something trivially reversible — don't; an undo beats a
  question.

## How

```tsx
import { ConfirmDialog } from '@estiva-app/ui'

{confirming && (
  <ConfirmDialog
    title="Delete this?"
    confirmLabel="Delete"
    destructive
    onConfirm={() => remove()}
    onClose={() => setConfirming(false)}
  >
    <p>This removes it for everyone. There is no undo.</p>
  </ConfirmDialog>
)}
```

- While `onConfirm` runs, both buttons wait. Resolving `false` keeps the
  dialog open — your surface has said why; a resolved `void`/`true`
  closes it.
- **Escape cancels; a press on the backdrop does not.** This is Base UI's
  `AlertDialog`, through the shell's `alert`: a
  destructive question is answered rather than clicked away. The backdrop
  used to cancel, and that is the one behaviour stage 3 deliberately changed.
- It announces itself as an alert (`role="alertdialog"`), so a screen reader
  reads the question on arrival instead of waiting to be asked.
- Focus is trapped in the card and returns to whatever opened it, as for
  every dialog since stage 3.

## What it owns

It does these by itself. Write none of them around it.

| It does | So you never write | Refused when written by hand |
|---|---|---|
| Floats on top of the page | a portal, or a `z-index` to win | ✓ |
| Says what it is to assistive technology: a dialog that must be answered | `role="alertdialog"` | ✓ |
| Keeps focus inside while open, as DialogShell does, and gives it back to whatever opened it | focus code |  |
| Ignores a press outside, because the question has to be answered; Escape cancels | a backdrop handler |  |

## Keys

Different from `DialogShell`'s in one row, and it is the row that matters.

| Input | What happens |
|---|---|
| Escape | cancels |
| backdrop click | **nothing** — the question has to be answered |
| close button | cancels |
| Tab / Shift+Tab | cycles the controls inside the card, and cannot leave it |
| on close | focus returns to whatever opened it |

## Props

<Controls of={ConfirmDialogStories.Destructive} />
