---
title: "Notificaciones — Docs de zenit Zig UI"
description: "Usa el Notifier para notificaciones dentro de la ventana que nunca bloquean la tarea en curso — éxito, error, progreso, deshacer y mensajes —; el apilado, la…"
url: https://zenit.z.express/es/docs/advanced/notifications
language: es
alternate_en: https://zenit.z.express/docs/advanced/notifications.md
alternate_zh: https://zenit.z.express/zh/docs/advanced/notifications.md
alternate_ja: https://zenit.z.express/ja/docs/advanced/notifications.md
alternate_ko: https://zenit.z.express/ko/docs/advanced/notifications.md
alternate_fr: https://zenit.z.express/fr/docs/advanced/notifications.md
alternate_de: https://zenit.z.express/de/docs/advanced/notifications.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# Notificaciones

Usa el Notifier para notificaciones dentro de la ventana que nunca bloquean la tarea en curso — éxito, error, progreso, deshacer y mensajes —; el apilado, la expansión al pasar el cursor y las ocho posiciones de anclaje ya vienen resueltos.

## Qué es el Notifier

`ui.widgets.Notifier` es un servicio de nivel de ventana: inicialízalo una vez y luego llama a `show` desde cualquier sitio. Las tarjetas viven en la capa toast del portal de superposición de la ventana (z 2000: por encima de los diálogos, por debajo de los tooltips) y nunca participan en el layout de la página. Cada tarjeta tiene un nodo fijo, así que quitar una nunca reconstruye las demás ni repite su entrada. Sustituye al antiguo ToastManager.

[Video](https://zenit.z.express/media/stories/notification.mp4?v=5f8cadb85b)

El Storybook real: éxito, error, advertencia, progreso, acción, persona, deshacer, silencioso y resumen uno tras otro; luego una ráfaga de cuatro que forma una pila, expandida al pasar el cursor, y se cierra la tarjeta del medio.

La API campo por campo (`Notification`, `NotifierOptions` y la firma de cada método) está en la [página de Notification](https://zenit.z.express/es/components/notification) del sitio de componentes.

## Crear un Notifier

Créalo una vez en tu función de montaje raíz y pasa el puntero a lo que necesite notificar (por ejemplo, el estado de la app guardado con `cx.bindState`). El Notifier pertenece al Scope que le pasas y desaparece con él.

`app.zig`

```zig
const notifier = try ui.widgets.Notifier.init(scope, cx, .{
    .position = .bottom_center,
    // Keep the stack clear of a 56px toolbar.
    .content_insets = .{ .top = 56 },
    .max_visible = 4,
});
```

| Campo de NotifierOptions | Función |
| --- | --- |
| `position` | Una de ocho posiciones, por defecto .bottom\_center; cámbiala en tiempo de ejecución con setPosition |
| `max_visible` | Cuántas tarjetas se muestran al expandir (2–6, por defecto 4) |
| `expand_on_hover` | Si es false, el hover solo pausa los temporizadores y no expande |
| `content_insets` | Márgenes interiores desde los bordes de la ventana (barra de título, barra de herramientas, barra de estado); el margen de anclaje de 22px empieza aquí |
| `width` | Ancho de la tarjeta, por defecto 392 |
| `strings` | Textos de la UI ("now", "Undo", "Reply…", la insignia plegada…) para localizar |
| `listener` | Callback para acciones del usuario y expiración; también se puede fijar con setListener |

## Mostrar una notificación

`show` recibe un valor `ui.widgets.Notification` y devuelve su id. El Notifier copia cada cadena, así que puedes reutilizar tus búferes de inmediato. Con más de seis tarjetas en pantalla, la más antigua se va con su animación de salida normal.

`notify.zig`

```zig
// Success: auto-dismisses after 3.6 s.
_ = try notifier.show(.{
    .tone = .success,
    .title = "Saved to iCloud",
    .body = "3 files synced · 2.1 MB",
});

// Error with two actions: errors stay until the user acts.
const failed = try notifier.show(.{
    .tone = .@"error",
    .title = "Upload failed",
    .body = "network timeout · dist/app.zip",
    .actions = &.{
        .{ .label = "Retry", .primary = true, .tag = "retry" },
        .{ .label = "View log", .tag = "log" },
    },
});

// Undo: a 7 s countdown ring and a default "Undo" button.
_ = try notifier.show(.{
    .kind = .undo,
    .title = "Moved 4 items to the Trash",
    .body = "You can undo this for 7 seconds.",
});

// A person's message with an inline reply box.
_ = try notifier.show(.{
    .tone = .violet,
    .avatar = "L",
    .title = "Lin",
    .body = "I finished the table widths in section three.",
    .reply = true,
});
```

> NOTE
> 
> **Como máximo dos botones.** Los botones se colocan bajo un separador, con el mismo ancho y un relleno neutro; primary solo implica un relleno y un peso más marcados: nunca toma el color del tono.

## Tipos, tonos y duración

El aspecto de una tarjeta depende de dos ejes: `kind` (layout) y `tone` (color semántico). El icono inicial se deriva de ambos o se fija explícitamente con `lead` / `glyph`.

| kind | Layout |
| --- | --- |
| `.default` | Icono, título y cuerpo, con botones, cuadro de respuesta o avatar opcionales |
| `.progress` | Spinner, barra determinada y un contador n / N; sin barra de vida |
| `.undo` | Anillo de cuenta atrás con los segundos restantes, más un botón "Undo" por defecto |

| tone | Uso | Duración por defecto |
| --- | --- | --- |
| `.success` | Algo terminó | 3.6 s |
| `.@"error"` | Un fallo que requiere atención | fija |
| `.warning` | Conviene verlo, no bloquea | 5.6 s |
| `.info` | Información general (por defecto) | 4.2 s |
| `.violet` | Personas, invitaciones y otros mensajes sociales | 4.2 s; fija con botones |
| `.quiet` | Estado discreto (un punto pequeño en lugar de un icono) | 2.8 s |

-   **Fijas por defecto:** las tarjetas progress, las que tienen cuadro de respuesta, el tono error y las tarjetas violet con botones nunca se cierran solas.
    
-   **Ajustes explícitos:** `sticky = true` la fija; `duration_ms` sustituye la duración por defecto; `life_bar` activa o desactiva la barra de vida.
    
-   **Undo** dura 7 segundos por defecto, con el anillo siguiendo el temporizador.
    

## Actualizaciones en el sitio y progreso

`update(id, …)` reescribe el tipo, el tono, el título y el cuerpo de la misma tarjeta y reinicia su duración: sin destruir, sin reconstruir, sin repetir la entrada. Haz avanzar una tarjeta de progreso con `setProgress`, que solo toca la capa de progreso. Llamar a `show` con un `id` existente también la transforma en el sitio.

`upload.zig`

```zig
const id = try notifier.show(.{
    .kind = .progress,
    .title = "Uploading attachment",
    .body = "assets/hero-shot.png",
    .progress = .{ .value = 0, .label = "Uploading · about 5 s", .count = "0 / 5" },
});

// Each tick: only the progress layer is touched, the card isn't rebuilt.
notifier.setProgress(id, 0.6, "Uploading · about 2 s", "3 / 5");

// Done: the same card turns into a success card in place —
// no new entrance, and it now dismisses itself after 3.4 s.
try notifier.update(id, .{
    .tone = .success,
    .title = "Upload complete",
    .body = "assets/hero-shot.png",
    .duration_ms = 3400,
});
```

## Gestionar las acciones del usuario

El Notifier informa a través de un único `ui.widgets.NotificationListener`. Un `NotificationEvent` lleva el `id` de la tarjeta, el `kind` del evento y el `tag` / `index` del botón o el `text` de la respuesta.

| EventKind | Cuándo |
| --- | --- |
| `.action` | Se pulsó un botón (distínguelos por tag) |
| `.undo` | Se pulsó Undo; el anillo ya se ha convertido en un ✓ |
| `.reply` | Se envió el cuadro de respuesta (Enter o Send); text lo contiene |
| `.dismissed` | El usuario la cerró (✕ o arrastrándola fuera) |
| `.expired` | Expiró |

`uploads.zig`

```zig
const Uploads = struct {
    fn onEvent(ctx: ?*anyopaque, n: *ui.widgets.Notifier, e: ui.widgets.NotificationEvent) void {
        const self: *Uploads = @ptrCast(@alignCast(ctx orelse return));
        switch (e.kind) {
            .action => if (std.mem.eql(u8, e.tag, "retry")) {
                // Turn the sticky error card into a progress card in place.
                n.update(e.id, .{
                    .kind = .progress,
                    .title = "Retrying upload",
                    .progress = .{ .value = 0, .label = "Uploading", .count = "0 / 5" },
                }) catch return;
                self.restart(e.id);
            } else n.dismiss(e.id),
            .reply => self.send(e.text),
            .undo => self.restoreTrash(),
            .dismissed, .expired => {},
        }
    }
    // …restart / send / restoreTrash
};

const uploads = try cx.bindState(Uploads, .{});
notifier.setListener(.{ .context = @ptrCast(uploads), .callback = Uploads.onEvent });
```

> TIP
> 
> **¿Falló el envío de la respuesta?** Llama a `notifier.replyFailed(id, title, body)` para convertir la misma tarjeta en un estado de fallo en el sitio sin perder lo que escribió el usuario.

## Apilado y hover

Varias notificaciones se pliegan en una pila: la más reciente queda más cerca del ancla con la z más alta; cada capa de detrás asoma 9px y se reduce un 3.8%, hasta tres capas, con una insignia "N más · pasa el cursor para expandir". Cuando el puntero entra en los límites de la pila (ampliados 18px), se expande con separaciones de 9px y todos los temporizadores se pausan; al salir se pliega y se reanudan.

STACK

Los valores provienen de Spec en notification/model.zig: borde visible de 9px, escala del 3.8% por capa, separación de 9px al expandir.

**Borrar todo**

Junto a la insignia hay un botón para borrar todo: el primer clic muestra su texto, el segundo borra de verdad y, al apartar el cursor, se vuelve a plegar. En código, llama a dismissAll().

**Deslizar para cerrar**

Una tarjeta suelta se puede lanzar fuera, lo que emite dismissed.

**Redimensionar la ventana**

Al redimensionar la ventana, la pila sigue a su ancla de forma rígida, sin interpolación que se quede atrás.

## Posiciones

`setPosition` solo cambia el ancla, la dirección de crecimiento y el desplazamiento de entrada: las tarjetas no se reconstruyen, y cualquier tarjeta que esté saliendo termina su salida en la nueva dirección.

POSITIONS

[Video](https://zenit.z.express/media/stories/notification-positions.mp4?v=2df7ff87b6)

Las mismas cuatro notificaciones ancladas en cada una de las ocho posiciones; encuadre de ventana completa, porque las posiciones de la izquierda van pegadas al borde de la ventana.

## El centro de notificaciones es tuyo

El historial, el modo no molestar y un punto de entrada con campana — las funciones de un centro de notificaciones — son lógica de la app y quedan fuera de zenit: registra el historial donde llamas a show, decide si mostrar una tarjeta o no y entérate de cierres, expiraciones y acciones de botones a través del Listener. La tarjeta de resumen del Storybook muestra el patrón: al terminar el modo no molestar, una tarjeta quiet resume lo que llegó.

> WARNING
> 
> **La accesibilidad aún no está validada.** Como en el resto de zenit, la validación con VoiceOver de las tarjetas de notificación aún no está hecha; no las conviertas en el único canal para información crítica.
