Guía técnica y de uso
Un paquete Angular privado con design tokens, tema, iconos y componentes de marca. Se desarrolla una vez, se publica en el registro privado de GitLab y se consume desde cada proyecto del cliente — con una identidad visual idéntica y garantizada.
En una frase: es la fuente única de verdad de la interfaz del cliente. Cada botón, campo o color vive en un solo sitio versionado; los proyectos lo instalan como dependencia. Un cambio se hace una vez y se propaga a todos con una nueva versión.
Qué es y qué problema resuelve
El objetivo de negocio: que todos los proyectos del cliente se vean iguales, sin reinventar ni mantener la interfaz por separado en cada repositorio.
Arquitectura
La librería no es solo componentes: es un sistema en capas donde cada nivel se apoya en el anterior. Esta es la clave de que todo se vea coherente.
La base: la paleta, tipografía, espaciados, radios y sombras como design tokens. Un módulo TypeScript es la fuente de verdad de los valores; de ahí se derivan el preset de PrimeNG (que tinta todos sus componentes de azul de marca) y las utilidades de Tailwind. Ningún componente hardcodea un color.
La familia de iconos de marca (SVG propios, optimizados) se sirve inline con <bui-icon>. El trazo usa currentColor, así que cada icono hereda el color del texto que lo rodea. Un registro central los carga al arrancar; un proyecto puede añadir iconos propios sin tocar la librería.
Componentes de presentación (standalone, OnPush, signals) que envuelven PrimeNG tras una API de marca estable — o migran componentes propios. El equipo consume <bui-button> en vez de repetir la configuración cruda de PrimeNG por todos lados.
El motor del tema
Este es el corazón técnico: cómo un solo azul de marca (#1c59ba) llega de forma consistente a PrimeNG, a Tailwind y a los componentes.
| Pieza | Rol |
|---|---|
tokens.ts | Fuente de verdad en TypeScript de los valores crudos (rampa de azul, neutros, estado). Con tests que verifican contraste AA. |
BrasiliaPreset | definePreset(Aura, …): sobrescribe el primitivo blue con la rampa de marca, de modo que la variable --p-primary-* de PrimeNG resuelve al azul Expreso. Ajusta botón y select. |
_tokens.scss | Replica los tokens como variables CSS (--color-*, --space-*, --radius-*) que consumen los componentes. |
@theme (Tailwind) | Puente que genera las utilidades oficiales (bg-primary, rounded-sm, text-body) desde esos mismos valores. |
| Orden de capas CSS | @layer theme, base, primeng, components, utilities: garantiza que los estilos del kit ganen a los de PrimeNG sin usar !important. |
Registrar el tema en una app es una sola llamada:
import { providePrimeNG } from 'primeng/config';
import { BrasiliaPreset, PRIMENG_ES } from '@aspsols/brasilia-ui';
providePrimeNG({
translation: PRIMENG_ES,
theme: { preset: BrasiliaPreset },
});
Catálogo
Todos son standalone: se importan y se usan. Cada uno trae su documentación viva en Storybook (con código copiable) y sus pruebas. Despliega cada uno para ver su API.
Envuelve p-button + BrasiliaPreset tras una API de variant, en vez de combinar severity/outlined/text a mano.
<!-- variantes, icono del catálogo, estados -->
<bui-button label="Guardar" variant="primary" />
<bui-button label="Cancelar" variant="secondary" />
<bui-button label="Eliminar" variant="danger" [loading]="saving()" />
<bui-button label="Nueva solicitud" icon="plus" />
variant | primary · secondary · tertiary · danger |
size | small · normal · large |
icon / iconPos | Icono del catálogo (izquierda/derecha) |
loading · disabled · fullWidth · type | Estados y tipo (submit) |
Campo completo: label + input + error/ayuda, con los id de accesibilidad enlazados. Implementa ControlValueAccessor, así que funciona con formControlName.
<bui-input
label="Email"
type="email"
formControlName="requesterEmail"
[error]="errorFor('requesterEmail')"
required />
label · required | Etiqueta y asterisco de requerido |
type | text · email · password · number · tel · url · search |
error · hint | Mensaje de error (marca inválido) o ayuda |
readonly · disabled | Estados |
Sobre p-select / p-multiSelect. Las variantes se controlan por input(): básico, filtrable, panel de tabla y multiselección. ControlValueAccessor + proyección de plantillas para filas a medida.
<!-- panel de tabla: basta con optionMeta + rótulos -->
<bui-select
[options]="vehiculos()"
optionLabel="placa" optionMeta="numeroBus"
headerLabel="Placa" metaLabel="Bus"
[filter]="true" formControlName="placa" />
multiple | Simple o multiselección |
optionMeta + headerLabel/metaLabel | Panel de tabla de dos columnas, sin plantillas |
filter · filterBy | Buscador interno |
invalid · errorText · loading | Estados |
plantillas #item/#selectedItem | Filas personalizadas proyectadas |
Píldora de estado con 5 tonos semánticos (neutro, info, éxito, aviso, peligro). Cada proyecto la envuelve para mapear sus propios estados de dominio al tono correcto, sin duplicar el estilo.
<bui-status-pill label="Aprobado" tone="success" />
<bui-status-pill label="Pendiente" tone="warning" />
Renderiza inline un SVG del catálogo por su name. Hereda el color del texto (currentColor) y admite tamaños sm/md/lg o un valor CSS.
<bui-icon name="bus" size="lg" />
// icono propio de un proyecto, sin tocar la librería
iconRegistry.register('mi-icono', '<svg>…</svg>');
El catálogo incluye además bui-card (superficie), bui-datepicker (fecha en español) y bui-page-subheader (cabecera de página). 7 componentes, 55 pruebas en verde.
Para el equipo
Tras autenticar el scope @aspsols contra el registro de GitLab (una vez, con un token):
pnpm add @aspsols/brasilia-ui
En el styles.scss de la app. Incluye Tailwind, los tokens, el puente @theme y el chrome de los overlays:
@use '@aspsols/brasilia-ui/styles';
En app.config.ts (ver el bloque de «El motor del tema» arriba).
Se importan como cualquier standalone y se usan en la plantilla:
import { ButtonComponent } from '@aspsols/brasilia-ui';
// …
<bui-button label="Enviar" type="submit" [loading]="saving()" />
Decisiones técnicas
Las preguntas que un revisor técnico hará, respondidas.
Componentes envoltura (wrappers), no forks de PrimeNG. Exponemos variant="primary" en vez de la mezcla cruda de PrimeNG. Ventaja: una API de marca estable que aísla a las apps de los cambios internos de PrimeNG, y un punto único donde encapsular variantes, estados y accesibilidad.
Estilos encapsulados salvo los overlays. Los estilos de cada componente van encapsulados (no se escapan). La excepción son los paneles que PrimeNG monta en <body> (appendTo="body", para que no los recorte un contenedor): esos deben ser globales y viajan en la hoja de estilos del kit. Es un híbrido deliberado, no una fuga.
Angular y PrimeNG como peerDependencies. La librería no empaqueta Angular ni PrimeNG: los declara como «pares». La app consumidora manda la versión; así no hay duplicados ni conflictos de versión.
Ingeniería y calidad
| Herramienta | Rol |
|---|---|
| Angular 21 | Framework de las apps del cliente; componentes standalone, OnPush y signals. |
| PrimeNG 21 + @primeuix/themes | Componentes ricos ya resueltos y el motor de tema (preset). |
| Tailwind v4 | Utilidades de layout y espaciado, atadas a los tokens. |
| Storybook 10 | Documentación viva: cada componente con sus estados y código copiable. |
| Vitest | Pruebas unitarias; un componente no se da por terminado sin ellas en verde. |
| ng-packagr | Empaqueta la librería en el formato estándar (FESM + tipos) que se publica. |
| pnpm · Node 22 | Gestor y runtime, fijados para builds reproducibles. |
Definición de hecho por componente: API con input()/output(), standalone + OnPush, cero valores hardcodeados (todo por token), story con estados y spec en verde.
Distribución
El componente se construye y aprueba en Storybook, con pruebas.
ng-packagr genera el paquete en dist/.
Se sube el número (SemVer) y se publica al GitLab Registry.
Cada proyecto actualiza a la nueva versión cuando le conviene.
El versionado semántico (mayor.menor.parche) le dice a cada proyecto si una actualización trae cambios que rompen (mayor), funciones nuevas (menor) o solo correcciones (parche). Nadie se actualiza a la fuerza.
Adopción en producción
La versión 0.1.0 está publicada en el GitLab Registry y es el primer proyecto que la instala como dependencia real — no un enlace local, sino el paquete descargado del registro.
1664)Relevobui-button y bui-status-pillbui-button en la app, en una veintena de pantallasbui-button reemplaza a p-button en botones de acción y diálogos de toda la app.bui-status-pill: el chip de estado propio ahora envuelve el del kit, con los 5 tonos semánticos unificados..npmrc con token de GitLab.PRIMENG_ES local).p-button crudos que aún quedan en algunas plantillas.input, select, card, datepicker y subheader.Estado del proyecto
Workspace, librería, azul de marca y tokens, Storybook funcionando.
36 iconos de marca como bui-icon, con galería y pruebas.
7 componentes migrados (botón, input, select, chip, tarjeta, datepicker, subheader), 55 pruebas en verde.
v0.1.0 publicada en el Registry. Relevo Tarjetón ya consume el paquete: botón y chip de estado adoptados; falta el tema y el resto de componentes.
Buscador, estado vacío, diálogo de confirmación y más.