docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
# Eidos
`Eidos` es la **capa visual** de UIX. Cubre lo que en la rama muerta `air/`
era el "runtime visual" más el sistema de tokens — sin heredar código.
Lee del DOM lo que las capas anteriores han escrito (morfo runtime + sema
visual channel) y aplica estilos, animaciones y wrappers ergonómicos.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
```
Morfo declara la genética
↓
Soma transcribe el comportamiento → DOM (data-state, data-color, aria-*)
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
↓
Sema emite señales perceptivas → DOM (data-event-*) durante el hold
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
↓
Eidos aplica el visual: tokens, themes, recipes, archetypes, wrappers
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
```
Eidos nunca importa internals de soma ni de sema. Su fuente de verdad es
**lo que está escrito en el DOM** (parts, data-attrs, ARIA, archetypes,
event signals) y los tipos públicos de Soma que necesita para componer
wrappers.
## Handoff 2026-05-14
Eidos queda congelado a nivel de componentes hasta reauditar la arquitectura
de UIX. No tocar `src/uix/eidos/components/*` salvo orden explicita.
Actualización 2026-05-17: la migración de componentes se reanudó por orden
explícita. La regla vigente no cambia: cada componente nuevo debe seguir
`components/README.md` , envolver partes públicas de Soma directamente y añadir
sólo superficie visual de Eidos.
Antes de seguir con wrappers o recipes por componente hay que respetar estas
decisiones:
- que contrato minimo consume `Eidos` desde `ActiveUix` ;
- `ActiveEidos` asume authoring, validacion, generacion CSS, persistencia y
contexto visual;
- `events` es el servicio perceptivo runtime y `morfo.translations` es el
catalogo declarativo de texto owned por el componente;
- que parte se genera desde codigo y que parte puede venir solo por CSS;
- como se mantiene la regla de escritura DOM unica en standalone `dom:false` .
La referencia de arranque esta en
[`../active_architecture.md` ](../active_architecture.md ), seccion
`Handoff 2026-05-14` .
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
## No es solo CSS
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
El primer mental model fue "eidos = CSS reactivo". Insuficiente: hay
concerns visuales puros (variant, size, layout flags, icon slots) que
no son parte del comportamiento headless pero sí son ortogonales al CSS.
Eidos los aloja como **wrappers Svelte sobre el Soma** .
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
```
src/uix/eidos/
active-eidos.svelte.ts → runtime/contexto visual y generacion CSS
index.css → entrypoint que importa todo el CSS
archetypes.css → reglas comunes a [data-archetype=*]
events.css → reacciones a [data-event-*] (sema visual)
generated/base.css → salida estatica generada desde EidosConfig base
themes/fonts.css → font faces usados por el theme base generado
lib/ → soporte de config, recipes, contrato CSS y tipos compartidos
components/{x}/ → recipe + wrapper + tipos por componente
{x}.css recipe CSS (selectores [data-{x}], etc.)
{x}.svelte wrapper Svelte sobre el componente Soma
types.ts props del wrapper (extiende el contrato público Soma)
index.ts namespace publico (default + partes attached)
```
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
`lib/` contiene el soporte puro de configuracion visual: primitivas, semantica
visual, themes, contrato CSS y render. `generated/base.css` es el primer
artefacto estatico generado desde esa configuracion (`npm run generate:eidos-css`).
Los antiguos `contracts/` y `themes/base/` CSS se retiraron del arbol activo:
el contrato publico se obtiene con `ActiveEidos.getCssContract()` /
`renderContractCss()` y el base visual sale de `generated/base.css` .
Los antiguos `tokens/components/*` tambien se retiraron: los nombres de
custom properties de recipe (`--toast-*`, `--dialog-*` , etc.) siguen siendo
el contrato estable, pero sus valores base viven en `EidosConfig.recipes` y
se generan en `generated/base.css` .
## Runtime activo
Eidos tiene una clase activa:
- `ActiveEidos` es el runtime activo y contexto visual de los wrappers Svelte.
Gestiona configuracion visual pura, primitivas, roles semanticos, themes,
validacion, render de CSS y persistencia. Conecta esa configuracion con los
servicios de `ActiveUix` cuando hay contexto:
`prefs` , `dom` , `langs` , `format` y helpers visuales como `resolve(...)` ,
`breakpoint(...)` o `isBelow(...)` . Si `applyDom` esta activo, inyecta/quita
`<style data-uix-eidos>` usando `uix.dom` .
Regla de dependencia: un componente en `src/uix/eidos/components/*` no importa
`getActiveUix()` directamente. Consume `ActiveEidos.require()` y solo conoce la
superficie visual de Eidos.
Regla de ownership: `ActiveEidos` no crea servicios compartidos. En modo
contexto, `ActiveEidos.create(...)` obtiene esos servicios de `ActiveUix` ; si
un wrapper requiere uno que no existe, lanza error. En modo explicito,
`createActiveEidos(...)` recibe servicios ya construidos. Con `applyDom:false`
queda como runtime sin escritura DOM: puede renderizar, serializar y validar
CSS sin insertar estilos.
Matiz importante: `prefs` , `langs` y `format` son opcionales durante la
construccion porque `ActiveEidos` tambien sirve para generar/serializar CSS.
Los getters `activeEidos.prefs` y `activeEidos.langs` si fallan temprano si un
wrapper visual los lee y no fueron inyectados. `dom` solo es obligatorio cuando
`applyDom` esta activo.
La configuracion vive en `EidosConfig` :
```ts
interface EidosConfig {
primitives: PrimitiveSet;
semantics: SemanticSet;
themes?: ThemeMap;
recipes?: RecipeTokenSet;
}
```
Para authoring incremental sobre el theme base existe
`EidosConfigPatch` . No sustituye al objeto completo: lo extiende de
forma profunda, preservando lo no declarado y reemplazando arrays completos
(por ejemplo `fallbacks` de una familia tipografica).
```ts
const config = createThemeBaseEidosConfig({
primitives: {
typography: {
families: {
primary: { family: 'Inter' }
}
}
},
semantics: {
color: {
roles: {
primary: 'blue'
}
}
}
});
```
Si la app quiere partir de cero, usa `defineEidosConfig()` con un
`EidosConfig` completo y lo pasa a `ActiveEidos.create({ config })` . Si quiere
partir del theme base, usa `createThemeBaseEidosConfig(patch)` o directamente
`ActiveEidos.create({ themeBase: patch })` .
`primitives` contiene las bases no semanticas: escalas de color de 12 pasos,
size map canonico, espacios, alturas de control, radios, borde, opacidad,
z-index, focus ring, layout, tipografia, sombras, motion e iconos.
`semantics.color.roles` mapea esas escalas a los roles canonicos:
```text
primary · secondary · tertiary · neutral · affirm · fulfill · risk · threat · loss
```
No hay `danger` , `success` , `warning` ni `info` : esos nombres pertenecen a
otros modelos. En Eidos los componentes hablan por intents y jerarquia visual.
`recipes` contiene los aliases publicos de cada recipe activa. No define
selectores ni estados de componente: solo valores para custom properties que
las recipes CSS consumen. Por ejemplo, `recipes.tooltip['content-z']` genera
`--tooltip-content-z` ; `recipes.dialog['overlay-bg']` genera
`--dialog-overlay-bg` . Asi los componentes mantienen su CSS estable y el tema
puede persistir/editar esos valores desde el mismo objeto de authoring.
El contrato recipe/CSS se valida en `recipe-css-contract.test.ts` : si una
recipe CSS consume `--{component}-*` , ese alias debe existir en
`EidosConfig.recipes` ; y si el theme base declara un alias publico, debe estar
consumido por el componente o por otro token compuesto. No hay reservas
fantasma ni paletas que el componente no pueda activar desde su API real.
Para editores de theme, `ActiveEidos.listRecipes()` enumera los componentes
con recipe tokens y `ActiveEidos.getRecipeTokens(component)` devuelve una
copia defensiva del mapa de aliases. No muta el config interno.
La decision vigente es mantener `recipes` como mapa plano de aliases
(`RecipeTokenSet`). Subir una recipe a tipo estructurado propio solo se
justifica cuando exista un builder o consumer real que necesite semantica
interna; mientras las recipes sigan siendo CSS plano, el contrato publico es
el custom property generado.
ActiveEidos genera tambien la escala alpha de cada paleta fisica:
```text
--scale-blue-a1 … --scale-blue-a12
--primitive-primary-a1 … --primitive-primary-a12
```
Si el theme declara `color.alphaScales` , esos valores se respetan. Si no, se
derivan desde el paso sólido de la escala (`--scale-{name}-9`) con una
progresion canonica de opacidad. Esto permite usar tintas translucidas para
overlays, rings, hovers suaves o scrims sin que cada recipe invente su propia
formula.
### Size canonico
`Size` es discreto y estable:
```text
xxs · xs · sm · md · lg · xl · xxl · full
```
`full` es semantica de layout y no genera primitiva fisica. La config mapea
solo `xxs..xxl` a tokens coordinados:
```text
--size-md-control-height
--size-md-font-size
--size-md-font-line-height
--size-md-font-letter-spacing
--size-md-icon-size
--size-md-padding-inline
--size-md-padding-block
--size-md-gap
--size-md-radius
```
La regla es: `md` no cambia de significado por viewport. Lo responsive decide
que size activo se usa (`ResponsiveProp< Size > `), no redefine los tokens de
`md` . Porcentajes, `vw` , `dvh` , `clamp()` o `min()` pertenecen a layouts
como `full` , panels y containers; no al size canonico de controles, iconos o
tipografia.
### Primitivas transversales
El bloque static ya genera las primitivas compartidas que suelen aparecer en
Radix Themes, Ark/Panda, Chakra, Tailwind o shadcn como foundation tokens:
- `layout` : anchuras de container, padding inline de container, anchuras de
contenido y ratios canonicos. Genera:
`--container-width-*` , `--container-padding-inline` ,
`--content-width-*` y `--aspect-ratio-*` .
- `density` : escalas `compact · comfortable · spacious` para que las recipes
puedan ajustar espacio, altura de control o contenido sin redefinir los
tokens canonicos. Genera `--density-{key}-*` y aliases activos como
`--density-space-scale` .
- `border` : anchuras `none · hairline · thin · medium · thick` , estilos
`solid · dashed · dotted` y aliases `--border-width` , `--border-style` ,
`--border` .
- `opacity` : `0 · muted · disabled · scrim · overlay · hover · press · full` .
- `zIndex` : `base · raised · sticky · dropdown · popover · tooltip · modal · toast` .
- `shadow` : escala fisica `1..6` más aliases semanticos
`none · subtle · raised · overlay` por theme.
La regla es la misma que en size: estos tokens no cambian de significado por
breakpoint. Un componente o wrapper puede elegir otro token en un viewport
concreto, pero `--shadow-3` , `--opacity-disabled` o `--z-index-modal` siguen
siendo la misma coordenada del sistema.
El bridge responsive vive en `ActiveDom` /`ActiveEidos`: los wrappers usan
`ActiveEidos.resolve(...)` , `breakpoint(...)` , `isAtLeast(...)` e
`isBelow(...)` para decidir que token canonico aplica en cada viewport.
`--container-width-md` o `--content-width-lg` no se recalculan por responsive;
lo que cambia es la eleccion del token. La densidad sigue el mismo principio:
`ActiveEidos` proyecta `data-density` y publica scalars activos:
```css
:root {
--density-compact-space-scale: 0.84;
--density-comfortable-space-scale: 1;
--density-spacious-space-scale: 1.16;
--density-space-scale: var(--density-comfortable-space-scale);
}
[data-density='compact'] {
--density-space-scale: var(--density-compact-space-scale);
}
```
Una recipe puede usar `calc(var(--space-4) * var(--density-space-scale))` .
`--space-4` no cambia de significado; cambia la policy visual activa.
`themes` permite sobrescribir escalas, roles, superficies, contenido, bordes,
focus y sombras por theme. El theme base actual expone `base-light` y
`base-dark` ; `defaultActiveEidosThemeResolver` usa el theme activo si existe
como id exacto, preserva ids externos ya cualificados (`*-light`, `*-dark` ) y,
si no, prueba `${theme}-${mode}` .
`ActiveEidos` no persiste CSS en disco. Si `applyDom` esta activo, escribe en
el DOM:
- `${styleId}-static` con primitivas estables (`renderStaticCss()`).
- `${styleId}-theme` con el theme resuelto cuando procede de la config.
`themeSource` decide de donde salen los valores de theme:
- `'auto'` (default): genera CSS si la config conoce el theme; si no lo
conoce, asume que viene de CSS externo y deja solo los tokens static.
- `'config'` : modo estricto; si el theme resuelto no existe en la config,
`renderThemeCss()` lanza error.
- `'css'` : nunca genera CSS de theme; el integrador aporta los valores con
CSS externo que respeta el contrato de custom properties.
Para inspeccionar o publicar ese contrato, `ActiveEidos` expone dos superficies:
- `getCssContract()` devuelve el contrato estructurado, typed, con cada token
(`name`, `cssVar` , `scope` , `category` , `path` ). Es la superficie pensada
para editores de theme, validadores, tooling o persistencia de usuario.
- `renderContractCss()` renderiza ese mismo contrato como CSS vacío para
documentar o bootstrappear themes externos.
- `renderCssVariables()` acepta un mapa de custom properties y lo convierte
en CSS runtime validado contra el contrato de Eidos.
```ts
const tokens = eidos.getCssContract();
const recipes = eidos.listRecipes();
const tooltipTokens = eidos.getRecipeTokens('tooltip');
const contract = eidos.renderContractCss({
staticSelector: ':root',
themeSelector: "[data-theme='acme-light']"
});
```
El resultado no asigna valores reales; declara las custom properties que un
theme CSS-only puede aportar o sobrescribir:
```css
[data-theme='acme-light'] {
--scale-blue-9: ;
--scale-blue-a9: ;
--primitive-primary-9: ;
--primitive-primary-a9: ;
--color-primary-solid: ;
--size-md-control-height: ;
--border-width-thin: ;
--opacity-disabled: ;
--z-index-modal: ;
--shadow-3: ;
}
```
La persistencia usa un envelope versionado:
```ts
const document = eidos.toDocument();
const json = eidos.serialize();
const hydrated = createActiveEidos({
config: JSON.parse(json),
prefs,
dom
});
```
El documento tiene forma `{ kind: 'uix.eidos-config', version: 1, options }` .
`EidosConfig` no lleva `version` dentro: sigue siendo configuracion
visual pura. Si el shape cambia en el futuro, se sube
`EIDOS_CONFIG_DOCUMENT_VERSION` ; Eidos no intenta compatibilidad silenciosa
con versiones no soportadas. La app decide dónde guardar ese documento
(prefs, backend, archivo, etc.) y qué metadata de producto lo envuelve
(`name`, owner, timestamps).
Al hidratar un documento como runtime (`config: document`,
`readEidosConfigFromDocument(...)` o `parseEidosConfigFromJson(...)` ), Eidos
valida también las `options` contra el contrato completo de `EidosConfig` .
`parseEidosConfigDocument(...)` queda como parser de envelope: confirma
`kind/version/options` , pero no convierte ese envelope en configuracion
visual usable por si solo.
Integracion normal dentro de un arbol con `ActiveUix` :
```ts
const uix = createActiveUix({
langs: { schema, defaultLocale: 'es' }
});
setActiveUix(uix);
ActiveEidos.create({
themeBase: {
semantics: {
color: {
roles: { primary: 'blue' }
}
}
},
themeSource: 'auto',
themeResolver,
styleId: 'uix-eidos'
});
```
`config` acepta un `EidosConfig` completo o un `EidosConfigDocument` .
`themeBase` acepta solo un patch sobre el theme base. Son
mutuamente excluyentes para que no haya ambiguedad entre "config completa" y
"override del base".
`theme` en Eidos nombra la familia/theme visual (`base`, `acme` ,
`acme-light` , etc.). `mode` nombra el esquema efectivo `light | dark` y
`density` nombra la ergonomia visual activa. Cuando `applyDom` esta activo,
`ActiveEidos` proyecta `data-theme` , `data-mode` y `data-density` en el
documento a traves de `ActiveDom` .
`mode` y `density` se inyectan como fuentes visuales, no como dimensiones de
`prefs` :
```ts
const eidos = ActiveEidos.create({
theme: 'base',
modeSource: {
get: () => colorMode,
onChange: (handler) => subscribeColorMode(handler)
},
densitySource,
applyDom: true
});
```
Si no se pasa `modeSource` , `ActiveEidos` usa `prefers-color-scheme` con
fallback `light` . Si no se pasa `densitySource` , usa `comfortable` . No leer ni
escribir `uix.prefs.theme` para UIX: el modo visual pertenece a Eidos.
Un theme CSS-only puede vivir fuera de TypeScript:
```css
[data-theme='acme-light'] {
--scale-blue-9: #006adc ;
--scale-blue-a9: color-mix(in srgb, var(--scale-blue-9) 56%, transparent);
--primitive-primary-9: var(--scale-blue-9);
--primitive-primary-a9: var(--scale-blue-a9);
--color-primary-solid: var(--primitive-primary-9);
--font-family-primary: Inter, system-ui, sans-serif;
--size-md-control-height: 38px;
--shadow-3: 0 8px 24px rgb(15 23 42 / 0.12);
}
```
Para pasar valores desde runtime sin recompilar:
```ts
activeEidos.setCssVariables({
'--color-primary-solid': 'rebeccapurple',
'size-md-control-height': '40px',
'shadow-3': '0 10px 28px rgb(20 20 20 / 0.16)'
});
```
`ActiveEidos` lo escribe en `${styleId}-variables` como un `<style>`
gestionado. Por defecto valida los nombres contra `getCssContract()` ; si una
app necesita variables locales fuera del contrato puede usar
`{ strict: false }` . La actualizacion es transaccional: primero renderiza y
valida el siguiente bloque, y solo reemplaza el estado runtime si el mapa es
usable. Un token desconocido no deja el style block anterior a medias.
No crear `ActiveEidos` desactiva la capa visual runtime de Eidos. Los
componentes Soma siguen funcionando headless porque el comportamiento pertenece
a Soma.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
## Qué consume
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
### De morfo (declaración)
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
| Pieza | Eidos la usa para |
| -------------------------------------------------------------- | --------------------------------------------------------- |
| `parts[].kebab` | selectores `[data-{component}-{kebab}]` |
| `parts[].archetype` | reglas transversales `[data-archetype=trigger]` |
| `parts[].states` + `data[].values` | variantes `[data-state=open]` |
| `parts[].data` con `data-starting-style` / `data-ending-style` | hooks de animación enter/exit |
| `events[].name` | selectores `[data-event=dismiss]` , `[data-event^=commit]` |
| `events[].semantic.family` + `.intent` | tinta semántica de transiciones |
| `events[].prewrite[]` (e.g. `data-last-action` ) | tintar exit anim por causa |
| `focus.trap` | hint de layout para overlays |
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
### De Soma
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
Los wrappers de `components/*` importan las partes públicas de Soma
directamente (`$soma/components/{x}`) y sólo añaden superficie visual de
Eidos: tokens, recipes, layout shells y data-attrs de presentación. No hay
facade intermedio por componente. Ejemplo:
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
```ts
// eidos/components/toggle/types.ts
import type { ProviderProps } from '$soma/components/toggle';
export type ToggleProps = ProviderProps & { variant?: ToggleVariant; size?: ToggleSize; … };
```
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
El wrapper `.svelte` importa el namespace público de Soma y usa sus partes con
ese mismo namespace:
```svelte
import * as Select from '$soma/components/select';
< Select.Provider { . . . rest } >
< Select.Trigger / >
< Select.Content / >
< / Select.Provider >
```
No usar aliases como `Parts` , `SelectBase` o `SomaSelectProvider` . Tampoco usar
etiquetas sueltas `<Provider>` / `<Trigger>` dentro de Eidos. El wrapper añade
los data-attrs de tokens visuales (`data-variant`, `data-size` , `data-block` ,
`data-icon-only` ) y no reimplementa el estado.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
### De sema (DOM)
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
Sólo el DOM. El visual channel proyecta `data-event-*` durante el hold
mediante `SignalProjector` y eidos reacciona vía `events.css` :
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
```css
[data-event-family='commit'][data-event-phase='active'] {
animation: eidos-commit-settle 260ms var(--ease-out);
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
}
[data-event-family='commit'][data-event-intent='threat'][data-event-phase='active'] {
animation: eidos-announce-pulse-threat 400ms var(--ease-spring);
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
}
```
`events.css` documenta los hold defaults por familia y por qué se usa
`animation: @keyframes` (no `transition` ) para reacciones a señales.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
## Qué NO consume
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
- **Computed state lógico** del provider (e.g. la composición de
`isDisabled` propio del componente con el `disabled` heredado de un
Field). Eidos sólo ve el resultado: `[data-disabled]` está o no está.
- **Internals de runtime**. No sabe si un attr lo escribió `dom.apply` ,
Svelte render o el provider manualmente. Sólo le importa que esté.
- **Layers de soma** (Presence, Dismissal, ScrollLock, FocusScope).
Reacciona a sus efectos visibles, no a su existencia.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
## La regla de los `--*` tokens
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
Eidos posee el namespace `--*` en el visual layer. Razones:
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
1. **Authorship clarity en debug** — inspeccionar un elemento y ver
`--toggle-bg` informa que viene del visual layer de UIX.
2. **Override discipline** — un consumer que sobreescribe
`--color-primary-element` sabe que está tocando contrato visual,
no nombrando-colisionando con una variable local.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
Las capas superiores (sema, soma, morfo) **NO consumen** estos tokens y
**no usan** el prefijo. Cada una carga sus propias concerns
(perceptual durations, behavior, contract DNA) ortogonales al
rendering visual.
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
feat(eidos): TSC v2.2 (parts + composition) + universal theming coverage
Token Scope Contract universal — no más excepciones arquitectónicas.
Los 3 componentes que vivían fuera de TSC v2.1 (select, avatar,
toggle-group) ahora están dentro del contrato via dos extensiones nuevas.
TSC v2.2 extensiones (lib/config-types.ts + render-css.ts + config.ts):
- `parts: readonly string[]` en RecipeTokenMultiDeclaration — emite
selectores comma-separados (`[data-{c}-x], [data-{c}-y]`) para
componentes con data-color cascadeado per-part. Consumer: select.
- `composition: { foreignRecipe: { targetSelector, tokens } }` sibling
key — overrides cross-recipe scoped a la cascade del host. Consumer:
toggle-group modifica `--toggle-palette-*` en sus items.
Migraciones:
- select: 3 private `_accent-{track,border,text}` con parts: ['trigger',
'content'] + 7 cascades color:X each. Removed orphan `_accent-solid`
(CSS no consumía).
- avatar: 6 tokens via composite scopes `['variant:X', 'color:Y']` con
matrix helper inline. Badge usa parts: ['badge']. Reemplaza 24 bloques
CSS × 2 partes.
- toggle-group: composition block con 8 palette tokens × 4 colors.
Reemplaza 4 bloques CSS per-color.
Bug toggle-group post-composition (encontrado y arreglado):
Tras la composition migration, el cascade del toggle-group seguía roto
porque los tokens derivados (`--toggle-solid-on-bg`, `--toggle-outline-fg`,
etc.) viven en scope `[data-toggle]`. El `[data-toggle-group-item]` es
sibling (no descendant), así que `var(--toggle-solid-on-bg)` resolvía
undefined. Fix: inlined derivation expressions directamente en
`[data-toggle-group-item]` y sus variant cascades (solid/outline/ghost),
referenciando palette tokens en su propio scope local.
Validador + emisor + contract:
- `validateRecipeComposition` valida el shape `{ targetSelector, tokens }`
y rechaza composition entries con scope='root'.
- `stripCompositionKey` + `emitComposition` separan el pipeline.
- `appendRecipeContractTokens` skip-list para `composition` (no aparece
como fake `--{c}-composition` knob).
- `tokenKeys`/`tokenEntries` helpers en recipe-css-contract.test.ts
filtran composition en todos los iteradores.
Documentación:
- THEMING.md §18 reescrito como "Cobertura universal de TSC". §7
extendido con subsecciones "Multi-part scope" y "Cross-recipe
composition" + ejemplos completos. TOC actualizado.
- eidos/README.md tabla de referencia ampliada con TSC v2.2 + §18.
- CLAUDE.md gana hand-off "2026-05-27 #5" (TSC v2.2 + cobertura universal).
- CONTINUE.md reescrito al estado actual de la sesión.
Working tree también incluye sprint Words en paralelo (multiple authors):
slash menu, find/replace regex, code language picker, table audit,
toolbar family menu, code highlight engine.
Tests: 786/786 pass en src/uix/{eidos,morfo,soma,sema}. `npm run check`:
6 errores pre-existentes (lib/_demo, soma/components/internal,
web/routes/active) no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 months ago
## Theming, tokens, bundle — ver `THEMING.md`
La doctrina completa del sistema de theming (token scope contract, token
layers, naming conventions, bundle purge, motion via `event:*` , comparación
con referencias, anti-patterns, FAQ) vive en
[`src/uix/eidos/THEMING.md` ](./THEMING.md ). Ese es el reference canónico.
Resumen rápido de lo que cubre, para no duplicar aquí:
| Tema | Sección en THEMING.md |
| --- | --- |
| Por qué el theming vive en Eidos y no en Morfo | §1.bis |
| 7 capas de tokens y override points | §3 |
| 9 roles canónicos de color | §4 |
| 6 sizes canónicos | §5 |
| Naming conventions | §6 |
| Token Scope Contract (TSC): tipo, álgebra de scope, cross-axis | §7 |
| TSC v2.2: multi-part scope (`parts: [...]`) + cross-recipe composition | §7 |
| Cómo añadir un componente nuevo | §8 |
| Cómo definir un theme | §9 |
| Cómo overridear tokens en runtime | §10 |
| Bundle strategy + `eidos:purge` | §11 |
| Integración con sema vía `event:*` | §13 |
| Anti-patterns y FAQ | §16, §17 |
| Cobertura universal de TSC (sin excepciones) | §18 |
feat(eidos): variants canon — EIDOS_VARIANTS + per-component lint
Variants son canon del eidos, NO del theme. Decisión arquitectónica
firmemente sostenida: el vocabulario de variants (solid/outline/ghost/
soft/surface/line/pills) está fijo a nivel del framework — paralelo
a las 8 sema families del libro. Theme = retintar lo perceptualmente
fijo; cambia QUÉ color es `affirm`, no QUÉ significa `outline`.
Cambios:
- lib/types.ts: nueva constante `EIDOS_VARIANTS` con los 5 archetypes
canónicos (control / selection / chip / marker / tabs). Los 5 union
types se derivan via `[number]` indexed access — valor y tipo no
pueden desincronizarse. Nueva `EIDOS_VARIANT_VALUES` Set flat con
todos los valores canónicos + utilidades cross-component (`plain`,
`subtle`).
- recipe-css-contract.test.ts: nuevo test "variant CSS selectors per
component match the declared type union". Por cada componente:
extrae el union type de `components/{c}/types.ts` (soporta literal
unions + archetype aliases; cae a advisory mode en Extract<> y
conditional types); compara con `[data-{c}][data-variant='X']`
selectores en `{c}.css`; reporta typos y unauthorized extensions
bidireccionalmente.
- THEMING.md §19: nueva sección "Variants son canon del eidos, NO
del theme" con argumentación (portabilidad, type safety, archetypes
perceptuales paralelos a sema families), tabla de las 3 capas de
la cebolla, referencia a `EIDOS_VARIANTS`, comparación con Radix
Themes 3.x / Mantine 7 / Chakra v3 / Ark / shadcn. TOC actualizado.
- eidos/README.md: tabla de referencia ampliada con §19.
- CLAUDE.md: hand-off "2026-05-27 #6 (variants canon)".
- CONTINUE.md: nota de la decisión arquitectónica.
Variants component-specific permitidos (Banner inline/overlay/
persistent, Spinner bars/dots/ring, Button 'plain'): viven en cada
`components/{c}/types.ts` y el lint los valida contra la CSS del
componente.
Tests: 101/101 pass en `src/uix/eidos`. `npm run check`: los mismos 6
errores pre-existentes (lib/_demo, soma/components/internal, web/
routes/active) — no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 months ago
| Variants son canon del eidos, NO del theme (con `EIDOS_VARIANTS` ) | §19 |
feat(eidos): TSC v2.2 (parts + composition) + universal theming coverage
Token Scope Contract universal — no más excepciones arquitectónicas.
Los 3 componentes que vivían fuera de TSC v2.1 (select, avatar,
toggle-group) ahora están dentro del contrato via dos extensiones nuevas.
TSC v2.2 extensiones (lib/config-types.ts + render-css.ts + config.ts):
- `parts: readonly string[]` en RecipeTokenMultiDeclaration — emite
selectores comma-separados (`[data-{c}-x], [data-{c}-y]`) para
componentes con data-color cascadeado per-part. Consumer: select.
- `composition: { foreignRecipe: { targetSelector, tokens } }` sibling
key — overrides cross-recipe scoped a la cascade del host. Consumer:
toggle-group modifica `--toggle-palette-*` en sus items.
Migraciones:
- select: 3 private `_accent-{track,border,text}` con parts: ['trigger',
'content'] + 7 cascades color:X each. Removed orphan `_accent-solid`
(CSS no consumía).
- avatar: 6 tokens via composite scopes `['variant:X', 'color:Y']` con
matrix helper inline. Badge usa parts: ['badge']. Reemplaza 24 bloques
CSS × 2 partes.
- toggle-group: composition block con 8 palette tokens × 4 colors.
Reemplaza 4 bloques CSS per-color.
Bug toggle-group post-composition (encontrado y arreglado):
Tras la composition migration, el cascade del toggle-group seguía roto
porque los tokens derivados (`--toggle-solid-on-bg`, `--toggle-outline-fg`,
etc.) viven en scope `[data-toggle]`. El `[data-toggle-group-item]` es
sibling (no descendant), así que `var(--toggle-solid-on-bg)` resolvía
undefined. Fix: inlined derivation expressions directamente en
`[data-toggle-group-item]` y sus variant cascades (solid/outline/ghost),
referenciando palette tokens en su propio scope local.
Validador + emisor + contract:
- `validateRecipeComposition` valida el shape `{ targetSelector, tokens }`
y rechaza composition entries con scope='root'.
- `stripCompositionKey` + `emitComposition` separan el pipeline.
- `appendRecipeContractTokens` skip-list para `composition` (no aparece
como fake `--{c}-composition` knob).
- `tokenKeys`/`tokenEntries` helpers en recipe-css-contract.test.ts
filtran composition en todos los iteradores.
Documentación:
- THEMING.md §18 reescrito como "Cobertura universal de TSC". §7
extendido con subsecciones "Multi-part scope" y "Cross-recipe
composition" + ejemplos completos. TOC actualizado.
- eidos/README.md tabla de referencia ampliada con TSC v2.2 + §18.
- CLAUDE.md gana hand-off "2026-05-27 #5" (TSC v2.2 + cobertura universal).
- CONTINUE.md reescrito al estado actual de la sesión.
Working tree también incluye sprint Words en paralelo (multiple authors):
slash menu, find/replace regex, code language picker, table audit,
toolbar family menu, code highlight engine.
Tests: 786/786 pass en src/uix/{eidos,morfo,soma,sema}. `npm run check`:
6 errores pre-existentes (lib/_demo, soma/components/internal,
web/routes/active) no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 months ago
Lo que sigue en este README son las decisiones operativas de la **capa
visual como módulo** (typography sourcing, picker patterns, API
conventions, runtime activo), independientes del sistema de theming.
feat(eidos foundation): vertebrate typography via named-style aliases + R-2.7
Single source of truth for typography values that the recipe layer
consumes. The foundation aliases `--font-ui` and `--leading-ui` (read
by ~30 recipe tokens in `lib/recipes/base.ts`) now derive from the
canonical `label` named style instead of carrying duplicate literals:
--style-label-font-family: var(--font-family-primary);
--style-label-line-height: 1.25;
--font-ui: var(--style-label-font-family, var(--font-family-primary));
--leading-ui: var(--style-label-line-height, 1.25);
Chain: typography.ts styles → --style-{name}-* → --leading-ui / --font-ui
→ recipe tokens → component CSS. Editing
`STATIC_TYPOGRAPHY.styles.label.lineHeight` now propagates to every
recipe in one go.
Why not push recipes to consume `--style-{name}-*` directly:
- t-shirt sizes (xs/sm/md/lg/xl) don't map to four semantic buckets
- per-component matices (description/caption/hint) need their own
color / weight / letter-spacing
- ref libraries (Radix Themes, Mantine, MUI, Chakra) all keep
numerical scale for component internals; semantic layer is only for
user-facing typography primitives (`<Text variant="body2">`)
Audit rule R-2.7 (warn): detects literal font-size / font-weight /
line-height / letter-spacing in eidos component CSS. Escape valves:
var(...), numeric identities (0/0px/1), keywords (inherit/initial/
unset), or trailing `/* literal: <reason> */` comment. Current run
flags 6 components with letter-spacing/font-size literals (all
intentional micro-tracking and em-relative; can be annotated case by
case).
Documentation:
- src/uix/eidos/README.md § "Vertebración tipográfica" — two-layer
architecture rationale, alias chain diagram, comparison vs Radix
Themes / Chakra / Mantine / MUI, escape valves
- web/routes/uix/lib/COMPONENT_AUDIT_GUIDE.md § 4.11 — pointer to
R-2.7 + cross-link to the foundation doc
Verified end-to-end in browser at /uix/components/field:
--font-ui → 'Instrument Sans', system-ui, sans-serif
--style-label-font-family → 'Instrument Sans', system-ui, sans-serif
--leading-ui → 1.25
--style-label-line-height → 1.25
computed [data-field-label].line-height → 17.5px (= 14 × 1.25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
## Vertebración tipográfica — single source of truth en foundation
Eidos tiene **dos anclas tipográficas, en capas distintas, por diseño** .
Esta sección documenta por qué y cómo se relacionan.
### Las dos capas
```
src/uix/eidos/lib/primitives/typography.ts
│
├── families / sizes / weights (escala numérica)
│ ↓
│ foundation tokens
│ --font-family-{primary,secondary,display,mono}
│ --font-size-{xxs..xxxl}
│ --font-weight-{regular,medium,semibold,bold}
│ --font-line-height-{xxs..xxxl}
│
└── styles (capa semántica)
↓
named-style tokens
--style-{hero,h1..h6,body,prose,label,caption,code}-{font-family,
font-size,line-height,letter-spacing,font-weight,color}
```
| Capa | Quién la consume | Para qué |
|---|---|---|
| **Foundation numerical** (`--font-size-*`, `--font-family-primary` , …) | recipe tokens en `lib/recipes/base.ts` + foundation aliases (`--font-ui`, `--leading-ui` , …) | Internals de componentes (Field labels, Combobox triggers, Button text, …) — necesitan **escalado t-shirt** (`xs/sm/md/lg/xl`) que NO mapea limpio a una semántica fija. |
| **Named styles** (`--style-label-*`, `--style-body-*` , `--style-caption-*` , `--style-h{1..6}-*` , `--style-{hero,prose,code}-*` ) | typography primitives (`< Text > `, `<Heading>` , `<Display>` , `<Code>` , `<Link>` , …) | API de usuario para componer contenido — el USUARIO eligió "label" o "body" y quiere que ese rol semántico se respete. |
**Las dos capas no son redundantes**: sirven a contextos distintos. La
numérica vertebra el _interior_ del sistema; la semántica vertebra la
_superficie_ que el consumer compone.
### Cómo se vertebran sin duplicarse — la chain de aliases
Donde un valor coincide entre las dos capas, **el foundation alias lee
del named style, no al revés**. Single source of truth: el named style.
```css
/* generated/base.css (vía render-css.ts) */
:root {
/* Named style — fuente de verdad */
--style-label-font-family: var(--font-family-primary);
--style-label-line-height: 1.25;
/* Foundation alias — vertebra los recipes */
--font-ui: var(--style-label-font-family, var(--font-family-primary));
--leading-ui: var(--style-label-line-height, 1.25);
}
/* recipes/base.ts → generated/base.css */
:root {
--field-label-line-height: var(--leading-ui);
--field-control-line-height: var(--leading-ui);
/* … docenas de recipe tokens más */
}
/* components/field/field.css */
[data-field-label] {
line-height: var(--field-label-line-height);
}
```
Cambiar `STATIC_TYPOGRAPHY.styles.label.lineHeight = '1.3'` (en
`primitives/typography.ts` ) propaga a `--style-label-line-height` →
`--leading-ui` → todos los recipes → todos los componentes. **Una sola
edición** llega a Field, Form, Combobox, Select, Toolbar, Toast y los
typography primitives simultáneamente.
El fallback `, 1.25` / `, var(--font-family-primary)` garantiza que el
sistema sigue produciendo CSS válido si el consumer apaga los named
styles en su foundation override.
### Por qué los component recipes NO leen `--style-{name}-*` directamente
Tentación recurrente: "cada componente debería leer `--style-label-font-size`
para que sea coherente". **No es la forma.**
1. **Las t-shirts no caben en cuatro buckets.** Un Field con `size="xs"`
tiene un label más pequeño que el "label canónico". Si su recipe leyera
`--style-label-font-size` , perderías ese escalado o tendrías que crear
`--style-label-{xs,sm,md,lg,xl}-*` , replicando lo que ya viven los
recipe tokens.
2. **Los matices por componente son legítimos.** El message-de-Field, el
description-de-Tooltip y el subtitle-de-Card son todos "caption-ish"
pero cada uno quiere su color/weight/letter-spacing propios. Forzarlos
a un único `--style-caption-*` mata expresividad.
3. **Coupling lock-in.** Día 100 el sistema quiere `label-form` ,
`label-table` , `label-chart` . Forzar acoplamiento día 1 te lleva a
replicar la jerarquía recipe en la capa semántica.
4. **Cómo lo hacen las referencias.** Radix Themes, Mantine, MUI todos
tienen escala numérica que los componentes leen; la capa semántica
existe sólo para los typography primitives (`< Text variant = "body2" > `).
Chakra v3 ofrece `textStyle` acoplable pero la mayoría de sus
componentes hardcodean igualmente. **Acoplar todo a la capa semántica
no es la práctica dominante** y por buenas razones (1-3).
### Auditoría: regla `R-2.7`
`scripts/component-audit.ts` detecta literales tipográficos en CSS de
componentes: `font-size: 12px` , `line-height: 1.4` , `font-weight: 500` ,
`letter-spacing: 0.02em` que **no** estén envueltos en `var()` . Severidad
`warn` , no `error` — el componente sigue pasando, pero queda visible en
el report.
**Escape valves** (no cuentan como drift):
- valores en `var(...)`
- ceros e identidades: `0` , `0px` , `0em` , `0rem` , `1`
- keywords: `inherit` , `initial` , `unset`
- comentario en línea: `font-size: 13px; /* literal: tight icon affordance */`
Si necesitas un literal con justificación, anótalo. Si no, tokenizalo.
## La regla "2-de-3" (heredada de morfo)
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
Una extensión a morfo se justifica si **al menos dos de las tres capas**
(soma, sema, eidos) la consumen. Las que entraron por el voto de eidos:
docs: cross-layer articulation — eidos README + 2-of-3 rule across all layer docs
Closes the documentation loop on the cross-layer extension pass: morfo
now articulates between soma, sema, and (future) eidos. The "2-of-3 rule"
formalizes when an extension to morfo is justified vs when it should
stay as provider logic.
src/uix/eidos/README.md (new)
- Documents eidos's role and what it consumes from morfo + sema BEFORE
any code exists, so the contract is preparedly clean when implementation
starts.
- Catalogs which morfo fields eidos reads (parts, archetype, states,
data values, events, prewrite, focus, supportsNesting) and which it
ignores (computed state, runtime internals, layers).
- Documents the DOM-as-channel pattern: sema writes data-event* on emit;
eidos reacts to selectors like `[data-event^="dismiss"]`.
- Establishes the boundary with `air` (dead branch reference, not base).
src/uix/README.md (top-level)
- §8 Reglas de dependencia: adds the 2-of-3 rule table making the
morfo-extension contract explicit, plus a list of canonical vocabularies
(archetypes, verbs).
- §10 Reading order: includes eidos README + lib/dom + clarifies which
layers are dead branches.
src/uix/morfo/README.md
- New "Archetypes" section documenting the 24-verb vocabulary, the
Provider-as-trigger vs Provider-as-container distinction, and the rule
for adding new archetypes (≥2 components share the role).
- New "The 2-of-3 rule" section with the same table as the top-level,
listing which extensions did/didn't make it past the rule and why.
- `parts[].archetype` mentioned in the "What morfo contains" list.
src/uix/sema/README.md
- New "Vocabulario canónico de verbs" section listing SEMA_VERBS by
family and the `{verb}-{variant}` composite naming convention.
- Documents `validateEventName()` as advisory tooling.
src/uix/soma/SOMA_ARCHITECTURE.md
- partProps documentation now mentions data-archetype emission.
- New "Cross-layer hooks que soma emite por la regla 2-de-3" section
listing the data-* attrs soma writes that sema and eidos consume.
- Reading-order links updated.
No code changes — all docs.
6 months ago
- `archetype` — eidos + sema (+ soma como emisor)
- `events[].semantic.family/intent` — sema + eidos
- `events[].prewrite[]` — soma (ejecuta) + eidos (anima)
- `data-starting-style` / `data-ending-style` — soma (Presence) + eidos (anima)
## Convenciones del API — disciplined option C (vigente 2026-05-10)
Las convenciones doctrinales viven en
[`src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md` ](../../docs/GUIA_IMPLEMENTACION_SEMAUIX.md )
sección 13 (operación instantánea = un evento; sistema
unificado de 8 tokens; intent ↔ color resolution; subset por
componente; iconOnly sr-only; sound prepare-time priming).
La convención del **shape público** del componente eidos vive en
[`components/README.md` ](./components/README.md ). Resumen — 7 reglas
duras:
1. **Un solo punto de entrada por componente** — la default export es
el componente root visual, llamado igual que el componente
(`< Drawer > `, `<Tabs>` , `<Checkbox>` ). NO `<Drawer.Provider>` ,
NO `<Drawer.Root>` .
2. **El root vive en `{name}.svelte`** — NO en `{name}-provider.svelte` .
Un solo fichero por root.
3. **NO exportar `Provider` públicamente.** La separación
"Provider compound vs flat" es invención retirada; hay UNA forma
compound (root + hijos atados como propiedades).
4. **Hijos siguen el naming de air / headless** : `Trigger` , `Content` ,
`Overlay` , `Title` , `Description` , `Close` , `Portal` , `Header` ,
`Footer` , `Item` , `Indicator` , `HiddenInput` , `Group` , `Label` .
No inventar nombres.
5. ** `Portal` se incluye donde air lo tenía** (Dialog, Drawer, Popover,
Tooltip — overlays portaled). Importado de
`$soma/components/internal` .
6. **NO flat con snippet slots como API principal** —
`<Drawer trigger={...} title={...}>` está retirado. La compound
explícita expone las decisiones de composición que el flat escondía.
7. **Hijos atados con asignación explícita** , no `Object.assign`
(Svelte 5 puede manejar mal la mutación bulk del component
constructor durante hidratación):
```ts
const Drawer = DrawerRoot as DrawerNamespace;
Drawer.Trigger = Trigger;
Drawer.Content = Content;
```
Plus reglas de implementación:
8. **Wrapper, no fork.** El `.svelte` de eidos importa el namespace
público de Soma (`import * as Drawer from '$soma/components/drawer'`),
usa `<Drawer.Provider>` / `<Drawer.Trigger>` internamente y añade
los data-attrs de tokens visuales. No
reimplementa estado.
9. ** `Size` desde `lib/types.ts` .** Componentes que aceptan tamaños
reusan el tipo compartido y narrowingan al subset que su recipe
soporta (`Extract< Size , ' sm ' | ' md ' | ' lg ' > `).
10. **Sin prefijo `Eidos`** en los tipos. El path
`$uix/eidos/components/{x}` ya identifica la capa.
11. **CSS recipe sin prefijo `--eidos-`.** Los custom properties usan
`--{component}-…` para los públicos y `--_{component}-…` para los
internos.
### Por qué disciplined option C
El patrón anterior (default flat con snippet slots + Provider compound
duplicado) tenía dos problemas:
- **Doble verdad**: dos APIs (flat con `trigger` /`title`/`actions`
snippets, compound con children explícitos) llevaban a la misma
funcionalidad por caminos divergentes. Cualquier tweak visual
exigía actualizar ambas.
- **Inventaba sobre air**: air era pure compound (`< Drawer.Provider > `
con children). El flat con snippets fue una invención sin
baseline ni firma del usuario.
Option C disciplinada:
- Toma de **air** la convención de hijos (Trigger, Content, Portal, …)
- Toma de **bits-ui / shadcn-svelte** la ergonomía del root con propiedades
attached (`< Drawer > < Drawer.Trigger > `)
- Elimina la invención del flat con snippets (no era ni air ni soma)
### Caso especial — Toast
Tiene dos roots independientes (no anidados):
- `<Toast>` — manual compound (consumer itera `toaster.toasts` )
- `<Toaster />` — imperative auto-mount (template default)
Export separados; `Toaster` NO va attached como `Toast.Toaster` porque
es un root competidor, no un hijo. Documentado en
[`components/toast/index.ts` ](./components/toast/index.ts ).
## Defensa contra drift de selectores
La cadena morfo → soma → eidos depende de que los selectores que eidos
escribe (`[data-{component}]`, `[data-{component}-{part}]` ,
`[data-state=...]` , `[data-event-*=...]` ) se mantengan en sintonía con
los attrs que el morfo declara y el runtime emite. Hay dos defensas
distintas según el tipo de consumidor:
### Compile-time (TS / Svelte) — typed builder
Cualquier consumidor TypeScript que construya selectores
**MUST** usar `semaSelector(morfo, partKebab, matchers?)` desde
`$uix/morfo` . Esto cubre las cascade rules de `sema/components/*.ts` y
cualquier lógica TypeScript en `eidos/components/{x}/` que apunte a
attrs morfo-backed.
```ts
import { semaSelector } from '$uix/morfo';
import { toggleMorfo } from '$uix/morfo/components/toggle';
semaSelector(toggleMorfo, 'provider', { eventName: 'commit-toggle' });
// → '[data-toggle][data-event="commit-toggle"]'
```
Renombrar una part o un evento en el morfo rompe el typecheck. Es
imposible que un selector TypeScript drifte silenciosamente. Ver
[`morfo/README.md#typed-selector-builder--semaselector` ](../morfo/README.md#typed-selector-builder--semaselector ).
### Run-time (CSS recipes) — `eidos-lint` como red de seguridad opt-in
Los recipes son CSS plano (`components/{x}/{x}.css`); no hay typed
builder en el lado CSS. Para esa superficie:
```bash
node scripts/eidos-lint.ts toggle # un componente
node scripts/eidos-lint-all.ts # todos
```
Clasifica cada selector `[data-*]` como:
- **morfo-backed** — declarado en el morfo; soma runtime lo emite;
el valor (si hay enum) cae dentro de `data[].values` .
- **eidos-only** — el marker está, pero al menos un `data-*` no está
declarado en el morfo. Válido por convención (tokens visuales como
`data-variant` , `data-size` vienen del wrapper).
- **invalid** — referencia un attr declarado pero con un valor fuera
del enum. Bug.
**El lint es una red de seguridad, no el contrato.** El contrato vive
en el morfo y se defiende a nivel de tipos donde se puede. El lint
existe sólo para la porción CSS-pura que aún no consume el morfo a
través de TypeScript. Cuando los recipes migren a un builder, el lint
podrá retirarse.
## Cambios 2026-05-21 — pickers: kind + composition
- **`kind: 'date' | 'month' | 'year'`** sobre `DatePicker` y
`DateRangePicker` . Single source for input segments + popover view.
Inputs filtran segments en el `DateFieldProvider` (soma) — los
consumers nunca filtran en el snippet. Views como parts canónicas
Eidos: `<DatePicker.YearView>` , `<DatePicker.MonthView>` , idem en
range. Range views implementan state machine: empty → start, pending
→ end (con swap automático si reverse), complete → reset.
- **Footer = composición pura**. Drop de `clearButton/cancelButton/
closeButton` root props. `<Picker.Footer>` contiene las parts que
compongas; cada part renderiza siempre que se monta (sin checks
internos). Modal mode no fuerza Close visible — el consumer es
responsable de incluirlo (documentado en la part).
- **Modal mode + footer pattern** documentado en
[`PENDIENTES.md` ](../PENDIENTES.md ) (norma N-6 y N-7).
- **Provider helpers**: `commit() / cancel() / clear()` en
DatePickerProvider y DateRangePickerProvider. `cancel()` revierte
al snapshot capturado en el OPEN edge vía `watch(open)` .
- **Composition wins**: no hay `MonthPicker` / `YearPicker` /
`MonthRangePicker` / `YearRangePicker` como componentes propios.
Esas variantes son `<DatePicker kind='month'>` /
`<DateRangePicker kind='year'>` etc.
## Picker patterns (contrato reutilizable)
Los pickers (`date-picker`, `date-range-picker` , y los futuros
`time-picker` , `time-range-picker` , `color-picker` ) comparten un
contrato común. Documentado aquí como referencia canónica — cualquier
picker nuevo se construye sobre este esqueleto.
### P-1 · Provider helpers: `commit() / cancel() / clear()`
Cada `*PickerProvider` expone tres métodos imperativos consumidos por
las parts del Footer:
- **`commit()`** — cierra el popover preservando `value.current` tal
cual. Es la confirmación normal del valor seleccionado.
- **`cancel()`** — revierte `value.current` al snapshot capturado en
el **OPEN edge** y cierra el popover. El snapshot se toma vía
`watch(opts.open)` cuando `open` transita de `false → true` :
```ts
private valueOnOpen: TValue | undefined = undefined;
constructor(...) {
watch(() => this.opts.open.current, (isOpen) => {
if (isOpen) this.valueOnOpen = $state.snapshot(this.opts.value.current);
});
}
cancel() {
this.opts.value.current = this.valueOnOpen;
this.opts.open.current = false;
}
```
- **`clear()`** — pone `value.current = undefined` . NO cierra el
popover (es una acción destructiva visible que el usuario puede
querer seguir editando). Si el consumer quiere cierre tras clear,
compone `<Picker.Close/>` en el mismo footer.
Estas tres operaciones son ortogonales: cada part Footer hace exactamente
una. No mezcles (ej. `clear` no debe cerrar; `cancel` no debe limpiar).
### P-2 · `mode: 'inline' | 'modal'` → `popover.modal`
`mode` es un opt root del provider que se propaga al `Popover.modal`
underlying:
- **`mode='inline'`** (default) — popover no-modal. Outside-click
cierra. Escape cierra. Body scroll libre.
- **`mode='modal'`** — popover modal. Outside-click NO cierra (el
usuario debe usar `<Picker.Close/>` o `<Picker.Cancel/>` ). Escape
sigue cerrando. Focus trap dentro del popover. Body scroll lock.
El consumer NO setea `popover.modal` directamente — eso es decisión
del provider:
```svelte
< Popover.Provider modal = {provider.opts.mode.current = = = ' modal ' } . . . >
```
Modal mode obliga al consumer a componer un Footer con `<Cancel/>` o
`<Close/>` para escapar; sin ellos el popover sólo cierra por Escape.
Sigue siendo el consumer responsable (no auto-injecta nada).
### P-3 · Shell composition (Provider > Input > Portal > Content > view + Footer)
Layout canónico de un picker:
```svelte
< X.Provider value = {...} open = {...} mode = 'modal' kind = 'date' >
{#snippet trigger()}
< X.Input / > {!-- field input con segments, button, etc. --}
{/snippet}
{#snippet content()}
< X.Content >
{#if kind === 'year'} < X.YearView / >
{:else if kind === 'month'} < X.MonthView / >
{:else} < X.Calendar / >
{/if}
< X.Footer >
< X.Clear / >
< X.Cancel / >
< X.Close / >
< / X.Footer >
< / X.Content >
{/snippet}
< / X.Provider >
```
- **Trigger snippet** — entry surface (input + segments, button, swatch…).
- **Content** — popover content; sólo `<X.Content>` puede ir aquí.
- **View** — `Calendar` , `YearView` , `MonthView` , `Clock` , `Picker`
(color), etc. El consumer hace branching estructural por `kind` o
variante (P-4 abajo).
- **Footer** — `<X.Footer>` es contenedor archetype='footer'. Las
parts (`Clear`, `Cancel` , `Close` , etc.) se componen dentro. Cada
part renderiza sin checks internos contra props del provider —
presencia = visibilidad (N-7).
Si quieres omitir el footer entero, no compones `<X.Footer>` . Si
quieres sólo `Close` , compones sólo `<X.Close>` dentro.
### P-4 · `kind` o equivalente como single source of truth
Cuando un picker tiene variantes de granularidad (date: day/month/year;
time: hour/minute/second), el opt `kind` (o equivalente) es el ** único
punto de configuración**. Drives:
1. **Segments del input** — filtrado a nivel del FieldProvider (soma),
no en el snippet del consumer. El provider expone una derivación
tipo `visiblePartsByKind: Set<PartName>` y `segmentContents` filtra
`allSegmentContent.arr` colapsando literal runs.
2. **View del popover** — el consumer hace branching estructural sobre
el opt (`{#if kind === 'year'} < YearView / > ` etc).
**No existen** componentes separados por variante (`MonthPicker`,
`HourPicker` , etc). Esas formas son `<X kind='month'>` ,
`<X kind='hour'>` .
### P-5 · Range state machine (para `*-range-picker`)
Para selección de rangos, el provider mantiene un estado interno
implícito (no expuesto como opt):
- **empty** (`value === undefined` o `{start: undefined, end: undefined}` )
— siguiente click setea `start` . Estado pasa a `pending` .
- **pending** (`start` definido, `end` undefined) — siguiente click
setea `end` . Si el nuevo punto < `start` , **swap automático**
(start ↔ end). Estado pasa a `complete` .
- **complete** (`start` y `end` definidos) — siguiente click reinicia:
setea `start = click` , `end = undefined` . Estado pasa a `pending` .
Cada granularidad normaliza los endpoints:
- **Year range** — start = Jan 1, end = Dec 31.
- **Month range** — start = day 1, end = último día del mes.
- **Day range** — start/end son la fecha clickada tal cual.
- **Hour range** — start = `:00` , end = `:59:59` .
Implementado en `YearView` /`MonthView`/`Calendar` (range variant). El
provider sólo expone `setValue(start, end)` ; la state machine vive
en los views.
eidos: theming fixes + size/variant parity batch + docs
- theme: add surface.muted + content.muted to color contract (neutral-3
+ neutral-10). Plugs 17 broken --color-content-muted and 3 broken
--color-surface-muted references in recipes/components.
- form.css: fix --color-neutral-element-hover typo → --color-neutral-hover.
- archetypes.css + events.css: replace raw hsl/rgba indigo with
color-mix(var(--color-primary-solid) …) — no raw colors left in eidos.
- combobox dark scrollbar: unscope ::-webkit-scrollbar rules in uix.css
and duplicate --uix-line on :root + :root[data-mode='dark'] so portaled
overlays (Combobox listbox, Popover, Dialog, Drawer) inherit the theme.
- sizes: 20 components expand from sm/md/lg to xs..xl (form controls,
text inputs, progress/meter, field/form) or xs..lg (nav controls:
breadcrumb, pagination, tag-group, toolbar). Composite panels keep
sm/md/lg deliberately.
- variants: field + toolbar drop arbitrary ControlVariant narrowings;
both expose all 3 (surface | outline | ghost) with new outline CSS.
- pagination demo: disambiguate siblingCount/boundaryCount as "per side"
in label + API table (Radix/MUI convention).
- docs: CHECKLIST §C-2.6 (contract token presence) + §D-7.4 (chip parity)
+ §D-7.5 (size category) added. DEMO_AUTHORING §12.7 (chip parity) +
§12.8 (size category cheatsheet) added. eidos/README +
active_architecture.md sync texts/migration nomenclature.
- PENDIENTES.md: normas N-1..N-5 implantadas en esta sesión.
Verification: 88/88 eidos tests, 0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
## Cambios 2026-05-21
- **Tokens muted añadidos al contrato.** `SurfaceColorRoles` y
`ContentColorRoles` ahora incluyen `muted` (entre `overlay` +`backdrop`
y entre `secondary` +`disabled` respectivamente). Mapeo base:
`--color-surface-muted: var(--primitive-neutral-3)` (light + dark) y
`--color-content-muted: var(--primitive-neutral-10)` . Antes existían
17+3 referencias rotas en recipes/components que el browser caía a
initial-value (texto invisible para placeholders, separadores,
weekday del calendar, group-heading del select, etc.). Solucionado
vía `themes/base.ts` + `render-css.ts` + regen.
- **Typo `--color-neutral-element-hover` corregido** en `form.css:76`
→ `--color-neutral-hover` (el token correcto existente).
- **Raw colors removidos.** `archetypes.css:122` (hsl indigo fijo para
`[aria-selected]` ) y `events.css:eidos-commit-settle` (rgba indigo
fijo) sustituidos por `color-mix(var(--color-primary-solid) …)` . Ya
no quedan hex/rgb/hsl crudos en `src/uix/eidos/**/*.css` ni en
`recipes/base.ts` .
- **Cobertura de tamaños expandida.** 20 componentes pasan de
`sm·md·lg` a `xs·sm·md·lg·xl` (form controls + text inputs +
progress/meter + field/form) o a `xs·sm·md·lg` (nav controls:
breadcrumb, pagination, tag-group, toolbar). Categorización
documentada en
[`web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md §12.8` ](../../../web/routes/uix/lib/DEMO_AUTHORING_GUIDE.md ).
Paneles compuestos (calendar, date-picker, date-range-picker,
file-upload, stepper, tooltip) mantienen `sm·md·lg` . La elección
responde a uso real, no a artificio: barras y controles tactiles
escalan limpio en 5 escalones; paneles compuestos no se benefician
por debajo de `sm` .
- **Paridad de chips en demos.** `field.variant` y `toolbar.variant`
dejaron de narrowar `ControlVariant` a 2 valores; ahora exponen los
3 (`surface | outline | ghost`). El CSS añade selectores
`[data-variant='outline']` con bg transparente + border visible para
ambos componentes. La norma queda fijada en CHECKLIST §D-7.4.
- **Scrollbar portaled.** Las reglas `::-webkit-scrollbar*` viven sin
scope en `web/routes/uix/uix.css` (sólo se carga bajo `/uix` ).
`--uix-line` se duplica en `:root` con override
`:root[data-mode='dark']` (atributo escrito por `ActiveEidos` ),
permitiendo que portals (Combobox listbox, Popover, Dialog, Drawer)
resuelvan el token aunque vivan fuera de `[data-uix-docs]` .
## Estado actual (2026-05-17)
- **ActiveEidos**: implementado como runtime/contexto visual y superficie de
configuracion. Gestiona primitivas, roles canonicos, themes, validacion,
contrato CSS, persistencia y render CSS (`renderStaticCss`,
`renderThemeCss` ).
- **Authoring API**: `defineEidosConfig` , `extendEidosConfig` y
`createThemeBaseEidosConfig`
permiten crear configuraciones completas o extender el theme base sin
mutar las constantes del sistema. `getCssContract()` expone el contrato
estructurado, `renderContractCss()` lo materializa como CSS para themes
externos, `renderCssVariables()` permite escribir overrides runtime
contract-aware y `toDocument()` / `serialize()` exponen el envelope
versionado para persistencia.
- **Runtime CSS**: `ActiveEidos` reacciona a su `preferences` compuesto o a
fuentes explicitas `modeSource` / `densitySource` , soporta themes de config
y CSS-only via `themeSource` , acepta variables runtime en un style block
propio, y con `applyDom:false` no escribe en el DOM.
- **Wrappers por componente**: la superficie migrada desde Soma ya incluye
`toggle` , `switch` , `collapsible` , `dialog` , `drawer` , `popover` , `toast` ,
`accordion` , `avatar` , `tooltip` , `tabs` , `checkbox` , `radio-group` ,
`meter` , `progress` , `slider` , `pagination` , `rating-group` ,
`search-field` , `number-field` y `breadcrumb` . Todos usan root visual +
partes attached, sin `Provider` público ni API flat.
- **Color**: basado en roles canonicos de jerarquia e intents
(`primary`, `secondary` , `tertiary` , `neutral` , `affirm` , `fulfill` ,
`risk` , `threat` , `loss` ) y escalas de 12 pasos. Por cada escala genera
alpha tokens `a1..a12` , derivadas automaticamente o sobrescribibles con
`color.alphaScales` por theme. Los roles semanticos validos son solo los
declarados por el contrato de Eidos.
- **Size**: `xxs..xxl` se renderiza como map global coordinado
(`control-height`, font, icon, padding, gap, radius). `full` queda como
eidos: theming fixes + size/variant parity batch + docs
- theme: add surface.muted + content.muted to color contract (neutral-3
+ neutral-10). Plugs 17 broken --color-content-muted and 3 broken
--color-surface-muted references in recipes/components.
- form.css: fix --color-neutral-element-hover typo → --color-neutral-hover.
- archetypes.css + events.css: replace raw hsl/rgba indigo with
color-mix(var(--color-primary-solid) …) — no raw colors left in eidos.
- combobox dark scrollbar: unscope ::-webkit-scrollbar rules in uix.css
and duplicate --uix-line on :root + :root[data-mode='dark'] so portaled
overlays (Combobox listbox, Popover, Dialog, Drawer) inherit the theme.
- sizes: 20 components expand from sm/md/lg to xs..xl (form controls,
text inputs, progress/meter, field/form) or xs..lg (nav controls:
breadcrumb, pagination, tag-group, toolbar). Composite panels keep
sm/md/lg deliberately.
- variants: field + toolbar drop arbitrary ControlVariant narrowings;
both expose all 3 (surface | outline | ghost) with new outline CSS.
- pagination demo: disambiguate siblingCount/boundaryCount as "per side"
in label + API table (Radix/MUI convention).
- docs: CHECKLIST §C-2.6 (contract token presence) + §D-7.4 (chip parity)
+ §D-7.5 (size category) added. DEMO_AUTHORING §12.7 (chip parity) +
§12.8 (size category cheatsheet) added. eidos/README +
active_architecture.md sync texts/migration nomenclature.
- PENDIENTES.md: normas N-1..N-5 implantadas en esta sesión.
Verification: 88/88 eidos tests, 0 type errors, 67/67 component:audit PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
valor de layout, no como primitiva fisica. Cada componente declara
el sub-rango que su recipe mapea — la categorización canónica está
en `DEMO_AUTHORING_GUIDE.md §12.8` (form controls + text inputs +
progress/meter + field/form usan `xs..xl` ; nav controls usan
`xs..lg` ; paneles compuestos mantienen `sm..lg` ).
- **Border / opacity / z-index / shadow**: ya forman parte del contrato
generado. Border define escala de width/style y aliases globales; opacity
cubre estados de UI y overlays; z-index cubre capas comunes; shadow combina
escala fisica `1..6` con aliases semanticos por theme.
- **Layout**: ya forma parte del contrato generado. Incluye
`containerWidth` , `containerPaddingInline` , `contentWidth` y `aspectRatio`
como tokens estables y authorables desde `EidosConfig` .
- **Density**: ya forma parte del contrato generado. Incluye `scale` ,
`spaceScale` , `controlScale` y `contentScale` para los tres niveles
canonicos `compact` , `comfortable` y `spacious` , conectados al
`data-density` que proyecta `ActiveEidos` .
- **Tipografia**: usa tamaños canonicos `xxs` a `xxxl` , familias
libres por key y estilos tipograficos (`h1`, `h2` , `body` , etc.) como
`Record<string, TypographyStyle>` .
- **Convencion del API de componentes**: disciplined option C esta
documentada en [`components/README.md` ](./components/README.md ). La migracion
de componentes avanza por tandas pequenas y no debe arrastrar cambios de
demos/rutas ni reimplementar comportamiento que pertenece a Soma.
- **CSS generado**: `generated/base.css` ya se genera desde la config
base de Eidos con `npm run generate:eidos-css` y se importa como foundation
estatica. Los CSS historicos de `contracts/` y `themes/base/` ya no existen
en el arbol activo; el contrato se publica desde `ActiveEidos` y los valores
base desde `generated/base.css` . Los antiguos `tokens/components/*` tambien
salen del entrypoint: `EidosConfig.recipes` genera los aliases de recipe
estables.
- **Recipes**: quedan deliberadamente como `RecipeTokenSet` plano. No se crea
jerarquia estructurada hasta que una recipe tenga un builder/consumer real
que necesite mas semantica que aliases CSS. La guardia
`recipe-css-contract.test.ts` evita que el theme base declare aliases no
consumidos o que un CSS de componente use variables fuera del contrato.
- **Check del repo**: `npm run check` no reporta errores ni warnings en este
punto.