@roaxai/design-system
v0.1.4
Published
ROAX design system: tokens, primitivas y marca compartidos por los frontends
Downloads
0
Readme
@roaxai/design-system
El sistema de diseño de ROAX: los tokens, las primitivas y la marca que
comparten frontend-auth, admin y frontend-platform. Lo visual vive acá;
cada front consume, no redefine.
El diseño sale del canvas «Inicio de sesión ROAX» (86 pantallas). Los valores de este paquete están tomados de ahí, no inventados.
Contenido
Instalación
El paquete es público en npm, así que no hace falta token, ni .npmrc, ni
configurar nada:
pnpm add @roaxai/design-systemPúblico no quiere decir libre: la licencia es UNLICENSED — el código se lee,
pero no se concede permiso de uso a terceros. Se publica así porque un registro
público es la forma más simple de que lo instalen nuestros frontends, nuestras
VMs y el CI sin credenciales dando vueltas.
Uso
Los estilos se importan una sola vez, en la raíz de la app:
import '@roaxai/design-system/index.css'Y después:
import { AuthShell, Button, Field, Text, Title } from '@roaxai/design-system'
export function SignIn() {
return (
<AuthShell logo={<Logo />} footer={<SignUpLink />}>
<Title>Hola de nuevo</Title>
<Text>Entra con el correo de tu cuenta.</Text>
<form className="mt-9 flex flex-col gap-4.5">
<Field label="Correo" type="email" autoComplete="email" />
<Button type="submit">Continuar</Button>
</form>
</AuthShell>
)
}No hace falta conocer ninguna clase del sistema: Title ya trae el punto rojo
de la marca, Field ya pone el error debajo del campo, Button ya bloquea el
doble envío.
El logo tiene su propia entrada, porque sus dos imágenes son 33 KB y en el índice principal se las llevaría también quien nunca lo renderiza:
import { Logo } from '@roaxai/design-system/logo'
<Logo /> // sigue el tema
<Logo tone="ink" /> // fijo, para un correo o una capturaQué hay adentro
23 componentes, uno por carpeta, cada uno con su implementación, su test,
su historia de Storybook y su index.ts.
| Familia | Componentes |
| --- | --- |
| Estructura | AuthShell |
| Tipografía | Title · Text · Link |
| Formulario | Button · Field · Input · Label · Checkbox · Select · OptionMenu · CodeInput · SocialButton |
| Retroalimentación | Alert · Spinner |
| Presentación | Avatar · Pill · Separator · Mark |
| Marca | BrandDot · BrandCurve · BrandGlow · EnvelopeIcon · PhoneIcon · OffChartIcon |
| Marca (entrada aparte) | Logo |
Más tres hojas: theme.css (los tokens), base.css (la base del documento) e
index.css (las dos más Tailwind).
Decisiones
Los tokens son semánticos y van en pares. Quien usa el sistema elige un rol
—primary, destructive, muted— y nunca un color; el par -foreground
garantiza el contraste sobre su fondo.
Hay dos rosas a propósito. --color-primary (#D6176B, 5,0:1) es el que
lleva texto: botones y enlaces. --color-brand-pink (#ED1E78) no llega a
AA y queda para la curva, el anillo de foco y los acentos sin texto.
El contraste se mide, no se anota. contrast.test.ts calcula el ratio de
11 pares en los dos temas y falla bajo 4,5:1. Ya encontró tres defectos del
canvas: el rojo de error sin versión oscura (3,89:1), el botón deshabilitado
con texto blanco sobre rosa pálido (1,92:1) y el aviso amarillo sin modo
oscuro.
Cada caso de prueba declara con qué mutación se pone roja, en una línea. Un caso sin esa línea no entra.
La curva se estira; su punto, no. El SVG usa preserveAspectRatio="none"
para que el trazo cruce la página, y ese estiramiento es no uniforme. El punto
del sello vive fuera del SVG, con el tamaño en píxeles y la posición en
porcentaje, así nunca se deforma. Y el trazo no lleva
vector-effect="non-scaling-stroke": con él, el patrón de guiones se resuelve
en píxeles de pantalla y la animación de dibujo deja el trazo cortado antes de
llegar al punto.
Lo que se publica es sólo lo que alguien usa. El fuente viaja para que los
mapas de declaración resuelvan y se pueda saltar a la definición; los tests,
las historias y las imágenes ya inlineadas no, porque nadie los lee desde
node_modules. El recorte va en src/.npmignore, que es donde funciona: el
campo files de npm no admite patrones negados, y un .npmignore en la raíz
no lo sobrescribe — en un subdirectorio, sí.
Este paquete jubila a @roax/ui (frontend-platform/packages/ui), que
está construido sobre CoreUI Pro, no lo consume nadie y quedó fuera con la
decisión de sacar CoreUI.
Desarrollo
Todo corre en contenedor (R13):
pnpm install
pnpm storybook # la galería, en el 6310
pnpm test # vitest
pnpm lint
pnpm typecheck
pnpm buildCI
| Workflow | Cuándo | Estado |
| --- | --- | --- |
| ci.yml | push a main y cada PR | activo |
| chromatic.yml | push a main y cada PR | apagado hasta que exista el secreto CHROMATIC_PROJECT_TOKEN |
| publish.yml | tag v* | publica en npm público por Trusted Publishing; exige PUBLISH_ENABLED=true |
Los dos apagados están completos en código y arrancan solos al cargar su secreto o su variable, sin editar ningún archivo.
El de Chromatic condiciona el paso y no el job porque el contexto secrets
no está disponible en jobs.<id>.if; el de publicación sí condiciona el job,
porque vars sí lo está.
Publicar
La versión la manda el tag:
# 1. subir la versión en package.json
# 2. commit
git tag v0.2.0
git push origin v0.2.0El workflow comprueba que el tag esté en main y que coincida con el
package.json, corre lint, typecheck, tests y build, y publica.
No hay ningún token. La publicación usa Trusted Publishing: el runner se
identifica ante npm por OIDC, con el permiso id-token: write, y npm lo
reconoce porque en el paquete está declarado este repositorio y este archivo de
workflow como editor de confianza. No hay nada que guardar, rotar ni filtrar.
Dos consecuencias que conviene saber antes de tocar:
- El nombre
publish.ymles parte de la configuración. El editor de confianza apunta a ese archivo; renombrarlo corta la publicación. - El paso de publicar usa
npmy nopnpm. Trusted Publishing pidenpm >= 11.5.1—node 22 trae 10.9.8, así que el workflow lo actualiza— y pnpm implementapublishpor su cuenta sin documentar OIDC. El resto del repo sigue con pnpm.
