|
|
|
|
@ -186,14 +186,20 @@ Provider aporta sources/handlers (Soma — TypeScript class)
|
|
|
|
|
↓
|
|
|
|
|
Effects sincronizan attrs (Soma — $effect + dom.apply)
|
|
|
|
|
↓
|
|
|
|
|
EngineSemantic emite señales (Sema — orquestación rAF + hold)
|
|
|
|
|
SemanticEngine despacha señales (Sema — registry + dispatch a canales)
|
|
|
|
|
↓
|
|
|
|
|
ADom aplica mutaciones DOM (adom — setAttribute/removeAttribute)
|
|
|
|
|
VisualChannel escribe data-event* (Sema — Channel built-in)
|
|
|
|
|
↓
|
|
|
|
|
Eidos lee el DOM y aplica CSS (Eidos — selectores + tokens)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Seis piezas en sucesión, ninguna invade a la siguiente:
|
|
|
|
|
Más, en paralelo (no en cadena):
|
|
|
|
|
- **ADom** materializa los `dom.apply`/`dom.remove` que Soma le pide para
|
|
|
|
|
los attrs estructurales derivados (data-state, aria-*, etc.).
|
|
|
|
|
- **Otros canales de Sema** (sound, vibra, futuros) reciben la misma señal
|
|
|
|
|
que VisualChannel y la materializan en su modalidad — fire-and-forget.
|
|
|
|
|
|
|
|
|
|
Las piezas con responsabilidades disjuntas:
|
|
|
|
|
|
|
|
|
|
| Pieza | Responsabilidad | No hace |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
@ -201,8 +207,9 @@ Seis piezas en sucesión, ninguna invade a la siguiente:
|
|
|
|
|
| **MorfoRuntime** | Transcribir morfo a comportamiento | Decidir lógica de negocio |
|
|
|
|
|
| **Provider** | Aportar fuentes reactivas + handlers | Escribir attrs mutables al DOM |
|
|
|
|
|
| **Effects** | Aplicar attrs derivados via `dom.apply` | Decidir qué attrs (eso lo dice morfo) |
|
|
|
|
|
| **EngineSemantic** | Orquestar señales perceptivas (`emit`) | Decidir cuándo |
|
|
|
|
|
| **ADom** | Mutaciones DOM imperativas | Conocer las capas superiores |
|
|
|
|
|
| **SemanticEngine** | Registry de canales + dispatch | Conocer DOM, audio, vibración |
|
|
|
|
|
| **VisualChannel** | Escribir `data-event*` con hold | Decidir cuándo emitir |
|
|
|
|
|
| **ADom** | Mutaciones DOM imperativas para attrs estructurales | Conocer las capas superiores |
|
|
|
|
|
|
|
|
|
|
`Eidos` queda fuera de esa cadena: lee del DOM, no participa en la
|
|
|
|
|
transcripción.
|
|
|
|
|
@ -222,12 +229,15 @@ Ejemplo concreto: el usuario clickea el botón **×** de un Toast.
|
|
|
|
|
3. MorfoRuntime.trigger('dismiss'):
|
|
|
|
|
3.1. Busca event 'dismiss' en morfo.events ✓
|
|
|
|
|
3.2. Resuelve target = Item DOM element via partRef('item')
|
|
|
|
|
3.3. PREWRITE — applies dom.apply(target, { ...event signal })
|
|
|
|
|
→ DOM ahora tiene data-event="dismiss" data-event-id="sig-N"
|
|
|
|
|
data-event-phase="active" data-event-family="emerge"
|
|
|
|
|
3.4. AWAIT semantic.emit({ target, name: 'dismiss', family: 'emerge' })
|
|
|
|
|
Sema espera 1 rAF — CSS observa la señal y arranca una transición
|
|
|
|
|
Sema resuelve la Promise
|
|
|
|
|
3.3. AWAIT semantic.emit({ target, name: 'dismiss', family: 'emerge' })
|
|
|
|
|
SemanticEngine despacha la señal a TODOS los canales registrados:
|
|
|
|
|
- VisualChannel: setAttribute(target, 'data-event', 'dismiss') +
|
|
|
|
|
'data-event-id', 'data-event-phase=active', 'data-event-family=emerge';
|
|
|
|
|
mantiene los attrs durante el hold (240ms para emerge);
|
|
|
|
|
removeAttribute al terminar el hold
|
|
|
|
|
- SoundChannel, VibraChannel: fire-and-forget (no awaited)
|
|
|
|
|
La Promise resuelve cuando el VisualChannel ha terminado el cleanup
|
|
|
|
|
(semántica secuencial estricta)
|
|
|
|
|
|
|
|
|
|
4. MorfoRuntime invoca el handler del provider:
|
|
|
|
|
sources.events.dismiss() →
|
|
|
|
|
@ -238,18 +248,18 @@ Ejemplo concreto: el usuario clickea el botón **×** de un Toast.
|
|
|
|
|
resolvePartAttrs recomputa los attrs del item part
|
|
|
|
|
dom.apply(target, { 'data-state': 'closed' }) en el siguiente tick
|
|
|
|
|
|
|
|
|
|
6. Sema mantiene data-event* el hold perceptual (240ms para emerge),
|
|
|
|
|
luego limpia: dom.remove(target, ['data-event', 'data-event-id', ...])
|
|
|
|
|
|
|
|
|
|
7. Eidos (CSS) ha estado reaccionando todo el tiempo:
|
|
|
|
|
- durante t=0..240ms: [data-event="dismiss"] dispara animation fade-out
|
|
|
|
|
- en t=5ms: [data-state="closed"] continúa la coreografía
|
|
|
|
|
6. Eidos (CSS) ha reaccionado durante toda la secuencia:
|
|
|
|
|
- durante t=0..240ms: [data-event^="dismiss"] dispara animation @keyframes
|
|
|
|
|
fade-out (CSS animation, no transition: corre full-duration aunque el
|
|
|
|
|
attr desaparezca después)
|
|
|
|
|
- en t≈245ms: [data-state="closed"] toma el relevo
|
|
|
|
|
- Presence layer aplica data-ending-style; CSS termina la animación
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
State es la única fuente de verdad. El DOM es derivación. La señal
|
|
|
|
|
perceptiva precede al cambio estructural en una ventana de un frame —
|
|
|
|
|
suficiente para que CSS coreografíe ambos.
|
|
|
|
|
perceptiva PRECEDE al cambio estructural por el hold completo (~240ms para
|
|
|
|
|
emerge) — el caller espera el cleanup antes de mutar estado, dándole a CSS
|
|
|
|
|
una ventana perceptible para coreografiar la salida.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
@ -396,8 +406,9 @@ Para evitar mission creep, conviene fijar lo que UIX **no quiere ser**:
|
|
|
|
|
- **No es un design system clásico.** Tokens, themes y recipes pertenecen
|
|
|
|
|
a Eidos, no al núcleo.
|
|
|
|
|
- **No es un semantic engine centralizado que ejecuta todas las
|
|
|
|
|
modalidades.** Sound, Vibra, Motion y futuras modalidades **suscriben**
|
|
|
|
|
a `EngineSemantic`; no son parte de él.
|
|
|
|
|
modalidades.** Sound, Vibra, Motion y futuras modalidades se registran
|
|
|
|
|
como **canales** del `SemanticEngine`; cada uno gestiona su propia
|
|
|
|
|
modalidad. El engine es solo registry + dispatch.
|
|
|
|
|
- **No es un EventEmitter global disfrazado de arquitectura.** Cada
|
|
|
|
|
evento tiene un target específico en el DOM y un dueño semántico
|
|
|
|
|
declarado en morfo.
|
|
|
|
|
@ -407,7 +418,7 @@ Para evitar mission creep, conviene fijar lo que UIX **no quiere ser**:
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 10. Estado actual (2026-04-26)
|
|
|
|
|
## 10. Estado actual (2026-04-27)
|
|
|
|
|
|
|
|
|
|
**Implementado y verificado**:
|
|
|
|
|
- `morfo` — 66 componentes con declaración completa, sium validator,
|
|
|
|
|
@ -415,8 +426,10 @@ Para evitar mission creep, conviene fijar lo que UIX **no quiere ser**:
|
|
|
|
|
- `soma/morfo/runtime` — `partProps`, `registerPart`, `keydown`,
|
|
|
|
|
`trigger`. Cinco componentes piloto migrados (Toggle, Switch,
|
|
|
|
|
Collapsible, Toast, Avatar). 22/22 unit tests verdes.
|
|
|
|
|
- `sema` — `EngineSemantic.emit(signal)` con lifecycle rAF + hold +
|
|
|
|
|
cleanup. SEMA_VERBS catalog. 10 unit tests verdes.
|
|
|
|
|
- `sema` — `SemanticEngine` (registry + dispatch) + `chans/` modulares
|
|
|
|
|
(VisualChannel built-in escribe `data-event*` con hold per-family;
|
|
|
|
|
SoundChannel/VibraChannel placeholders). SEMA_VERBS catalog. 39 unit
|
|
|
|
|
tests verdes.
|
|
|
|
|
- `adom` — `dom.apply(change)`, `dom.remove(target, names)`. Toda la
|
|
|
|
|
superficie reactiva (viewport, breakpoints, BodyScrollLock,
|
|
|
|
|
DOMContext, RovingFocusGroup) ya estable.
|
|
|
|
|
@ -486,8 +499,8 @@ Si las fronteras se mantienen, UIX ofrece algo poco común:
|
|
|
|
|
- **Validación automática del contrato**. Sium schema + smoke + morfo-check
|
|
|
|
|
detectan drift estructural antes de que llegue a producción.
|
|
|
|
|
- **Más libertad para introducir engines nuevos**. Sound, Vibra, Motion,
|
|
|
|
|
cualquier modalidad futura suscribe a `EngineSemantic` sin tocar morfo
|
|
|
|
|
ni soma.
|
|
|
|
|
cualquier modalidad futura se registra como un `Channel` adicional en
|
|
|
|
|
`SemanticEngine` sin tocar morfo ni soma.
|
|
|
|
|
- **Honestidad sobre fronteras de framework vs integrador**. UIX provee
|
|
|
|
|
vocabularios, contratos, transporte y puntos de extensión; no finge
|
|
|
|
|
decidir por todas las modalidades de todas las apps.
|
|
|
|
|
|