|
|
4 months ago | |
|---|---|---|
| .. | ||
| README.md | 4 months ago | |
| index.ts | 4 months ago | |
| motion.svelte | 4 months ago | |
| types.ts | 4 months ago | |
README.md
Motion
A single-element content animator (RFC §D.12 — the content domain). Wrap any content you
want to animate in and out; it rides the existing state-presets + reduced-motion — no new
mechanism, no JS engine. Same motion selector as the overlays and <Cascade>.
<script>
import { Motion } from '$uix/eidos/components/motion'
let show = $state(true)
</script>
{#if show}
<Motion motion="scale-fade">
<div class="card">…</div>
</Motion>
{/if}
motion is any registered preset (fade / scale-fade / slide-fade / …); 'none' disables.
The keyframe / duration / easing / reduced-motion all come from the preset.
How it works
| Phase | Mechanism |
|---|---|
| enter (on mount) | motionAttrs(motion) puts data-animation-style + a presentation data-state="open" on the element → the EXISTING [data-animation-style][data-state='open'] enter rule plays once. Flash-free (attrs at insertion, backwards fill). |
| exit (on removal) | Svelte out: flips the node to data-state='closed' (the existing exit rule plays) and retains it for the eidos-declared duration (read via the ActiveDom getComputedStyle), then unmounts. |
The wrapper writes no visual var and runs no JS animation — it only sets the state attr and holds the node during exit. Eidos owns the keyframes.
<Motion> vs motionAttrs
| Use | Extra node | Exit | |
|---|---|---|---|
<Motion> |
wrap content to animate in/out | yes (a real box — needed for transform/opacity) | ✓ (out: retention) |
motionAttrs(preset) |
spread onto your OWN element | no | — (enter only; you manage exit) |
Reach for motionAttrs when an extra wrapper would disrupt layout (inline content) and you only
need the entrance; reach for <Motion> when you want the full in/out lifecycle.
Domain boundary
Motion is the content domain only — content that simply appears/disappears, with no semantic event and no state machine. Do not wrap:
- a stateful component (its own
data-state: a Card'sselected/idle, a checkbox'schecked) — Motion's presentationdata-statewould clash; that component selects its preset via its ownmotionprop tied to its own state. - an event surface (an overlay's
emerge, acommit) — the firma owns the motion; the prop there is an override, not a wrapper.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
motion |
MotionPresetName |
'fade' |
The preset played on mount (enter) and removal (exit). 'none' disables. |
Plus any HTMLAttributes<HTMLDivElement>.
Decisions
- No recipe, no morfo events. Motion is structural lifecycle + a preset selector; the morfo
(
scope: ['eidos']) declares only thedata-stateof its single part. It reuses themotionregistry + the state-presets — it adds no keyframes of its own. - Reuses
data-state, not a bespoke trigger. The content domain fires via a constant presentationdata-state="open"(the<Cascade.Item>pattern), so the existing enter/exit + reduced-motion rules apply verbatim and the generator stays untouched (RFC §D.12). - A real box, not
display: contents. The transform/opacity need a layout box. For zero-extra-node, usemotionAttrson your own element.