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

242 lines
5.6 KiB

---
title: Eidos Theming — Guías de autoría
type: guide
audience: human + agent
status: current
source: 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`](./THEMING.md) (referencia E1)
> para vivir como guía E4. El contrato de tokens que sostiene todo esto es
> [`TSC.md`](./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`
```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
```bash
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`:
```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`
```css
@import './components/my-component/my-component.css';
```
### Paso 6 — Verifica
```bash
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`
```ts
// ❌ 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:
```ts
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:
```ts
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:
```ts
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:
```css
[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
```ts
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.