diff --git a/src/uix/eidos/MOTION_SERVICE_RFC.md b/src/uix/eidos/MOTION_SERVICE_RFC.md index 9386d41c6..659935826 100644 --- a/src/uix/eidos/MOTION_SERVICE_RFC.md +++ b/src/uix/eidos/MOTION_SERVICE_RFC.md @@ -1494,12 +1494,21 @@ existe pero está **dormido** (todos los presets shipped son `driver: 'css'`). E eje exige **estrenar el driver `spring`** con un primer preset JS — trabajo aparte de (a)+(b). **Plan de implementación (a)+(b) — acotado a eidos, NO el `PresenceGroup` pesado.** -- **(a) Unificar el nombre.** `` `animation` → `motion`; confirmar que ningún otro wrapper use - `animation`. El catálogo ya es `MotionPresetName`. -- **(b) Universalizar.** Un mecanismo uniforme para que cualquier componente acepte `motion` y emita - `data-animation-style` (un helper/acción que los wrappers compongan, o un wrapper-primitivo ``). - Decidir cómo dispara el dominio **contenido** (sin `data-state`): un attr/clase que corra el keyframe - on-mount o en loop, porque hoy los presets reaccionan SOLO a `data-state` (montaje). +- **(a) Unificar el nombre — ✅ HECHO** (commit `bfac34dd`). `` `animation` → `motion` (prop + + `CascadeContext`); ningún otro wrapper usaba `animation`. El catálogo es `MotionPresetName`. +- **(b) Universalizar — paso 1 HECHO.** El helper `motionAttrs(preset)` (exportado de `$uix/eidos`, + `lib/motion/motion-attrs.ts`) hace de cualquier elemento una **superficie de contenido**: `
` juega el ENTER del preset al montar. + - **Decisión de cómo dispara el contenido — RESUELTA, y al revés de lo que esta sección preveía.** El plan + decía «sin `data-state`» (un trigger nuevo). Se reusa **un `data-state="open"` de presentación constante** + — el MISMO patrón que `` ya usa para contenido — porque (1) reusa la regla de enter/exit + + reduced-motion sin tocar el generador, (2) da el exit gratis, (3) es patrón establecido. La línea + evento/estado/contenido es de **PROPIETARIO de la animación** (firma / máquina de estado / la prop + directa), NO de si el trigger CSS es `data-state`: el contenido es "siempre mostrado" (un `data-state` + constante), sin máquina que lo conmute. Flash-free al spreadear en markup (attrs en la inserción, `backwards` + fill). `'none'`/undefined → sin attrs (opt-out explícito). + - **Paso 2 (pendiente):** un wrapper `` (con `out:` retención → exit en desmontaje, + su morfo) y + cablear el prop `motion` en componentes reales. Loops (contenido infinito) = variante posterior. - **(c) El guard.** Tipos/lint: un componente con evento-que-posee-la-animación marca el prop como override; los demás, primario. - Cierra §6 (routing) en su parte vigente: el enrutado a superficie sigue siendo la idea (el dev nombra, el diff --git a/src/uix/eidos/index.ts b/src/uix/eidos/index.ts index f7ac2592b..9a848b4ba 100644 --- a/src/uix/eidos/index.ts +++ b/src/uix/eidos/index.ts @@ -199,6 +199,9 @@ export type { // Momento-`--state` preset-name registry (F7 typegen) — app-extensible via // `declare module '$uix/eidos' { interface EidosMotionPresets { … } }`. export type { EidosMotionPresets, MotionPresetName } from './lib/motion/registry'; +// `motionAttrs(preset)` — make any element a content-domain animation surface +// (plays the preset's enter on mount via a presentation `data-state`). RFC §D.12. +export { motionAttrs } from './lib/motion/motion-attrs'; export { ASPECT_RATIO_KEYS, BORDER_STYLE_KEYS, diff --git a/src/uix/eidos/lib/motion/motion-attrs.ts b/src/uix/eidos/lib/motion/motion-attrs.ts new file mode 100644 index 000000000..326420ee7 --- /dev/null +++ b/src/uix/eidos/lib/motion/motion-attrs.ts @@ -0,0 +1,24 @@ +import type { MotionPresetName } from './registry' + +/** + * Make ANY element a CONTENT-domain animation surface (RFC §D.12 / §D.13): spread + * these attrs and it plays the `preset`'s ENTER on mount. Reuses the existing + * state-preset enter rule via a constant presentation `data-state="open"` — the + * same mechanism `` uses for content — so there is NO new trigger, + * no generator change, no JS. Flash-free when spread in markup: the attrs are + * present at insertion and the preset's `backwards` fill holds the from-state + * before the first paint. + * + *
…
// fades + scales in on mount + * + * `'none'` / `undefined` → no attrs (the explicit opt-out). Exit on unmount needs + * a retention primitive (`out:` / `Presence`) + flipping `data-state` to + * `'closed'`; that is the `` wrapper's job, not a bare attr spread. + * + * For a STATEFUL component (its own `data-state` machine) or an EVENT firma, do + * NOT spread this — those own the trigger; this is the content domain only. + */ +export function motionAttrs(preset: MotionPresetName | undefined): Record { + if (!preset || preset === 'none') return {} + return { 'data-animation-style': preset, 'data-state': 'open' } +}