# Confirmer

## Overview

Promise-based confirmation dialog utility built on top of `AlertDialog`. Mount the `Confirmer` component once, then call `confirm()` to open a dialog and await the user decision.

---

## API

### `Confirmer` (Component)

Mount this once at app root (or Story scope) to enable dialogs.

```tsx
import { Confirmer } from "laif-ds";

export function AppRoot() {
  return (
    <>
      {/* ...your app... */}
      <Confirmer />
    </>
  );
}
```

### `confirm(options)`

Returns a Promise that resolves when the user confirms and rejects when the user cancels.

```ts
type ConfirmOptions = {
  title?: React.ReactNode;
  description?: React.ReactNode;
  cancelText?: React.ReactNode;
  actionText?: React.ReactNode;
  CancelProps?: React.ComponentProps<typeof AlertDialogCancel>;
  ActionProps?: React.ComponentProps<typeof Button>;
  variant?: "default" | "destructive";
};

declare function confirm(options: ConfirmOptions): Promise<boolean>;
declare function safeConfirm(
  options: ConfirmOptions,
): Promise<boolean | undefined>;
```

- `variant`: when set to `"destructive"`, shows a destructive style and warning icon.
- `safeConfirm`: resolves `undefined` instead of throwing on cancel.

---

## Behavior

- **Resolve/Reject**: `confirm()` resolves on action click, rejects on cancel or close.
- **Destructive mode**: Adds an alert icon and uses destructive button variant.
- **Custom buttons**: Pass `ActionProps` and `CancelProps` to customize.

---

## Examples

### Destructive

```tsx
import { Button } from "laif-ds";
import { Confirmer, confirm } from "laif-ds";

export function DeleteFile() {
  const onClick = async () => {
    try {
      await confirm({
        variant: "destructive",
        title: "Permanently delete file?",
        description:
          "This action cannot be undone. The file will be removed permanently.",
        cancelText: "Cancel",
        actionText: "Delete",
      });
      console.log("File deleted");
    } catch {
      console.log("Deletion cancelled");
    }
  };

  return (
    <>
      <Button variant="destructive" onClick={onClick}>
        Delete File
      </Button>
      <Confirmer />
    </>
  );
}
```

### Custom Text and Buttons

```tsx
import { Button } from "laif-ds";
import { Confirmer, confirm } from "laif-ds";

export function PublishArticle() {
  const onClick = async () => {
    try {
      await confirm({
        title: "Publish article?",
        description: "This will make your article visible to the public.",
        cancelText: "Save as draft",
        actionText: "Publish now",
        ActionProps: {
          variant: "default",
        },
      });
      console.log("Article published");
    } catch {
      console.log("Article saved as draft");
    }
  };

  return (
    <>
      <Button onClick={onClick}>Publish Article</Button>
      <Confirmer />
    </>
  );
}
```

### Multiple Confirmers (independent flows)

```tsx
import { Button } from "laif-ds";
import { Confirmer, confirm } from "laif-ds";

export function MultipleActions() {
  const accept1 = async () => {
    try {
      await confirm({
        title: "Confirm action 1",
        description: "This is the first confirmation dialog.",
      });
      console.log("Action 1 confirmed");
    } catch {
      console.log("Action 1 cancelled");
    }
  };

  const accept2 = async () => {
    try {
      await confirm({
        title: "Confirm action 2",
        description: "This is the second confirmation dialog.",
        cancelText: "Reject",
        actionText: "Accept",
      });
      console.log("Action 2 confirmed");
    } catch {
      console.log("Action 2 cancelled");
    }
  };

  return (
    <>
      <div className="flex gap-4">
        <Button onClick={accept1}>Action 1</Button>
        <Button onClick={accept2}>Action 2</Button>
      </div>
      <Confirmer />
    </>
  );
}
```

---

## Notes

- **Mount once**: Add a single `<Confirmer />` near app root.
- **Error handling**: Use `try/catch` with `confirm()`; or `safeConfirm()` to avoid throwing.
- **Theming**: `variant="destructive"` changes icon and button styling accordingly.
