ng-hub-ui-ds

La base de design tokens compartida de la familia ng-hub-ui: las variables CSS --hub-ref-* (primitivas) y --hub-sys-* (semánticas), con claro/oscuro y 8 temas. Impórtala una vez y toda la familia lee la misma paleta.

¿Qué es y para qué sirve?

Su función es homogeneizar y cablear las variables de estilo a lo largo de todas las bibliotecas de la familia. Cada librería se tematiza con variables --hub-* pero no las define: las consume. Este paquete es la fuente de verdad única que las conecta, de modo que:

  • Una sola paleta alimenta panels, forms, calendar, board… a la vez.
  • Re-tematizas una vez (un token) y el cambio se propaga a toda la familia.
  • Modo oscuro y 8 temas listos, conmutables con un atributo.
  • La usas también en tu propio CSS, así tu UI casa con los componentes.

El cableado se está desplegando biblioteca a biblioteca: más abajo, en la familia, está el estado de integración de cada una. ¿Buscas el catálogo completo de tokens? Está en la referencia de tokens.

Instalación e importación

Sin dependencias: es CSS/SCSS puro. Impórtalo una sola vez, en la raíz de tu app.

Instalar

npm install ng-hub-ui-ds

CSS drop-in (cualquier app, sin Sass)

@import 'ng-hub-ui-ds/styles/tokens/hub-tokens.css';

o en angular.json:

"styles": [
  "node_modules/ng-hub-ui-ds/styles/tokens/hub-tokens.css",
  "src/styles.scss"
]

Código SCSS (si usas Sass)

@use 'ng-hub-ui-ds/styles/tokens/hub-tokens';

Arquitectura: las dos capas

ref

--hub-ref-*

Valores crudos sin contexto: rampas de color, espaciado, radios, tipografía.

--hub-ref-color-blue-500
sys

--hub-sys-*

Asignaciones con significado que consumen los componentes.

--hub-sys-color-primary

Regla de oro: los componentes referencian solo tokens sys; los sys apuntan a los ref. Cambiar un sys re-tematiza; cambiar un ref ajusta la paleta base.

Colores semánticos · temas en vivo

El set es abierto: 9 variantes por defecto (5 cromáticas + 4 neutrales) y las que tú añadas. Cada acento expone una familia uniforme de roles — subtle, border-subtle, emphasis y el par de contraste on. Cambia el tema y observa cómo toda la paleta se re-colorea.

primary
base
subtle
border
emphasis
on
secondary
base
subtle
border
emphasis
on
success
base
subtle
border
emphasis
on
danger
base
subtle
border
emphasis
on
warning
base
subtle
border
emphasis
on
info
base
subtle
border
emphasis
on
neutral
base
subtle
border
emphasis
on
light
base
subtle
border
emphasis
on
dark
base
subtle
border
emphasis
on
Aviso primary
Aviso secondary
Aviso success
Aviso danger
Aviso warning
Aviso info
Aviso neutral
Aviso light
Aviso dark

Crea tu tema · cambia solo los colores base

Define únicamente el color base de cada familia semántica. El resto (subtle, border-subtle, emphasis, on) se deriva automáticamente con color-mix / relative color — y los componentes de abajo se re-tematizan en vivo, demostrando el cableado compartido.

primary base → derivados
base
subtle
border
emphasis
on
secondary base → derivados
base
subtle
border
emphasis
on
success base → derivados
base
subtle
border
emphasis
on
danger base → derivados
base
subtle
border
emphasis
on
warning base → derivados
base
subtle
border
emphasis
on
info base → derivados
base
subtle
border
emphasis
on
neutral base → derivados
base
subtle
border
emphasis
on
light base → derivados
base
subtle
border
emphasis
on
dark base → derivados
base
subtle
border
emphasis
on

Componentes en vivo

Aviso primary
Aviso secondary
Aviso success
Aviso danger
Aviso warning
Aviso info
Aviso neutral
Aviso light
Aviso dark
primarysecondarysuccessdangerwarninginfoneutrallightdark
.mi-tema {
  /* define SOLO el color base de cada familia */
  --hub-sys-color-primary: #6d28d9;

  /* el resto se deriva en runtime con color-mix / relative color — nada que mantener */
  --hub-sys-color-primary-subtle:        color-mix(in oklch, var(--hub-sys-color-primary) 12%, var(--hub-sys-surface-page));
  --hub-sys-color-primary-border-subtle: color-mix(in oklch, var(--hub-sys-color-primary) 35%, var(--hub-sys-surface-page));
  --hub-sys-color-primary-emphasis:      color-mix(in oklch, var(--hub-sys-color-primary) 80%, var(--hub-sys-color-ink));
  --hub-sys-color-primary-on:            oklch(from var(--hub-sys-color-primary) clamp(0, (0.62 - l) * 1000, 1) 0 h);
}

La familia · estado de integración

Toda la familia lee estos tokens. El badge indica si la biblioteca ya está cableada a --hub-sys-* (se re-tematiza con el design-system) o está pendiente de cablear (la abordamos luego). Pulsa cualquiera para ver sus ejemplos.

Cómo modificarlo

1. Sobrescribir un token (CSS) — el camino principal

Cada valor es una variable CSS, así que re-tematizar es una línea y cascada a toda la familia:

:root {
  --hub-sys-color-primary: #7c3aed;
  --hub-sys-color-primary-subtle: #ede9fe;
  --hub-sys-color-primary-emphasis: #5b21b6;
}

2. Añadir tu propio acento

Define una familia --hub-sys-color-<nombre> y los componentes que aceptan una variante semántica la recogen sin cambios. Pruébalo aquí en vivo:

Aviso brand — fondo, texto y borde derivados del acento con color-mix.
:root {
  --hub-sys-color-brand: #9333ea;
  --hub-sys-color-brand-subtle: #f3e8ff;
  --hub-sys-color-brand-border-subtle: #d8b4fe;
  --hub-sys-color-brand-emphasis: #6b21a8;
}

<!-- en cualquier componente que acepte una variante semántica -->
<hub-panel appearance="alert" variant="brand">Aviso de marca</hub-panel>

Con solo --hub-sys-color-brand ya funciona (los componentes derivan el resto con color-mix). Define la familia completa cuando quieras tintes exactos.

… o predefínelo en el mapa abierto (Sass)

Si usas Sass, amplía el mapa abierto de acentos antes de incluir el paquete con $hub-accents-extra. Solo se recompila el dsnunca las librerías— y cada variante nueva obtiene su familia completa (subtle · border-subtle · emphasis · on):

// Añade tus propias variantes — solo recompila el ds, nunca las librerías.
@use 'ng-hub-ui-ds/styles/tokens/hub-tokens' with (
  $hub-accents-extra: (
    brand:    #ff6b00,
    accent:   #00b8d9,
    tertiary: #9c36b5
  )
);
// brand · accent · tertiary obtienen subtle · border-subtle · emphasis · on automáticamente.

3. Crear un tema propio

[data-theme='corporate'] {
  --hub-sys-color-primary: #0033a0;
  --hub-sys-surface-page: #fbfcff;
  --hub-sys-text-primary: #0a1f44;
  /* …el resto de tokens que difieran del base */
}

Funciones SCSS: cómo se genera por dentro

Las familias de color semántico no se escriben a mano: el set de acentos es un mapa abierto con !default y la familia se deriva con un @each sobre map.keys($hub-accents). Por eso añadir un color (o nueve) es uniforme y sin boilerplate: toda clave del mapa obtiene su familia automáticamente.

// El set de acentos es un mapa ABIERTO con !default — añade los que quieras.
$hub-accents: (
  primary: …, secondary: …, success: …, danger: …, warning: …,
  info: …, neutral: …, light: …, dark: …
) !default;

// La familia se deriva UNA vez en :root, iterando TODAS las claves del mapa,
// así que cualquier acento que añadas obtiene su familia gratis.
@mixin hub-color-derive() {
  @each $name in map.keys($hub-accents) {
    --hub-sys-color-#{$name}-subtle:   color-mix(in oklch, var(--hub-sys-color-#{$name}) 12%, var(--hub-sys-surface-page));
    --hub-sys-color-#{$name}-emphasis: color-mix(in oklch, var(--hub-sys-color-#{$name}) 80%, var(--hub-sys-color-ink));
    --hub-sys-color-#{$name}-on:       oklch(from var(--hub-sys-color-#{$name}) clamp(0, (0.62 - l) * 1000, 1) 0 h);
  }
}

Para la mayoría de casos no necesitas tocar el SCSS: la sobrescritura de variables CSS cubre re-tematizar y añadir acentos. El mapa + mixin es la mecánica interna, útil si contribuyes al paquete.

Capa estructural · tokens en vivo

Además del color, el ds define una capa estructural canónica: escala de spacing (--hub-ref-space-*), sizing y fracciones (--hub-sys-size-*), grid (--hub-sys-grid-columns, gutters) y una escala de gap semántica (--hub-sys-gap-*). Todo abajo se pinta consumiendo esas variables.

Escala de spacing · --hub-ref-space-0…7

space-0
space-1
space-2
space-3
space-4
space-5
space-6
space-7

Escala de gap · --hub-sys-gap-0…5

gap-0
ABC
gap-1
ABC
gap-2
ABC
gap-3
ABC
gap-4
ABC
gap-5
ABC

Fracciones de ancho · --hub-sys-size-*

size-1-21/2
size-1-31/3
size-2-32/3
size-1-41/4
size-3-43/4
size-fullfull

Grid auto-fit + container widths

col 1col 2col 3col 4col 5col 6
max-sm
max-md
max-lg
max-xl
max-xxl
/* Tokens estructurales canónicos (ref → sys) */
gap: var(--hub-sys-gap-3);                  /* escala de spacing  */
padding-inline: var(--hub-ref-space-4);
max-width: var(--hub-sys-container-max-width-lg);
grid-template-columns: repeat(var(--hub-sys-grid-columns), minmax(0, 1fr));

/* Mixins de layout */
@use 'ng-hub-ui-ds' as hub;
.page    { @include hub.center($max: xl); }
.toolbar { @include hub.cluster($gap: 2); }
.cards   { @include hub.grid($min: 16rem, $gap: 3); }

/* Utilidades opt-in (canónicas hub- o sin prefijo) */
@use 'ng-hub-ui-ds/styles/utilities/layout.hub';  // .hub-stack .hub-gap-3 .hub-w-50 .hub-vh-100
@use 'ng-hub-ui-ds/styles/utilities/layout';      // .stack .gap-3 .w-auto .vw-100 (sin prefijo)

Mixins de layout

Helpers Sass que consumen los tokens estructurales — sin hornear spacing ni color. Se importan namespaced con @use 'ng-hub-ui-ds' as hub. Cada demo de abajo está construida desde el mixin real.

Cada mixin tiene una utilidad equivalente; las demos de abajo consumen la clase real del ds (.hub-cluster, .hub-stack…) — esta página no re-aplica ningún mixin.

hub.cluster() · .hub-cluster — fila que envuelve

InicioProductosPreciosContactoMás

hub.stack() · .hub-stack — columna

Bloque 1Bloque 2Bloque 3

hub.grid() · .hub-grid — grid auto-fit

12345678

hub.center() · .hub-center — wrapper centrado

contenido centrado (max-width xl)
@use 'ng-hub-ui-ds' as hub;

.toolbar { @include hub.cluster($gap: 2); }          // fila que envuelve
.feed    { @include hub.stack($gap: 3); }            // columna
.cards   { @include hub.grid($min: 8rem, $gap: 2); } // grid auto-fit
.page    { @include hub.center($max: sm); }          // wrapper centrado

Utilidades

Clases opt-in que envuelven la misma capa. Dos sabores con idéntica regla de nombrado: canónicas con prefijo hub- (seguras, sin colisiones) o sin prefijo (.stack, .w-auto, .vh-100, .min-vh-100…) estilo framework. La demo usa las clases hub- reales:

.hub-cluster .hub-gap-2

unodostrescuatro

.hub-grid .hub-gap-2

ABCDEF

Sizing · .hub-w-50 · .hub-w-25 · .hub-w-auto

w-50w-25w-auto
// importa la hoja una vez (canónica con prefijo hub- …)
@use 'ng-hub-ui-ds/styles/utilities/layout.hub';
// … o sin prefijo, estilo framework:
@use 'ng-hub-ui-ds/styles/utilities/layout';

<div class="hub-cluster hub-gap-2"> … </div>
<div class="hub-grid hub-gap-2"> … </div>
<div class="hub-w-50">mitad</div>
<div class="hub-vh-100 hub-min-vh-100">alto de viewport</div>

Flexbox

Set completo de utilidades de display y flexbox (40 clases), simétrico en ambas hojas (hub- y sin prefijo). Las demos usan las clases reales del ds.

justify-content · .hub-justify-* — eje principal

.hub-justify-start
ABC
.hub-justify-end
ABC
.hub-justify-center
ABC
.hub-justify-between
ABC
.hub-justify-around
ABC
.hub-justify-evenly
ABC

align-items · .hub-items-* — eje cruzado

.hub-items-start
smmdlg
.hub-items-center
smmdlg
.hub-items-end
smmdlg
.hub-items-stretch
smmdlg
.hub-items-baseline
smmdlg

flex-direction · .hub-flex-column

fila 1fila 2fila 3

flex-1 / flex-none — crecer y fijar

.hub-flex-1 (crece).hub-flex-none
<!-- display + dirección / wrap -->
<div class="hub-d-flex hub-flex-wrap hub-gap-2"> … </div>
<div class="hub-d-flex hub-flex-column"> … </div>

<!-- eje principal (justify) y cruzado (items) -->
<div class="hub-d-flex hub-justify-between hub-items-center"> … </div>

<!-- crecer / fijar -->
<div class="hub-d-flex hub-gap-2">
  <span class="hub-flex-1">crece</span>
  <span class="hub-flex-none">fijo</span>
</div>

Columnas, anchos y spacing

Rejilla de 12 columnas (.hub-row + .hub-col-1…12, driven por --hub-sys-grid-columns), anchos y padding/margin direccionales. Cada demo usa las utilidades reales.

Columnas · .hub-row + .hub-col-N

col-6
col-6
col-4
col-4
col-4
col-3
col-3
col-6
col-8
col-4
col-12
col-2
col-2
col-2
col-2
col-2
col-2

Anchos · .hub-w-25 / 50 / 75 / 100 / auto

w-25w-25
w-50w-50
w-75w-75
w-100w-100
w-autow-auto

Padding · .hub-p-1…5 (los 4 lados)

p-1
p-2
p-3
p-4
p-5

Padding por eje · .hub-px-* / .hub-py-*

px-4 · py-1
px-2 · py-4
px-5 · py-3

Margin · .hub-m-1…5 (dentro de un marco de referencia)

m-1
m-2
m-3
m-4
m-5

Margin por eje · .hub-mx-* / .hub-my-*

mx-4
my-3
<!-- 12-column grid: cada fila suma 12 -->
<div class="hub-row">
  <div class="hub-col-6">col-6</div>
  <div class="hub-col-6">col-6</div>
</div>
<div class="hub-row">
  <div class="hub-col-4">col-4</div>
  <div class="hub-col-4">col-4</div>
  <div class="hub-col-4">col-4</div>
</div>

<!-- anchos · padding · margin direccionales -->
<div class="hub-w-50">w-50</div>
<div class="hub-p-3">padding 1rem en los 4 lados</div>
<div class="hub-px-4 hub-py-2">padding-inline 1.5rem · padding-block .5rem</div>
<div class="hub-mx-3">margin-inline 1rem</div>

Puentes a otros sistemas

Mixins opt-in que conectan hub con el framework presente. Coste cero si no los llamas. Dos direcciones con $mode: adopt (hub toma el tema del host) y project (hub proyecta su tema sobre el host).

@use 'ng-hub-ui-ds' as hub;

/* "tengo Bootstrap y quiero que hub adopte su paleta" */
:root { @include hub.bridge-bootstrap($mode: adopt); }

/* "quiero teñir Material y Tailwind con MI tema hub" */
:root { @include hub.bridge-material($mode: project); }
:root { @include hub.bridge-tailwind($mode: project); }
MixinSistemaadoptproject
hub.bridge-bootstrapBootstrap 5.3+lee --bs-*tiñe --bs-* + gutters/radius
hub.bridge-materialAngular Material 3lee --mat-sys-*tiñe --mat-sys-* (par color/on)
hub.bridge-tailwindTailwind v4lee --color-*emite --color-* para @theme
hub.bridge-open-propsOpen Propsalias de rampas

Referencia rápida

Quiero…Cómo
Usar la paleta@use '…/hub-tokens'
Cambiar un color global:root { --hub-sys-color-primary: … }
Añadir variantes propiaswith ($hub-accents-extra: (brand: …))
Texto con contrastecolor: var(--hub-sys-color-primary-on)
Layout (mixin / utilidad)@include hub.center() · .hub-stack
Puente a Bootstrap/Material@include hub.bridge-bootstrap($mode: adopt)
Crear un tema[data-theme='<nombre>'] { … }