Arquitectura de Sistemas de Diseño en la Práctica: El Camino Completo de Construcción desde Design Tokens hasta Bibliotecas de Componentes

前端工程

La Arquitectura de Tres Capas de los Sistemas de Diseño

┌─────────────────────────────────┐
│  Capa de Componentes            │  Button, Card, Modal...
├─────────────────────────────────┤
│  Capa de Patrones               │  Formularios, Navegación, Tablas de Datos
├─────────────────────────────────┤
│  Capa de Tokens (Design Tokens) │  Colores, Espaciado, Tamaños de Fuente, Sombras
└─────────────────────────────────┘

Los tokens son la base, los patrones son la composición, los componentes son el punto final. Construir de abajo hacia arriba, consumir de arriba hacia abajo.


El Sistema de Design Tokens

1. Tokens de Color

/* Tokens semánticos de tres capas */

/* Capa 1: Valores Primitivos */
:root {
  --blue-50: #eff6ff;
  --blue-500: #3b82f6;
  --blue-700: #1d4ed8;
  --gray-50: #f9fafb;
  --gray-900: #111827;
  --red-500: #ef4444;
  --green-500: #22c55e;
}

/* Capa 2: Mapeo Semántico */
:root {
  --color-primary: var(--blue-500);
  --color-primary-hover: var(--blue-700);
  --color-surface: var(--gray-50);
  --color-text: var(--gray-900);
  --color-danger: var(--red-500);
  --color-success: var(--green-500);
}

/* Capa 3: Específica del Componente */
:root {
  --button-bg: var(--color-primary);
  --button-bg-hover: var(--color-primary-hover);
  --button-text: white;
  --input-border: var(--color-border);
  --input-border-focus: var(--color-primary);
}

2. Tokens de Espaciado (Sistema de Cuadrícula de 8pt)

:root {
  --space-0: 0;
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-8: 3rem;     /* 48px */
  --space-10: 4rem;    /* 64px */
}

3. Tokens de Tipografía

:root {
  /* Tamaños de fuente */
  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  --text-3xl: 1.875rem;  /* 30px */

  /* Alturas de línea */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* Pesos de fuente */
  --font-normal: 400;
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;
}

4. Tokens de Sombra

:root {
  --shadow-xs: 0 1px 2px rgba(0,0,0,0.05);
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
  --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06);
  --shadow-lg: 0 10px 15px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05);
  --shadow-xl: 0 20px 25px rgba(0,0,0,0.1), 0 8px 10px rgba(0,0,0,0.04);
}

Mecanismo de Cambio de Tema

Enfoque con Variables CSS

/* Tema claro (predeterminado) */
:root {
  --color-surface: #ffffff;
  --color-text: #111827;
  --color-border: #e5e7eb;
  --color-primary: #3b82f6;
}

/* Tema oscuro */
[data-theme="dark"] {
  --color-surface: #1f2937;
  --color-text: #f9fafb;
  --color-border: #374151;
  --color-primary: #60a5fa;
}

/* Tema de alto contraste */
[data-theme="high-contrast"] {
  --color-surface: #000000;
  --color-text: #ffffff;
  --color-border: #ffffff;
  --color-primary: #ffff00;
}

Cambio de Tema en React

import { useEffect, useState } from 'react';

type Theme = 'light' | 'dark' | 'system';

function useTheme() {
  const [theme, setTheme] = useState<Theme>(() => {
    return (localStorage.getItem('theme') as Theme) || 'system';
  });

  useEffect(() => {
    const root = document.documentElement;
    const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    const resolved = theme === 'system' ? (systemDark ? 'dark' : 'light') : theme;

    root.setAttribute('data-theme', resolved);
    localStorage.setItem('theme', theme);
  }, [theme]);

  return { theme, setTheme };
}

Modo Oscuro con Tailwind CSS v4

/* tailwind.config.ts usando modo de variables CSS */
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
<!-- Auto-responsivo al tema -->
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
  El contenido se adapta automáticamente al tema actual
</div>

Principios de Diseño de API de Componentes

1. Responsabilidad Única + Composición Primero

// ❌ Sobre-encapsulación: Todas las funcionalidades metidas en un componente
<SuperButton variant="primary" size="lg" icon="save" loading disabled />

// ✅ Patrón de composición: Ensamblar mediante componentes hijos
<Button variant="primary" size="lg">
  <Icon name="save" />
  <Button.Label>Guardar</Button.Label>
  <Button.Loading />
</Button>

2. Controlado vs No Controlado

// Modo controlado: Estado gestionado externamente
<Input value={value} onChange={setValue} />

// Modo no controlado: Estado gestionado internamente por el componente
<Input defaultValue="hello" onChange={handleChange} />

// Compatible con ambos
interface InputProps {
  value?: string;          // Controlado
  defaultValue?: string;   // No controlado
  onChange?: (value: string) => void;
}

3. Componentes Polimórficos

// Button puede renderizarse como button, a, o Link de Next.js
type ButtonProps<C extends React.ElementType = 'button'> = {
  as?: C;
} & React.ComponentPropsWithoutRef<C>;

function Button<C extends React.ElementType = 'button'>(
  { as, ...props }: ButtonProps<C>
) {
  const Component = as || 'button';
  return <Component className="btn" {...props} />;
}

// Uso
<Button>Hacer clic</Button>
<Button as="a" href="/link">Enlace</Button>
<Button as={Link} to="/page">Enlace de ruta</Button>

4. Patrón de Slots

// Diseño de Slots del componente Card
interface CardSlots {
  header?: React.ReactNode;
  media?: React.ReactNode;
  content: React.ReactNode;
  footer?: React.ReactNode;
  actions?: React.ReactNode;
}

function Card({ header, media, content, footer, actions }: CardSlots) {
  return (
    <div className="card">
      {header && <div className="card-header">{header}</div>}
      {media && <div className="card-media">{media}</div>}
      <div className="card-content">{content}</div>
      {footer && <div className="card-footer">{footer}</div>}
      {actions && <div className="card-actions">{actions}</div>}
    </div>
  );
}

Adaptación Multi-Marca

Capa de Sobrescritura de Marca

/* Tokens base (Marca A) */
:root {
  --brand-primary: #3b82f6;
  --brand-radius: 8px;
  --brand-font: 'Inter', sans-serif;
}

/* Sobrescritura Marca B */
[data-brand="b"] {
  --brand-primary: #8b5cf6;
  --brand-radius: 12px;
  --brand-font: 'Poppins', sans-serif;
}

/* Sobrescritura Marca C */
[data-brand="c"] {
  --brand-primary: #f59e0b;
  --brand-radius: 4px;
  --brand-font: 'Roboto', sans-serif;
}

Pipeline de Compilación de Tokens

Archivos fuente de diseño (Figma)
  ↓
Compilación Style Dictionary
  ↓
├── Variables CSS (Web)
├── Configuración Tailwind (Proyectos Tailwind)
├── Archivos Swift para iOS
├── Archivos Kotlin para Android
└── JSON (Sitio de documentación)
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');

module.exports = {
  source: ['tokens/**/*.json'],
  platforms: {
    css: {
      transformGroup: 'css',
      buildPath: 'dist/css/',
      files: [{ destination: 'variables.css', format: 'css/variables' }],
    },
    tailwind: {
      transformGroup: 'js',
      buildPath: 'dist/tailwind/',
      files: [{ destination: 'theme.js', format: 'javascript/module' }],
    },
  },
};

Prácticas del Sistema de Diseño de ToolsKu

ToolsKu usa Tailwind CSS v4 + variables CSS para construir su sistema de diseño:

/* Tokens de tema de ToolsKu */
:root {
  --color-primary: #2563eb;
  --color-surface: #ffffff;
  --color-text: #1f2937;
  --radius: 8px;
  --font-sans: 'Inter', system-ui, sans-serif;
}

/* Componente de tarjeta de herramienta */
.tool-card {
  padding: var(--space-4);
  border-radius: var(--radius);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  transition: transform 0.2s, box-shadow 0.2s;
}

.tool-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

Gobernanza del Sistema de Diseño

Gestión de Versiones

@toolsku/tokens     v2.4.0  → Paquete de Design Tokens
@toolsku/components v3.1.0  → Biblioteca de componentes
@toolsku/patterns   v1.2.0  → Biblioteca de patrones

Cadena de dependencias: patterns → components → tokens

Flujo de Cambios

1. El diseñador modifica tokens en Figma
2. Auto-sincronización al repositorio Git (Plugin de Figma)
3. CI ejecuta compilación de Style Dictionary
4. Pruebas de regresión visual (Chromatic/Storybook)
5. Auto-publicación de nueva versión (Changesets)

Sitio de Documentación

Storybook
├── Tokens      → Muestra de colores, espaciado, tamaños de fuente
├── Components  → Documentación de interacción de componentes
├── Patterns    → Guía de uso de patrones
└── Guidelines  → Documentación de especificaciones de diseño

Resumen

Un sistema de diseño no es solo una biblioteca de componentes, sino una arquitectura completa desde Tokens hasta Componentes hasta Patrones. Los tokens de tres capas (Primitivo → Semántico → Componente) son la base de la escalabilidad. Los patrones de composición superan a la sobre-encapsulación, y las variables CSS + Tailwind son la elección tecnológica más práctica en 2026. Recuerda: un buen sistema de diseño permite a diseñadores y desarrolladores hablar el mismo idioma, y los tokens son el vocabulario de ese idioma.

Prueba estas herramientas que se ejecutan en tu navegador — no requieren registro →

#设计系统#Design Token#组件库#Tailwind CSS#前端架构