# @amset/ui 0.17.1 — referencia completa ## Reglas que no se discuten - No inventes componentes ni props: lo que no está en `api.json` no existe. Ante la duda, consulta `node_modules/@amset/ui/dist/api.json`. - Importa siempre del índice: `import { Button } from '@amset/ui'`. El formulario conectado, de `@amset/ui/form`. - Estilos: no hay que importar ninguna hoja, cada componente trae la suya (y no importes `styles.css` además: saldría duplicado). Con Next Pages Router hace falta `transpilePackages: ['@amset/ui']`. Los colores salen de los roles de `tokens.css` (`var(--amset-...)`); no escribas colores a mano. - El tema va en `data-theme="light|dark"` sobre `` (sin prefijo). La densidad, en `data-density`. - No depende de Tailwind ni de ningún framework de CSS: funciona con cualquiera o sin ninguno. - Todos los componentes aceptan los atributos HTML nativos de su elemento raíz (`id`, `aria-*`, `data-*`, `onClick`...). - Con React 19, `ref` es una prop normal. - Los textos propios salen del idioma de `LocaleProvider` (español o inglés; otro idioma cae en inglés; sin proveedor, español). Una prop de texto (`closeLabel`, `label`...) manda sobre el catálogo y `messages` en el proveedor cambia un texto en toda la app. ## Accordion — Acordeón (Navegación) Secciones plegables una debajo de otra, cada una con su título y, si hace falta, un resumen de lo que hay dentro. Por defecto solo hay una abierta a la vez. **Cuándo usarlo** - Para información secundaria que no todo el mundo va a leer: materiales, cuidados, envío, preguntas frecuentes. - `allowsMultipleExpanded` cuando tiene sentido tener varias abiertas y compararlas. - `summary` en cada sección para que se sepa qué hay dentro sin abrirla («NIF, domicilio y provincia»). - `headingLevel` según dónde vaya: debajo de un `h2`, los títulos del acordeón son `h3`. **Cuándo no** - Para lo que hay que leer sí o sí (el precio, un aviso legal): a la vista, sin plegar. - Para vistas del mismo objeto que se miran de una en una: `Tabs`. - Para un árbol de más de un nivel: `Tree`. **Teclado**: Tab recorre los títulos de las secciones; Intro o Espacio abren y cierran la que tiene el foco. Una sección deshabilitada no coge el foco. Si una sección se cierra con el foco dentro (un «Guardar y seguir» que la pliega con `expandedKeys`), el foco vuelve a su título en vez de caerse a la página. **Accesibilidad**: cada título es un encabezado de verdad (`h3` por defecto) con un botón dentro que dice si está abierta con `aria-expanded`. Quien navega por encabezados salta de sección en sección. Lo plegado no se ve ni se lee, pero la búsqueda del navegador sí lo encuentra y abre la sección. La flecha es decorativa. **Aspecto fino**: variables CSS `--amset-accordion-*`: `-background`, `-font`, `-gap`, `-padding-block`, `-padding-inline`, `-radius`. El tamaño mueve el relleno, el hueco, el cuerpo de letra y el radio. - `sections` (obligatoria): `readonly import("./index.js").AccordionSection[]` - `allowsMultipleExpanded`: `boolean | undefined` — Varias secciones abiertas a la vez. Por defecto, solo una. - `className`: `string | undefined` - `defaultExpandedKeys`: `Iterable | undefined` — Las secciones abiertas al empezar. - `disabled`: `boolean | undefined` — Apaga el acordeon entero, sin tocar la lista de secciones. - `expandedKeys`: `Iterable | undefined` — Las secciones abiertas, controladas desde fuera. - `headingLevel`: `(3 | 4 | 2) | undefined` — Nivel del encabezado para que la jerarquía de la página no se rompa. - `onExpandedChange`: `((keys: Set) => void) | undefined` - `size`: `"sm" | "md" | "lg" | undefined` — El relleno y el cuerpo de letra de cada sección. Acepta además los atributos HTML nativos de su elemento raíz. ## ActionMenu — Menú de acciones (Acciones) El menú de los tres puntos: las acciones de una fila, de una tarjeta o de una ficha, recogidas detrás de un botón y abiertas en un panel flotante pegado a él. `MenuItem` es cada acción; lo usan este menú y el de `SplitButton`, así que los dos se ven y se oyen igual. **Cuándo usarlo** - Varias acciones que pesan lo mismo sobre una misma cosa: ver, duplicar, descargar, anular. - En cada fila de una tabla o una lista, donde no caben los botones sueltos. - Con `sections` para agrupar con título («Documentos», «Zona peligrosa»), o con `trigger` para abrirlo desde un botón con texto. `placement` y `offset` dicen dónde sale el panel. **Cuándo no** - Si hay una acción principal y el resto son variantes de ella: `SplitButton`. - Si son una o dos acciones, van a la vista: `Button` o `IconButton`. - Para elegir un valor (un estado, un orden), no para hacer algo: `Select`. **Teclado**: Intro, Espacio o flecha abajo sobre el botón abren el menú con el foco en la primera acción, y la flecha arriba en la última; las flechas lo recorren dando la vuelta y saltándose las deshabilitadas, Inicio y Fin van a los extremos, y escribir salta a la acción que empieza así; Intro y Espacio eligen; Escape cierra. Tanto al elegir como al cerrar, el foco vuelve al botón. Abierto con el ratón o desde fuera con `open`, el foco entra en la lista y no se marca ninguna acción. Las deshabilitadas (`disabled` en la acción, o `disabledKeys` en el menú) se ven, pero no se pueden elegir ni alcanzar. **Accesibilidad**: `label` nombra el menú y, si no hay `trigger` propio, también el botón de tres puntos: que diga de qué son («Acciones del pedido 1042»), no «Menú». Las acciones con `destructive` van en rojo **y** con su verbo escrito: el color nunca va solo. Las que llevan `href` son enlaces de verdad (otra pestaña, copiar la dirección), y si la aplicación registra su enrutador con el proveedor de enrutado de la biblioteca, navegan con él. **Aspecto fino**: sin variables propias: se ajusta con las clases `amset-menu`, `amset-menu__panel`, `amset-menu__action` y `amset-menu__action--danger`; el ancho del panel, con `minWidth`. El botón de serie es un `IconButton` y admite las `--amset-button-*`. - `label` (obligatoria): `string` — Lo que se anuncia al abrir. "Acciones de la factura F-2026-0007", no "Menú". - `onSelect` (obligatoria): `(key: string) => void` - `actions`: `readonly import("./index.js").MenuAction[] | undefined` — Lista plana de acciones. Para agrupar con títulos, usa `sections`. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `disabledKeys`: `readonly string[] | undefined` — Claves deshabilitadas de golpe, sin tocar la lista de acciones. - `minWidth`: `string | undefined` — Ancho mínimo del panel, para que no baile entre estados. - `offset`: `number | undefined` — Separación en píxeles entre el botón y el menú. - `onOpenChange`: `((open: boolean) => void) | undefined` - `open`: `boolean | undefined` — Abierto controlado desde fuera (por ejemplo, desde un atajo de teclado). - `placement`: `import("./index.js").Placement | undefined` — Dónde sale el menú. Por defecto, debajo y alineado al final del botón. - `sections`: `readonly import("./index.js").MenuSection[] | undefined` — Grupos con título: "Exportar", "Zona peligrosa". - `size`: `"sm" | "md" | "lg" | undefined` — Tamaño del botón de tres puntos de serie. - `trigger`: `import("react").ReactElement> | undefined` — Disparador propio. Por defecto, un botón de tres puntos. Acepta además los atributos HTML nativos de su elemento raíz. ## ActivityLog — Registro de actividad (IA) El registro de lo que está haciendo un agente: llamadas a herramientas, resultados, razonamiento y respuestas, una fila por evento y con su hora. **Cuándo usarlo** - Para ver en directo qué hace un proceso largo: un agente, un despliegue, una importación. - Para repasar después qué pasó y en qué orden. **Cuándo no** - Para un solo paso con su entrada y su resultado: es un `ToolCall`. - Para el historial de cambios de un registro de negocio: es un `History`. **Varias tareas en un registro**: `group` en cada evento reparte el registro por secciones (la tarea a la que pertenecen): al cambiar de una a otra sale un título, y dos eventos iguales de secciones distintas no se juntan. `renderText` deja pintar cada fila a quien la usa (la herramienta en negrita, una ruta como enlace) sin perder el tipo para el lector. `loading` enseña unas filas de esqueleto, con el registro ocupado, mientras llega el historial. **Teclado**: es una zona desplazable y se enfoca con Tab; con el foco dentro, las flechas, Re Pág y Av Pág la recorren. El botón «Ir a lo último» aparece cuando te has alejado del final. **Accesibilidad**: es un `role="log"`: el lector anuncia lo nuevo sin quitarle el foco. Cada fila dice su tipo con texto («Error de herramienta: …») además del color del punto, y un evento repetido dice cuántas veces. En vivo se marca como ocupado. **Aspecto fino**: el color de cada tipo sale de `--amset-eventlog-dot` sobre cada fila; `maxHeight` fija cuánto crece antes de desplazarse. - `events` (obligatoria): `readonly import("./index.js").ActivityEvent[]` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `collapseRepeats`: `boolean | undefined` — Junta los eventos iguales y seguidos. Por defecto, si. - `empty`: `import("react").ReactNode` — Lo que sale sin eventos: un texto, o un nodo con su propia ilustracion. - `emptyIcon`: `import("react").ReactNode` — Un icono sobre el texto de «sin actividad»: una antena apagada, un reloj. - `endedAt`: `number | undefined` — Cuando acabo: el contador se para en lo que duro. - `label`: `string | undefined` — Que es: «Actividad de la tarea». Por defecto, «Actividad». - `live`: `boolean | undefined` — Sigue llegando: el final lleva un cursor y el registro se marca como ocupado. - `loading`: `boolean | undefined` — Se esta cargando el historial: unas filas de esqueleto y el registro, ocupado, en vez de «sin actividad». - `maxHeight`: `string | undefined` — Alto maximo antes de desplazarse dentro. - `renderText`: `((row: import("./index.js").ActivityRow) => import("react").ReactNode) | undefined` — Como se pinta el texto de una fila, si no basta con el texto: un enlace, un fragmento de codigo, la herramienta en negrita. La fila sigue llevando su punto, su tipo para el lector, el recuento y la hora. - `startedAt`: `number | undefined` — Cuando empezo la tarea (una marca de `Date.now()`): el registro enseña arriba cuanto lleva, y se actualiza en vivo hasta que se pasa `endedAt`. Acepta además los atributos HTML nativos de su elemento raíz. ## ActivityMap — Mapa de actividad (Datos) La rejilla de días por semanas, como la del perfil de GitHub: cada columna es una semana (de lunes a domingo), cada cuadro un día, y el color dice cuánta actividad hubo. Arriba, el título y el total del periodo, y encima de las columnas el nombre de cada mes en la semana en que empieza. Si el periodo no arranca en lunes, la primera columna sale con huecos en los días de antes: es la misma semana, no un descuadre. **Cuándo usarlo** - Para ver de un vistazo qué días hay más movimiento en unos meses: pedidos, entradas al taller, reseñas. - `from` y `to` marcan el periodo, los dos incluidos; los días sin datos cuentan como cero, no como hueco. Son días de calendario, sin hora: el cambio de hora de marzo y de octubre no repite ni se come ninguno. - `label` dice qué se mide y `unit` de qué es cada cuenta («pedidos»). - `tableVisible` enseña debajo la tabla de días con su cuenta, cuando el número exacto importa. - El color se reparte en cuatro niveles sobre el máximo real del periodo: si el mejor día son cuatro pedidos, cuatro es el tope. **Cuándo no** - Para comparar cantidades de unas pocas categorías: `BarChart`. - Para la evolución de una cifra, con su subida o bajada: `Trend`. - Para citas y eventos de un mes que se pueden abrir: `MonthAgenda`. **Teclado**: no tiene: no hay nada que pulsar. **Accesibilidad**: la rejilla es una `table` de verdad, con el título en el `caption` y el día de la semana como cabecera de cada fila. Cada cuadro lleva escritos, ocultos a la vista, su fecha completa y su cuenta («lunes, 14 de septiembre de 2026: 3 pedidos»): un cuadrado de color no se lee en voz alta ni se distingue si no se ven bien los colores. La leyenda «Menos … Más» es decorativa. Con `tableVisible`, la tabla de días es el dato para todos y la rejilla pasa a ser el dibujo (`aria-hidden`), para que el lector no lo oiga dos veces. Si `from` va después de `to`, lo dice («No hay fechas que enseñar») en vez de pintar una rejilla vacía. **Aspecto fino**: variables CSS `--amset-activity-*`: `-cell`, `-day`, `-label`, `-radius`, `-slot`, `-title`. El tamaño mueve el lado de la casilla, el hueco entre ellas y los rótulos. - `days` (obligatoria): `readonly import("./index.js").ActivityDay[]` - `from` (obligatoria): `string | import("./utils/date.js").PlainDate | Date` — Primer dia, incluido: `AAAA-MM-DD`, un dia suelto o un `Date`. - `label` (obligatoria): `string` — Que se esta midiendo. Es el nombre de la tabla. - `to` (obligatoria): `string | import("./utils/date.js").PlainDate | Date` — Ultimo dia, incluido. - `unit` (obligatoria): `string` — De que es la actividad: «pedidos», «entrenamientos», «publicaciones». - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `size`: `"sm" | "md" | "lg" | undefined` - `tableVisible`: `boolean | undefined` — Enseña tambien la tabla de dias y cuentas debajo de la rejilla. Entonces la tabla es el dato para todos y la rejilla, el dibujo; sin ella, la propia rejilla es la tabla para el lector de pantalla. Acepta además los atributos HTML nativos de su elemento raíz. ## AddressField — Dirección (Campos) La dirección postal de España en un bloque: calle y número, piso, código postal y población. La provincia no se pregunta: sale de las dos primeras cifras del código postal y se escribe debajo («Madrid»), así que no puede llegar un 28001 en Sevilla. **Cuándo usarlo** - Envío y facturación en la compra, la ficha de un cliente, la dirección de una tienda. - `value` y `onChange` llevan la dirección entera (`EMPTY_ADDRESS` para empezar en blanco). - `section="billing"` para la de facturación: el navegador distingue las dos y no rellena una con la otra. - `addressErrors(value)` dice qué falta antes de seguir; `errors` pinta los del servidor, que mandan sobre los de aquí. **Cuándo no** - Una dirección de fuera de España: el código postal se comprueba contra las provincias españolas y uno de fuera sale como error. Para otro país, campos sueltos con `TextField`. **Teclado**: Tab recorre los cuatro campos. Cada uno se comprueba al salir de él, no en cada tecla. El código postal se queda en cinco cifras aunque se pegue otra cosa. **Accesibilidad**: es un `fieldset` con su leyenda (el `label`, «Dirección de envío» por defecto), y cada campo tiene la suya. Calle, código postal y población son obligatorios (`aria-required`); el piso lleva «Opcional» de ayuda. Un código que no es de España lo dice con esas palabras. Los `autocomplete` son los de la especificación con su sección (`shipping address-line1`, `shipping postal-code`…): con ellos el autorrelleno resuelve medio formulario. **Aspecto fino**: sin variables propias: los campos usan `--amset-field-*` y el bloque se ajusta con las clases `amset-address__title`, `amset-address__row` y `amset-address__cp`. - `onChange` (obligatoria): `(address: import("./index.js").PostalAddress) => void` - `value` (obligatoria): `import("./index.js").PostalAddress` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `disabled`: `boolean | undefined` - `errors`: `import("./index.js").AddressErrors | undefined` — Errores de fuera (los del servidor). Mandan sobre los de aqui. - `label`: `string | undefined` — Titulo del bloque. Es la leyenda del grupo de campos. - `section`: `"shipping" | "billing" | undefined` — Prefijo de los `autocomplete`: `shipping` o `billing`. Con el, el navegador distingue la direccion de envio de la de facturacion y no rellena una con la otra. - `size`: `"sm" | "md" | "lg" | undefined` - `variant`: `import("./index.js").FieldVariant | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## Affix — Pegado al desplazar (Navegación) Un bloque que se queda pegado al desplazar: el índice de una página larga, un resumen de compra, una barra de acciones. **Cuándo usarlo** - Un índice o un resumen que tiene que seguir a la vista mientras se lee o se rellena un formulario largo. - `offsetTop` para dejarlo a una distancia del borde de arriba (debajo de una cabecera fija); `offsetBottom` para pegarlo abajo en vez de arriba. **Cuándo no** - Una cabecera de toda la aplicación: es `TopBar` con `sticky`, o el `AppShell`, que la fija y deja la columna lateral debajo. **Cómo funciona**: es `position: sticky`, no un bloque que se pasa a `fixed` con scripts. El navegador lo coloca solo, sin saltos ni hueco que rellenar, y vale con el desplazamiento táctil. A cambio, la regla de `sticky`: **el contenedor tiene que ser más alto que el bloque**, y ningún ancestro puede tener `overflow: hidden` ni `auto`. **Accesibilidad**: no cambia el orden del documento ni el foco. `onChange` avisa de si está pegado ahora; se mide con un centinela y un `IntersectionObserver`, no escuchando `scroll`. **Aspecto fino**: no tiene variables propias. Va en la capa 1 para quedar por encima del contenido que pasa por debajo; mientras está pegado lleva `data-affixed`, por si hace falta darle sombra o fondo desde fuera. - `children` (obligatoria): `import("react").ReactNode` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `offsetBottom`: `number | undefined` — Si se pasa, se pega por ABAJO en vez de por arriba, a esta distancia del borde de abajo. - `offsetTop`: `number | undefined` — Distancia en pixeles al borde de ARRIBA de la ventana a la que se queda pegado. Por defecto, 0. - `onChange`: `((affixed: boolean) => void) | undefined` — Avisa cuando empieza y cuando deja de estar pegado. Acepta además los atributos HTML nativos de su elemento raíz. ## Alert — Aviso (Superficies) Banda de estado dentro de una pantalla: algo ha ido bien, algo ha fallado, algo vence. Siempre lleva icono Y texto, y cada tono tiene su silueta (círculo para información y correcto, triángulo para el aviso, octógono para el error): el color solo no cuenta lo que pasa, porque hay quien no lo distingue. **Cuándo usarlo** - Para contar algo sobre lo que se está viendo o rellenando: un guardado que ha fallado, una factura que vence mañana, una importación a medias. - `variant`: `soft` (por defecto), `solid` para lo que no se puede pasar por alto, `outline` sobre un fondo que ya es de color, `ghost` para una nota en línea sin caja. - `size`: `sm` dentro de una tarjeta o de una fila, `lg` para encabezar una pantalla. - `title` en negrita cuando el aviso tiene más de una frase; uno corto no lo necesita. - `actions` para lo que se puede hacer al respecto («Reintentar», «Ver el detalle»). - `onClose` para que se pueda descartar. El aviso no se quita solo: lo quita quien lo pinta, al recibir la llamada. - `icon` cambia el icono del tono; `withoutIcon` lo quita, solo si el título ya dice de qué va. **Cuándo no** - Lo que afecta a la aplicación entera (mantenimiento, prueba que caduca): `GlobalAlert`, la cinta de arriba de la página. - Una confirmación que se va sola («Guardado»): una notificación con `useNotifications`. - La pantalla que queda después de pagar o de un fallo sin vuelta atrás: `Result`. - El error de un campo concreto: la prop `error` del propio campo. **Teclado**: el aviso no es enfocable. Con `onClose` aparece un botón de cerrar con su parada de Tab (Intro y Espacio lo pulsan); los botones de `actions` tienen la suya. **Accesibilidad**: un error se anuncia al momento (`role="alert"`); el resto espera a que el lector de pantalla termine lo que estaba diciendo (`role="status"`). `announcement` lo fuerza en un sentido u otro (`alert` o `status`), o lo quita con `none` para una nota que ya está en la página al cargar. El icono es decorativo. La equis se ve de 24 a 32 px y se pulsa en 44 × 44 con el dedo; se llama «Cerrar aviso» y `closeLabel` lo cambia. **Aspecto fino**: variables CSS `--amset-alert-*`: `-padding-block`, `-padding-line`, `-slot`, `-font`, `-font-title`, `-icon`, `-close` y `-radius`. Los colores del tono van en `--amset-alert-tone`, `-tone-soft`, `-tone-solid` y `-tone-ink`. - `children` (obligatoria): `import("react").ReactNode` - `actions`: `import("react").ReactNode` — Botones al pie del aviso: "Reintentar", "Ver el detalle". - `announcement`: `import("./index.js").AlertAnnouncement | undefined` — Fuerza como se anuncia. Por defecto un error interrumpe (`alert`) y el resto espera turno (`status`). - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `closeLabel`: `string | undefined` - `icon`: `import("react").ReactNode` — Icono propio en lugar del que corresponde al tono. - `onClose`: `(() => void) | undefined` — Muestra el boton de cerrar y avisa al pulsarlo. - `size`: `"sm" | "md" | "lg" | undefined` — `sm` dentro de una tarjeta o de una fila; `lg` para encabezar una pantalla. - `title`: `import("react").ReactNode` — Titulo en negrita sobre el texto. Opcional: un aviso corto no lo necesita. - `tone`: `"neutral" | "accent" | "secondary" | "tertiary" | "info" | "success" | "warning" | "error" | undefined` — Que quiere decir. Por defecto, `info`. - `variant`: `"solid" | "soft" | "outline" | "ghost" | undefined` — Como se pinta: `soft` (fondo del tono, por defecto), `solid` (relleno fuerte, para lo que no se puede pasar por alto), `outline` (solo el borde, sobre la superficie) o `ghost` (sin caja: una nota en linea). - `withoutIcon`: `boolean | undefined` — Sin icono. Solo si el titulo ya dice de que tono es: el color solo no lo cuenta. Acepta además los atributos HTML nativos de su elemento raíz. ## Amount — Importe (Superficies) Un precio, con su moneda y en el formato del idioma activo: `1234,56 €` en español, `$1,234.56` en inglés. Con precio anterior lo tacha, escribe «Antes» para quien no lo ve y dice lo que se ahorra. **Cuándo usarlo** - Precios de producto, líneas de carrito, totales, cuotas: todo importe que se enseña. - Los céntimos se quitan cuando no aportan nada (`20 €` y no `20,00 €`). `withDecimals` los fuerza aunque el importe sea redondo; `withDecimals={false}` los quita siempre, redondeando. - `before` para una rebaja: sale tachado y con el ahorro en una pastilla («25 %»), redondeado hacia abajo, porque decir «-50 %» cuando es el 49,6 % es mentira. Solo hay oferta si `before` es mayor que `quantity`. `highlightOffer={false}` quita el rojo de la cifra. - `currency` con el código ISO de la moneda (euros por defecto); `freeText` para el cero («Gratis»); `perUnit` para lo que va detrás («/mes», «por kg»). **Cuándo no** - Un importe que se escribe: `NumberField` con `format="currency"`. - Un resumen de compra con sus líneas y su total: `OrderSummary`. - La cifra de un cuadro de mando con su variación: `Stat`. **Teclado**: no es enfocable. **Accesibilidad**: ningún lector de pantalla anuncia un tachado, así que el precio anterior lleva «Antes:» escrito y oculto a la vista, y la pastilla dice «Ahorras un 25 %». El texto seguido se lee «14,90 € Antes: 19,90 € Ahorras un 25 %». **Aspecto fino**: sin variables propias: se ajusta con las clases `amset-amount`, `amset-amount--sm`/`--md`/`--lg` (el cuerpo de la cifra) y `amset-amount--offer` (la cifra en `--amset-error`). **Contexto**: va dentro de `LocaleProvider` (o de `AmsetProvider`), que decide la coma decimal, el punto de los miles y dónde va el símbolo. - `quantity` (obligatoria): `number` - `before`: `number | undefined` — Precio anterior. Sale tachado y con lo que se ahorra. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `currency`: `string | undefined` — Codigo ISO. Por defecto euros. - `freeText`: `string | undefined` — Texto cuando la cantidad es cero. Sin esto se pinta «0 €». - `highlightOffer`: `boolean | undefined` — Lo pinta en rojo de oferta cuando hay precio anterior. - `perUnit`: `string | undefined` — Lo que va detras: «/mes», «por kg», «la unidad». - `size`: `import("./index.js").AmountSize | undefined` - `withDecimals`: `boolean | undefined` — Sin decir nada, los centimos salen solo si los hay. Con `true` salen siempre, aunque el importe sea redondo (`20,00 €`); con `false` no salen nunca y el importe se REDONDEA al entero (`14,90 €` se pinta `15 €`, y el precio anterior tambien): solo para precios que ya son redondos o donde el centimo no importa. Acepta además los atributos HTML nativos de su elemento raíz. ## AmsetProvider — Proveedor AMSET (Más) Todo lo que la librería necesita alrededor, en una línea: `{children}`. Por dentro son tres: el idioma (`LocaleProvider`, que decide cómo se escriben fechas, números e importes y hacia qué lado se escribe), la cola de notificaciones (`useNotifications`) y el diálogo de confirmación (`useConfirmation`). **Cuándo usarlo** - Una vez, arriba del todo: en el layout raíz de Next o alrededor de la aplicación. - `locale` fija el idioma (por defecto, `es-ES`) y `notifications` pasa sus opciones a la cola (cuántas caben, en qué esquina salen). - `theme` y `density` para fijarlos al arrancar. Sin ellos no se toca nada: manda lo que ya tenga el `` (lo que puso el script del tema, o el sistema operativo). **Cuándo no** - Si la aplicación trae su propio diálogo de confirmación: `withoutConfirm`, o las piezas por separado (`LocaleProvider`, `NotificationProvider`, `ConfirmProvider`). - Para rutas, estado global o un cliente HTTP: no los trae a propósito. Un proveedor que monta todo eso es lo que impide usar una librería en el proyecto de al lado. **Teclado**: no tiene, es un proveedor. Las notificaciones y el diálogo que monta traen el suyo. **Accesibilidad**: las notificaciones van en una región con nombre («Notificaciones»): las normales se anuncian con `role="status"`, que espera a que el lector termine, y los errores con `role="alert"`, que interrumpe. El diálogo de confirmación responde `false` si se cierra, con Escape o si se desmonta el proveedor: el `await` de quien preguntaba nunca se queda colgado. **Aspecto fino**: no pinta nada propio. `theme` escribe `data-theme` en el `` (y lo guarda) y `density`, `data-density`: en esta ficha afectan a toda la vista previa. - `children` (obligatoria): `import("react").ReactNode` - `catalogs`: `Readonly> | undefined` — Idiomas enteros de la aplicacion por etiqueta BCP-47; ver `LocaleProvider`. - `density`: `"compact" | "comfortable" | undefined` — `compact` baja el alto de los controles (30 px en vez de 36) para pantallas con muchos datos. Sin esto no se toca: manda el atributo `data-density` que ya tenga el ``. - `locale`: `string | undefined` — Etiqueta BCP-47. Por defecto `es-ES`. - `messages`: `Readonly | undefined` - `onCatalogError`: `import("./index.js").CatalogErrorHandler | undefined` — Se llama si un catalogo perezoso no se pudo cargar; ver `LocaleProvider`. - `theme`: `import("./index.js").ThemePreference | undefined` — Tema al arrancar. Sin esto no se toca nada: manda lo que ya haya puesto el script que evita el parpadeo, y si no, el sistema operativo. - `withoutConfirm`: `boolean | undefined` — Quita el dialogo de confirmacion, si la aplicacion trae el suyo. ## AppliedFilters — Filtros aplicados (Gestión) Las fichas de los filtros que están puestos ahora mismo, encima de una tabla o de una lista. Sirven para dos cosas: que se vea por qué faltan resultados y que se pueda quitar uno sin volver al panel de filtros. **Cuándo usarlo** - Encima de una tabla, una lista de pedidos o unos resultados de búsqueda, cada ficha con su campo y su valor (`field` y `value`: «Estado: Pendiente de envío»). - Es controlado: `onRemove` llega con la clave y quien lo usa quita el filtro de verdad. - `onClear` añade «Limpiar todo» (`clearText` lo cambia); `max` resume los que no caben en «+N»; `empty` dice qué se ve cuando no hay ninguno (por defecto, nada). **Cuándo no** - Elegir los filtros: `FilterGroup`. - Marcas que no se quitan (el estado de un pedido): `Tag`. - Elegir varias opciones dentro de un campo: `MultiSelect`. **Teclado**: las fichas son una rejilla (`role="grid"`) con una sola parada del Tab: las flechas pasan de una a otra (dando la vuelta en los extremos), Inicio y Fin van a la primera y a la última, y Supr o Retroceso quitan la que tiene el foco, además de su botón. Al quitar una, el foco pasa a la siguiente (o a la anterior, si era la última) en vez de perderse. «Limpiar todo» es un botón aparte, con su propia parada. Al quitar la última o limpiar todo, el foco pasa al texto de `empty`; sin él, a lo siguiente de la página (o a lo anterior, o al contenedor), nunca al `body`. Si quien lo usa lleva el foco a otro sitio en `onRemove` o `onClear`, se respeta. **Accesibilidad**: el grupo se llama como `label` («Filtros aplicados»), cada ficha se lee entera («Estado: Pendiente de envío») y cada botón de quitar dice una sola vez qué filtro quita («Quitar el filtro Estado: Pendiente de envío»). El «+N» se ve como «+2» y se oye entero, con el plural del idioma: «2 filtros más». **Aspecto fino**: variables CSS `--amset-filters-*`: `-chip-padding`, `-extra`, `-font`, `-gap`, `-radius`, `-remove`, `-remove-icon`, `-target`. El tamaño mueve el hueco, el relleno de la pildora y el cuerpo de letra. La equis se VE en `-remove` y se PULSA en `-target`: 24 px con raton y el objetivo tactil con el dedo. - `filters` (obligatoria): `readonly import("./index.js").AppliedFilter[]` - `onRemove` (obligatoria): `(key: string) => void` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `clearText`: `string | undefined` - `empty`: `import("react").ReactNode` — Qué se ve cuando no hay ninguno. Por defecto, nada. Al vaciar la lista, el foco pasa aquí. - `label`: `string | undefined` — Texto de delante: "Filtros:". Va como nombre del grupo. - `max`: `number | undefined` — Cuántos se ven antes de resumir en "+N". - `onClear`: `(() => void) | undefined` — Con esto aparece el botón de limpiar todo. - `size`: `"sm" | "md" | "lg" | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## AppShell — Armazón de aplicación (Estructura) El armazón de una aplicación: cabecera, columna lateral, contenido y pie, en una rejilla de CSS y en un solo componente: `header`, `sider`, `children` y `footer`. **Cuándo usarlo** - La carcasa de una pantalla de gestión: `TopBar` arriba, `SideNav` a la izquierda y el contenido en medio. **Cuándo no** - Una página pública o una landing: ahí no hay columna ni cabecera de aplicación. **Lo que da sin pedirlo**: el contenido es un `
` con `id` (`mainId`, `content` por defecto) y `tabindex="-1"` —el destino de «saltar al contenido» del `TopBar` (`skipTo`)—, la cabecera se queda fija (`stickyHeader={false}` para que no), y la columna lateral se queda fija **justo debajo** de ella (mide su alto) con su propio desplazamiento si el menú es más alto que la ventana. **Pantalla estrecha** (menos de 48 rem): la columna pasa encima del contenido y deja de ser fija, salvo si es un `SideNav`: ese ya se queda en su carril de baldosas por debajo de 40 rem y sigue al lado del contenido, fijo y hasta abajo. Un menú que se esconde tras un botón necesita su propio panel (`Drawer`) y eso se monta fuera. **Teclado**: Tab recorre cabecera, columna y contenido en ese orden. Con un `TopBar` que lleve `skipTo`, el primer Tab ofrece «Saltar al contenido». **Aspecto fino**: `--amset-shell-sider-width` (16 rem; también con la prop `siderWidth`) y `--amset-shell-gap` (relleno del contenido). - `children` (obligatoria): `import("react").ReactNode` — El contenido de la pantalla. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `footer`: `import("react").ReactNode` — El pie de la pagina, bajo el contenido. - `header`: `import("react").ReactNode` — La barra de arriba: normalmente un `TopBar`. Se queda fija al desplazar. - `mainId`: `string | undefined` — El `id` del contenido principal. A el apunta el enlace «saltar al contenido» del `TopBar` (`skipTo`). Por defecto, `content`. - `sider`: `import("react").ReactNode` — La columna de la izquierda: normalmente un `SideNav`. Se queda fija bajo la cabecera. - `siderWidth`: `string | undefined` — Ancho de la columna de la izquierda. Por defecto, el de `--amset-shell-sider-width` (16 rem). - `stickyHeader`: `boolean | undefined` — La cabecera se queda pegada arriba al desplazar. Por defecto, si. Acepta además los atributos HTML nativos de su elemento raíz. ## AreaChart — Gráfico de áreas (Datos) Lo mismo que `LineChart`, con el área de debajo de cada línea rellena: la evolución de una o varias series sobre las mismas categorías, con el peso de cada una a la vista. Comparte con `LineChart` y `StackedBarChart` los datos, la escala, la leyenda y la tabla. **El dibujo es el adorno y la tabla es el dato**: debajo va una tabla de verdad (una fila por categoría, una columna por serie), oculta a la vista salvo con `tableVisible`. Al pasar el ratón por una categoría salen los valores de todas las series. **Cuándo usarlo** - Un volumen que se acumula en el tiempo: ventas, visitas, horas. - `stacked` apila las series: el borde de arriba es el total y cada capa, lo que aporta cada una. Al apilar, un hueco (`null`) cuenta como cero. Sin `stacked` las áreas se superponen, translúcidas, y conviene que sean dos o tres; un `null` es un hueco y corta el área ahí. - El eje empieza siempre en cero, porque un área que arranca en otro sitio exagera las diferencias; `min` y `max` fijan la escala a mano, para comparar dos gráficos. - `format` escribe los valores (euros, porcentajes) en el eje, al pasar el ratón, en el resumen y en la tabla; `categoryName` es la cabecera de la primera columna de la tabla. **Cuándo no** - Comparar la forma de varias series sin relleno, o con el eje ajustado a los datos: `LineChart`. - Pocas categorías en las que importa el total de cada una: `StackedBarChart`. - Partes de un total en un solo momento: `DonutChart`. **Teclado**: no tiene: no hay nada que pulsar. El dato completo está en la tabla. **Accesibilidad**: el dibujo es una imagen (`role="img"`) con un resumen escrito («2 series, 9 puntos. Tienda: de 4200 € a 7800 €, el máximo, 7800 €, en Sep. …») y la tabla está siempre para el lector de pantalla. El color nunca es la única pista: la leyenda (por defecto, solo con más de una serie) y el resumen llevan el nombre de cada serie. **Aspecto fino**: variables CSS `--amset-series-*`: `-axis`, `-cap`, `-footer`, `-height`, `-label` y `-stroke`. El tamaño mueve el alto (10, 14 o 18 rem); `height` manda si se pasa. El color de cada serie sale de su `tone`, y el relleno es ese color al 22 %. - `categories` (obligatoria): `readonly string[]` — Lo que va en el eje de abajo: los meses, los dias. Una por valor de cada serie. - `label` (obligatoria): `string` — Que se esta midiendo. Obligatoria: un grafico sin titulo no informa. - `series` (obligatoria): `readonly import("./index.js").ChartSeries[]` - `axes`: `boolean | undefined` — Rayas de fondo con su numero. - `categoryName`: `string | undefined` — Como se llama la primera columna de la tabla. Por defecto, «Periodo». - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `format`: `((value: number) => string) | undefined` - `height`: `number | undefined` — Alto del dibujo en pixeles. Por defecto, el del tamaño. - `legend`: `boolean | undefined` — La leyenda con el nombre de cada serie. Por defecto, solo si hay mas de una. - `max`: `number | undefined` - `min`: `number | undefined` — Minimo y maximo del eje a mano, para comparar dos graficos con la misma escala. - `size`: `"sm" | "md" | "lg" | undefined` - `stacked`: `boolean | undefined` — Las series se suman unas sobre otras: el area total es la suma. Por defecto, `false` (se superponen). - `tableVisible`: `boolean | undefined` — Enseña tambien la tabla. Para el lector de pantalla esta siempre. Acepta además los atributos HTML nativos de su elemento raíz. ## ArtifactCard — Tarjeta de artefacto (IA) Un fichero que ha generado un asistente, con su vista previa a un clic: la miniatura o el icono según el tipo, el nombre, el tamaño y las acciones de abrir y descargar. **Cuándo usarlo** - Debajo de la respuesta de un asistente, para los ficheros que ha creado: informes, páginas, hojas de cálculo, imágenes. - Con una vista previa propia dentro (`ArtifactFrame` para HTML o PDF, markdown ya pintado, un vídeo). **Cuándo no** - Para un fichero que alguien va a adjuntar a un mensaje: es un `Attachment`. - Para una lista de ficheros con fechas y descarga masiva: es una `FileList`. **Teclado**: si hay vista previa, la cabecera es un botón de despliegue (Intro o Espacio); abrir y descargar son botones aparte, hermanos de la cabecera -un botón dentro de otro botón no es HTML válido-. Una imagen con `onView` no despliega: abre el visor. **Accesibilidad**: el botón lleva `aria-expanded` y el cuerpo es una región con nombre. Cargando se anuncia y un fallo es una alerta con su texto. Las acciones llevan el nombre del fichero en su etiqueta («Descargar informe.pdf»). Con `onVisible` se pide el contenido solo de lo que entra en pantalla, y el cuerpo solo se monta mientras está abierto: un `iframe` no carga hasta que alguien lo pide. **Seguridad**: `ArtifactFrame` aísla lo que muestra con `sandbox="allow-scripts"` y **nunca** `allow-same-origin`, así que lo que haya dentro corre pero no toca la página, sus cookies ni su almacenamiento. Es lo que permite enseñar lo que generó un modelo. **Aspecto fino**: variables CSS `--amset-artifact-thumb` (lado de la miniatura) y `--amset-artifact-body-max` (alto máximo de la vista previa antes de desplazarse). - `name` (obligatoria): `string` - `children`: `import("react").ReactNode` — La vista previa. Con esto la cabecera es un botón que despliega; el cuerpo solo se monta mientras está abierto, así que un `iframe` o un vídeo no cargan hasta que alguien los pide. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `defaultExpanded`: `boolean | undefined` - `detail`: `import("react").ReactNode` — Más datos junto al tamaño: la fecha, quién lo generó. - `error`: `string | boolean | undefined` — Por qué no se pudo cargar. Sin texto propio, «No se pudo cargar el fichero». - `expanded`: `boolean | undefined` - `loading`: `boolean | undefined` — El contenido se está pidiendo. - `mimeType`: `string | undefined` - `onDownload`: `(() => void) | undefined` — Con esto aparece «Descargar». - `onExpandedChange`: `((expanded: boolean) => void) | undefined` - `onOpen`: `(() => void) | undefined` — Con esto aparece «Abrir». - `onRetry`: `(() => void) | undefined` — Con esto, si la carga ha fallado (`error`), aparece «Reintentar» junto a las demas acciones. - `onView`: `(() => void) | undefined` — Se pulsa para ver una imagen en grande. - `onVisible`: `(() => void) | undefined` — Se llama UNA vez cuando la tarjeta entra en pantalla: para pedir la miniatura solo de lo que se ve. - `size`: `number | undefined` — En bytes. Se escribe en el idioma: «1,5 MB». - `thumbnailUrl`: `string | undefined` — Miniatura de una imagen. Con ella, pulsar la tarjeta llama a `onView` en vez de desplegar. Acepta además los atributos HTML nativos de su elemento raíz. ## ArtifactFrame - `title` (obligatoria): `string` — Qué es, para quien no lo ve: el nombre del fichero. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `height`: `string | undefined` — Alto de la vista previa. Por defecto 26 rem. - `html`: `string | undefined` — HTML como texto, o la dirección de un PDF o una página. Uno de los dos. - `src`: `string | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## AspectRatio — Proporción (Maquetación) Una caja con una proporción fija, ancho entre alto, que ocupa todo el ancho de su hueco. Lo de dentro la llena entera aunque no traiga tamaño propio. **Cuándo usarlo** - Un vídeo incrustado, un mapa o un `iframe`: no traen tamaño propio, y sin una caja que les reserve el sitio la página salta cuando terminan de cargar. - `ratio` es la proporción tal y como se escribe en CSS: `16 / 9` (por defecto), `4 / 3`, `1` para un cuadrado. - `as` pinta el elemento que toque en vez del `div`. **Cuándo no** - Una IMAGEN: `Thumbnail`, que además trae el respaldo si falla, el recorte y la carga diferida. - Una zona que crece con su contenido: lo que no cabe en la proporción se recorta (`overflow: hidden`), así que no vale para texto de largo variable. **Teclado**: no participa: solo da tamaño. Lo de dentro conserva el suyo (un `iframe` o un vídeo se enfocan como siempre). **Accesibilidad**: reservar el sitio antes de que cargue evita que el contenido de debajo se mueva mientras se lee. El nombre de lo de dentro lo pone quien lo pinta: un `iframe` necesita su `title` y un vídeo, sus subtítulos. **Aspecto fino**: `--amset-ratio`, la proporción; la escribe `ratio` en línea. - `children` (obligatoria): `import("react").ReactNode` - `as`: `"article" | "aside" | "div" | "footer" | "header" | "main" | "nav" | "section" | "span" | undefined` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `ratio`: `string | undefined` — La proporcion, ancho entre alto: `16 / 9` se escribe `16 / 9`. Por defecto `16 / 9`. - `style`: `import("react").CSSProperties | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## Attachment — Adjunto (IA) Un fichero adjunto a un mensaje: su miniatura o icono, el nombre, el tamaño y, mientras sube, una barra de progreso de verdad. **Cuándo usarlo** - Encima de la caja de un chat, para lo que se va a enviar con el mensaje. - Dentro de un mensaje ya enviado, para los ficheros que llevaba. **Cuándo no** - Para una lista de ficheros de un proyecto con descarga y fechas: es una `FileList`. - Para elegir ficheros: es un `FileUpload`. **Teclado**: quitarlo es un botón y Tab llega a él. **Accesibilidad**: el estado -subiendo, subido, con error- se dice con texto, no solo con color; la subida es un `` con su nombre y su valor, y un fallo se anuncia como alerta. El botón de quitar lleva el nombre del fichero en su etiqueta («Quitar informe.pdf»). La miniatura es decorativa; con `onPreview` es un botón con el nombre del fichero («Ver informe.png»). Al terminar una subida se anuncia «Subido». El tamaño se escribe en el idioma («1,5 MB»). **Aspecto fino**: variables CSS `--amset-attachment-max` (ancho máximo) y `--amset-attachment-thumb` (lado de la miniatura). - `name` (obligatoria): `string` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `compact`: `boolean | undefined` — Mas pequeño, para una barra estrecha: la miniatura de 1,75 rem y el texto en una sola linea. - `detail`: `import("react").ReactNode` — Una linea mas junto al tamaño: «Termina en ••4f2a», «3 paginas». - `errorText`: `string | undefined` — Que ha pasado, si ha fallado: «Pesa mas de 10 MB». Por defecto, «No se ha subido». - `icon`: `import("react").ReactNode` — Un icono propio en lugar del de fichero: una llave para una variable, un enlace. Sin `previewUrl`. - `onPreview`: `(() => void) | undefined` — Con esto la miniatura es un boton -«Ver informe.png»- que abre el visor, el zoom o lo que toque. - `onRemove`: `(() => void) | undefined` — Con esto aparece el boton de quitar. - `previewUrl`: `string | undefined` — Una miniatura, si es una imagen. Sin ella sale el icono de fichero. - `progress`: `number | undefined` — De 0 a 100, mientras sube. Sin esto, la barra no tiene recuento. - `size`: `number | undefined` — En bytes. Se escribe en el idioma: «1,5 MB». - `status`: `import("./index.js").AttachmentStatus | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## AudioPlayer — Reproductor de audio (Más) Notas de voz, un mensaje grabado, un audio corto: el audio con sus controles. Los controles son propios y no los del navegador, porque esos cambian de uno a otro y en varios no se llega con el teclado a la barra de posición. **Cuándo usarlo** - La nota de voz de un pedido o de un ticket, el mensaje de un cliente, una locución corta. - `src` es el fichero y `subtitle`, la línea pequeña de debajo del título (quién habla, cuándo). - Con `duration` (en segundos) si se sabe de antemano: así no enseña «–:––» ni tiene la barra apagada hasta que llegan los metadatos. **Cuándo no** - Vídeo: esto es solo audio. - Un sonido de aviso que suena solo, sin que nadie lo pida: no necesita reproductor. **Teclado**: Tab pasa por el botón de reproducir, la barra de posición y el botón de velocidad. En la barra, las flechas avanzan y retroceden de segundo en segundo, Re Pág y Av Pág saltan una décima parte de la duración, e Inicio y Fin van al principio y al final. La velocidad da la vuelta: 1×, 1,25×, 1,5× y 2×. **Accesibilidad**: `title` es obligatorio y nombra los controles: «Reproducir Nota de voz de Aitor» (o «Pausar…»), «Posición en Nota de voz de Aitor». La posición se anuncia en segundos, no como un porcentaje sin unidad. Si el audio no carga o el navegador no deja reproducir, se dice con palabras (`role="alert"`) en vez de dejar un botón que no hace nada. **Aspecto fino**: sin variables propias: se ajusta con las clases `amset-audio`, `amset-audio--playing`, `amset-audio__track`, `amset-audio__thumb` y `amset-audio__speed`. - `src` (obligatoria): `string` - `title` (obligatoria): `string` — Que se escucha. Obligatorio: nombra el reproductor y sus botones. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `duration`: `number | undefined` — Duracion conocida de antemano, para no enseñar 0:00 hasta que cargue. - `subtitle`: `string | undefined` — Quien habla, cuando: la linea pequeña de debajo. Acepta además los atributos HTML nativos de su elemento raíz. ## Avatar — Avatar (Superficies) La cara, o las iniciales, de una persona. Si no hay foto, si falla al cargar o mientras llega, se ven las iniciales: nunca un hueco en blanco ni un icono roto. Cuando la foto carga, se funde por encima. **Cuándo usarlo** - Junto a quien escribe, firma o tiene algo asignado. Si el nombre ya está escrito al lado, `decorative`, para que no se lea dos veces. - Las iniciales salen solas: la primera del nombre y la del último apellido, saltándose las partículas («María de la Fuente» es MF). Si el nombre no tiene ninguna letra, sale el icono de persona. `content` pone otra cosa en su lugar (un icono). - Sin `tone` (por defecto) sale del nombre un color estable: el mismo nombre sale siempre del mismo color. `tone` lo fija con cualquiera de los ocho tonos comunes. - `variant`: `soft` (fondo claro del tono, por defecto) o `solid` (relleno fuerte con las iniciales en blanco). `shape`: `circle` (por defecto) o `square`. - `state` pinta el punto de presencia: `inline` (en línea), `away`, `busy` u `offline` (un aro hueco, no un punto gris). - `onError` avisa con la dirección de la foto si no se puede cargar. **Cuándo no** - Varias personas juntas: `AvatarGroup`, que las apila con un «+N» que dice quiénes faltan. - La foto de un producto o de un adjunto: `Thumbnail`. **Teclado**: no es enfocable ni interactivo. **Accesibilidad**: es una imagen (`role="img"`) con el nombre como texto alternativo. Con `state`, el estado va en el nombre («Marta Ruiz (ocupado)»), no solo en el color del punto. La foto lleva `alt=""`, porque el nombre ya lo da el contenedor. `decorative` lo saca del árbol accesible (`aria-hidden`). **Aspecto fino**: variables CSS `--amset-avatar-*`: `-size` (el lado: 24, 30, 36, 48 o 64 px según `size`, de `xs` a `xl`), `-text` (el cuerpo de las iniciales), `-radius` (el del `square`) y `-ring`, el color del borde que lo separa de lo de detrás (el punto de estado y los vecinos de un grupo): cámbialo si el avatar va sobre algo que no es la superficie. Los colores del tono, en `--amset-avatar-tone`, `-tone-soft`, `-tone-solid` y `-tone-ink`. - `name` (obligatoria): `string` — De aqui salen las iniciales y el texto alternativo. Obligatorio. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `content`: `import("react").ReactNode` — En lugar de las iniciales: un icono, un emoji, una letra propia. - `decorative`: `boolean | undefined` — Cuando el nombre ya esta escrito al lado: el avatar deja de anunciarse y no se repite dos veces lo mismo. - `onError`: `((src: string) => void) | undefined` — Avisa de que la foto de `src` no ha cargado, con su direccion. El avatar ya se queda en iniciales por su cuenta: esto es para quien quiere reintentar con otra direccion o dejar constancia. Una foto nueva vuelve a intentarlo. - `shape`: `import("./index.js").AvatarShape | undefined` - `size`: `"sm" | "md" | "lg" | "xs" | "xl" | undefined` — De 24 a 64 px: `xs`, `sm`, `md` (36, por defecto), `lg` y `xl`. - `src`: `string | undefined` - `state`: `import("./index.js").AvatarStatus | undefined` — Punto de presencia en la esquina. Lleva su texto, no solo el color. - `tone`: `"neutral" | "accent" | "secondary" | "tertiary" | "info" | "success" | "warning" | "error" | undefined` — Sin tono, sale del nombre un color estable (`tonoDeNombre`). - `variant`: `import("./index.js").AvatarVariant | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## AvatarGroup — Grupo de avatares (Superficies) Varios avatares apilados, con un «+N» al final para los que no caben. Es una lista de verdad, y el «+N» dice quiénes son los que no se ven: un «+3» a secas no informa. **Cuándo usarlo** - Quién está en algo: el equipo de un proyecto, los asistentes a una cita, quién ha visto un documento. - `people` es la lista, cada persona con su `name` (y `src` si hay foto). `max` decide cuántos se ven antes del «+N» (4 por defecto). Siempre se ve al menos uno. - `size`, `shape` y `variant` son los de `Avatar` y valen para todos. **Cuándo no** - Una sola persona: `Avatar`. - Cuando hay que elegir o repartir personas (asignar, quitar): `SelectableList` o `TransferList`, con los nombres escritos. El grupo solo enseña. **Teclado**: no es enfocable ni interactivo. **Accesibilidad**: es una `ul` con nombre (`label`, obligatorio) y un `li` por avatar, que se anuncia con el nombre de la persona. El «+N» se lee con los nombres que faltan: «y 2 más: Jorge Peña, Sara Lima». **Aspecto fino**: las variables de `Avatar` (`--amset-avatar-size`, `--amset-avatar-text`, `--amset-avatar-ring`…) y `--amset-avatars-overlap`, lo que se pisan: 0,5rem (0,375rem en `xs`; 0,75rem en `lg` y `xl`). El aro, del color de la superficie, es lo que los separa: si el grupo va sobre otro fondo, cambia `--amset-avatar-ring`. - `label` (obligatoria): `string` — Que se esta listando: "Equipo del proyecto", "Asistentes". Obligatorio. - `people` (obligatoria): `readonly import("./index.js").AvatarPerson[]` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `max`: `number | undefined` — Cuantos se ven antes del "+N". - `shape`: `import("./index.js").AvatarShape | undefined` - `size`: `"sm" | "md" | "lg" | "xs" | "xl" | undefined` - `variant`: `import("./index.js").AvatarVariant | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## BackToTop — Volver arriba (Acciones) El botón de subir: aparece en una esquina cuando se ha bajado por la página, la sube de vuelta y **lleva el foco** al principio: al primer `h1` que se vea, o al elemento cuyo id diga `focusTarget`. Aparece a partir de los píxeles de bajada que diga `from` (400 por defecto). Mientras no se ve, no está en el DOM, así que tampoco ocupa una parada del Tab. **Cuándo usarlo** - Páginas largas de verdad: un catálogo con muchas filas, una guía, unas condiciones. - Junto a otro botón flotante, dentro de un `FloatingGroup` para que no se pisen. **Cuándo no** - Una página que cabe en dos pantallas: no aporta nada. - Para saltar a una sección concreta: `TableOfContents`, que también se lleva el foco. - Cualquier otra acción flotante: `FloatingButton`. **Teclado**: cuando aparece es un botón en el sitio del DOM donde se ponga: al final, que es donde el teclado lo espera. Intro o Espacio suben la página y dejan el foco arriba, así que el siguiente Tab sigue desde el principio y no desde la mitad. Subir solo el scroll no es volver arriba. **Accesibilidad**: se llama «Volver arriba» (`label`), o lo que diga `text` si se quiere a la vista. El desplazamiento es suave, salvo con movimiento reducido, que salta sin animación. Si el destino no es enfocable, se le pone `tabindex="-1"` mientras tiene el foco y se le quita al salir. **Aspecto fino**: es un `FloatingButton` de contorno: sin variables propias; se ajusta con las `--amset-button-*` sobre `.amset-button-floating`. En esta ficha, baja dentro del marco de cada historia para que aparezca. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `corner`: `import("./index.js").FloatingCorner | undefined` - `focusTarget`: `string | undefined` — Id de lo que recibe el foco al subir. Sin el, el primer `h1` de la pagina. Subir solo el scroll deja el foco donde estaba y el siguiente tabulador devuelve a media pagina: eso no es volver arriba. - `from`: `number | undefined` — A partir de cuantos pixeles de bajada aparece. Por defecto 400. - `label`: `string | undefined` — El nombre si no lleva texto visible. - `size`: `"sm" | "md" | "lg" | undefined` - `text`: `string | undefined` — Texto visible: entonces el nombre es este. Acepta además los atributos HTML nativos de su elemento raíz. ## Badge — Insignia (Estado) Insignia sobre otra cosa: el contador de una campana, el punto verde de «en línea», el número del carrito. **Cuándo usarlo** - Cuando el dato va ENCIMA de otro elemento, en una esquina. - `dot` para «hay algo nuevo» sin decir cuánto. - `count` para la cifra: con 0 no se pinta nada, salvo con `showZero`, y pasado `max` (99 por defecto) sale «99+». `tone` (`error` por defecto) y `placement` eligen color y esquina. **Cuándo no** - Para una etiqueta que va SOLA en la línea del texto (un estado, una categoría), `Tag`. - Para un número que es el contenido y no un adorno de otro, `Stat`. **Teclado**: no participa. Lo enfocable es lo que lleva debajo. **Accesibilidad**: lo que se lee es `label`, la frase entera («3 mensajes sin leer»), no la cifra: el globo va marcado como decorativo. Un «3» suelto no dice nada, y además el globo puede haberse recortado a «99+». Ojo con el envoltorio: el globo sale de la caja, así que un ancestro con `overflow: hidden` lo corta — es lo primero que mirar si no se ve. **Aspecto fino**: `--amset-badge-background`, `--amset-badge-color` y `--amset-badge-ring`. - `children` (obligatoria): `import("react").ReactNode` — Lo que lleva la insignia encima: un icono, un avatar, un boton. - `label` (obligatoria): `string` — La frase entera que se lee: «3 mensajes sin leer». Obligatoria, porque un «3» suelto no dice nada, y el numero va marcado como decorativo para que no se lea dos veces. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `count`: `number | undefined` — El numero. Con `0` no se pinta nada, salvo que se pida `showZero`. - `dot`: `boolean | undefined` — Solo un punto, sin cifra. Para «hay algo nuevo» sin decir cuanto. - `max`: `number | undefined` — A partir de cuanto pone «+». Por defecto, 99. - `placement`: `"bottom-end" | "bottom-start" | "top-end" | "top-start" | undefined` - `showZero`: `boolean | undefined` - `tone`: `"neutral" | "accent" | "secondary" | "tertiary" | "info" | "success" | "warning" | "error" | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## BarChart — Gráfico de barras (Datos) Las barras de un cuadro de mando: ventas por categoría, pedidos por día, visitas por canal. El dibujo es el adorno y **la tabla es el dato**: debajo va una tabla de verdad, oculta a la vista salvo que se pida. **Cuándo usarlo** - Para comparar cantidades de unas pocas categorías (de 3 a 12) de un vistazo. - `orientation="rows"` cuando los nombres son largos; `tableVisible` cuando el número exacto importa tanto como la forma. - `max` para que dos gráficos que se comparan tengan la misma escala. - `format` para escribir los valores (euros, unidades); sin él, números en el idioma del `LocaleProvider`. `valueName` es la cabecera de la columna de valores en la tabla («Valor» por defecto). - `markers` para una línea de referencia sobre las barras (la media del grupo, un objetivo): cruza todas a su valor, entra en el techo del eje y en la tabla. - `detail` en una barra para una segunda cifra visible junto a su número («+8 pts»); solo en filas, y en columnas se queda en la tabla. - `tone` colorea las barras; `axes` y `values` quitan o ponen el eje y las cifras. **Cuándo no** - Para la evolución en el tiempo, con muchos puntos: `Trend`. - Para las partes de un total: `DonutChart`. - Para una sola cifra con su variación: `Stat`. **Teclado**: no tiene: no hay nada que pulsar. **Accesibilidad**: el dibujo es una imagen (`role="img"`) con el resumen escrito («5 barras, total 7810 €. La mayor, Anillos con 3240 €. La menor, Relojes con 310 €») y la tabla, con cabeceras de fila y de columna, está siempre para el lector de pantalla. Son cajas con alto en porcentaje, no un SVG: se imprimen y se amplían sin deformarse. El eje sube al número redondo de encima del mayor valor. **Aspecto fino**: variables CSS `--amset-bars-*`: `-axis`, `-bar`, `-cap`, `-figure-slot`, `-footer`, `-gap`, `-height`, `-label`, `-name` (lo que ocupa el nombre en filas), `-thickness`. El tamaño mueve el alto del dibujo (8, 11.25 o 15 rem), el grosor de la barra y el eje; `height` sigue mandando si se pasa. - `data` (obligatoria): `readonly import("./index.js").DataBar[]` - `label` (obligatoria): `string` — Que se esta comparando. Obligatoria: un grafico sin titulo no informa. - `axes`: `boolean | undefined` — Rayas de fondo con su numero. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `format`: `((value: number) => string) | undefined` - `height`: `number | undefined` — Alto del dibujo cuando son columnas. - `markers`: `readonly import("./components/bar-chart.js").BarMarker[] | undefined` — Lineas de referencia sobre las barras (la media, un objetivo): entran en el techo del eje y en la tabla. - `max`: `number | undefined` — Techo del eje a mano, para comparar dos graficos con la misma escala. - `orientation`: `"rows" | "columns" | undefined` — `columns` sube desde el suelo; `rows` crece hacia el lado. - `size`: `"sm" | "md" | "lg" | undefined` - `tableVisible`: `boolean | undefined` — Enseña tambien la tabla. Para el lector de pantalla esta siempre. - `tone`: `"neutral" | "accent" | "secondary" | "tertiary" | "info" | "success" | "warning" | "error" | undefined` — El color de la serie, del vocabulario comun (`neutral` para lo secundario). - `valueName`: `string | undefined` — Como se llama la columna de valores en la tabla. - `values`: `boolean | undefined` — El numero encima (o al final) de cada barra. Acepta además los atributos HTML nativos de su elemento raíz. ## BarGroup - `children` (obligatoria): `import("react").ReactNode` — Los botones del grupo: se recorren juntos con las flechas. - `className`: `string | undefined` — Clases CSS propias para el grupo. - `label`: `string | undefined` — Nombre del grupo: "Formato", "Alineación". Se anuncia al entrar. ## BarSeparator - `className`: `string | undefined` — Clases CSS propias para el separador. ## Blockquote — Cita (Tipografía) Una cita en bloque, con una raya a su lado y, si se dice quién lo dijo, la atribución debajo precedida de una raya larga. **Cuándo usarlo** - Lo que dijo un cliente en una reseña, un párrafo de un contrato que se comenta, una frase de alguien con nombre. - `cite` es quién lo dijo, y puede llevar formato o un enlace. `source` es la dirección de donde sale el texto y va al atributo `cite` del elemento. **Cuándo no** - Un aviso o una nota destacada: `Alert`. - Las valoraciones de un producto, con sus estrellas: `RatingSummary`. - Un bloque de código: `CodeBlock`. **Teclado**: no participa. Si `cite` lleva un enlace, ese enlace se enfoca como cualquier otro. **Accesibilidad**: sin `cite` es un `
` y nada más. Con `cite`, la raíz pasa a ser un `
` con la cita dentro y la atribución en su `
`: es la única forma de que el nombre quede unido a la cita sin formar parte de lo citado, que es lo que pasaría dentro del `
`. Los atributos que se le pasen van siempre a la raíz, sea cual sea. El atributo `cite` que escribe `source` no lo enseña ningún navegador ni lo lee ningún lector: si la fuente importa a quien lee, va también a la vista, en `cite`. **Aspecto fino**: `--amset-quote-rule` (el color de la raya; por defecto, el acento) y `--amset-quote-color` (el del texto). - `children` (obligatoria): `import("react").ReactNode` - `cite`: `import("react").ReactNode` — Quien lo dijo. Se pinta debajo, precedido de una raya. - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `source`: `string | undefined` — La direccion de la fuente. Va al atributo `cite` del elemento. Acepta además los atributos HTML nativos de su elemento raíz. ## Board — Tablero (Datos) Un tablero tipo kanban: columnas de tarjetas que pasan de una a otra (pendiente, en curso, en revisión, hecho). Se mueve arrastrando **y** con el teclado, que es la mitad que falta en casi todos los tableros. **Cuándo usarlo** - Para trabajo que avanza por fases y se reparte a la vista: los encargos del taller, las tareas de la tienda. - `limit` en una columna para el trabajo a la vez que admite: pasarse avisa con texto («Por encima del límite»), no bloquea. - `Board` es controlado: recibe `columns` y avisa con `onMove`, con el tablero entero ya movido y el movimiento (`key`, `target`, `position`). `BoardInner` lleva el orden por dentro (parte de `initial`), para una demo o un panel; con `onMove` (opcional) avisa igual de cada movimiento, para guardarlo sin tener que llevar el estado. **Cuándo no** - Para reordenar una sola lista: `SortableList`. - Para repartir elementos entre dos listas (permisos, categorías): `TransferList`. - Para el estado de un único proceso: `Steps`. **Teclado**: la primera tarjeta de cada columna es una parada de Tab; desde ahí, las flechas arriba y abajo recorren las tarjetas de la columna, izquierda y derecha pasan a la de al lado (al mismo puesto o a la última), e Inicio y Fin van a la primera y a la última. Con una tarjeta enfocada, **Control (o Cmd) y las flechas** la mueven: izquierda y derecha la cambian de columna, arriba y abajo de puesto. El foco se va con la tarjeta. En el borde no se mueve ni se pierde el foco. **Accesibilidad**: es una sección con nombre obligatorio (`label`) y cada columna se llama por su título y su cuenta («En curso, 2 tarjetas»). Después de cada movimiento se anuncia dónde ha caído («Pulir el collar Luna, a En revisión, puesto 2 de 2»): sin el puesto y el total, mover con el teclado es a ciegas. La línea de ayuda de arriba explica las teclas, y el agarre de puntos es un dibujo, no un botón. **Aspecto fino**: variables CSS `--amset-board-*`: `-card-padding`, `-column`, `-description`, `-detail`, `-gap`, `-name`, `-padding`, `-radius`, `-title`. El tamaño mueve el ancho de la columna (12, 15 o 18 rem), el relleno de la tarjeta y los cuerpos de letra. - `columns` (obligatoria): `readonly import("./index.js").BoardColumn[]` - `label` (obligatoria): `string` — De que es el tablero. Obligatoria: nombra la region entera. - `onMove` (obligatoria): `(columns: readonly import("./index.js").BoardColumn[], move: import("./index.js").BoardMove) => void` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `empty`: `string | undefined` - `hint`: `string | undefined` — La linea de instrucciones. Cambiala si tu app usa otras teclas. - `size`: `"sm" | "md" | "lg" | undefined` Acepta además los atributos HTML nativos de su elemento raíz. ## BoardInner - `initial` (obligatoria): `readonly import("./index.js").BoardColumn[]` — Las columnas y tarjetas de partida. A partir de ahi, el orden lo guarda el propio tablero. - `label` (obligatoria): `string` — De que es el tablero. Obligatorio: es su nombre para el lector de pantalla. - `className`: `string | undefined` — Clases CSS propias para el tablero. - `empty`: `string | undefined` — Lo que se ve en una columna sin tarjetas. - `hint`: `string | undefined` — Como se mueven las tarjetas, encima del tablero. - `onMove`: `((columns: readonly import("./index.js").BoardColumn[], move: import("./index.js").BoardMove) => void) | undefined` — Avisa de cada movimiento, con el tablero ya cambiado y lo que se ha movido: para guardarlo. Solo avisa: el orden lo sigue llevando el propio tablero. ## Breadcrumbs — Migas (Navegación) La ruta desde la portada hasta la pantalla en la que estás: «Inicio › Catálogo › Anillos › Anillo Aurelia». Todas las migas son enlaces menos la última, que es donde estás. **Cuándo usarlo** - En pantallas que cuelgan de otras (la ficha de un producto dentro de una categoría, una factura dentro de un cliente), para subir a cualquier nivel de un salto. - Con `onNavigate` cuando la navegación la lleva el enrutador del proyecto: se llama con la `key` de la miga pulsada **en lugar de** seguir el `href` (el clic del navegador se cancela). Con Ctrl, Cmd, Mayúsculas o Alt, o con el botón central, la miga se abre en otra pestaña o ventana y `onNavigate` no se llama. Por eso las migas llevan `href` también con enrutador: sin él no se pueden abrir aparte ni copiar. Si la aplicación ya registra su enrutador en la raíz con el proveedor de enrutado de la biblioteca, las migas navegan con él y `onNavigate` sobra. - `renderCrumb` para pintar cada miga a tu manera (un icono delante); se sigue anunciando por su `label`. **Cuándo no** - En la portada o en una pantalla de primer nivel: una miga sola no orienta a nadie. - Encima del título de una pantalla con sus acciones: `PageHeader` ya las pinta con su `crumbs`. - Para las fases de un proceso (compra, alta): eso es `Steps`. **Teclado**: Tab recorre las migas que son enlace e Intro las sigue (con `onNavigate`, Intro también lo lleva el enrutador). La última no es un enlace y no coge el foco. **Accesibilidad**: es un `nav` con nombre («Ruta de navegación», o lo que diga `label`), así que es un punto de referencia al que se puede saltar. La miga actual lleva `aria-current="page"`: el lector de pantalla dice «página actual» en vez de leer un enlace más. Los separadores son iconos decorativos. **Aspecto fino**: variables CSS `--amset-crumbs-*`: `-font`, `-gap`, `-padding`, `-radius`, `-separator`. El tamaño mueve el cuerpo de letra, el hueco y el separador. - `crumbs` (obligatoria): `readonly import("./index.js").Crumb[]` - `className`: `string | undefined` — Se une a las clases de la biblioteca, no las sustituye. - `label`: `string | undefined` — Lo que se anuncia al llegar. Por defecto, "Ruta de navegación". - `onNavigate`: `((key: string) => void) | undefined` — Para que navegue el enrutador del proyecto y no el navegador. Si se pasa, el clic normal y el Intro en una miga llaman aquí con su `key` **en lugar de** seguir el `href`: el clic del navegador se cancela. Con Ctrl, Cmd, Mayúsculas o Alt, o con el botón central, la miga se abre en otra pestaña o ventana y aquí no se llama. Una miga sin `href` solo avisa. - `renderCrumb`: `((crumb: import("./index.js").Crumb, state: { readonly current: boolean; }) => import("react").ReactNode) | undefined` — Pinta cada miga: un icono delante, un nombre con un distintivo. La miga sigue llamandose por su `label` para el lector de pantalla. `current` es la ultima, la pagina en la que se esta. - `size`: `"sm" | "md" | "lg" | undefined` — El cuerpo de letra y el hueco entre migas: xs, sm (por defecto) o base. Acepta además los atributos HTML nativos de su elemento raíz. ## Button — Botón (Acciones) El botón de siempre: hace algo en la misma pantalla (guardar, enviar, borrar, abrir un diálogo). **Cuándo usarlo** - Para una acción. Si lo que hace es llevar a otra página, es un `ButtonLink`: se abre en otra pestaña y el lector de pantalla dice «enlace». - Un solo botón `solid` por pantalla o por diálogo: es la acción principal. El resto, `outline`, `soft` o `ghost`. - `tone="error"` para lo que borra o da de baja, mejor dentro de un `ConfirmAction`. - `startIcon` y `endIcon` para acompañar el texto; `fullWidth` para que ocupe todo el ancho; `shape="pill"` para las esquinas redondas. **Cuándo no** - Solo con icono: `IconButton`, que obliga a ponerle nombre. - Varias acciones que pesan lo mismo: `SplitButton` o `ActionMenu`. **Teclado**: es un `