# ActionSheet

> iOS-style action sheet anchored to the bottom of the screen.

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

# ActionSheet

`ActionSheet` is the iOS-style action sheet: a rounded card anchored to the **bottom of the screen** with a list of option buttons and a separate **Cancel** button below it. When there are too many options to fit, they spread across multiple columns (up to `maxColumns`). Behind the sheet there is a gray "scrim" (`fullscreenColor = 0xD0DDDDDD`) that produces the modal effect.

> 🟢 · **Package:** `dev.crossfly.ui` · **Extends:** `Window` · **Style:** `ComponentStyle`/`WindowStyle`

## When to use
- Contextual action menu over an item (share, rename, delete…).
- When you want to visually highlight a destructive action (red), as in the iOS pattern.

## When NOT to use
- Simple yes/no choice or confirmation with a message → use [`Alert`](/docs/ui/widgets/alert).
- Passive/ephemeral feedback → use [`Hint`](/docs/ui/widgets/hint).

## Appearance
A bottom card about 92% of the screen width with the options stacked, separated by thin lines, and the fully rounded Cancel button right below it. The screen background is covered by a gray scrim.

## 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 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); });
         // Destructive action in red
         sheet.buttonStyle(2, ActionSheet.createDefaultButtonStyle().textColor(0xFFFF0000));
         sheet.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
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();
```

## Constructors
| Constructor | Description |
|---|---|
| `ActionSheet(String cancelText, String... buttonTexts)` | `cancelText` (default `"Cancel"`) and the option texts (empty/`null` → `{"OK"}`). |

## Properties and customization
| Property / method | Type | Default | What it does |
|---|---|---|---|
| `buttonStyle(ComponentStyle)` | fluent | skin | Default style for **all** options. |
| `buttonStyle(int index, ComponentStyle)` | fluent | — | Style override for a specific option. |
| `buttonStyle(int index)` | `ComponentStyle` | — | Resolved style of the option. |
| `cancelStyle(ComponentStyle)` | fluent | skin | Style of the Cancel button. |
| `containerStyle(ComponentStyle)` | fluent | skin | Style of the card (corner radius). |
| `maxColumns(int)` | fluent | `1` | Maximum columns on overflow (>=1). |
| `getButton(int)` / `getCancelButton()` | `Button` | — | Buttons after `show()`/`onAdd`. |
| `createDefaultButtonStyle()` / `createDefaultCancelStyle()` / `createDefaultContainerStyle()` | `ComponentStyle` (static) | — | Factories for the default styles. |

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

> Since `ActionSheet` extends `Window` (not `Picker`), **the response comes through these callbacks**, not through `show(onAnswer)`. There is no `getAnswer()`. The `Component.Action` lambda is `void run(Component origin)` — do not return a value.

## States
- Option **without** a callback → receives the default action `hide()` (closes the sheet).
- Option **with** a callback → runs the callback; if it does not call `hide()`, the sheet stays open.
- Tap on the scrim (outside the sheet) or back → closes when `canHide` is active (default).

### Highlight the destructive action and allow 2 columns
```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(); });

// Destructive option in red
sheet.buttonStyle(2, ActionSheet.createDefaultButtonStyle().textColor(0xFFFF0000));

// Allow up to 2 columns if there are many options
sheet.maxColumns(2);

sheet.show();
```

## Best practices
- Use it for a set of contextual actions; for a simple yes/no, prefer [`Alert`](/docs/ui/widgets/alert).
- Highlight destructive actions with `buttonStyle(index, ...)` in red.
- On long lists, set `maxColumns` so the sheet does not exceed the screen.

## Common mistakes
- **Callback without `hide()`** — the sheet stays open; the automatic `hide()` only happens when there is **no** registered callback.
- **Making the lambda return a value** — `Component.Action.run(...)` is `void`.
- **Accessing `getButton(i)` before `show()`** — the buttons are created in `onAdd`.

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