# ActionSheet

> Hoja de acciones estilo iOS anclada en la base de la pantalla.

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

# ActionSheet

`ActionSheet` es la hoja de acciones estilo iOS: una tarjeta redondeada anclada en la **base de la pantalla** con una lista de botones de opción y un botón **Cancelar** separado debajo. Cuando hay demasiadas opciones para caber, se distribuyen en múltiples columnas (hasta `maxColumns`). Detrás de la hoja hay un "scrim" gris (`fullscreenColor = 0xD0DDDDDD`) que da el efecto modal.

> 🟢 · **Paquete:** `dev.crossfly.ui` · **Extiende:** `Window` · **Estilo:** `ComponentStyle`/`WindowStyle`

## Cuándo usar
- Menú de acciones contextuales sobre un elemento (compartir, renombrar, eliminar…).
- Cuando quieras destacar visualmente una acción destructiva (rojo), como en el patrón iOS.

## Cuándo NO usar
- Elección sí/no simple o confirmación con mensaje → usa [`Alert`](/docs/ui/widgets/alert).
- Feedback pasivo/efímero → usa [`Hint`](/docs/ui/widgets/hint).

## Apariencia
Tarjeta inferior con un ancho de ~92% de la pantalla con las opciones apiladas, separadas por líneas finas, y el botón Cancelar totalmente redondeado justo debajo. El fondo de la pantalla queda cubierto por un scrim gris.

## 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 folha de ações");
      abrir.onAction(c ->
      {
         ActionSheet sheet = new ActionSheet("Cancelar", "Compartilhar", "Renomear", "Excluir");
         sheet.buttonAction(0, origin -> { sheet.hide(); Hint.show("Compartilhar", 2000); });
         sheet.buttonAction(1, origin -> { sheet.hide(); Hint.show("Renomear", 2000); });
         sheet.buttonAction(2, origin -> { sheet.hide(); Hint.show("Excluído", 2000); });
         // Acción destructiva en rojo
         sheet.buttonStyle(2, ActionSheet.createDefaultButtonStyle().textColor(0xFFFF0000));
         sheet.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
ActionSheet sheet = new ActionSheet("Cancelar", "Compartilhar", "Renomear", "Excluir");
sheet.buttonAction(0, origin -> { compartilhar(); sheet.hide(); });
sheet.buttonAction(1, origin -> { renomear();     sheet.hide(); });
sheet.buttonAction(2, origin -> { excluir();      sheet.hide(); });
sheet.show();
```

## Constructores
| Constructor | Descripción |
|---|---|
| `ActionSheet(String cancelText, String... buttonTexts)` | `cancelText` (por defecto `"Cancel"`) y los textos de las opciones (vacío/`null` → `{"OK"}`). |

## Propiedades y personalización
| Propiedad / método | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `buttonStyle(ComponentStyle)` | fluido | skin | Estilo por defecto de **todas** las opciones. |
| `buttonStyle(int index, ComponentStyle)` | fluido | — | Override de estilo de una opción específica. |
| `buttonStyle(int index)` | `ComponentStyle` | — | Estilo resuelto de la opción. |
| `cancelStyle(ComponentStyle)` | fluido | skin | Estilo del botón Cancelar. |
| `containerStyle(ComponentStyle)` | fluido | skin | Estilo de la tarjeta (radio de los bordes). |
| `maxColumns(int)` | fluido | `1` | Máximo de columnas en overflow (>=1). |
| `getButton(int)` / `getCancelButton()` | `Button` | — | Botones tras `show()`/`onAdd`. |
| `createDefaultButtonStyle()` / `createDefaultCancelStyle()` / `createDefaultContainerStyle()` | `ComponentStyle` (static) | — | Fábricas de los estilos por defecto. |

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

> Como `ActionSheet` extiende `Window` (no `Picker`), **la respuesta llega por esos callbacks**, no por `show(onAnswer)`. No hay `getAnswer()`. El lambda de `Component.Action` es `void run(Component origin)` — no devuelve valor.

## Estados
- Opción **sin** callback → recibe la acción por defecto `hide()` (cierra la hoja).
- Opción **con** callback → ejecuta el callback; si no llama a `hide()`, la hoja permanece abierta.
- Tap en el scrim (fuera de la hoja) o back → cierra cuando `canHide` está activo (por defecto).

### Destacar la acción destructiva y permitir 2 columnas
```java
ActionSheet sheet = new ActionSheet("Cancelar", "Compartilhar", "Renomear", "Excluir");

sheet.buttonAction(0, origin -> { compartilhar(); sheet.hide(); });
sheet.buttonAction(1, origin -> { renomear();     sheet.hide(); });
sheet.buttonAction(2, origin -> { excluir();      sheet.hide(); });

// Opción destructiva en rojo
sheet.buttonStyle(2, ActionSheet.createDefaultButtonStyle().textColor(0xFFFF0000));

// Permitir hasta 2 columnas si hay muchas opciones
sheet.maxColumns(2);

sheet.show();
```

## Buenas prácticas
- Usa para un conjunto de acciones contextuales; para sí/no simple, prefiere [`Alert`](/docs/ui/widgets/alert).
- Destaca acciones destructivas con `buttonStyle(index, ...)` en rojo.
- En listas largas, configura `maxColumns` para que la hoja no rebase la pantalla.

## Errores comunes
- **Callback sin `hide()`** — la hoja queda abierta; el `hide()` automático solo ocurre cuando **no** hay callback registrado.
- **Hacer que el lambda devuelva valor** — `Component.Action.run(...)` es `void`.
- **Acceder a `getButton(i)` antes de `show()`** — los botones se crean en `onAdd`.

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