# Alert

> Modal dialog box with title, message and action buttons.

Source: https://crossfly.dev/docs/ui/widgets/alert — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Alert

`Alert` is CrossFly's modal dialog box — the equivalent of a `MessageBox`/`AlertDialog`. It shows a **title**, a **message** (with automatic word-wrap) and one or more **action buttons** laid out in rows. Each button can have its own callback; without a callback, the button just closes the dialog. The visuals (colors, fonts, button layout) come from the active `Skin`.

> 🟢 · **Package:** `dev.crossfly.ui` · **Extends:** `Window` · **Style:** `AlertStyle` + `WindowStyle`

## When to use
- Confirmations that require user acknowledgment (delete? save? discard?).
- Simple yes/no choices or a message that needs an "OK".

## When NOT to use
- Passive and ephemeral feedback (success/error/status) → use [`Hint`](/docs/ui/widgets/hint).
- Contextual action list over an item (share/edit/delete) → use [`ActionSheet`](/docs/ui/widgets/actionsheet).

## Appearance
A centered card with the title at the top, the message in the middle and a row of buttons at the bottom. By default the background is **not** dimmed — adjust `WindowStyle.fadeBackground` for the classic modal effect.

## Complete example (copy, paste and run)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Button abrir = new Button("Abrir alerta");
      abrir.onAction(c ->
      {
         Alert a = new Alert("Excluir item",
            "Tem certeza que deseja excluir este item? Esta ação não pode ser desfeita.",
            "Excluir", "Cancelar");
         // Darkened background to reinforce the modality (alpha 0..255)
         WindowStyle ws = a.getStyle();
         ws.fadeBackground(150);
         // Button 0 = Delete -> executes, closes and gives feedback
         a.buttonAction(0, origin ->
         {
            a.hide();
            Hint.show("Item excluído", 2000);
         });
         // Button 1 = Cancel: no callback -> default already calls hide()
         a.show();
      });
      add(LAY_AUTO, abrir);
   }
}
```

> The snippets below show **only the core** (what goes inside `onShow()`). To run them, place them in the `MainWindow` skeleton above.

## Basic usage
```java
// buttonTexts is optional varargs — if empty/null, becomes {"OK"}
Alert a = new Alert("Aviso", "Operação concluída com sucesso.", "OK");
a.show();
```

## Constructors
| Constructor | Description |
|---|---|
| `Alert(String title, String message, String... buttonTexts)` | `title` can be `""` (visually hides the title). `buttonTexts` optional; empty/`null` → `{"OK"}`. |

> ⚠️ **There is no static `Alert.show(...)` nor a constructor that fires a callback.** Always instantiate with `new Alert(...)`, register the per-button callbacks and call `show()`.

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `style()` | `AlertStyle` | skin | Returns the current `AlertStyle`. |
| `style(AlertStyle)` | fluent | — | Sets a custom `AlertStyle`. |
| `style().buttonLayout(...)` | `IOS`/`FLUTTER`/`MATERIAL` | `MATERIAL` | Button layout style. |
| `style().maxButtonsPerRow(int)` | `int` | skin | Buttons per row; extras wrap to new rows. |
| `skin(Skin)` | fluent | — | Swaps the skin and refreshes the `AlertStyle`. |
| `getButton(int index)` | `Button` | — | Button after `show()` (before that, `null`). |
| `getAutoWidth()` / `getAutoHeight()` | `int` | — | Computed dimensions. |

## Callbacks and events
| Callback | When it fires |
|---|---|
| `buttonAction(int index, Component.Action action)` | on tapping the button at index `index` (0-based). |

> ⚠️ **The response does NOT come through `show(onAnswer)`.** `Alert` extends `Window`, not `Picker` — and `Window.hide()` only delivers `onAnswer` when `this instanceof Picker`. So, to react to each button, use `buttonAction(index, action)`. There is no `getAnswer()` on `Alert`.

The callback type is `Component.Action`, whose method is `void run(Component origin)` — the lambda body **does not return a value** (no `return null;`).

## States
- Button without a registered callback → receives the default action `hide()` (closes the dialog).
- Button with a callback → runs the callback; if the callback does not close it, the dialog stays open (call `a.hide()` yourself).
- "Back" gesture → honored if `WindowStyle.canHide` (default `true`).

### Confirmation with dimmed background
```java
Alert confirm = new Alert("Excluir item",
   "Tem certeza que deseja excluir este item? Esta ação não pode ser desfeita.",
   "Excluir", "Cancelar");

// Reinforces the modality by darkening the background (alpha 0..255)
WindowStyle ws = confirm.getStyle();
ws.fadeBackground(150);

// Button 0 = Delete -> executes, closes and gives feedback
confirm.buttonAction(0, origin ->
{
   excluirItem();
   confirm.hide();
   Hint.show("Item excluído", 2000);
});
// Button 1 = Cancel: no callback -> default already calls hide()

confirm.show();
```

### Choose the button layout
```java
Alert a = new Alert("Salvar", "Deseja salvar as alterações?", "Salvar", "Descartar");
a.style().buttonLayout(AlertStyle.ButtonLayout.IOS)  // IOS / FLUTTER / MATERIAL
         .maxButtonsPerRow(2);
a.show();
```

## Best practices
- Use it for decisions that require acknowledgment. For passive feedback, prefer [`Hint`](/docs/ui/widgets/hint).
- Keep few buttons — too many wrap into rows and make the dialog tall.
- Combine with `fadeBackground` whenever you want the classic modal effect.

## Common mistakes
- **Expecting a response via `show(onAnswer)`** — that is exclusive to `Picker`. Register `buttonAction(...)`.
- **Accessing `getButton(i)` before `show()`** — the buttons are created in `onAdd` and return `null` before that.
- **Making the `buttonAction` lambda return a value** — `Action.run(...)` is `void`.

## See also
- Area guide: [`ui/`](/docs/ui) · Recipes: [`cookbook/`](/docs/cookbook)
- Related components: [`ActionSheet`](/docs/ui/widgets/actionsheet) · [`Hint`](/docs/ui/widgets/hint)
