use-scroll-animate 9.3.0 → 9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/components/fx-safe.cjs +155 -0
- package/dist/components/fx-safe.cjs.map +1 -0
- package/dist/components/fx-safe.d.cts +85 -0
- package/dist/components/fx-safe.d.ts +85 -0
- package/dist/components/fx-safe.js +145 -0
- package/dist/components/fx-safe.js.map +1 -0
- package/dist/components/fx-video.cjs +111 -0
- package/dist/components/fx-video.cjs.map +1 -0
- package/dist/components/fx-video.d.cts +80 -0
- package/dist/components/fx-video.d.ts +80 -0
- package/dist/components/fx-video.js +105 -0
- package/dist/components/fx-video.js.map +1 -0
- package/dist/components/fx2.cjs +20 -0
- package/dist/components/fx2.cjs.map +1 -1
- package/dist/components/fx2.d.cts +76 -1
- package/dist/components/fx2.d.ts +76 -1
- package/dist/components/fx2.js +9 -1
- package/dist/components/fx2.js.map +1 -1
- package/dist/components/marketplace.cjs +2 -0
- package/dist/components/marketplace.cjs.map +1 -1
- package/dist/components/marketplace.js +2 -0
- package/dist/components/marketplace.js.map +1 -1
- package/dist/components/widgets.cjs +483 -181
- package/dist/components/widgets.cjs.map +1 -1
- package/dist/components/widgets.d.cts +94 -2
- package/dist/components/widgets.d.ts +94 -2
- package/dist/components/widgets.js +480 -182
- package/dist/components/widgets.js.map +1 -1
- package/dist/widgets.umd.js +1 -1
- package/dist/widgets.umd.js.map +1 -1
- package/docs/ROADMAP.md +2 -2
- package/docs/components.md +35 -0
- package/package.json +42 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [9.5.0] - 2026-10-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Accessible motion 2.0 — `motionary/fx/safe`** (= `motionary/components/fx-safe`, `registerSafePack()`, also in `registerEffectPacks()` and the marketplace): `vestibularSafe(keyframes)` (strip movement, keep opacity / colour), `flashCount()` / `isFlashSafe(keyframes, duration, iterations)` (WCAG 2.3.1 three-flashes check), `applyMotionPreferences(prefs)` / `loadMotionPreferences()` (sensitivity level, shared clock speed, `data-usa-pause-autoplay` / `data-usa-no-parallax` on `<html>`, persisted). Effects that never move: `safe-fade` (enter), `focus-glow` (attention), `color-pulse` (attention), `underline-sweep` (hover) — they run under reduced motion too.
|
|
14
|
+
- **2 new components (9.5)** in `motionary/components/widgets`:
|
|
15
|
+
- `<usa-motion-prefs>` — motion preference panel: level (Full · Gentle · Minimal · None), speed 0.25–2×, pause autoplaying video, no parallax, live sample, Reset; applies instantly and persists; `prefs`, `reset()`; `usa:change` { prefs }.
|
|
16
|
+
- `<usa-pause-all>` — one button that pauses / resumes all motion (shared clock, CSS / Web animations, autoplaying media; WCAG 2.2.2), `aria-pressed`, synced with `motionClock`; `scope` limits it to a subtree; `paused`, `toggle()`; `usa:pause-all` { paused }.
|
|
17
|
+
- Showcase: 3 new gallery cards with copyable code, live demos and live Store thumbnails.
|
|
18
|
+
|
|
19
|
+
### Accessibility
|
|
20
|
+
- The preference panel is a labelled `form` with a `fieldset` / `legend` of radio buttons, a labelled range with an `<output>`, and checkboxes; its sample is `aria-hidden`. The pause button is a real `button` with `aria-pressed` and a text label.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Build: Rollup ran out of heap at the 4 GB cap (`npm run build` aborted with "JavaScript heap out of memory") once the 9.5 entries were added; the build script's `--max-old-space-size` is raised to 6144.
|
|
25
|
+
|
|
26
|
+
## [9.4.0] - 2026-10-09
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- **Video motion — `motionary/fx/video`** (= `motionary/components/fx-video`, `registerVideoPack()`, also in `registerEffectPacks()` and the marketplace): `scrubVideo(video, trigger?)` (scroll-driven video, eased `currentTime`), `frameSequence(canvas, { count, src | draw }, trigger?)` (Apple-style image sequences scrubbed by scroll, preloaded), `scrollProgress(el)`. Effects `film-burn` (enter) and `jump-cut` (attention).
|
|
30
|
+
- **2 new components (9.4)** in `motionary/components/widgets`:
|
|
31
|
+
- `<usa-video-card>` — hover / focus plays a muted preview with a progress line, play badge and duration chip (`duration` or read from the video); poster Ken Burns drift when there is no playable video; click / Enter → `usa:open` { src }; `previewing`.
|
|
32
|
+
- `<usa-hero-video>` — full-bleed hero: poster (`poster`, `<img>` or gradient) cross-fades to the background video when it can play, scrim, always-present pause / play button, `scrub` for a scroll-driven video, poster drift when no video; `paused`, `toggle()`; `usa:play` / `usa:pause`.
|
|
33
|
+
- Showcase: 3 new gallery cards with copyable code, live demos and live Store thumbnails.
|
|
34
|
+
|
|
35
|
+
### Accessibility
|
|
36
|
+
- The hero always offers a labelled pause / play button for moving video (WCAG 2.2.2) and is a labelled `region`; background videos are muted and `aria-hidden`. The video card is a focusable button labelled "Play <title>". Reduced motion: no autoplay or preview (poster only), scrubbing shows the first frame, `film-burn` fades, `jump-cut` does nothing.
|
|
37
|
+
|
|
10
38
|
## [9.3.0] - 2026-10-09
|
|
11
39
|
|
|
12
40
|
### Added
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var registry = require('../chunks/registry-BVklOepd.cjs');
|
|
4
|
+
var base = require('../chunks/base-DoRUZBy-.cjs');
|
|
5
|
+
|
|
6
|
+
const MOVE = /^(transform|translate|scale|rotate|offset|offsetPath|offsetDistance|clipPath|top|left|right|bottom|margin.*|perspective)$/;
|
|
7
|
+
/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */
|
|
8
|
+
function vestibularSafe(frames) {
|
|
9
|
+
return frames.map((f) => {
|
|
10
|
+
const o = {};
|
|
11
|
+
for (const [k, v] of Object.entries(f)) {
|
|
12
|
+
if (MOVE.test(k))
|
|
13
|
+
continue;
|
|
14
|
+
if (k === 'filter' && typeof v === 'string') {
|
|
15
|
+
const nf = v.replace(/blur\([^)]*\)/g, '').trim();
|
|
16
|
+
if (nf)
|
|
17
|
+
o.filter = nf;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
o[k] = v;
|
|
21
|
+
}
|
|
22
|
+
return o;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const lum = (f) => {
|
|
26
|
+
let l = f.opacity != null ? Number(f.opacity) : 1;
|
|
27
|
+
const m = typeof f.filter === 'string' ? f.filter.match(/brightness\(([\d.]+)\)/) : null;
|
|
28
|
+
if (m)
|
|
29
|
+
l *= Number(m[1]);
|
|
30
|
+
return l;
|
|
31
|
+
};
|
|
32
|
+
/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */
|
|
33
|
+
function flashCount(frames) {
|
|
34
|
+
const ls = frames.map(lum);
|
|
35
|
+
let n = 0;
|
|
36
|
+
let dir = 0;
|
|
37
|
+
let ref = ls[0] ?? 1;
|
|
38
|
+
for (const l of ls.slice(1)) {
|
|
39
|
+
const d = l - ref;
|
|
40
|
+
if (Math.abs(d) >= 0.3) {
|
|
41
|
+
const s = Math.sign(d);
|
|
42
|
+
if (dir && s !== dir)
|
|
43
|
+
n++;
|
|
44
|
+
dir = s;
|
|
45
|
+
ref = l;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */
|
|
51
|
+
function isFlashSafe(frames, duration, iterations = 1) {
|
|
52
|
+
const per = flashCount(frames);
|
|
53
|
+
if (!per)
|
|
54
|
+
return true;
|
|
55
|
+
const perSecond = (per * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / Math.max(0.001, (duration * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / 1000);
|
|
56
|
+
return perSecond <= 3;
|
|
57
|
+
}
|
|
58
|
+
const MOTION_PREFS_KEY = 'usa-motion-prefs';
|
|
59
|
+
const DEFAULT_MOTION_PREFS = { sensitivity: 'full', speed: 1, pauseAutoplay: false, noParallax: false };
|
|
60
|
+
/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */
|
|
61
|
+
function applyMotionPreferences(p, persist = true) {
|
|
62
|
+
const prefs = { ...DEFAULT_MOTION_PREFS, ...p };
|
|
63
|
+
if (!['full', 'gentle', 'minimal', 'static'].includes(prefs.sensitivity))
|
|
64
|
+
prefs.sensitivity = 'full';
|
|
65
|
+
prefs.speed = Math.min(2, Math.max(0.25, Number(prefs.speed) || 1));
|
|
66
|
+
base.configureComponents({ motionSensitivity: prefs.sensitivity });
|
|
67
|
+
base.setClock({ rate: prefs.speed });
|
|
68
|
+
if (typeof document !== 'undefined') {
|
|
69
|
+
const h = document.documentElement;
|
|
70
|
+
h.toggleAttribute('data-usa-pause-autoplay', prefs.pauseAutoplay);
|
|
71
|
+
h.toggleAttribute('data-usa-no-parallax', prefs.noParallax);
|
|
72
|
+
if (prefs.pauseAutoplay)
|
|
73
|
+
document.querySelectorAll('video[autoplay], audio[autoplay]').forEach((m) => m.pause?.());
|
|
74
|
+
}
|
|
75
|
+
if (persist)
|
|
76
|
+
try {
|
|
77
|
+
localStorage.setItem(MOTION_PREFS_KEY, JSON.stringify(prefs));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
/* storage blocked */
|
|
81
|
+
}
|
|
82
|
+
return prefs;
|
|
83
|
+
}
|
|
84
|
+
/** Saved preferences (or the defaults) (9.5). */
|
|
85
|
+
function loadMotionPreferences() {
|
|
86
|
+
try {
|
|
87
|
+
const j = JSON.parse(localStorage.getItem(MOTION_PREFS_KEY) || 'null');
|
|
88
|
+
if (j && typeof j === 'object')
|
|
89
|
+
return { ...DEFAULT_MOTION_PREFS, ...j };
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
/* none */
|
|
93
|
+
}
|
|
94
|
+
return { ...DEFAULT_MOTION_PREFS };
|
|
95
|
+
}
|
|
96
|
+
const SAFE_FX = [
|
|
97
|
+
{
|
|
98
|
+
name: 'safe-fade',
|
|
99
|
+
kind: 'enter',
|
|
100
|
+
description: 'An entrance that never moves: opacity only (also used as the reduced-motion twin of other entrances).',
|
|
101
|
+
defaults: { duration: 500 },
|
|
102
|
+
reduced: 'run',
|
|
103
|
+
run: (el, o, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: o.duration, delay: o.delay, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'focus-glow',
|
|
107
|
+
kind: 'attention',
|
|
108
|
+
description: 'Draws attention with a pulsing focus-ring glow instead of movement (`color`).',
|
|
109
|
+
defaults: { color: '#6366f1', duration: 1200 },
|
|
110
|
+
reduced: 'run',
|
|
111
|
+
run: (el, o, ctx) => ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}00` }, { boxShadow: `0 0 0 4px ${o.color}`, offset: 0.4 }, { boxShadow: `0 0 0 8px ${o.color}00` }], { duration: o.duration })?.finished.catch(() => undefined),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'color-pulse',
|
|
115
|
+
kind: 'attention',
|
|
116
|
+
description: 'Draws attention with a colour change instead of movement (`color`).',
|
|
117
|
+
defaults: { color: '#fde047', duration: 1000 },
|
|
118
|
+
reduced: 'run',
|
|
119
|
+
run: (el, o, ctx) => ctx.animate(el, [{ backgroundColor: 'transparent' }, { backgroundColor: o.color, offset: 0.35 }, { backgroundColor: 'transparent' }], { duration: o.duration })?.finished.catch(() => undefined),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'underline-sweep',
|
|
123
|
+
kind: 'hover',
|
|
124
|
+
description: 'A text underline grows from the left on hover / focus — motion-light, no layout shift (`color`).',
|
|
125
|
+
defaults: { color: 'currentColor', duration: 300 },
|
|
126
|
+
reduced: 'run',
|
|
127
|
+
run: (el, o, ctx) => {
|
|
128
|
+
const prev = [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition];
|
|
129
|
+
Object.assign(el.style, { backgroundImage: `linear-gradient(${o.color}, ${o.color})`, backgroundRepeat: 'no-repeat', backgroundPosition: '0 100%' });
|
|
130
|
+
ctx.onCleanup(() => {
|
|
131
|
+
[el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition] = prev;
|
|
132
|
+
});
|
|
133
|
+
if (ctx.reduced) {
|
|
134
|
+
el.style.backgroundSize = '100% 2px';
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
return ctx.animate(el, [{ backgroundSize: '0% 2px' }, { backgroundSize: '100% 2px' }], { duration: o.duration, easing: 'ease-out', fill: 'forwards' })?.finished.catch(() => undefined);
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */
|
|
142
|
+
function registerSafePack() {
|
|
143
|
+
registry.registerEffects(SAFE_FX);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
exports.DEFAULT_MOTION_PREFS = DEFAULT_MOTION_PREFS;
|
|
147
|
+
exports.MOTION_PREFS_KEY = MOTION_PREFS_KEY;
|
|
148
|
+
exports.SAFE_FX = SAFE_FX;
|
|
149
|
+
exports.applyMotionPreferences = applyMotionPreferences;
|
|
150
|
+
exports.flashCount = flashCount;
|
|
151
|
+
exports.isFlashSafe = isFlashSafe;
|
|
152
|
+
exports.loadMotionPreferences = loadMotionPreferences;
|
|
153
|
+
exports.registerSafePack = registerSafePack;
|
|
154
|
+
exports.vestibularSafe = vestibularSafe;
|
|
155
|
+
//# sourceMappingURL=fx-safe.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-safe.cjs","sources":["../../src/components/fx2/safemotion.ts"],"sourcesContent":["/**\n * 9.5 — Accessible motion 2.0 (`motionary/fx/safe`, also `motionary/components/fx-safe`):\n *\n * - `vestibularSafe(keyframes)` — strips movement (translate / scale /\n * rotate / skew / perspective, clip and blur) from keyframes, keeping\n * opacity and colour, so any animation can get a vestibular-safe twin.\n * - `flashCount(keyframes, duration)` / `isFlashSafe(...)` — counts large\n * opacity / brightness swings and checks WCAG 2.3.1's three-flashes-per-\n * second limit.\n * - `applyMotionPreferences(prefs)` / `loadMotionPreferences()` — the\n * settings behind `<usa-motion-prefs>`: sensitivity level, speed (shared\n * clock rate), pause autoplay, no parallax; persisted in localStorage and\n * exposed as `data-usa-*` attributes on `<html>` for your CSS.\n *\n * Effects that never move anything: `safe-fade` (enter), `focus-glow`\n * (attention), `color-pulse` (attention), `underline-sweep` (hover).\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\nimport { configureComponents, setClock, type MotionSensitivity } from '../base';\n\nconst MOVE = /^(transform|translate|scale|rotate|offset|offsetPath|offsetDistance|clipPath|top|left|right|bottom|margin.*|perspective)$/;\n/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */\nexport function vestibularSafe(frames: Keyframe[]): Keyframe[] {\n return frames.map((f) => {\n const o: Keyframe = {};\n for (const [k, v] of Object.entries(f)) {\n if (MOVE.test(k)) continue;\n if (k === 'filter' && typeof v === 'string') {\n const nf = v.replace(/blur\\([^)]*\\)/g, '').trim();\n if (nf) o.filter = nf;\n continue;\n }\n (o as any)[k] = v;\n }\n return o;\n });\n}\n\nconst lum = (f: Keyframe): number => {\n let l = f.opacity != null ? Number(f.opacity) : 1;\n const m = typeof f.filter === 'string' ? f.filter.match(/brightness\\(([\\d.]+)\\)/) : null;\n if (m) l *= Number(m[1]);\n return l;\n};\n/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */\nexport function flashCount(frames: Keyframe[]): number {\n const ls = frames.map(lum);\n let n = 0;\n let dir = 0;\n let ref = ls[0] ?? 1;\n for (const l of ls.slice(1)) {\n const d = l - ref;\n if (Math.abs(d) >= 0.3) {\n const s = Math.sign(d);\n if (dir && s !== dir) n++;\n dir = s;\n ref = l;\n }\n }\n return n;\n}\n/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */\nexport function isFlashSafe(frames: Keyframe[], duration: number, iterations = 1): boolean {\n const per = flashCount(frames);\n if (!per) return true;\n const perSecond = (per * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / Math.max(0.001, (duration * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / 1000);\n return perSecond <= 3;\n}\n\nexport interface MotionPreferences {\n sensitivity: MotionSensitivity;\n speed: number;\n pauseAutoplay: boolean;\n noParallax: boolean;\n}\nexport const MOTION_PREFS_KEY = 'usa-motion-prefs';\nexport const DEFAULT_MOTION_PREFS: MotionPreferences = { sensitivity: 'full', speed: 1, pauseAutoplay: false, noParallax: false };\n\n/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */\nexport function applyMotionPreferences(p: Partial<MotionPreferences>, persist = true): MotionPreferences {\n const prefs: MotionPreferences = { ...DEFAULT_MOTION_PREFS, ...p };\n if (!['full', 'gentle', 'minimal', 'static'].includes(prefs.sensitivity)) prefs.sensitivity = 'full';\n prefs.speed = Math.min(2, Math.max(0.25, Number(prefs.speed) || 1));\n configureComponents({ motionSensitivity: prefs.sensitivity });\n setClock({ rate: prefs.speed });\n if (typeof document !== 'undefined') {\n const h = document.documentElement;\n h.toggleAttribute('data-usa-pause-autoplay', prefs.pauseAutoplay);\n h.toggleAttribute('data-usa-no-parallax', prefs.noParallax);\n if (prefs.pauseAutoplay) document.querySelectorAll<HTMLMediaElement>('video[autoplay], audio[autoplay]').forEach((m) => m.pause?.());\n }\n if (persist)\n try {\n localStorage.setItem(MOTION_PREFS_KEY, JSON.stringify(prefs));\n } catch {\n /* storage blocked */\n }\n return prefs;\n}\n/** Saved preferences (or the defaults) (9.5). */\nexport function loadMotionPreferences(): MotionPreferences {\n try {\n const j = JSON.parse(localStorage.getItem(MOTION_PREFS_KEY) || 'null');\n if (j && typeof j === 'object') return { ...DEFAULT_MOTION_PREFS, ...j };\n } catch {\n /* none */\n }\n return { ...DEFAULT_MOTION_PREFS };\n}\n\nexport const SAFE_FX: EffectDefinition[] = [\n {\n name: 'safe-fade',\n kind: 'enter',\n description: 'An entrance that never moves: opacity only (also used as the reduced-motion twin of other entrances).',\n defaults: { duration: 500 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: o.duration, delay: o.delay, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined),\n },\n {\n name: 'focus-glow',\n kind: 'attention',\n description: 'Draws attention with a pulsing focus-ring glow instead of movement (`color`).',\n defaults: { color: '#6366f1', duration: 1200 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}00` }, { boxShadow: `0 0 0 4px ${o.color}`, offset: 0.4 }, { boxShadow: `0 0 0 8px ${o.color}00` }], { duration: o.duration })?.finished.catch(() => undefined),\n },\n {\n name: 'color-pulse',\n kind: 'attention',\n description: 'Draws attention with a colour change instead of movement (`color`).',\n defaults: { color: '#fde047', duration: 1000 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ backgroundColor: 'transparent' }, { backgroundColor: o.color, offset: 0.35 }, { backgroundColor: 'transparent' }], { duration: o.duration })?.finished.catch(() => undefined),\n },\n {\n name: 'underline-sweep',\n kind: 'hover',\n description: 'A text underline grows from the left on hover / focus — motion-light, no layout shift (`color`).',\n defaults: { color: 'currentColor', duration: 300 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const prev = [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition];\n Object.assign(el.style, { backgroundImage: `linear-gradient(${o.color}, ${o.color})`, backgroundRepeat: 'no-repeat', backgroundPosition: '0 100%' });\n ctx.onCleanup(() => {\n [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition] = prev;\n });\n if (ctx.reduced) {\n el.style.backgroundSize = '100% 2px';\n return;\n }\n return ctx.animate(el, [{ backgroundSize: '0% 2px' }, { backgroundSize: '100% 2px' }], { duration: o.duration, easing: 'ease-out', fill: 'forwards' })?.finished.catch(() => undefined);\n },\n },\n];\n\n/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */\nexport function registerSafePack(): void {\n registerEffects(SAFE_FX);\n}\n"],"names":["configureComponents","setClock","registerEffects"],"mappings":";;;;;AAqBA,MAAM,IAAI,GAAG,2HAA2H;AACxI;AACM,SAAU,cAAc,CAAC,MAAkB,EAAA;AAC/C,IAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAI;QACtB,MAAM,CAAC,GAAa,EAAE;AACtB,QAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE;YAClB,IAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;AAC3C,gBAAA,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;AACjD,gBAAA,IAAI,EAAE;AAAE,oBAAA,CAAC,CAAC,MAAM,GAAG,EAAE;gBACrB;YACF;AACC,YAAA,CAAS,CAAC,CAAC,CAAC,GAAG,CAAC;QACnB;AACA,QAAA,OAAO,CAAC;AACV,IAAA,CAAC,CAAC;AACJ;AAEA,MAAM,GAAG,GAAG,CAAC,CAAW,KAAY;IAClC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IACjD,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,GAAG,IAAI;AACxF,IAAA,IAAI,CAAC;QAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,IAAA,OAAO,CAAC;AACV,CAAC;AACD;AACM,SAAU,UAAU,CAAC,MAAkB,EAAA;IAC3C,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC;IACT,IAAI,GAAG,GAAG,CAAC;IACX,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC3B,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG;QACjB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE;YACtB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,YAAA,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG;AAAE,gBAAA,CAAC,EAAE;YACzB,GAAG,GAAG,CAAC;YACP,GAAG,GAAG,CAAC;QACT;IACF;AACA,IAAA,OAAO,CAAC;AACV;AACA;AACM,SAAU,WAAW,CAAC,MAAkB,EAAE,QAAgB,EAAE,UAAU,GAAG,CAAC,EAAA;AAC9E,IAAA,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC;AAC9B,IAAA,IAAI,CAAC,GAAG;AAAE,QAAA,OAAO,IAAI;AACrB,IAAA,MAAM,SAAS,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IACpL,OAAO,SAAS,IAAI,CAAC;AACvB;AAQO,MAAM,gBAAgB,GAAG;MACnB,oBAAoB,GAAsB,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK;AAE/H;SACgB,sBAAsB,CAAC,CAA6B,EAAE,OAAO,GAAG,IAAI,EAAA;IAClF,MAAM,KAAK,GAAsB,EAAE,GAAG,oBAAoB,EAAE,GAAG,CAAC,EAAE;AAClE,IAAA,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC;AAAE,QAAA,KAAK,CAAC,WAAW,GAAG,MAAM;IACpG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACnEA,wBAAmB,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;IAC7DC,aAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;AAC/B,IAAA,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE;AACnC,QAAA,MAAM,CAAC,GAAG,QAAQ,CAAC,eAAe;QAClC,CAAC,CAAC,eAAe,CAAC,yBAAyB,EAAE,KAAK,CAAC,aAAa,CAAC;QACjE,CAAC,CAAC,eAAe,CAAC,sBAAsB,EAAE,KAAK,CAAC,UAAU,CAAC;QAC3D,IAAI,KAAK,CAAC,aAAa;AAAE,YAAA,QAAQ,CAAC,gBAAgB,CAAmB,kCAAkC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;IACtI;AACA,IAAA,IAAI,OAAO;AACT,QAAA,IAAI;AACF,YAAA,YAAY,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/D;AAAE,QAAA,MAAM;;QAER;AACF,IAAA,OAAO,KAAK;AACd;AACA;SACgB,qBAAqB,GAAA;AACnC,IAAA,IAAI;AACF,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC;AACtE,QAAA,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;AAAE,YAAA,OAAO,EAAE,GAAG,oBAAoB,EAAE,GAAG,CAAC,EAAE;IAC1E;AAAE,IAAA,MAAM;;IAER;AACA,IAAA,OAAO,EAAE,GAAG,oBAAoB,EAAE;AACpC;AAEO,MAAM,OAAO,GAAuB;AACzC,IAAA;AACE,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,uGAAuG;AACpH,QAAA,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;AAC3B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC1N,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,+EAA+E;QAC5F,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;AAC9C,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,CAAA,QAAA,EAAW,CAAC,CAAC,KAAK,CAAA,EAAA,CAAI,EAAE,EAAE,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,KAAK,CAAA,CAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,KAAK,CAAA,EAAA,CAAI,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AACvQ,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,aAAa;AACnB,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,qEAAqE;QAClF,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;AAC9C,QAAA,OAAO,EAAE,KAAK;QACd,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,eAAe,EAAE,aAAa,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AACvP,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,iBAAiB;AACvB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,kGAAkG;QAC/G,QAAQ,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,EAAE;AAClD,QAAA,OAAO,EAAE,KAAK;QACd,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC;AACxH,YAAA,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,eAAe,EAAE,CAAA,gBAAA,EAAmB,CAAC,CAAC,KAAK,CAAA,EAAA,EAAK,CAAC,CAAC,KAAK,CAAA,CAAA,CAAG,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AACpJ,YAAA,GAAG,CAAC,SAAS,CAAC,MAAK;gBACjB,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,IAAI;AACpH,YAAA,CAAC,CAAC;AACF,YAAA,IAAI,GAAG,CAAC,OAAO,EAAE;AACf,gBAAA,EAAE,CAAC,KAAK,CAAC,cAAc,GAAG,UAAU;gBACpC;YACF;YACA,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACzL,CAAC;AACF,KAAA;;AAGH;SACgB,gBAAgB,GAAA;IAC9BC,wBAAe,CAAC,OAAO,CAAC;AAC1B;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
|
|
2
|
+
type Cleanup = () => void;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 5.0 — unified plugin-style effect registration. Every effect (built-in or
|
|
6
|
+
* yours) is a plain object registered once and played the same way:
|
|
7
|
+
* `playEffect(el, name)`, `bindEffect(el, name, { trigger })` or
|
|
8
|
+
* `<usa-fx effect="name" trigger="click">`. Effects get a context that
|
|
9
|
+
* already applies reduced motion, motion sensitivity, intensity and the
|
|
10
|
+
* animation budget.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
declare const EFFECT_KINDS: readonly ["enter", "exit", "attention", "click", "hover", "card", "loop", "page", "background", "text", "cursor", "scroll"];
|
|
14
|
+
type EffectKind = (typeof EFFECT_KINDS)[number];
|
|
15
|
+
interface EffectContext {
|
|
16
|
+
/** Reduced motion applies (OS setting, `minimal` / `static` sensitivity). */
|
|
17
|
+
readonly reduced: boolean;
|
|
18
|
+
readonly sensitivity: MotionSensitivity;
|
|
19
|
+
/** The triggering event (pointer position for click effects), if any. */
|
|
20
|
+
readonly event?: Event;
|
|
21
|
+
/** `el.animate()` with the library's motion rules (may return `null`). */
|
|
22
|
+
animate(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
|
|
23
|
+
/** Register teardown for long-running effects (loops, listeners). */
|
|
24
|
+
onCleanup(fn: Cleanup): void;
|
|
25
|
+
}
|
|
26
|
+
interface EffectDefinition<O extends Record<string, unknown> = Record<string, any>> {
|
|
27
|
+
/** Unique, kebab-case. */
|
|
28
|
+
name: string;
|
|
29
|
+
kind: EffectKind;
|
|
30
|
+
/** One line for docs and the gallery. */
|
|
31
|
+
description?: string;
|
|
32
|
+
/** Option defaults (merged under the caller's options). */
|
|
33
|
+
defaults?: Partial<O>;
|
|
34
|
+
/**
|
|
35
|
+
* Under reduced motion: `'skip'` (do nothing — default for loop, background
|
|
36
|
+
* and cursor effects) or `'run'` (run with `ctx.reduced === true`, the
|
|
37
|
+
* effect degrades itself — default for everything else).
|
|
38
|
+
*/
|
|
39
|
+
reduced?: 'skip' | 'run';
|
|
40
|
+
/** Play the effect. Return an Animation / Promise to be awaited, or a cleanup. */
|
|
41
|
+
run(el: HTMLElement, options: O, ctx: EffectContext): void | Cleanup | Animation | null | Promise<unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 9.5 — Accessible motion 2.0 (`motionary/fx/safe`, also `motionary/components/fx-safe`):
|
|
46
|
+
*
|
|
47
|
+
* - `vestibularSafe(keyframes)` — strips movement (translate / scale /
|
|
48
|
+
* rotate / skew / perspective, clip and blur) from keyframes, keeping
|
|
49
|
+
* opacity and colour, so any animation can get a vestibular-safe twin.
|
|
50
|
+
* - `flashCount(keyframes, duration)` / `isFlashSafe(...)` — counts large
|
|
51
|
+
* opacity / brightness swings and checks WCAG 2.3.1's three-flashes-per-
|
|
52
|
+
* second limit.
|
|
53
|
+
* - `applyMotionPreferences(prefs)` / `loadMotionPreferences()` — the
|
|
54
|
+
* settings behind `<usa-motion-prefs>`: sensitivity level, speed (shared
|
|
55
|
+
* clock rate), pause autoplay, no parallax; persisted in localStorage and
|
|
56
|
+
* exposed as `data-usa-*` attributes on `<html>` for your CSS.
|
|
57
|
+
*
|
|
58
|
+
* Effects that never move anything: `safe-fade` (enter), `focus-glow`
|
|
59
|
+
* (attention), `color-pulse` (attention), `underline-sweep` (hover).
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */
|
|
63
|
+
declare function vestibularSafe(frames: Keyframe[]): Keyframe[];
|
|
64
|
+
/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */
|
|
65
|
+
declare function flashCount(frames: Keyframe[]): number;
|
|
66
|
+
/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */
|
|
67
|
+
declare function isFlashSafe(frames: Keyframe[], duration: number, iterations?: number): boolean;
|
|
68
|
+
interface MotionPreferences {
|
|
69
|
+
sensitivity: MotionSensitivity;
|
|
70
|
+
speed: number;
|
|
71
|
+
pauseAutoplay: boolean;
|
|
72
|
+
noParallax: boolean;
|
|
73
|
+
}
|
|
74
|
+
declare const MOTION_PREFS_KEY = "usa-motion-prefs";
|
|
75
|
+
declare const DEFAULT_MOTION_PREFS: MotionPreferences;
|
|
76
|
+
/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */
|
|
77
|
+
declare function applyMotionPreferences(p: Partial<MotionPreferences>, persist?: boolean): MotionPreferences;
|
|
78
|
+
/** Saved preferences (or the defaults) (9.5). */
|
|
79
|
+
declare function loadMotionPreferences(): MotionPreferences;
|
|
80
|
+
declare const SAFE_FX: EffectDefinition[];
|
|
81
|
+
/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */
|
|
82
|
+
declare function registerSafePack(): void;
|
|
83
|
+
|
|
84
|
+
export { DEFAULT_MOTION_PREFS, MOTION_PREFS_KEY, SAFE_FX, applyMotionPreferences, flashCount, isFlashSafe, loadMotionPreferences, registerSafePack, vestibularSafe };
|
|
85
|
+
export type { MotionPreferences };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
|
|
2
|
+
type Cleanup = () => void;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 5.0 — unified plugin-style effect registration. Every effect (built-in or
|
|
6
|
+
* yours) is a plain object registered once and played the same way:
|
|
7
|
+
* `playEffect(el, name)`, `bindEffect(el, name, { trigger })` or
|
|
8
|
+
* `<usa-fx effect="name" trigger="click">`. Effects get a context that
|
|
9
|
+
* already applies reduced motion, motion sensitivity, intensity and the
|
|
10
|
+
* animation budget.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
declare const EFFECT_KINDS: readonly ["enter", "exit", "attention", "click", "hover", "card", "loop", "page", "background", "text", "cursor", "scroll"];
|
|
14
|
+
type EffectKind = (typeof EFFECT_KINDS)[number];
|
|
15
|
+
interface EffectContext {
|
|
16
|
+
/** Reduced motion applies (OS setting, `minimal` / `static` sensitivity). */
|
|
17
|
+
readonly reduced: boolean;
|
|
18
|
+
readonly sensitivity: MotionSensitivity;
|
|
19
|
+
/** The triggering event (pointer position for click effects), if any. */
|
|
20
|
+
readonly event?: Event;
|
|
21
|
+
/** `el.animate()` with the library's motion rules (may return `null`). */
|
|
22
|
+
animate(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
|
|
23
|
+
/** Register teardown for long-running effects (loops, listeners). */
|
|
24
|
+
onCleanup(fn: Cleanup): void;
|
|
25
|
+
}
|
|
26
|
+
interface EffectDefinition<O extends Record<string, unknown> = Record<string, any>> {
|
|
27
|
+
/** Unique, kebab-case. */
|
|
28
|
+
name: string;
|
|
29
|
+
kind: EffectKind;
|
|
30
|
+
/** One line for docs and the gallery. */
|
|
31
|
+
description?: string;
|
|
32
|
+
/** Option defaults (merged under the caller's options). */
|
|
33
|
+
defaults?: Partial<O>;
|
|
34
|
+
/**
|
|
35
|
+
* Under reduced motion: `'skip'` (do nothing — default for loop, background
|
|
36
|
+
* and cursor effects) or `'run'` (run with `ctx.reduced === true`, the
|
|
37
|
+
* effect degrades itself — default for everything else).
|
|
38
|
+
*/
|
|
39
|
+
reduced?: 'skip' | 'run';
|
|
40
|
+
/** Play the effect. Return an Animation / Promise to be awaited, or a cleanup. */
|
|
41
|
+
run(el: HTMLElement, options: O, ctx: EffectContext): void | Cleanup | Animation | null | Promise<unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 9.5 — Accessible motion 2.0 (`motionary/fx/safe`, also `motionary/components/fx-safe`):
|
|
46
|
+
*
|
|
47
|
+
* - `vestibularSafe(keyframes)` — strips movement (translate / scale /
|
|
48
|
+
* rotate / skew / perspective, clip and blur) from keyframes, keeping
|
|
49
|
+
* opacity and colour, so any animation can get a vestibular-safe twin.
|
|
50
|
+
* - `flashCount(keyframes, duration)` / `isFlashSafe(...)` — counts large
|
|
51
|
+
* opacity / brightness swings and checks WCAG 2.3.1's three-flashes-per-
|
|
52
|
+
* second limit.
|
|
53
|
+
* - `applyMotionPreferences(prefs)` / `loadMotionPreferences()` — the
|
|
54
|
+
* settings behind `<usa-motion-prefs>`: sensitivity level, speed (shared
|
|
55
|
+
* clock rate), pause autoplay, no parallax; persisted in localStorage and
|
|
56
|
+
* exposed as `data-usa-*` attributes on `<html>` for your CSS.
|
|
57
|
+
*
|
|
58
|
+
* Effects that never move anything: `safe-fade` (enter), `focus-glow`
|
|
59
|
+
* (attention), `color-pulse` (attention), `underline-sweep` (hover).
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */
|
|
63
|
+
declare function vestibularSafe(frames: Keyframe[]): Keyframe[];
|
|
64
|
+
/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */
|
|
65
|
+
declare function flashCount(frames: Keyframe[]): number;
|
|
66
|
+
/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */
|
|
67
|
+
declare function isFlashSafe(frames: Keyframe[], duration: number, iterations?: number): boolean;
|
|
68
|
+
interface MotionPreferences {
|
|
69
|
+
sensitivity: MotionSensitivity;
|
|
70
|
+
speed: number;
|
|
71
|
+
pauseAutoplay: boolean;
|
|
72
|
+
noParallax: boolean;
|
|
73
|
+
}
|
|
74
|
+
declare const MOTION_PREFS_KEY = "usa-motion-prefs";
|
|
75
|
+
declare const DEFAULT_MOTION_PREFS: MotionPreferences;
|
|
76
|
+
/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */
|
|
77
|
+
declare function applyMotionPreferences(p: Partial<MotionPreferences>, persist?: boolean): MotionPreferences;
|
|
78
|
+
/** Saved preferences (or the defaults) (9.5). */
|
|
79
|
+
declare function loadMotionPreferences(): MotionPreferences;
|
|
80
|
+
declare const SAFE_FX: EffectDefinition[];
|
|
81
|
+
/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */
|
|
82
|
+
declare function registerSafePack(): void;
|
|
83
|
+
|
|
84
|
+
export { DEFAULT_MOTION_PREFS, MOTION_PREFS_KEY, SAFE_FX, applyMotionPreferences, flashCount, isFlashSafe, loadMotionPreferences, registerSafePack, vestibularSafe };
|
|
85
|
+
export type { MotionPreferences };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { registerEffects } from '../chunks/registry-CnO7ZVPK.js';
|
|
2
|
+
import { g as configureComponents, x as setClock } from '../chunks/base-CLuqlLfG.js';
|
|
3
|
+
|
|
4
|
+
const MOVE = /^(transform|translate|scale|rotate|offset|offsetPath|offsetDistance|clipPath|top|left|right|bottom|margin.*|perspective)$/;
|
|
5
|
+
/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */
|
|
6
|
+
function vestibularSafe(frames) {
|
|
7
|
+
return frames.map((f) => {
|
|
8
|
+
const o = {};
|
|
9
|
+
for (const [k, v] of Object.entries(f)) {
|
|
10
|
+
if (MOVE.test(k))
|
|
11
|
+
continue;
|
|
12
|
+
if (k === 'filter' && typeof v === 'string') {
|
|
13
|
+
const nf = v.replace(/blur\([^)]*\)/g, '').trim();
|
|
14
|
+
if (nf)
|
|
15
|
+
o.filter = nf;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
o[k] = v;
|
|
19
|
+
}
|
|
20
|
+
return o;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const lum = (f) => {
|
|
24
|
+
let l = f.opacity != null ? Number(f.opacity) : 1;
|
|
25
|
+
const m = typeof f.filter === 'string' ? f.filter.match(/brightness\(([\d.]+)\)/) : null;
|
|
26
|
+
if (m)
|
|
27
|
+
l *= Number(m[1]);
|
|
28
|
+
return l;
|
|
29
|
+
};
|
|
30
|
+
/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */
|
|
31
|
+
function flashCount(frames) {
|
|
32
|
+
const ls = frames.map(lum);
|
|
33
|
+
let n = 0;
|
|
34
|
+
let dir = 0;
|
|
35
|
+
let ref = ls[0] ?? 1;
|
|
36
|
+
for (const l of ls.slice(1)) {
|
|
37
|
+
const d = l - ref;
|
|
38
|
+
if (Math.abs(d) >= 0.3) {
|
|
39
|
+
const s = Math.sign(d);
|
|
40
|
+
if (dir && s !== dir)
|
|
41
|
+
n++;
|
|
42
|
+
dir = s;
|
|
43
|
+
ref = l;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return n;
|
|
47
|
+
}
|
|
48
|
+
/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */
|
|
49
|
+
function isFlashSafe(frames, duration, iterations = 1) {
|
|
50
|
+
const per = flashCount(frames);
|
|
51
|
+
if (!per)
|
|
52
|
+
return true;
|
|
53
|
+
const perSecond = (per * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / Math.max(0.001, (duration * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / 1000);
|
|
54
|
+
return perSecond <= 3;
|
|
55
|
+
}
|
|
56
|
+
const MOTION_PREFS_KEY = 'usa-motion-prefs';
|
|
57
|
+
const DEFAULT_MOTION_PREFS = { sensitivity: 'full', speed: 1, pauseAutoplay: false, noParallax: false };
|
|
58
|
+
/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */
|
|
59
|
+
function applyMotionPreferences(p, persist = true) {
|
|
60
|
+
const prefs = { ...DEFAULT_MOTION_PREFS, ...p };
|
|
61
|
+
if (!['full', 'gentle', 'minimal', 'static'].includes(prefs.sensitivity))
|
|
62
|
+
prefs.sensitivity = 'full';
|
|
63
|
+
prefs.speed = Math.min(2, Math.max(0.25, Number(prefs.speed) || 1));
|
|
64
|
+
configureComponents({ motionSensitivity: prefs.sensitivity });
|
|
65
|
+
setClock({ rate: prefs.speed });
|
|
66
|
+
if (typeof document !== 'undefined') {
|
|
67
|
+
const h = document.documentElement;
|
|
68
|
+
h.toggleAttribute('data-usa-pause-autoplay', prefs.pauseAutoplay);
|
|
69
|
+
h.toggleAttribute('data-usa-no-parallax', prefs.noParallax);
|
|
70
|
+
if (prefs.pauseAutoplay)
|
|
71
|
+
document.querySelectorAll('video[autoplay], audio[autoplay]').forEach((m) => m.pause?.());
|
|
72
|
+
}
|
|
73
|
+
if (persist)
|
|
74
|
+
try {
|
|
75
|
+
localStorage.setItem(MOTION_PREFS_KEY, JSON.stringify(prefs));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
/* storage blocked */
|
|
79
|
+
}
|
|
80
|
+
return prefs;
|
|
81
|
+
}
|
|
82
|
+
/** Saved preferences (or the defaults) (9.5). */
|
|
83
|
+
function loadMotionPreferences() {
|
|
84
|
+
try {
|
|
85
|
+
const j = JSON.parse(localStorage.getItem(MOTION_PREFS_KEY) || 'null');
|
|
86
|
+
if (j && typeof j === 'object')
|
|
87
|
+
return { ...DEFAULT_MOTION_PREFS, ...j };
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* none */
|
|
91
|
+
}
|
|
92
|
+
return { ...DEFAULT_MOTION_PREFS };
|
|
93
|
+
}
|
|
94
|
+
const SAFE_FX = [
|
|
95
|
+
{
|
|
96
|
+
name: 'safe-fade',
|
|
97
|
+
kind: 'enter',
|
|
98
|
+
description: 'An entrance that never moves: opacity only (also used as the reduced-motion twin of other entrances).',
|
|
99
|
+
defaults: { duration: 500 },
|
|
100
|
+
reduced: 'run',
|
|
101
|
+
run: (el, o, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: o.duration, delay: o.delay, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined),
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'focus-glow',
|
|
105
|
+
kind: 'attention',
|
|
106
|
+
description: 'Draws attention with a pulsing focus-ring glow instead of movement (`color`).',
|
|
107
|
+
defaults: { color: '#6366f1', duration: 1200 },
|
|
108
|
+
reduced: 'run',
|
|
109
|
+
run: (el, o, ctx) => ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}00` }, { boxShadow: `0 0 0 4px ${o.color}`, offset: 0.4 }, { boxShadow: `0 0 0 8px ${o.color}00` }], { duration: o.duration })?.finished.catch(() => undefined),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'color-pulse',
|
|
113
|
+
kind: 'attention',
|
|
114
|
+
description: 'Draws attention with a colour change instead of movement (`color`).',
|
|
115
|
+
defaults: { color: '#fde047', duration: 1000 },
|
|
116
|
+
reduced: 'run',
|
|
117
|
+
run: (el, o, ctx) => ctx.animate(el, [{ backgroundColor: 'transparent' }, { backgroundColor: o.color, offset: 0.35 }, { backgroundColor: 'transparent' }], { duration: o.duration })?.finished.catch(() => undefined),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'underline-sweep',
|
|
121
|
+
kind: 'hover',
|
|
122
|
+
description: 'A text underline grows from the left on hover / focus — motion-light, no layout shift (`color`).',
|
|
123
|
+
defaults: { color: 'currentColor', duration: 300 },
|
|
124
|
+
reduced: 'run',
|
|
125
|
+
run: (el, o, ctx) => {
|
|
126
|
+
const prev = [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition];
|
|
127
|
+
Object.assign(el.style, { backgroundImage: `linear-gradient(${o.color}, ${o.color})`, backgroundRepeat: 'no-repeat', backgroundPosition: '0 100%' });
|
|
128
|
+
ctx.onCleanup(() => {
|
|
129
|
+
[el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition] = prev;
|
|
130
|
+
});
|
|
131
|
+
if (ctx.reduced) {
|
|
132
|
+
el.style.backgroundSize = '100% 2px';
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
return ctx.animate(el, [{ backgroundSize: '0% 2px' }, { backgroundSize: '100% 2px' }], { duration: o.duration, easing: 'ease-out', fill: 'forwards' })?.finished.catch(() => undefined);
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */
|
|
140
|
+
function registerSafePack() {
|
|
141
|
+
registerEffects(SAFE_FX);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export { DEFAULT_MOTION_PREFS, MOTION_PREFS_KEY, SAFE_FX, applyMotionPreferences, flashCount, isFlashSafe, loadMotionPreferences, registerSafePack, vestibularSafe };
|
|
145
|
+
//# sourceMappingURL=fx-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-safe.js","sources":["../../src/components/fx2/safemotion.ts"],"sourcesContent":["/**\n * 9.5 — Accessible motion 2.0 (`motionary/fx/safe`, also `motionary/components/fx-safe`):\n *\n * - `vestibularSafe(keyframes)` — strips movement (translate / scale /\n * rotate / skew / perspective, clip and blur) from keyframes, keeping\n * opacity and colour, so any animation can get a vestibular-safe twin.\n * - `flashCount(keyframes, duration)` / `isFlashSafe(...)` — counts large\n * opacity / brightness swings and checks WCAG 2.3.1's three-flashes-per-\n * second limit.\n * - `applyMotionPreferences(prefs)` / `loadMotionPreferences()` — the\n * settings behind `<usa-motion-prefs>`: sensitivity level, speed (shared\n * clock rate), pause autoplay, no parallax; persisted in localStorage and\n * exposed as `data-usa-*` attributes on `<html>` for your CSS.\n *\n * Effects that never move anything: `safe-fade` (enter), `focus-glow`\n * (attention), `color-pulse` (attention), `underline-sweep` (hover).\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\nimport { configureComponents, setClock, type MotionSensitivity } from '../base';\n\nconst MOVE = /^(transform|translate|scale|rotate|offset|offsetPath|offsetDistance|clipPath|top|left|right|bottom|margin.*|perspective)$/;\n/** Keyframes with all movement removed (opacity / colour / shadow kept; blur removed from filters) (9.5). */\nexport function vestibularSafe(frames: Keyframe[]): Keyframe[] {\n return frames.map((f) => {\n const o: Keyframe = {};\n for (const [k, v] of Object.entries(f)) {\n if (MOVE.test(k)) continue;\n if (k === 'filter' && typeof v === 'string') {\n const nf = v.replace(/blur\\([^)]*\\)/g, '').trim();\n if (nf) o.filter = nf;\n continue;\n }\n (o as any)[k] = v;\n }\n return o;\n });\n}\n\nconst lum = (f: Keyframe): number => {\n let l = f.opacity != null ? Number(f.opacity) : 1;\n const m = typeof f.filter === 'string' ? f.filter.match(/brightness\\(([\\d.]+)\\)/) : null;\n if (m) l *= Number(m[1]);\n return l;\n};\n/** Number of flashes (a ≥ 0.3 luminance swing that comes back) in one run of `frames` (9.5). */\nexport function flashCount(frames: Keyframe[]): number {\n const ls = frames.map(lum);\n let n = 0;\n let dir = 0;\n let ref = ls[0] ?? 1;\n for (const l of ls.slice(1)) {\n const d = l - ref;\n if (Math.abs(d) >= 0.3) {\n const s = Math.sign(d);\n if (dir && s !== dir) n++;\n dir = s;\n ref = l;\n }\n }\n return n;\n}\n/** WCAG 2.3.1: no more than three flashes in any one second (9.5). */\nexport function isFlashSafe(frames: Keyframe[], duration: number, iterations = 1): boolean {\n const per = flashCount(frames);\n if (!per) return true;\n const perSecond = (per * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / Math.max(0.001, (duration * Math.max(1, Number.isFinite(iterations) ? iterations : 1)) / 1000);\n return perSecond <= 3;\n}\n\nexport interface MotionPreferences {\n sensitivity: MotionSensitivity;\n speed: number;\n pauseAutoplay: boolean;\n noParallax: boolean;\n}\nexport const MOTION_PREFS_KEY = 'usa-motion-prefs';\nexport const DEFAULT_MOTION_PREFS: MotionPreferences = { sensitivity: 'full', speed: 1, pauseAutoplay: false, noParallax: false };\n\n/** Apply (and persist) motion preferences: sensitivity, shared clock speed, `data-usa-*` flags on `<html>` (9.5). */\nexport function applyMotionPreferences(p: Partial<MotionPreferences>, persist = true): MotionPreferences {\n const prefs: MotionPreferences = { ...DEFAULT_MOTION_PREFS, ...p };\n if (!['full', 'gentle', 'minimal', 'static'].includes(prefs.sensitivity)) prefs.sensitivity = 'full';\n prefs.speed = Math.min(2, Math.max(0.25, Number(prefs.speed) || 1));\n configureComponents({ motionSensitivity: prefs.sensitivity });\n setClock({ rate: prefs.speed });\n if (typeof document !== 'undefined') {\n const h = document.documentElement;\n h.toggleAttribute('data-usa-pause-autoplay', prefs.pauseAutoplay);\n h.toggleAttribute('data-usa-no-parallax', prefs.noParallax);\n if (prefs.pauseAutoplay) document.querySelectorAll<HTMLMediaElement>('video[autoplay], audio[autoplay]').forEach((m) => m.pause?.());\n }\n if (persist)\n try {\n localStorage.setItem(MOTION_PREFS_KEY, JSON.stringify(prefs));\n } catch {\n /* storage blocked */\n }\n return prefs;\n}\n/** Saved preferences (or the defaults) (9.5). */\nexport function loadMotionPreferences(): MotionPreferences {\n try {\n const j = JSON.parse(localStorage.getItem(MOTION_PREFS_KEY) || 'null');\n if (j && typeof j === 'object') return { ...DEFAULT_MOTION_PREFS, ...j };\n } catch {\n /* none */\n }\n return { ...DEFAULT_MOTION_PREFS };\n}\n\nexport const SAFE_FX: EffectDefinition[] = [\n {\n name: 'safe-fade',\n kind: 'enter',\n description: 'An entrance that never moves: opacity only (also used as the reduced-motion twin of other entrances).',\n defaults: { duration: 500 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: o.duration, delay: o.delay, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined),\n },\n {\n name: 'focus-glow',\n kind: 'attention',\n description: 'Draws attention with a pulsing focus-ring glow instead of movement (`color`).',\n defaults: { color: '#6366f1', duration: 1200 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}00` }, { boxShadow: `0 0 0 4px ${o.color}`, offset: 0.4 }, { boxShadow: `0 0 0 8px ${o.color}00` }], { duration: o.duration })?.finished.catch(() => undefined),\n },\n {\n name: 'color-pulse',\n kind: 'attention',\n description: 'Draws attention with a colour change instead of movement (`color`).',\n defaults: { color: '#fde047', duration: 1000 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => ctx.animate(el, [{ backgroundColor: 'transparent' }, { backgroundColor: o.color, offset: 0.35 }, { backgroundColor: 'transparent' }], { duration: o.duration })?.finished.catch(() => undefined),\n },\n {\n name: 'underline-sweep',\n kind: 'hover',\n description: 'A text underline grows from the left on hover / focus — motion-light, no layout shift (`color`).',\n defaults: { color: 'currentColor', duration: 300 },\n reduced: 'run',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const prev = [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition];\n Object.assign(el.style, { backgroundImage: `linear-gradient(${o.color}, ${o.color})`, backgroundRepeat: 'no-repeat', backgroundPosition: '0 100%' });\n ctx.onCleanup(() => {\n [el.style.backgroundImage, el.style.backgroundSize, el.style.backgroundRepeat, el.style.backgroundPosition] = prev;\n });\n if (ctx.reduced) {\n el.style.backgroundSize = '100% 2px';\n return;\n }\n return ctx.animate(el, [{ backgroundSize: '0% 2px' }, { backgroundSize: '100% 2px' }], { duration: o.duration, easing: 'ease-out', fill: 'forwards' })?.finished.catch(() => undefined);\n },\n },\n];\n\n/** Register safe-fade, focus-glow, color-pulse and underline-sweep (9.5). */\nexport function registerSafePack(): void {\n registerEffects(SAFE_FX);\n}\n"],"names":[],"mappings":";;;AAqBA,MAAM,IAAI,GAAG,2HAA2H;AACxI;AACM,SAAU,cAAc,CAAC,MAAkB,EAAA;AAC/C,IAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAI;QACtB,MAAM,CAAC,GAAa,EAAE;AACtB,QAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE;YAClB,IAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;AAC3C,gBAAA,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;AACjD,gBAAA,IAAI,EAAE;AAAE,oBAAA,CAAC,CAAC,MAAM,GAAG,EAAE;gBACrB;YACF;AACC,YAAA,CAAS,CAAC,CAAC,CAAC,GAAG,CAAC;QACnB;AACA,QAAA,OAAO,CAAC;AACV,IAAA,CAAC,CAAC;AACJ;AAEA,MAAM,GAAG,GAAG,CAAC,CAAW,KAAY;IAClC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IACjD,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,GAAG,IAAI;AACxF,IAAA,IAAI,CAAC;QAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,IAAA,OAAO,CAAC;AACV,CAAC;AACD;AACM,SAAU,UAAU,CAAC,MAAkB,EAAA;IAC3C,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC;IACT,IAAI,GAAG,GAAG,CAAC;IACX,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC3B,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG;QACjB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE;YACtB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,YAAA,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG;AAAE,gBAAA,CAAC,EAAE;YACzB,GAAG,GAAG,CAAC;YACP,GAAG,GAAG,CAAC;QACT;IACF;AACA,IAAA,OAAO,CAAC;AACV;AACA;AACM,SAAU,WAAW,CAAC,MAAkB,EAAE,QAAgB,EAAE,UAAU,GAAG,CAAC,EAAA;AAC9E,IAAA,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC;AAC9B,IAAA,IAAI,CAAC,GAAG;AAAE,QAAA,OAAO,IAAI;AACrB,IAAA,MAAM,SAAS,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IACpL,OAAO,SAAS,IAAI,CAAC;AACvB;AAQO,MAAM,gBAAgB,GAAG;MACnB,oBAAoB,GAAsB,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK;AAE/H;SACgB,sBAAsB,CAAC,CAA6B,EAAE,OAAO,GAAG,IAAI,EAAA;IAClF,MAAM,KAAK,GAAsB,EAAE,GAAG,oBAAoB,EAAE,GAAG,CAAC,EAAE;AAClE,IAAA,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC;AAAE,QAAA,KAAK,CAAC,WAAW,GAAG,MAAM;IACpG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;IAC7D,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;AAC/B,IAAA,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE;AACnC,QAAA,MAAM,CAAC,GAAG,QAAQ,CAAC,eAAe;QAClC,CAAC,CAAC,eAAe,CAAC,yBAAyB,EAAE,KAAK,CAAC,aAAa,CAAC;QACjE,CAAC,CAAC,eAAe,CAAC,sBAAsB,EAAE,KAAK,CAAC,UAAU,CAAC;QAC3D,IAAI,KAAK,CAAC,aAAa;AAAE,YAAA,QAAQ,CAAC,gBAAgB,CAAmB,kCAAkC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;IACtI;AACA,IAAA,IAAI,OAAO;AACT,QAAA,IAAI;AACF,YAAA,YAAY,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/D;AAAE,QAAA,MAAM;;QAER;AACF,IAAA,OAAO,KAAK;AACd;AACA;SACgB,qBAAqB,GAAA;AACnC,IAAA,IAAI;AACF,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC;AACtE,QAAA,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;AAAE,YAAA,OAAO,EAAE,GAAG,oBAAoB,EAAE,GAAG,CAAC,EAAE;IAC1E;AAAE,IAAA,MAAM;;IAER;AACA,IAAA,OAAO,EAAE,GAAG,oBAAoB,EAAE;AACpC;AAEO,MAAM,OAAO,GAAuB;AACzC,IAAA;AACE,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,uGAAuG;AACpH,QAAA,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;AAC3B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC1N,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,+EAA+E;QAC5F,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;AAC9C,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,CAAA,QAAA,EAAW,CAAC,CAAC,KAAK,CAAA,EAAA,CAAI,EAAE,EAAE,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,KAAK,CAAA,CAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,KAAK,CAAA,EAAA,CAAI,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AACvQ,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,aAAa;AACnB,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,qEAAqE;QAClF,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;AAC9C,QAAA,OAAO,EAAE,KAAK;QACd,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,eAAe,EAAE,aAAa,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AACvP,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,iBAAiB;AACvB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,kGAAkG;QAC/G,QAAQ,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,EAAE;AAClD,QAAA,OAAO,EAAE,KAAK;QACd,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC;AACxH,YAAA,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,eAAe,EAAE,CAAA,gBAAA,EAAmB,CAAC,CAAC,KAAK,CAAA,EAAA,EAAK,CAAC,CAAC,KAAK,CAAA,CAAA,CAAG,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AACpJ,YAAA,GAAG,CAAC,SAAS,CAAC,MAAK;gBACjB,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,IAAI;AACpH,YAAA,CAAC,CAAC;AACF,YAAA,IAAI,GAAG,CAAC,OAAO,EAAE;AACf,gBAAA,EAAE,CAAC,KAAK,CAAC,cAAc,GAAG,UAAU;gBACpC;YACF;YACA,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACzL,CAAC;AACF,KAAA;;AAGH;SACgB,gBAAgB,GAAA;IAC9B,eAAe,CAAC,OAAO,CAAC;AAC1B;;;;"}
|