# Modal

> Una superficie de diálogo con título, contenido y botones al pie. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/modal/

:::tip[En pocas palabras]
Una ventana dentro de la ventana que pide tu atención antes de seguir.
:::

Una superficie de diálogo con título, botón de cerrar, tu contenido y un pie de botones. Úsala como capa de `ui.layer` o `ui.dialog_layer`. Los [diálogos](https://albakore.github.io/pyzed/es/library/confirm/) listos para usar están hechos con ella.

`ui.modal` · Categoría: [Capas flotantes](https://albakore.github.io/pyzed/es/library/#capas-flotantes) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#modal)

**Código:**

```python
ui.modal(
    ui.muted("notes.py has unsaved changes. Save them before closing?"),
    title="Save changes?",
    on_close=on_close,
    footer=[ui.button("Don't save", on_discard, variant="ghost"), ui.button("Cancel", on_close),
            ui.button("Save", on_save, variant="solid")],
    width=440,
)
```

## Cuándo usarlo

- Para diálogos con tu propio contenido: un formulario, ajustes, una caja Acerca de.

## Uso

```python
from pyzed import ui

ui.modal(
    ui.muted("notes.py has unsaved changes. Save them before closing?"),
    title="Save changes?",
    on_close=on_close,
    footer=[ui.button("Don't save", on_discard, variant="ghost"), ui.button("Cancel", on_close),
            ui.button("Save", on_save, variant="solid")],
    width=440,
)
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Contenido

```python
ui.modal(ui.muted("Your trial ends in 3 days."), width=320)
```

```python
ui.modal(ui.muted("Your trial ends in 3 days."), title="Trial", on_close=on_close, width=320)
```

```python
ui.modal(ui.muted("Discard the draft?"), title="Draft", on_close=on_close, width=320,
         footer=[ui.button("Cancel", on_close), ui.button("Discard", on_discard, variant="error")])
```

### Estados y eventos

`max_height=` desplaza el contenido largo, y Escape envía `on_close` mientras el diálogo tiene el foco.

```python
ui.modal(ui.input("notes.md", on_input), title="Rename", description="Choose a new name",
         icon="pencil", on_close=on_close, width="sm", footer=[ui.button("Rename", on_press, variant="solid")])
```

## Ejemplos

### Encima de la app

Envuelve la vista con `ui.dialog_layer` para centrarlo sobre un fondo oscurecido.

**Código:**

```python
ui.dialog_layer(main_view(), ui.modal(
    pz.column([ui.input("", on_input, placeholder="Project name"),
               ui.checkbox(True, on_toggle, label="Create a git repository")], spacing=10),
    title="New project", on_close=on_close,
    footer=[ui.button("Cancel", on_close), ui.button("Create", on_create, variant="solid")],
    width=380,
), on_dismiss=on_close)
```

## Eventos

Modal tiene **1 evento propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | El handler recibe | Cuándo |
| --- | --- | --- |
| `on_close` | `()` | El botón de cerrar; también lo envía Escape mientras el diálogo tiene el foco. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Notes(pz.App):
    def __init__(self):
        self.asking = True

    def save(self):
        self.asking = False

    def view(self):
        dialog = ui.modal(ui.muted("Save your changes before closing?"), title="Save changes?",
                          on_close=lambda: setattr(self, "asking", False),   # ✕ and Escape
                          footer=[ui.button("Save", self.save, variant="solid")], width=420)
        return ui.dialog_layer(main_view(), dialog if self.asking else None)
```

**Declarativo:**

```python
class Notes(pz.App):
    asking = True

    def update(self, message):
        if message in ("save", "close"):
            self.asking = False

    def view(self):
        dialog = ui.modal(ui.muted("Save your changes?"), title="Save changes?", on_close="close",
                          footer=[ui.button("Save", "save", variant="solid")])
        return ui.dialog_layer(main_view(), dialog if self.asking else None)
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    asking: bool = True

def view(state, set_state):
    close = lambda: set_state(asking=False)
    dialog = ui.modal(ui.muted("Save your changes?"), title="Save changes?", on_close=close,
                      footer=[ui.button("Save", close, variant="solid")])
    return ui.dialog_layer(main_view(), dialog if state.asking else None)
```

## Propiedades y API

### `ui.modal`

```python
modal(
    content,
    *,
    title=None,
    on_close=None,
    width=480,
    footer=(),
    description=None,
    icon=None,
    max_height=None,
    theme=None,
)
```

Un diálogo. Úsalo como `overlay` de `ui.layer`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `content` | *obligatorio* | Contenido: un `Widget`, un texto o un número (se convierte en texto). |
| `title` | `None` | Título. |
| `width` | `480` | Píxeles o `"sm"` (360), `"md"` (480), `"lg"` (640) o `"xl"` (820). |
| `footer` | `()` | Botones del pie, alineados a la derecha. |
| `description` | `None` | Línea atenuada bajo el título. |
| `icon` | `None` | Icono antes del título. |
| `max_height` | `None` | Desplaza el contenido más alto que esto, sin ocultar la cabecera ni el pie. |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

Eventos: `on_close` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#modal)

## Relacionados

- [Capa de diálogo](https://albakore.github.io/pyzed/es/library/dialog-layer/): Centra un diálogo encima de tu vista con el fondo oscurecido.
- [Capa](https://albakore.github.io/pyzed/es/library/layer/): Dibuja una capa encima de tu vista; al pulsar fuera se cierra.
- [Confirmación](https://albakore.github.io/pyzed/es/library/confirm/): Una pregunta de sí o no, en rojo para acciones destructivas.
