tdn-timeline
Paquete: @tiendana/ngx-core/ui
Cronología vertical de lo que le pasó a un registro, en orden, y qué tan avanzado va: el ciclo de vida de un pedido, los intentos de un pago, la auditoría de una importación. tdn-timeline es el contenedor; cada tdn-timeline-step dibuja su marcador y el tramo de riel hasta el siguiente paso.
Disponible desde @tiendana/ngx-core 0.8.12. Úselo cuando la pantalla reporta eventos. Para un flujo que el usuario recorre use tdn-stepper; para un único estado sin historia use tdn-status.
Características
✅ Seis estados con marcador propio: done, current, pending, warning, failed, neutral
✅ Hasta cuatro líneas por paso: título, detalle, vía y nota
✅ Modo dense para columnas angostas
✅ Modo grid para alinear acciones junto a cada título
✅ Nombre accesible que dice el estado con palabras, traducible
Selectores
tdn-timeline y tdn-timeline-step. Ambos se importan de @tiendana/ngx-core/ui como TdnTimelineComponent y TdnTimelineStepComponent.
API de tdn-timeline
Inputs
| Input | Tipo | Default | Descripción |
|---|---|---|---|
dense | boolean | false | Gutter y espaciado más ajustados (--timeline-indent 19px, --timeline-step-pad 5px). Acepta el atributo sin valor |
translations | Partial<TdnTimelineTranslations> | undefined | Reemplaza las palabras de estado del nombre accesible; solo cambian las claves dadas |
Sin outputs. La señal pública text (computed) combina TDN_TIMELINE_TRANSLATIONS con translations y la leen los pasos.
API de tdn-timeline-step
Inputs
| Input | Tipo | Default | Descripción |
|---|---|---|---|
title | string | '' | Qué pasó, ya traducido. Primera línea y primera parte del nombre accesible. Déjelo vacío si usa el slot tdn-timeline-title |
detail | string | '' | Cuándo: una fecha formateada o una palabra como «Pendiente». En cifras tabulares |
via | string | '' | Qué lo originó: «por webhook», «desde Admin», un nombre de usuario. En cursiva |
note | string | '' | Línea extra en color de error bajo el paso, para el motivo de un fallo |
state | TdnTimelineState | 'pending' | Qué tan avanzado está el evento; elige el marcador y la palabra de estado |
grid | boolean | false | Distribuye el paso en las columnas de --timeline-grid-cols. Acepta el atributo sin valor |
Estados
| Estado | Marcador | Palabra hablada | Uso |
|---|---|---|---|
done | Relleno natura | «completado» | Ocurrió y salió bien |
current | Relleno azul info, pulsa | «en curso» | En curso ahora mismo; a lo sumo un paso y nunca un estado terminal |
pending | Hueco con anillo punteado gris | «pendiente» | Aún no ocurre |
warning | Ámbar | «con novedad» | Ocurrió con algo digno de revisar (reembolso parcial, reintento) |
failed | Rojo | «falló» | Salió mal; acompáñelo de note con el motivo |
neutral | Relleno gris | «registrado» | Ocurrió y no hay resultado que reportar (nota, cancelación, edición manual) |
Tipos TdnTimelineState y TdnTimelineTranslations
export type TdnTimelineState = 'done' | 'current' | 'pending' | 'warning' | 'failed' | 'neutral';
export type TdnTimelineTranslations = Record<TdnTimelineState, string>;
// Valores por defecto (TDN_TIMELINE_TRANSLATIONS), una constante y no un token de inyección
{
done: 'completado',
current: 'en curso',
pending: 'pendiente',
warning: 'con novedad',
failed: 'falló',
neutral: 'registrado',
}
Contenido proyectado
Solo en tdn-timeline-step:
- Contenido por defecto: se dibuja bajo el texto del paso (un enlace, un botón pequeño, una cita del payload).
[tdn-timeline-title]: un elemento con ese atributo se proyecta en lugar del título, para un título que es un badge o un control. Dejetitlevacío o se dibujan ambos.
<tdn-timeline-step detail="12 sep, 10:41" state="current">
<tdn-status tdn-timeline-title tone="pending" label="En revisión" />
</tdn-timeline-step>
Distribución en grid
Con grid, el paso es una cuadrícula CSS sobre --timeline-grid-cols (por defecto 1fr). El texto propio del paso (slot o title, luego detail y via) es un solo bloque en la columna 1, fila 1; el contenido proyectado se coloca automáticamente en las columnas restantes de la fila 1. note ocupa la fila 2 en todas las columnas. Un elemento proyectado puede ubicarse por sí mismo con grid-column y grid-row. Cuando el paso mide 400px o menos (container query) vuelve a apilarse en el orden del código.
Propiedades CSS
Se declaran en el host tdn-timeline y los pasos las heredan. Defínalas sobre el propio elemento tdn-timeline: un valor puesto en un ancestro queda tapado por la declaración del host. Ganan un style en línea o una regla más específica que :host, como tdn-timeline.mi-clase en la hoja del componente consumidor; una única clase global empata con :host y pierde.
| Propiedad | Default | Descripción |
|---|---|---|
--timeline-indent | 22px (19px con dense) | Ancho del gutter de marcadores |
--timeline-marker | 11px | Diámetro del marcador; el riel permanece centrado en él |
--timeline-step-pad | 7px (5px con dense) | Padding vertical de cada paso |
--timeline-grid-cols | 1fr | grid-template-columns de los pasos con grid. No la declara el host: puede ir en la línea de tiempo, en un paso o en cualquier ancestro |
Clases: .tdn-timeline--dense en el host del contenedor; en cada paso .tdn-timeline__step, .tdn-timeline__step--{state} y .tdn-timeline__step--grid. Elementos internos: .tdn-timeline__marker, __head, __title, __detail, __via, __note, __body.
No requiere configuración para .scheme-dark: los anillos de los marcadores se mezclan hacia el color del texto (3:1, WCAG 1.4.11) y el riel es el color del texto al 22%.
Accesibilidad
- El host es
role="list"y cada pasorole="listitem". - Como los marcadores se distinguen solo por color y relleno (WCAG 1.4.1), el nombre accesible de cada paso dice el estado con palabras: «título. estado. detalle. vía. nota», por ejemplo «Pago. en curso. Esperando a la pasarela. por webhook».
- Los marcadores son
aria-hidden. El pulso decurrentse detiene conprefers-reduced-motion: reduce; conforced-colorsmarcadores y riel usanCanvasText. - Un
title="…"estático no se vuelve tooltip: el paso retira ese atributo.
- Los pasos deben ser hermanos directos dentro de
tdn-timeline: qué paso dibuja el riel y cuál quita su padding se decide con:first-of-typey:last-of-type. Envolver cada paso en su propio elemento hace que todos sean primero y último, y el riel desaparece.@fory<ng-container>no agregan elemento y son seguros. - Un
tdn-timeline-stepfuera de untdn-timelineno tiene gutter y su marcador queda fuera de su caja. pendingpromete algo por venir. Para un evento ocurrido sin resultado que reportar useneutral.- Solo
currentpulsa. No lo use en un estado terminal. - El nombre accesible se arma solo con los inputs: lo proyectado en el slot
tdn-timeline-titleo en el cuerpo no forma parte de él.
Ejemplos y Demos
Básico
Ver código
Denso
Ver código
Con acciones alineadas en columna
Ver código
Intentos de pago con palabras de estado en inglés
<tdn-timeline [translations]="{ done: 'completed', failed: 'failed', current: 'in progress' }">
@for (attempt of attempts(); track attempt.id) {
<tdn-timeline-step [title]="attempt.gateway" [detail]="attempt.createdAt | date: 'short'"
[state]="attempt.approved ? 'done' : 'failed'" [note]="attempt.error ?? ''" />
}
</tdn-timeline>