DataTable
La tabla densa del panel: columnas tipadas, orden, selección y estados vacío y cargando.
Usar
import { DataTable } from "@unozero-ai/ui/react";
<DataTable></DataTable>Columnas tipadas
Cada columna es un DataTableColumn<T>: una key, una cabecera (header) y, cuando la celda no es row[key] tal cual, una función cell que recibe la fila ya tipada. rowKey devuelve el identificador estable de cada fila (sin él, usa row.id o la posición) y label da el nombre accesible de la tabla. En móvil la tabla se desplaza en horizontal dentro de su borde, sin empujar la página.
Los importes llevan numeric: van a la derecha, en mono y con tabular-nums, porque son cifras que se comparan con la fila de abajo (la Regla de los Tres Papeles). Los números de factura y las fechas llevan mono, que pone la letra sin mover la alineación. Ninguna celda se parte en dos líneas: si no cabe, la tabla se desplaza. En el kit React esto se hacía con align="right" y clases en lo que devolvía cell; ahora la celda se pinta dentro del shadow DOM de la tabla, donde las clases de tu página no llegan. Para una cabecera fija, da un alto máximo a su parte: uz-data-table::part(scroller) { max-height: 24rem }.
Con estados
El estado de cada fila va en un Badge, no en texto coloreado. Mapea cada estado del dominio a su palabra y su variante en un solo objeto, así la tabla, los filtros y el detalle dicen lo mismo. La palabra carga el significado y el color lo confirma (la Regla del Tenant): «No show» y «Cancelada» se distinguen sin mirar el tono.
cell devuelve texto, un nodo del DOM o una plantilla de Lit, nunca JSX: React no pinta dentro del shadow DOM de la tabla. Aquí la celda crea un <uz-badge> con document.createElement. Si tu proyecto tiene lit entre sus dependencias, html`<uz-badge variant=${…}>…</uz-badge>` hace lo mismo en una línea.
Ordenar y seleccionar
Con sortable, la cabecera de la columna es un botón que alterna el orden ascendente y descendente, marca aria-sort y ordena por row[key]. Guarda en la fila el valor que ordena (la fecha en ISO, el importe como número) y dale formato en cell. Cada cambio llega a onSort con { key, direction }.
sortKey y sortDirection fijan el orden de partida. El envoltorio de React vuelve a poner las props en cada render: si pasas sortKey, guárdalo en el estado desde onSort, como aquí, o el siguiente render devolverá la tabla al orden inicial.
selectable añade una columna de casillas y una cabecera que marca todas, con estado intermedio. onSelectionChange recibe { selected, rows }: las claves de rowKey y las filas. selected también se puede fijar, por ejemplo para vaciar la selección después de enviar los recordatorios.
Marca las reservas a las que quieres enviar el recordatorio de llegada.
Fila clicable
Con clickable, cada fila recibe foco, se resalta al pasar el ratón y emite onRowClick con { row, index } al pulsarla o con Enter y Espacio. Úsalo cuando toda la fila lleva al detalle. En el kit React bastaba con pasar onRowClick y la fila no recibía foco, así que hacía falta un botón en cada fila para quien navega con teclado; ahora el teclado llega a la fila y ese botón sobra.
Pulsa una fila, o llega a ella con Tab y pulsa Enter.
Vacía
Sin filas, la tabla mantiene sus cabeceras y muestra emptyMessage (empty-message en HTML). Escribe un mensaje que diga por qué está vacía y si eso es bueno, no un «Sin datos» genérico (que es lo que sale si no pasas nada); si necesitas un enlace o formato, usa el slot empty. Para una sección entera sin contenido y con una acción para empezar, usa EmptyState en lugar de la tabla.
Cargando
Con loading, la tabla pinta filas de esqueleto bajo sus cabeceras reales (skeletonRows, 5 por defecto) y se marca con aria-busy. Sustituye al TableSkeleton del kit React: la tabla que espera es la misma que luego muestra los datos, así que nada salta cuando llegan. Pide tantas filas de esqueleto como esperas recibir. Pulsa el botón para volver a consultar.
Con paginación
DataTable pinta las filas que recibe; la paginación va fuera, con Pagination. Pide los datos ya paginados al servidor y di cuántos resultados hay en total: el lector necesita saber si está viendo 10 reservas o 10 de 47.
Cuando el orden lo hace el servidor, cancela el evento en onSort con e.preventDefault(): la tabla solo cambia el indicador de la cabecera y deja de reordenar la página visible, que sería ordenar 10 filas de 47. Pide entonces la primera página con el orden nuevo.
Mostrando 1–10 de 47 reservas
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).