Align Soma docs with current layering

active-uix
dev 5 months ago
parent ee84c84679
commit ad4a35800f

@ -83,6 +83,12 @@ Actualizacion 2026-05-16:
6. Dejar optimizaciones de rendimiento para despues de cerrar API publica y
wrappers: virtualizacion compartida, datetime compartido y micro-churn del
runtime solo si aparecen datos reales o tests que lo justifiquen.
7. Cerrado: guia/documentacion Soma alineada con el estado actual:
pertenencia no-Soma apunta a Eidos, no Air; `{name}-provider.svelte.ts`
contiene clases provider/state concretas sin herencia; `soma.runtime()` es
el camino canonico dentro de providers; demos viven en
`web/routes/uix/components/{name}`; Eidos consume Soma por subpaths
publicos y Sema posee percepcion/eventos.
- Auditoria `src/arts/sium/kimi-audit.md` leida y evaluada. Mi veredicto:
buena auditoria, bastante alineada con el rol real de Sium como codec +
validador + introspeccion para Active, pero con dos matices:

@ -20,11 +20,11 @@ Document what soma includes and what it skips (with reason).
The component must meet ALL of these:
- **WAI-ARIA pattern or semantic role** — the component implements a pattern from the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) (Dialog, Combobox, Treegrid, Feed, Tabs, Toolbar, …) OR a canonical ARIA role (`role="status"`, `role="meter"`, `role="progressbar"`, `role="searchbox"`, …). If the browser's native HTML gives you the right role + keyboard model with no extra behavior required (e.g. `<a>` for Link, `<hr>` for Separator, `<img>` for Image), the primitive belongs in **air**, not soma.
- **Composition of parts** — 2+ sub-components communicating via context (Provider + Trigger + Content, Provider + Row + Cell, etc.). A single-DOM wrapper is air-level styling, not headless behavior.
- **WAI-ARIA pattern or semantic role** — the component implements a pattern from the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) (Dialog, Combobox, Treegrid, Feed, Tabs, Toolbar, …) OR a canonical ARIA role (`role="status"`, `role="meter"`, `role="progressbar"`, `role="searchbox"`, …). If the browser's native HTML gives you the right role + keyboard model with no extra behavior required (e.g. `<a>` for Link, `<hr>` for Separator, `<img>` for Image), the primitive belongs in **Eidos**, not Soma.
- **Composition of parts** — 2+ sub-components communicating via context (Provider + Trigger + Content, Provider + Row + Cell, etc.). A single-DOM wrapper is Eidos-level styling, not headless behavior.
- **Complex behavior** — keyboard navigation, focus management, floating, ARIA relationships, state machines, drag, form integration, or live-region coordination. Adding `role="…"` + `aria-label` to a single element is not enough.
If it fails any of these → it's air-native, not soma.
If it fails any of these → it's Eidos-native, not Soma.
Accepted exceptions (composition criterion waived when WAI-ARIA defines a tight contract):
@ -35,7 +35,7 @@ Accepted exceptions (composition criterion waived when WAI-ARIA defines a tight
```
components/{name}/
├── {name}-provider.svelte.ts ← ALL state classes (Provider subclasses)
├── {name}-provider.svelte.ts ← ALL concrete provider/state classes
├── types.ts ← ALL prop types with JSDoc + canonical field shapes
├── langs.ts ← optional idlangref constants for imperative strings
├── exports.ts ← barrel (Provider, Trigger, Content, etc.)
@ -287,8 +287,8 @@ Pattern: `soma-{component}-{part}-{uid}`. Always descriptive.
[ ] 1. Compare with ark-ui, bits-ui, radix-ui — feature table with decisions
[ ] 2. Verify membership criteria (composition + complex behavior)
[ ] 3. Define parts: Provider + sub-parts (root part uses 'provider', not 'root' — A2)
[ ] 4. Create {name}-provider.svelte.ts with all Provider subclasses
[ ] 5. Use `createSomaRuntime()` / `soma.runtime()` so `registerMorfo()` runs — A1
[ ] 4. Create {name}-provider.svelte.ts with concrete provider/state classes
[ ] 5. Use `soma.runtime()` inside providers (or `createSomaRuntime()` in tests/tools) so `registerMorfo()` runs — A1
[ ] 6. Create types.ts with JSDoc on ALL props + canonical field shapes
[ ] 7. Add `morfo.translations` for component-owned text; create langs.ts only for imperative constants — A3
[ ] 8. Create wrapper .svelte files (thin: props → Active → Provider → mergeProps → render — A11)
@ -302,12 +302,12 @@ Pattern: `soma-{component}-{part}-{uid}`. Always descriptive.
[ ] 16. Verify: .get() for optional parents, .require() for required — A7
[ ] 17. Verify: no visual styles in provider (A8), static methods follow create/get/require pattern
[ ] 18. Verify: roving tabindex has exactly one tabindex=0 item — A14
[ ] 19. Create exports.ts (Provider, not Root)
[ ] 19. Create exports.ts (compound public parts; Provider only for the root headless entry)
[ ] 20. Add to components/index.ts barrel
[ ] 21. Create demo page in web/routes/{name} as an INTERACTIVE TESTBED (A29)
[ ] 21. Create demo page in web/routes/uix/components/{name} as an INTERACTIVE TESTBED (A29)
— every public prop wired to a live control, Field integration section,
state readout. Not a gallery of canned snippets.
[ ] 22. Add link to web/routes/+layout.svelte sidebar nav
[ ] 22. Add link to web/routes/uix/+layout@.svelte sidebar nav
[ ] 23. svelte-check: 0 errors
[ ] 24. Run `npm run smoke` — all routes pass, including the new one.
Smoke script catches runtime errors that svelte-check + HTTP 200 miss:
@ -484,10 +484,16 @@ These rules were extracted from a full audit of all 25 soma components. Every is
Every component MUST register its morfo before it relies on `assertContract`
or morfo-owned translations. The canonical path is to create a runtime:
```ts
const runtime = this.soma.runtime({name}Morfo, { states, props, parts, events });
```
For tests or a tool that does not have a `Soma` scope, use the lower-level factory:
```ts
const runtime = createSomaRuntime({name}Morfo, {
dom: this.soma.dom,
eventEngine: this.soma.events,
dom,
eventEngine,
states,
props,
parts,
@ -495,12 +501,6 @@ const runtime = createSomaRuntime({name}Morfo, {
});
```
or, when the provider has a `Soma` scope:
```ts
const runtime = soma.runtime({name}Morfo, { states, props, parts, events });
```
Both paths call `registerMorfo(morfo)` internally. That compiles the morfo,
registers its `data-*` contract and publishes `morfo.translations` to connected
`ActiveLangs` instances. Only call `registerMorfo(morfo)` manually for a
@ -686,7 +686,7 @@ Headless providers MUST NOT emit visual CSS properties (`border-radius`, `backgr
- `transform: translate3d(...)` — required during active drag for visual feedback
- CSS custom properties (`--drawer-progress`, `--drawer-offset-*`) — data for the visual layer
The visual layer (air/eidos) owns appearance. The provider owns behavior.
The visual layer (Eidos) owns appearance. The provider owns behavior.
### A9. Dismissal behavior for drawers vs dialogs
@ -947,7 +947,7 @@ Dias' `getPlaceholder('hour'|'minute'|'second', …)` returns `'––'` (two en
### A29. Demo pages are interactive testbeds
Every soma component demo at `web/routes/{name}` must expose **every public prop** of the Provider as a live control plus a Field-integration section when applicable. Not six static code snippets. Required coverage:
Every soma component demo at `web/routes/uix/components/{name}` must expose **every public prop** of the Provider as a live control plus a Field-integration section when applicable. Not six static code snippets. Required coverage:
1. Each boolean → switch/checkbox. Each enum → radio or chip group. Each number → input. Arrays (e.g. `readonlySegments`) → one toggle per valid value.
2. All format/locale/direction variants switchable (granularity, hourCycle, locale, dateOrder, dir).
@ -1028,7 +1028,7 @@ The comparison table (`## Comparison` in every component README) is a **contract
3. **Decide each `❌` / `⚠️` explicitly** — for every non-`✅`, the user approves one of:
- **Implement now** — the gap is strategic or blocks a WAI-ARIA / reference expectation. Bring it into scope and finish the component with the feature.
- **Defer to v2** — the gap exists but isn't blocking. Add it to the component's `## Out of scope (v2 roadmap)` section with: what it is, reference libraries that ship it, why deferred, cost estimate in lines. This becomes the PR backlog.
- **Drop** — the feature isn't a real gap for soma (e.g. a competitor's framework-specific quirk, or something the air layer should own). Document the reasoning and remove the row from the table.
- **Drop** — the feature isn't a real gap for Soma (e.g. a competitor's framework-specific quirk, or something Eidos should own). Document the reasoning and remove the row from the table.
4. **No silent gaps** — if a feature appears only as a footnote and nowhere else, that's a failure mode. The reader of the README should see `❌` and know it's a deliberate decision.
**Why this exists:** during the 2026-04-19 session, AlertDialog / Listbox / Carousel / NavigationMenu all shipped with strategic gaps (Escape default, range-select, multi-slide, Viewport, Sub, data-motion, skipDelayDuration) hidden inside comparison tables the user never saw in conversation. AlertDialog in particular inherited Dialog's `escapeKeydownBehavior='ignore'` default — a WAI-ARIA regression disguised as a `⚠️` row. The rule is: if the gap isn't argued explicitly, it doesn't get to ship.

@ -242,7 +242,8 @@ Cada componente tiene un archivo en `src/uix/morfo/components/{kebab}.ts` que de
- **apg** — URL al patrón WAI-ARIA APG cuando aplica.
- **scope** — las capas que implementan el componente: `['soma']`, `['soma', 'eidos']`, etc.
El morfo es la **única fuente de verdad** del contrato público. soma, air, eidos, sema y la docs auto-generada lo consumen todos.
El morfo es la **única fuente de verdad** del contrato público. Soma, Eidos,
Sema y la docs auto-generada lo consumen todos.
### ¿Por qué morfo existe?
@ -253,7 +254,7 @@ Antes de morfo, la información estructural de un componente vivía en seis siti
3. ARIA hard-coded en cada `$derived.by(...)` de props.
4. Keyboard handlers distribuidos por el provider.
5. Prose en el README.
6. Selectores en CSS de air/eidos, `.csem` de sema y tablas de docs.
6. Selectores en CSS de Eidos, `.csem` de Sema y tablas de docs.
Renombrar una parte (`content` → `panel`) tocaba 6+ sitios sin verificación automática. Drift cross-layer (soma emite `data-dialog-content`, eidos estiliza `data-dialog-panel`) era silencioso.
@ -523,7 +524,7 @@ y la escritura de attrs dinámicos pertenecen a `SomaRuntime.part(...)`.
- La parte `provider` genera `data-{component}` (sin sufijo `-provider`)
- Las demas partes generan `data-{component}-{part}`
- Estos attrs son API publica — cambiarlos es breaking change
- air/eidos los usa como selectores CSS
- Eidos los usa como selectores CSS
### Contracts (via morfo)
@ -1000,22 +1001,22 @@ Provider
---
## 17. Relacion con air/eidos
## 17. Relacion con Eidos
```
soma → headless behavior, accesibilidad, data-* contracts, context
air → visual layer: tokens, CSS recipes, sizes, variants
eidos → enhanced visual layer: motion, sound, advanced interactions
eidos → visual layer: tokens, CSS recipes, sizes, variants, event reactions
sema → perception/events: hold, sound, haptic
```
air/eidos consume soma:
Eidos consume Soma:
- Importa componentes: `import { Accordion } from '$soma/components'`
- Importa componentes por subpath publico: `import { Accordion } from '$soma/components/accordion'`
- Responde a data-\*: `[data-accordion][data-state='open'] { ... }`
- Añade props visuales: `size`, `variant`, `color`
- Usa mismas translations: `#?common.buttons.close|Close`, `#?components.dialog.trigger|Open dialog`
air/eidos NUNCA:
Eidos NUNCA:
- Importa Provider classes internas de soma
- Depende de estructura DOM incidental

@ -936,7 +936,7 @@ Un componente de soma se considera estable cuando:
- el wrapper y el Provider siguen el patron general
- su accesibilidad base esta resuelta (ARIA, roles, keyboard)
- sus props se han comparado con ark-ui, bits-ui y radix-ui
- tiene demo page funcional en `web/routes/{componente}/`
- tiene demo page funcional en `web/routes/uix/components/{componente}/`
- no depende de hacks locales, z-index hardcodeados, ni demo CSS para sostenerse
- compila con 0 errores (`svelte-check`)

Loading…
Cancel
Save

Powered by TurnKey Linux.