You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/THEMING_GUIDE.md

5.6 KiB

title type audience status source
Eidos Theming — Guías de autoría guide human + agent current extracted from src/uix/eidos/THEMING.md (was §8 + §9)

Eidos Theming — Guías de autoría

Las dos guías how-to del theming de eidos: añadir un componente nuevo y definir un theme. Extraídas de THEMING.md (referencia E1) para vivir como guía E4. El contrato de tokens que sostiene todo esto es TSC.md.


Cómo añadir un componente nuevo

Asumiendo que ya tienes el morfo, soma y el scaffolding del wrapper eidos (src/uix/eidos/components/{name}/):

Paso 1 — Decide qué tokens necesitas

Mira componentes similares (button, toggle, switch). Identifica qué dimensiones tu componente expone:

  • ¿Tiene data-color? → palette tokens.
  • ¿Tiene data-variant? → variant tokens.
  • ¿Tiene data-size? → size tokens.
  • ¿Cuántas partes tiene? → tokens por part.

Paso 2 — Añade el recipe en lib/recipes/base.ts

// Within THEME_BASE_RECIPE_TOKENS:
'my-component': {
  // size tokens — scope 'root' (estables)
  'height-md': '36px',
  'padding-inline-md': 'var(--space-3)',
  'gap': 'var(--space-2)',
  'radius': 'var(--radius-md)',

  // per-color literal definitions — scope 'root'
  'primary-solid': 'var(--color-primary-solid)',
  'affirm-solid':  'var(--color-affirm-solid)',
  'threat-solid':  'var(--color-threat-solid)',

  // palette dinámica — scope 'host' default + overrides por color
  'palette-solid': {
    declarations: [
      { value: 'var(--my-component-primary-solid)', scope: 'host' },
      { value: 'var(--my-component-affirm-solid)',  scope: 'color:affirm' },
      { value: 'var(--my-component-threat-solid)',  scope: 'color:threat' }
    ]
  },

  // tokens derivados — scope 'host' (deps inferidas)
  'solid-bg': {
    value: 'var(--my-component-palette-solid)',
    scope: 'host'
  }
}

Paso 3 — Regenera

npm run generate:eidos-css

Si tu config viola TSC, te avisa al regenerar:

Eidos recipe scope contract violations:
  - my-component.solid-bg (scope root): dependency 'palette-solid' is only
    declared at scopes [host], none of which is reachable from the
    consumer's scope.

Paso 4 — Escribe el recipe CSS

src/uix/eidos/components/my-component/my-component.css:

[data-my-component] {
  /* Private tokens — sólo este recipe los lee */
  --_my-component-bg: var(--my-component-solid-bg);
  --_my-component-radius: var(--my-component-radius);

  display: inline-flex;
  align-items: center;
  padding-inline: var(--my-component-padding-inline-md);
  height: var(--my-component-height-md);
  border-radius: var(--_my-component-radius);
  background: var(--_my-component-bg);
  gap: var(--my-component-gap);
}

[data-my-component][data-disabled] {
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

Paso 5 — Importa en index.css

@import './components/my-component/my-component.css';

Paso 6 — Verifica

npm run generate:eidos-css
npm test -- src/uix/eidos
npm run morfo:check
node --import tsx/esm scripts/eidos-lint.ts my-component

Anti-pattern común: declarar tokens compuestos en :root

// ❌ INCORRECTO — TSC fallará
'my-component': {
  'palette-solid': { value: 'var(--color-neutral-solid)', scope: 'host' },
  'solid-bg': 'var(--my-component-palette-solid)'  // ← scope 'root' implícito, deps en 'host'
}

// ✓ CORRECTO
'my-component': {
  'palette-solid': { value: 'var(--color-neutral-solid)', scope: 'host' },
  'solid-bg': {
    value: 'var(--my-component-palette-solid)',
    scope: 'host'
  }
}

Cómo definir un theme

Eidos soporta 3 modos de definir un theme:

Modo 1 — Patch del theme base (recomendado)

Cambia sólo lo que necesitas; el resto sigue el base:

import { ActiveEidos } from '$uix/eidos';

ActiveEidos.create({
  themeBase: {
    semantics: {
      color: {
        roles: {
          primary: 'blue',     // primary usa la escala blue Radix
          secondary: 'plum'
        }
      }
    },
    primitives: {
      typography: {
        families: {
          primary: { family: 'Inter' }
        }
      }
    }
  },
  applyDom: true
});

Modo 2 — Config completa

Si quieres autoría desde cero:

import { ActiveEidos, defineEidosConfig } from '$uix/eidos';

const config = defineEidosConfig({
  primitives: { /* … */ },
  semantics: { color: { /* … */ } },
  themes: { /* … */ }
});

ActiveEidos.create({ config, applyDom: true });

Modo 3 — Theme CSS-only (sin TypeScript)

Eidos publica el contrato como CSS vacío para que externals lo sobrescriban:

const contract = activeEidos.renderContractCss({
  themeSelector: "[data-theme='acme-light']"
});
// Output:
// [data-theme='acme-light'] {
//   --scale-blue-9: ;
//   --color-primary-solid: ;
//   --size-md-control-height: ;
//   ...
// }

El consumer rellena los valores:

[data-theme='acme-light'] {
  --scale-blue-9: #006adc;
  --color-primary-solid: var(--scale-blue-9);
  --size-md-control-height: 38px;
}

Y carga ese CSS junto con el de Eidos. Con themeSource: 'css', ActiveEidos no genera theme propio.

Persistencia versionada

const document = activeEidos.toDocument();
// → { kind: 'uix.eidos-config', version: 1, options: {...} }

const json = activeEidos.serialize();
localStorage.setItem('user-theme', json);

// Más tarde
const hydrated = createActiveEidos({
  config: JSON.parse(localStorage.getItem('user-theme')!),
  prefs, dom
});

El document envelope tiene version para migraciones futuras.


Powered by TurnKey Linux.