diff --git a/continue.md b/continue.md index 76b3503d7..b7c7720d2 100644 --- a/continue.md +++ b/continue.md @@ -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: diff --git a/src/uix/soma/COMPONENT_GUIDE.md b/src/uix/soma/COMPONENT_GUIDE.md index 194b70dc2..0ec253e06 100644 --- a/src/uix/soma/COMPONENT_GUIDE.md +++ b/src/uix/soma/COMPONENT_GUIDE.md @@ -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. `` for Link, `
` for Separator, `` 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. `
` for Link, `
` for Separator, `` 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. diff --git a/src/uix/soma/README.md b/src/uix/soma/README.md index eff253768..579cd7ce1 100644 --- a/src/uix/soma/README.md +++ b/src/uix/soma/README.md @@ -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 diff --git a/src/uix/soma/SOMA_ARCHITECTURE.md b/src/uix/soma/SOMA_ARCHITECTURE.md index 5b443062d..afff928d7 100644 --- a/src/uix/soma/SOMA_ARCHITECTURE.md +++ b/src/uix/soma/SOMA_ARCHITECTURE.md @@ -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`)