Superpuestos@unozero-ai/ui

Modal

Diálogo con foco protegido para una tarea que no puede esperar ni perderse.

Usar

import { Modal } from "@unozero-ai/ui/react";

<Modal></Modal>

Composición

heading y description pintan la cabecera con la ✕; los hijos son el cuerpo, y las acciones van al slot footer. Ya no hay ModalHeader, ModalBody ni ModalFooter. En el pie, una sola acción rellena y la otra en ghost (la Regla de una Sola Decisión). Sin heading no hay cabecera ni ✕: entonces el cierre lo pones tú.

Va sobre el <dialog> nativo, en la top layer: el foco entra al abrir, queda atrapado, vuelve al botón que lo abrió al cerrar, y el resto de la página queda inerte. Esc, el clic fuera y la ✕ lo cierran solos y emiten close (onClose). Tú controlas open: ciérralo también en tu estado dentro de onClose, o el siguiente render lo vuelve a abrir.

Cambiar de habitaciónCancelarMover reserva

Con formulario

El caso para el que existe: una tarea corta que no puede perderse a medias. Con dismissible={false} ni Esc ni un clic fuera lo cierran; solo la ✕ y tus botones. En el kit React, closeOnBackdrop={false} solo apagaba el clic fuera.

Los campos del kit entran en el FormData del <form>. El pie vive fuera del formulario, así que su botón lo envía con requestSubmit(), que valida los campos antes. Si necesitas decidir en el momento si se puede cerrar (hay cambios sin guardar), escucha onRequestClose: es cancelable. El ejemplo está en Sheet.

Registrar pago
CancelarRegistrar pago

Tamaños

El ancho máximo va de sm (384 px) a 2xl (1024 px); por debajo de ese ancho el modal ocupa la pantalla menos un margen de 16 px. Elige el más estrecho en el que quepa el contenido sin partirlo: cada botón dice para qué sirve el suyo.

smmdlgxl2xlEl tamaño por defecto. Un formulario de una columna, como registrar un pago.Entendido

Alturas

auto se ajusta al contenido y el cuerpo hace scroll a partir del 70 % de la pantalla. tall (85 %) y full (92 %) fijan el alto: la cabecera y el pie se quedan quietos y solo se desplaza el cuerpo. Úsalos para listas largas y editores con pestañas, donde un alto que cambia haría saltar los botones. El cambio de alto ya no se anima: entra y sale con opacidad y escala, 250 ms.

autotallfull
  • 10:53 · Tarifa Doble Estándar · 3 noches actualizadasOK
  • 10:46 · Tarifa Doble Superior · 4 noches actualizadasOK
  • 10:39 · Tarifa Suite Junior · 5 noches actualizadasOK
  • 10:32 · Tarifa Familiar · 6 noches actualizadasOK
  • 10:25 · Tarifa Doble Estándar · 7 noches actualizadasOK
  • 10:18 · Tarifa Doble Superior · 3 noches actualizadasError
  • 10:11 · Tarifa Suite Junior · 4 noches actualizadasOK
  • 10:04 · Tarifa Familiar · 5 noches actualizadasOK
  • 09:57 · Tarifa Doble Estándar · 6 noches actualizadasOK
  • 09:50 · Tarifa Doble Superior · 7 noches actualizadasOK
  • 09:43 · Tarifa Suite Junior · 3 noches actualizadasOK
  • 09:36 · Tarifa Familiar · 4 noches actualizadasOK
  • 09:29 · Tarifa Doble Estándar · 5 noches actualizadasOK
  • 09:22 · Tarifa Doble Superior · 6 noches actualizadasOK
  • 09:15 · Tarifa Suite Junior · 7 noches actualizadasOK
  • 09:08 · Tarifa Familiar · 3 noches actualizadasOK
  • 09:01 · Tarifa Doble Estándar · 4 noches actualizadasOK
  • 08:54 · Tarifa Doble Superior · 5 noches actualizadasOK
  • 08:47 · Tarifa Suite Junior · 6 noches actualizadasError
  • 08:40 · Tarifa Familiar · 7 noches actualizadasOK
  • 08:33 · Tarifa Doble Estándar · 3 noches actualizadasOK
  • 08:26 · Tarifa Doble Superior · 4 noches actualizadasOK
  • 08:19 · Tarifa Suite Junior · 5 noches actualizadasOK
  • 08:12 · Tarifa Familiar · 6 noches actualizadasOK
  • 08:05 · Tarifa Doble Estándar · 7 noches actualizadasOK
  • 07:58 · Tarifa Doble Superior · 3 noches actualizadasOK
  • 07:51 · Tarifa Suite Junior · 4 noches actualizadasOK
  • 07:44 · Tarifa Familiar · 5 noches actualizadasOK
  • 07:37 · Tarifa Doble Estándar · 6 noches actualizadasOK
  • 07:30 · Tarifa Doble Superior · 7 noches actualizadasOK
  • 07:23 · Tarifa Suite Junior · 3 noches actualizadasOK
  • 07:16 · Tarifa Familiar · 4 noches actualizadasError
  • 07:09 · Tarifa Doble Estándar · 5 noches actualizadasOK
  • 07:02 · Tarifa Doble Superior · 6 noches actualizadasOK
  • 06:55 · Tarifa Suite Junior · 7 noches actualizadasOK
  • 06:48 · Tarifa Familiar · 3 noches actualizadasOK
  • 06:41 · Tarifa Doble Estándar · 4 noches actualizadasOK
  • 06:34 · Tarifa Doble Superior · 5 noches actualizadasOK
  • 06:27 · Tarifa Suite Junior · 6 noches actualizadasOK
  • 06:20 · Tarifa Familiar · 7 noches actualizadasOK
CerrarReintentar fallidos

Cuándo no usar un modal

Un modal se lleva toda la pantalla y obliga a terminar o cancelar antes de seguir. Ese precio solo se paga cuando la tarea no puede esperar ni perderse. Si no es el caso, hay algo mejor:

  • Confirmar una acción: ConfirmDialog o confirm(), que ya traen el tono del riesgo y el botón en sólido.
  • Avisar de que algo salió bien: un toast. Un modal que solo dice «Guardado» es una interrupción sin tarea.
  • Consultar un detalle mientras se trabaja en la lista (la ficha de una reserva, el historial de un huésped): un Sheet o una página propia, que no tapan lo que se estaba mirando.
  • Editar un solo campo (renombrar una tarifa, cambiar una nota): edición en línea o un Popover.
  • Un flujo de varios pasos (dar de alta un hotel, conectar el PMS): una página con Stepper, que se puede dejar y retomar.

Nunca abras un modal desde otro modal.

API

Generada del custom-elements.json que publica @unozero-ai/ui. Las partes se estilan desde tu CSS con el nombre del elemento: uz-button::part(base).

Modal · <uz-modal>

PropTipoDefectoDescripción
openbooleanfalseAbierto o cerrado; se refleja como atributo.
headingstring""Título de la cabecera. Sin él no hay cabecera ni ✕.
descriptionstring""Línea bajo el título que da el contexto.
size"sm" | "md" | "lg" | "xl" | "2xl""md"Ancho máximo, de sm (384 px) a 2xl (1024 px).
height"auto" | "tall" | "full""auto"auto se ajusta al contenido; tall (85 %) y full (92 %) fijan el alto.
dismissiblebooleantruefalse: ni Escape ni el clic fuera lo cierran (formularios a medio llenar).
EventoDescripción
onRequestClose—
onClose—
SlotDescripción
(por defecto)El cuerpo.
footerLas acciones.
Parte CSSDescripción
uz-modal::part(panel)El <dialog>.
uz-modal::part(body)El cuerpo con scroll.
MétodoDescripción
requestClose()Cierre pedido por el usuario: se puede cancelar desde fuera.