# Alert

> Cuadro de diálogo modal con título, mensaje y botones de acción.

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

# Alert

`Alert` es el cuadro de diálogo modal de CrossFly — el equivalente a un `MessageBox`/`AlertDialog`. Muestra un **título**, un **mensaje** (con ajuste de línea automático) y uno o más **botones de acción** dispuestos en filas. Cada botón puede tener su propio callback; sin callback, el botón solo cierra el diálogo. La apariencia (colores, fuentes, disposición de los botones) proviene del `Skin` activo.

> 🟢 · **Paquete:** `dev.crossfly.ui` · **Extiende:** `Window` · **Estilo:** `AlertStyle` + `WindowStyle`

## Cuándo usar
- Confirmaciones que exigen reconocimiento del usuario (¿eliminar? ¿guardar? ¿descartar?).
- Elecciones simples sí/no o un mensaje que necesita un "OK".

## Cuándo NO usar
- Feedback pasivo y efímero (éxito/error/estado) → usa [`Hint`](/docs/ui/widgets/hint).
- Lista de acciones contextuales sobre un elemento (compartir/editar/eliminar) → usa [`ActionSheet`](/docs/ui/widgets/actionsheet).

## Apariencia
Tarjeta centrada con el título arriba, el mensaje en el medio y una fila de botones en la base. Por defecto el fondo **no** se oscurece — ajusta `WindowStyle.fadeBackground` para el efecto modal clásico.

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: 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");
         // Fondo oscurecido para reforzar la modalidad (alpha 0..255)
         WindowStyle ws = a.getStyle();
         ws.fadeBackground(150);
         // Botón 0 = Excluir -> ejecuta, cierra y da feedback
         a.buttonAction(0, origin ->
         {
            a.hide();
            Hint.show("Item excluído", 2000);
         });
         // Botón 1 = Cancelar: sin callback -> el default ya llama a hide()
         a.show();
      });
      add(LAY_AUTO, abrir);
   }
}
```

> Los fragmentos siguientes muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutarlos, colócalos en el esqueleto `MainWindow` de arriba.

## Uso básico
```java
// buttonTexts es varargs opcional — si está vacío/null, se vuelve {"OK"}
Alert a = new Alert("Aviso", "Operação concluída com sucesso.", "OK");
a.show();
```

## Constructores
| Constructor | Descripción |
|---|---|
| `Alert(String title, String message, String... buttonTexts)` | `title` puede ser `""` (oculta visualmente el título). `buttonTexts` opcional; vacío/`null` → `{"OK"}`. |

> ⚠️ **No existe `Alert.show(...)` estático ni constructor que dispare callback.** Instancia siempre con `new Alert(...)`, registra los callbacks por botón y llama a `show()`.

## Propiedades y personalización
| Propiedad / método | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `style()` | `AlertStyle` | skin | Devuelve el `AlertStyle` actual. |
| `style(AlertStyle)` | fluido | — | Define un `AlertStyle` personalizado. |
| `style().buttonLayout(...)` | `IOS`/`FLUTTER`/`MATERIAL` | `MATERIAL` | Estilo de disposición de los botones. |
| `style().maxButtonsPerRow(int)` | `int` | skin | Botones por fila; los excedentes saltan a nuevas filas. |
| `skin(Skin)` | fluido | — | Cambia el skin y reactualiza el `AlertStyle`. |
| `getButton(int index)` | `Button` | — | Botón tras `show()` (antes de eso, `null`). |
| `getAutoWidth()` / `getAutoHeight()` | `int` | — | Dimensiones calculadas. |

## Callbacks y eventos
| Callback | Cuándo se dispara |
|---|---|
| `buttonAction(int index, Component.Action action)` | al tocar el botón de índice `index` (0-based). |

> ⚠️ **La respuesta NO llega por `show(onAnswer)`.** `Alert` extiende `Window`, no `Picker` — y `Window.hide()` solo entrega `onAnswer` cuando `this instanceof Picker`. Por tanto, para reaccionar a cada botón usa `buttonAction(index, action)`. No hay `getAnswer()` en el `Alert`.

El tipo del callback es `Component.Action`, cuyo método es `void run(Component origin)` — el cuerpo del lambda **no devuelve valor** (nada de `return null;`).

## Estados
- Botón sin callback registrado → recibe la acción por defecto `hide()` (cierra el diálogo).
- Botón con callback → ejecuta el callback; si el callback no cierra, el diálogo sigue abierto (llama tú mismo a `a.hide()`).
- Gesto "atrás"/back → respetado si `WindowStyle.canHide` (por defecto `true`).

### Confirmación con fondo oscurecido
```java
Alert confirm = new Alert("Excluir item",
   "Tem certeza que deseja excluir este item? Esta ação não pode ser desfeita.",
   "Excluir", "Cancelar");

// Refuerza la modalidad oscureciendo el fondo (alpha 0..255)
WindowStyle ws = confirm.getStyle();
ws.fadeBackground(150);

// Botón 0 = Excluir -> ejecuta, cierra y da feedback
confirm.buttonAction(0, origin ->
{
   excluirItem();
   confirm.hide();
   Hint.show("Item excluído", 2000);
});
// Botón 1 = Cancelar: sin callback -> el default ya llama a hide()

confirm.show();
```

### Elegir la disposición de los botones
```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();
```

## Buenas prácticas
- Usa para decisiones que exigen reconocimiento. Para feedback pasivo, prefiere [`Hint`](/docs/ui/widgets/hint).
- Mantén pocos botones — muchos saltan a filas y hacen el diálogo alto.
- Combina con `fadeBackground` siempre que quieras el efecto modal clásico.

## Errores comunes
- **Esperar respuesta vía `show(onAnswer)`** — eso es exclusivo de `Picker`. Registra `buttonAction(...)`.
- **Acceder a `getButton(i)` antes de `show()`** — los botones se crean en `onAdd` y devuelven `null` antes de eso.
- **Hacer que el lambda de `buttonAction` devuelva valor** — `Action.run(...)` es `void`.

## Ver también
- Guía del área: [`ui/`](/docs/ui) · Recetas: [`cookbook/`](/docs/cookbook)
- Componentes relacionados: [`ActionSheet`](/docs/ui/widgets/actionsheet) · [`Hint`](/docs/ui/widgets/hint)
