feat(motion): unify the animation selector to one `motion` prop — (a) of §D.12

`<Cascade>` was the last component using `animation` as its preset selector — a
vestige of the coordinated `cascade-*` system retired in Plan A. Every other
animatable component (Dialog, Popover, Drawer, …) already uses `motion`. Renames
`<Cascade>`'s prop + its context field `animation` → `motion`, so the framework
has ONE universal selector name (RFC §D.12 step a). `MotionPresetName` and the
low-level `data-animation-style` attr are unchanged.

- cascade: types `animation?` → `motion?`; context `CascadeContext.animation` →
  `.motion`; component destructure + getter; item reads `ctx?.motion`.
- docs/demo: README props table + usage, index usage, panel-cascade demo.

Verified at runtime: `<Cascade motion="scale-fade">` produces identical wiring —
items carry `data-animation-style="scale-fade"`, `animation-name: scale-in,
fade-in`, structural index 0/1/2/3. `check` clean for the touched files; no
dangling `animation`-prop reference remains (only the `data-animation-style` attr).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
active-uix
dev 4 months ago
parent efb20a9c5f
commit bfac34dd4f

@ -12,7 +12,7 @@ same foundation stagger do it (see "Two ways" below).
let open = $state(true)
</script>
<Cascade {open} animation="scale-fade" style="display: grid; gap: 0.75rem; --motion-stagger-each: 60ms">
<Cascade {open} motion="scale-fade" style="display: grid; gap: 0.75rem; --motion-stagger-each: 60ms">
{#each items as item (item.id)}
<Cascade.Item>{item.label}</Cascade.Item>
{/each}
@ -20,7 +20,7 @@ same foundation stagger do it (see "Two ways" below).
```
`--motion-stagger-each: 0` (the default) → **parallel**; `N` → **cascade**. The keyframe,
duration, easing and reduced-motion all come from the `animation` preset.
duration, easing and reduced-motion all come from the `motion` preset.
## How it works — it reuses everything
@ -45,7 +45,7 @@ down (`:nth-last-child`) so the last item leaves first.
| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `open` | `boolean` | `true` | Drives the staggered enter (forward) / exit (reverse) via `data-state`. |
| `animation` | `MotionPresetName` | `'fade'` | The state-preset every item plays (`fade` / `scale-fade` / `slide-fade` / …). |
| `motion` | `MotionPresetName` | `'fade'` | The state-preset every item plays (`fade` / `scale-fade` / `slide-fade` / …). Unified with the overlays' selector (RFC §D.12). |
Plus any `HTMLAttributes<HTMLDivElement>`. Set the layout + the rhythm (`--motion-stagger-each`)
here.

@ -30,7 +30,7 @@
<div
data-cascade-item
data-animation-style={ctx?.animation ?? 'fade'}
data-animation-style={ctx?.motion ?? 'fade'}
data-state={ctx?.open ? 'open' : 'closed'}
out:leave
{...rest}

@ -17,14 +17,14 @@
import { setCascadeContext } from './context';
import type { CascadeProps } from './types';
let { open = true, animation = 'fade', children, ...rest }: CascadeProps = $props();
let { open = true, motion = 'fade', children, ...rest }: CascadeProps = $props();
setCascadeContext({
get open() {
return open;
},
get animation() {
return animation;
get motion() {
return motion;
}
});
</script>

@ -5,12 +5,13 @@ const KEY = Symbol('cascade');
/**
* What `<Cascade>` passes to its items: the container's open state + the state-preset the
* items should play. Items read it to carry `data-state` + `data-animation-style` — they
* never receive a timing or a visual var, only these two semantic/structural facts.
* items should play (the `motion` prop value). Items read it to carry `data-state` +
* `data-animation-style` — they never receive a timing or a visual var, only these two
* semantic/structural facts.
*/
export type CascadeContext = {
readonly open: boolean;
readonly animation: MotionPresetName;
readonly motion: MotionPresetName;
};
export function setCascadeContext(ctx: CascadeContext): void {

@ -2,7 +2,7 @@
//
// import { Cascade } from '$uix/eidos/components/cascade';
//
// <Cascade open={isOpen} animation="scale-fade" style="display: grid; gap: 0.75rem; --motion-stagger-each: 60ms">
// <Cascade open={isOpen} motion="scale-fade" style="display: grid; gap: 0.75rem; --motion-stagger-each: 60ms">
// {#each items as item (item.id)}
// <Cascade.Item>{item.label}</Cascade.Item>
// {/each}

@ -13,9 +13,10 @@ export type CascadeProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
/**
* The state-preset every item plays (its `data-animation-style`) — any registered eidos
* motion preset (`fade`, `scale-fade`, `slide-fade`, …). The keyframe / duration /
* reduced-motion all come from the preset. @default 'fade'
* reduced-motion all come from the preset. Unified with the overlays' selector: the
* universal `motion` prop (RFC §D.12), not a separate `animation` axis. @default 'fade'
*/
animation?: MotionPresetName;
motion?: MotionPresetName;
children?: Snippet;
};

@ -95,13 +95,13 @@
<p class="note">
Sin recipe propio: el contenedor se marca <code>data-stagger</code> (la foundation da el
índice por <code>:nth-child</code>), los items cargan un preset existente
(<code>animation="scale-fade"</code>) + <code>data-state</code>, y el stagger sale del
(<code>motion="scale-fade"</code>) + <code>data-state</code>, y el stagger sale del
preset (<code>--motion-stagger-each</code>, 0 = paralelo). Retención <code>out:</code> en el
item. Cero <code>--cascade-*</code>.
</p>
<Cascade
{open}
animation="scale-fade"
motion="scale-fade"
style="display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.75rem; padding: 1rem; border: 1px solid var(--color-border-subtle, #e5e5e5); border-radius: var(--radius-lg, 12px); min-block-size: 5rem; --motion-stagger-each: {rhythm}ms"
>
{#each cards as i (i)}

Loading…
Cancel
Save

Powered by TurnKey Linux.