Sistema de componentes

Por: Artiko
openpencilcomponentesdesign-systemvariablestemasvariantes

Sistema de componentes

Por qué los componentes cambian todo

Un diseño sin componentes es una fotografía: estático, difícil de mantener, imposible de escalar. Un diseño con componentes bien organizados es un sistema vivo: cambias el componente maestro y todas las instancias se actualizan automáticamente.

OpenPencil implementa un sistema de componentes que va un paso más allá del modelo tradicional de Figma. Los componentes en OpenPencil se conectan directamente con las variables de diseño, soportan múltiples temas de forma nativa, y tienen una correspondencia directa con los componentes del framework frontend que uses.

graph TD
    A[Componente Maestro] --> B[Instancia 1]
    A --> C[Instancia 2]
    A --> D[Instancia N]
    B --> B1[Override: texto diferente]
    C --> C1[Override: variante dark]
    D --> D1[Override: estado disabled]
    E[Variables de diseño] --> A
    E --> B
    E --> C
    E --> D

Crear un componente maestro

Método 1: Desde la interfaz

  1. Diseña el elemento que quieres convertir en componente (un frame con su contenido)
  2. Selecciónalo
  3. Click derecho → “Crear componente” (o Cmd+Alt+K)
  4. El frame se convierte en un componente: aparece con un ícono de diamante en el panel de capas

Una vez creado, el componente original es el maestro. Cualquier copia que hagas es una instancia.

Método 2: Con la IA

[En el chat, con un frame seleccionado]
"Convierte este botón en un componente con 4 variantes:
- primary: fondo azul, texto blanco
- secondary: fondo blanco, borde azul, texto azul
- ghost: sin fondo, sin borde, texto azul
- destructive: fondo rojo, texto blanco"

Método 3: Via CLI

# Crear un componente desde un nodo existente
op component create --file diseño.op --node "btn-principal" --name "Button/Primary"

# Crear componente con variantes
op component create \
  --file diseño.op \
  --node "btn-base" \
  --name "Button" \
  --variants "primary,secondary,ghost,destructive"

Anatomía de un componente

Un componente bien estructurado en OpenPencil tiene:

Button/Primary (Componente maestro)
├── frame "btn-container" (auto-layout horizontal, padding 12/20, gap 8)
│   ├── icon "btn-icon" (opcional, 16x16)
│   └── text "btn-label" ("Botón")

Buenas prácticas de nomenclatura

Usa la barra / para crear jerarquías en el panel de componentes:

Button/Primary
Button/Secondary
Button/Ghost
Button/Destructive
Button/Loading

Card/Default
Card/Highlighted
Card/Compact

Input/Default
Input/Focus
Input/Error
Input/Disabled

Badge/Success
Badge/Error
Badge/Warning
Badge/Info
Badge/Neutral

Esta nomenclatura crea una estructura de árbol en el panel de Assets (activos), facilitando la búsqueda y organización.

Instancias y overrides

Crear instancias

Para usar un componente en el diseño:

  1. Abre el panel de Assets (Cmd+Alt+O o click en el ícono de Assets)
  2. Busca el componente que quieres usar
  3. Arrastra al canvas para crear una instancia

O bien: copia el componente maestro (Cmd+C) y pégalo (Cmd+V). OpenPencil detecta automáticamente que es un componente y crea una instancia.

Tipos de overrides

Los overrides son propiedades que se pueden cambiar en una instancia sin romper el vínculo con el maestro:

Override de texto: Cambia el contenido del texto en la instancia.

Maestro: text "Enviar"
Instancia 1: text "Cancelar"  → Override de texto
Instancia 2: text "Confirmar" → Override de texto

Override de imagen: Reemplaza imágenes o iconos en la instancia.

Override de visibilidad: Oculta/muestra layers específicos de la instancia.

Override de variante: Cambia entre variantes del componente.

Override de propiedad de componente: Si el componente tiene props definidos, puedes cambiarlos en la instancia.

Definir props del componente

Al igual que los componentes React tienen props, los componentes de OpenPencil pueden tener props definidos:

  1. Selecciona el componente maestro
  2. En el panel derecho, sección “Component properties”
  3. Haz click en + para agregar una prop

Tipos de props disponibles:

Componente: Button
Props:
  - label: Text (default: "Botón")
  - icon: Instance swap (default: ninguno)
  - showIcon: Boolean (default: false)
  - variant: Variant (opciones: primary, secondary, ghost, destructive)
  - size: Variant (opciones: sm, md, lg)
  - isLoading: Boolean (default: false)

Cuando alguien usa una instancia de Button, puede configurar todos estos props desde el panel de propiedades sin entrar en el componente.

Variables de diseño

Las variables (también llamadas “tokens de diseño” o “design tokens”) son el sistema nervioso de un design system. Almacenan valores reutilizables que se pueden cambiar en un solo lugar y actualizar automáticamente en todo el diseño.

Tipos de variables

TipoEjemplos
Color#2563EB, rgba(37, 99, 235, 0.5)
Number8, 16, 24, 1.5
String"Inter", "400"
Booleantrue, false

Crear variables

  1. Abre el panel de Variables (Cmd+Alt+V)
  2. Click en + para crear una nueva colección
  3. Nómbrala (ej: “Brand Colors”)
  4. Agrega variables con +

Estructura recomendada para un sistema de tokens:

Colección: Primitives (valores base, no usar directamente en componentes)
  blue-50:   #EFF6FF
  blue-100:  #DBEAFE
  blue-500:  #3B82F6
  blue-600:  #2563EB
  blue-900:  #1E3A8A
  
  slate-50:  #F8FAFC
  slate-100: #F1F5F9
  slate-900: #0F172A
  
  green-500: #22C55E
  red-500:   #EF4444

Colección: Semantic (significado, referencian a Primitives)
  color/background:          → blue-50
  color/text/primary:        → slate-900
  color/text/secondary:      → slate-500
  color/border:              → slate-200
  color/action/primary:      → blue-600
  color/action/primary-hover:→ blue-700
  color/status/success:      → green-500
  color/status/error:        → red-500

Colección: Component (específico por componente, referencian a Semantic)
  button/bg:                 → color/action/primary
  button/text:               → #FFFFFF
  button/border-radius:      → 8
  input/border:              → color/border
  input/bg:                  → color/background

Vincular variables a propiedades

Para vincular una variable a la propiedad de un nodo:

  1. Selecciona el nodo
  2. En el panel de propiedades, haz click en el campo de valor
  3. Aparece el ícono de “variable” (una caja pequeña) a la derecha del campo
  4. Click en ese ícono para abrir el selector de variables
  5. Selecciona la variable correspondiente
Frame "btn-container"
  fills[0].color → button/bg
  cornerRadius   → button/border-radius

Text "btn-label"
  fills[0].color → button/text
  fontSize       → typography/size/base
  fontFamily     → typography/family/sans

Ahora si cambias el valor de button/bg, todos los botones del diseño se actualizan instantáneamente.

Sintaxis $variable en el chat de IA

Al hablar con el agente de IA, puedes referenciar variables con la notación $nombre-variable:

"Diseña un card para artículo de blog.
Usa $color/background para el fondo.
El título debe usar $typography/size/xl y $color/text/primary.
El extracto debe usar $typography/size/base y $color/text/secondary.
El borde debe ser $color/border."

El agente reconoce las variables y las vincula correctamente al crear los nodos.

Temas Light/Dark

OpenPencil soporta múltiples temas nativamente. Un tema es simplemente un conjunto de modos para las variables de diseño.

Crear modos de tema

En el panel de Variables, cada colección puede tener múltiples modos:

  1. En la colección “Semantic”, haz click en el ícono de modos
  2. El modo inicial es “Light” (o “Default”)
  3. Haz click en + para agregar el modo “Dark”
  4. Para cada variable en la colección, puedes definir un valor diferente por modo
color/background:
  Light mode → #FFFFFF
  Dark mode  → #0F172A

color/text/primary:
  Light mode → #0F172A
  Dark mode  → #F8FAFC

color/border:
  Light mode → #E2E8F0
  Dark mode  → #1E293B

color/action/primary:
  Light mode → #2563EB
  Dark mode  → #3B82F6  (ligeramente más claro en dark)

Previsualizar temas

Con un frame seleccionado, en el panel de propiedades en la sección “Variables”:

Frame "App" → modo: Light
  Frame "Sidebar" → hereda Light
  Frame "Content" → hereda Light
    Frame "DarkCard" → modo: Dark (override local)

Esto permite previsualizar componentes dark mode dentro de una pantalla light mode.

Exportar con soporte de temas

Al exportar a React + Tailwind, el motor genera el CSS de ambos modos:

op export react \
  --file diseño.op \
  --component "Card" \
  --out ./src/components \
  --themes "light,dark"

El código generado usa el atributo data-theme para alternar:

// Card.tsx — con soporte de temas
export function Card({ children }: { children: React.ReactNode }) {
  return (
    <div className="bg-background text-text-primary border border-border rounded-xl p-6">
      {children}
    </div>
  )
}
/* tokens.css — con temas */
:root, [data-theme="light"] {
  --background: #FFFFFF;
  --text-primary: #0F172A;
  --border: #E2E8F0;
}

[data-theme="dark"] {
  --background: #0F172A;
  --text-primary: #F8FAFC;
  --border: #1E293B;
}

Variantes de componentes

Las variantes son la forma de gestionar múltiples estados y versiones de un componente dentro de un único componente maestro.

Crear variantes

  1. Selecciona el componente maestro
  2. En el panel de propiedades, haz click en + junto a “Variants”
  3. Define las dimensiones de variación (ej: “variant” con valores “primary, secondary, ghost”)
  4. Para cada combinación de valores, diseña la apariencia
graph TD
    A[Button Component] --> B[variant=primary<br/>size=sm]
    A --> C[variant=primary<br/>size=md]
    A --> D[variant=primary<br/>size=lg]
    A --> E[variant=secondary<br/>size=sm]
    A --> F[variant=secondary<br/>size=md]
    A --> G[variant=secondary<br/>size=lg]
    A --> H[variant=ghost<br/>size=sm]
    A --> I[variant=ghost<br/>size=md]
    A --> J[variant=ghost<br/>size=lg]

Con 2 dimensiones (variant × size), tienes 9 variantes en un solo componente.

Seleccionar variante en una instancia

Cuando usas una instancia del componente Button, en el panel de propiedades ves los controles de variante:

Variante: [primary ▼]  Tamaño: [md ▼]

Cambiar la variante actualiza la apariencia de la instancia sin romper el vínculo con el maestro.

Auto-generar variantes con IA

[Con el componente Button seleccionado]
"Agrega una variante 'loading' para cada tamaño.
La variante loading debe mostrar un spinner (Heroicons: arrow-path) 
en lugar del texto, animado con rotate.
El botón debe estar deshabilitado durante loading."

Organizar una librería de diseño

Una librería de diseño profesional en OpenPencil tiene una estructura clara de páginas:

mi-design-system.op
├── Página: 🎨 Foundations
│   ├── Colors (palette completa)
│   ├── Typography (escala tipográfica)
│   ├── Spacing (escala de espaciado)
│   ├── Shadows (niveles de elevación)
│   └── Icons (iconografía)

├── Página: 🧩 Atoms (componentes básicos)
│   ├── Button (todas las variantes)
│   ├── Input
│   ├── Badge
│   ├── Avatar
│   ├── Checkbox / Radio / Toggle
│   └── Tag / Chip

├── Página: 🔧 Molecules (componentes compuestos)
│   ├── SearchBar
│   ├── FormField (label + input + error)
│   ├── Card
│   ├── Notification / Toast
│   └── Dropdown

├── Página: 🏗️ Organisms (secciones)
│   ├── Navbar
│   ├── Sidebar
│   ├── DataTable
│   ├── Modal
│   └── Form / Checkout

└── Página: 📋 Templates
    ├── Dashboard layout
    ├── Form page
    └── Marketing page

Publicar como librería compartida

Para que el equipo acceda a los componentes desde otros documentos:

# Publicar la librería
op library publish mi-design-system.op \
  --name "Mi Design System" \
  --version "1.2.0"

# En otros documentos, agregar la librería
op library add "Mi Design System" --to mi-proyecto.op

# Actualizar cuando hay cambios
op library update "Mi Design System" --in mi-proyecto.op

Desde la UI: Panel de Assets → Libraries → Manage Libraries → Add.

Versioning de la librería

Las librerías de OpenPencil soportan versioning semántico. Cuando publicas una nueva versión con cambios breaking (cambios en el API de los componentes), el sistema notifica a todos los documentos que usan la librería.

# Ver todos los documentos que usan una librería
op library dependents "Mi Design System"

# Ver qué versión usa cada documento
op library audit mi-proyecto.op

Documentación de componentes

OpenPencil permite agregar anotaciones de documentación directamente en el archivo de diseño:

Notas de componente

  1. Selecciona el componente maestro
  2. Panel derecho → sección “Documentation”
  3. Agrega descripción, props y ejemplos de uso
## Button Component

Un botón interactivo con soporte para múltiples variantes y estados.

### Props
- `variant`: primary | secondary | ghost | destructive
- `size`: sm | md | lg
- `isLoading`: boolean
- `disabled`: boolean

### Uso correcto
- Usa `primary` para la acción principal de cada pantalla
- Usa `secondary` para acciones alternativas
- Usa `ghost` para acciones de menor importancia
- Máximo 2 botones primarios visibles al mismo tiempo

### Accesibilidad
- Contraste mínimo 4.5:1 en todos los estados
- Focus visible siempre activo (no remover outline)
- Loading state comunica el estado con aria-label

Exportar documentación

# Generar sitio de documentación del design system
op docs generate mi-design-system.op --out ./docs --format html

# Generar en formato Storybook
op docs generate mi-design-system.op --out ./storybook --format storybook

Sincronizar componentes con el código

El flujo ideal de trabajo con componentes:

flowchart TD
    A[Diseñador crea/actualiza componente en OpenPencil] --> B[Exportar con op export]
    B --> C[Código en src/components/generated/]
    C --> D[Desarrollador extiende con lógica]
    D --> E[Componente en producción]
    F[Cambio en el diseño] --> G[Re-exportar el componente]
    G --> H{¿Cambio breaking?}
    H -->|No| I[Actualización automática del código generado]
    H -->|Sí| J[Desarrollador adapta la lógica]
    I --> E
    J --> E

Resumen

En este capítulo has aprendido:

En el último capítulo aplicaremos todo lo aprendido en un proyecto real de principio a fin.