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 por máquina — ver Primera vez: configurar el acceso más abajo):
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()" />
Para el equipo · primera vez
El paquete no vive en el npm público, sino en el registro privado de GitLab (proyecto 1666). Si al instalar te sale ERR_PNPM_FETCH_404 · registry.npmjs.org/@aspsols…: Not Found o No authorization header was set, es porque todavía no configuraste el acceso. Sigue estos 5 pasos en orden — se hacen una sola vez por máquina.
La idea, en dos archivos. El acceso se reparte en dos archivos .npmrc distintos, y esto es la clave para que funcione:
① El del proyecto (en la carpeta del frontend) → solo dice dónde buscar el paquete. Se puede subir al repo.
② El de tu usuario (en tu carpeta personal) → guarda tu token. Es personal y nunca se sube.
⚠️ Importante (pnpm v11): el token no puede ir en el .npmrc del proyecto — las versiones nuevas de pnpm lo ignoran por seguridad (para que no se filtre al subirlo al repo). Por eso va en el archivo de tu usuario. Si lo pones en el del proyecto verás el aviso Ignored project-level auth setting… environment variables are not expanded y no autenticará.
Cada persona genera su propio token — es personal y no se comparte. Abre este enlace (te lleva directo a la página de tokens):
https://git.aspsols.com/-/user_settings/personal_access_tokens
npm-brasilia-ui (o el nombre que quieras).read_api. Con eso basta para instalar. (Si aparece read_package_registry aparte, márcalo también.)⚠️ GitLab te muestra el token una sola vez. Cópialo apenas aparezca (empieza por glpat-…). Si cierras la página sin copiarlo, no lo vuelves a ver y toca crear otro. Guárdalo un momento en el bloc de notas: lo usarás en el paso 3.
.npmrc del proyecto (solo el registro)Este archivo dice «el scope @aspsols se descarga de GitLab». Abre la terminal en la raíz de tu frontend (donde está el package.json) y corre una línea según tu sistema. Crea un archivo .npmrc con una sola línea:
Windows · PowerShell
'@aspsols:registry=https://git.aspsols.com/api/v4/projects/1666/packages/npm/' | Out-File -FilePath .npmrc -Encoding utf8
WSL / Linux / Mac
echo '@aspsols:registry=https://git.aspsols.com/api/v4/projects/1666/packages/npm/' > .npmrc
Este archivo es seguro de subir al repositorio (no contiene tu token). De hecho, lo ideal es que quede versionado para que todo el equipo lo tenga sin repetir este paso.
.npmrc de tu usuarioAquí va tu token, en el .npmrc de tu carpeta personal (no la del proyecto). Reemplaza glpat-TU_TOKEN_AQUI por el token real del paso 1 y corre la línea de tu sistema:
Windows · PowerShell
Add-Content -Path "$HOME\.npmrc" -Value "//git.aspsols.com/api/v4/projects/1666/packages/npm/:_authToken=glpat-TU_TOKEN_AQUI"
WSL / Linux / Mac
echo '//git.aspsols.com/api/v4/projects/1666/packages/npm/:_authToken=glpat-TU_TOKEN_AQUI' >> ~/.npmrc
WSL tiene su propia carpeta personal, separada de Windows. Si vas a correr pnpm dentro de WSL, el token debe estar en el ~/.npmrc de WSL (con el comando de Linux de arriba), no en el de Windows. Si trabajas en los dos, ponlo en ambos.
No uses pnpm config get con el token: da el error option is protected a propósito (los tokens no se pueden leer así). En su lugar, abre el archivo y comprueba que aparece la línea con tu glpat-…:
Windows · PowerShell
Get-Content "$HOME\.npmrc"
WSL / Linux / Mac
cat ~/.npmrc
Si ves la línea //git.aspsols.com/...:_authToken=glpat-…, el token está bien guardado. Si no aparece o el archivo está vacío, repite el paso 3.
Parado en la raíz del proyecto:
pnpm install
Ahora pnpm encuentra @aspsols/brasilia-ui en GitLab (paso 2) y se autentica con tu token (paso 3). Debe terminar en Done, sin 404 ni 401. ✅
Usa pnpm install, no npm install — este proyecto usa pnpm. Si necesitas fijar la versión, es pnpm add @aspsols/brasilia-ui@0.1.1, que la escribe en el package.json como "^0.1.1".
| Mensaje que ves | Qué pasa | Solución |
|---|---|---|
404 Not Found · registry.npmjs.org/@aspsols… | Falta el .npmrc del proyecto, o pnpm no lo está leyendo. | Repite el paso 2 parado en la raíz del proyecto (donde está el package.json). |
| Ignored project-level auth setting · environment variables are not expanded | Pusiste el token en el .npmrc del proyecto; pnpm v11 lo ignora por seguridad. | Borra la línea del _authToken del .npmrc del proyecto (deja solo la del registro) y ponlo en el de tu usuario: paso 3. |
| 401 · No authorization header was set | Falta el token en el .npmrc de tu usuario, o está mal escrito. | Revisa con el paso 4 que la línea del token esté; si no, repite el paso 3. |
| 403 Forbidden | El token no tiene permiso de lectura del registro. | Crea uno nuevo con el scope read_api marcado (paso 1). |
| option is protected, can not be retrieved | Es normal: los tokens no se leen con config get. | No es un error. Verifica con Get-Content / cat (paso 4). |
| No aparece «Access Tokens» en GitLab | El admin deshabilitó los tokens personales. | Pide un Deploy Token del proyecto 1666 como alternativa. |
Remove-Item: no se puede quitar… el directorio no está vacío / ruta muy larga | El proyecto está en OneDrive: rutas de node_modules que superan el límite de 260 caracteres de Windows. | Mueve el proyecto fuera de OneDrive (ej. C:\Projects\…). Para borrar node_modules: mkdir vacia; robocopy vacia node_modules /MIR; rmdir vacia,node_modules. |
No pongas el proyecto dentro de OneDrive. Node genera miles de archivos en node_modules; OneDrive los sincroniza (lento, con conflictos) y alarga las rutas hasta romper el límite de Windows. Trabaja desde una ruta corta como C:\Projects\mi-proyecto.
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.