motionary 7.1.0 → 7.3.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/chunks/builtins-HlqAkK0f.js +99 -0
  3. package/dist/chunks/builtins-HlqAkK0f.js.map +1 -0
  4. package/dist/chunks/builtins-xalxV2d5.cjs +101 -0
  5. package/dist/chunks/builtins-xalxV2d5.cjs.map +1 -0
  6. package/dist/components/angular.cjs +1 -0
  7. package/dist/components/angular.cjs.map +1 -1
  8. package/dist/components/angular.js +1 -0
  9. package/dist/components/angular.js.map +1 -1
  10. package/dist/components/effects.cjs +1 -0
  11. package/dist/components/effects.cjs.map +1 -1
  12. package/dist/components/effects.js +1 -0
  13. package/dist/components/effects.js.map +1 -1
  14. package/dist/components/fx-chart.cjs +158 -0
  15. package/dist/components/fx-chart.cjs.map +1 -0
  16. package/dist/components/fx-chart.d.cts +73 -0
  17. package/dist/components/fx-chart.d.ts +73 -0
  18. package/dist/components/fx-chart.js +154 -0
  19. package/dist/components/fx-chart.js.map +1 -0
  20. package/dist/components/fx-shop.cjs +133 -0
  21. package/dist/components/fx-shop.cjs.map +1 -0
  22. package/dist/components/fx-shop.d.cts +70 -0
  23. package/dist/components/fx-shop.d.ts +70 -0
  24. package/dist/components/fx-shop.js +129 -0
  25. package/dist/components/fx-shop.js.map +1 -0
  26. package/dist/components/fx.cjs +5 -98
  27. package/dist/components/fx.cjs.map +1 -1
  28. package/dist/components/fx.js +3 -96
  29. package/dist/components/fx.js.map +1 -1
  30. package/dist/components/fx2.cjs +12 -0
  31. package/dist/components/fx2.cjs.map +1 -1
  32. package/dist/components/fx2.d.cts +56 -1
  33. package/dist/components/fx2.d.ts +56 -1
  34. package/dist/components/fx2.js +9 -1
  35. package/dist/components/fx2.js.map +1 -1
  36. package/dist/components/solid.cjs +1 -0
  37. package/dist/components/solid.cjs.map +1 -1
  38. package/dist/components/solid.js +1 -0
  39. package/dist/components/solid.js.map +1 -1
  40. package/dist/components/svelte.cjs +1 -0
  41. package/dist/components/svelte.cjs.map +1 -1
  42. package/dist/components/svelte.js +1 -0
  43. package/dist/components/svelte.js.map +1 -1
  44. package/dist/components/vue.cjs +1 -0
  45. package/dist/components/vue.cjs.map +1 -1
  46. package/dist/components/vue.js +1 -0
  47. package/dist/components/vue.js.map +1 -1
  48. package/dist/components/widgets.cjs +916 -70
  49. package/dist/components/widgets.cjs.map +1 -1
  50. package/dist/components/widgets.d.cts +158 -2
  51. package/dist/components/widgets.d.ts +158 -2
  52. package/dist/components/widgets.js +904 -71
  53. package/dist/components/widgets.js.map +1 -1
  54. package/dist/components.cjs +2 -1
  55. package/dist/components.cjs.map +1 -1
  56. package/dist/components.js +2 -1
  57. package/dist/components.js.map +1 -1
  58. package/dist/widgets.umd.js +1 -1
  59. package/dist/widgets.umd.js.map +1 -1
  60. package/docs/ROADMAP.md +2 -2
  61. package/docs/components.md +50 -0
  62. package/package.json +41 -1
@@ -0,0 +1,133 @@
1
+ 'use strict';
2
+
3
+ var registry = require('../chunks/registry-DehBVRDV.cjs');
4
+ require('../chunks/base-BaQV-2ha.cjs');
5
+
6
+ /** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */
7
+ function arcPath(ax, ay, bx, by, lift = 120, steps = 8) {
8
+ const cx = (ax + bx) / 2;
9
+ const cy = Math.min(ay, by) - lift;
10
+ return Array.from({ length: steps + 1 }, (_, i) => {
11
+ const t = i / steps;
12
+ const u = 1 - t;
13
+ return { x: u * u * ax + 2 * u * t * cx + t * t * bx, y: u * u * ay + 2 * u * t * cy + t * t * by };
14
+ });
15
+ }
16
+ const bump = (el, ctx) => el && ctx.animate(el, ctx.reduced ? [{ opacity: 0.5 }, { opacity: 1 }] : [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.35 }, { transform: 'scale(.92)', offset: 0.7 }, { transform: 'scale(1)' }], { duration: ctx.reduced ? 250 : 480, easing: 'ease-out' });
17
+ const SHOP_FX = [
18
+ {
19
+ name: 'fly-to-cart',
20
+ kind: 'click',
21
+ description: 'A ghost of the element (or its first `img`) flies on an arc into the cart (`to` selector, default `[data-cart]`), shrinking; the cart bumps (`duration`, `lift`).',
22
+ defaults: { to: '[data-cart]', duration: 750, lift: 120 },
23
+ run: (el, o, ctx) => {
24
+ const cart = document.querySelector(o.to);
25
+ if (!cart)
26
+ return;
27
+ if (ctx.reduced)
28
+ return void bump(cart, ctx);
29
+ const src = el.querySelector('img') || el;
30
+ const a = src.getBoundingClientRect();
31
+ const b = cart.getBoundingClientRect();
32
+ const ghost = src.cloneNode(true);
33
+ ghost.removeAttribute('id');
34
+ ghost.setAttribute('aria-hidden', 'true');
35
+ Object.assign(ghost.style, { position: 'fixed', left: `${a.left}px`, top: `${a.top}px`, width: `${a.width}px`, height: `${a.height}px`, margin: '0', zIndex: '2147483000', pointerEvents: 'none', borderRadius: '12px', overflow: 'hidden' });
36
+ document.body.appendChild(ghost);
37
+ const pts = arcPath(0, 0, b.left + b.width / 2 - (a.left + a.width / 2), b.top + b.height / 2 - (a.top + a.height / 2), o.lift);
38
+ const s = Math.max(0.12, Math.min(1, 28 / Math.max(a.width, a.height, 1)));
39
+ const anim = ctx.animate(ghost, pts.map((p, i) => ({ transform: `translate(${p.x.toFixed(1)}px,${p.y.toFixed(1)}px) scale(${(1 - (1 - s) * (i / (pts.length - 1))).toFixed(3)})`, opacity: i === pts.length - 1 ? 0.6 : 1 })), { duration: o.duration, easing: 'cubic-bezier(.5,0,.75,.4)', fill: 'forwards' });
40
+ const done = () => (ghost.remove(), bump(cart, ctx));
41
+ if (anim)
42
+ anim.finished.then(done, () => ghost.remove());
43
+ else
44
+ done();
45
+ ctx.onCleanup(() => ghost.remove());
46
+ return anim?.finished.catch(() => undefined);
47
+ },
48
+ },
49
+ {
50
+ name: 'price-flip',
51
+ kind: 'enter',
52
+ description: 'The price flips character by character like a split-flap display from `data-from` (or scrambled digits) to its text (`stagger`).',
53
+ defaults: { stagger: 55, duration: 380 },
54
+ run: (el, o, ctx) => {
55
+ const to = el.dataset.priceTo || el.textContent || '';
56
+ el.dataset.priceTo = to;
57
+ if (ctx.reduced)
58
+ return void (el.textContent = to);
59
+ const from = (el.dataset.from || '').padStart(to.length, ' ');
60
+ el.textContent = '';
61
+ el.setAttribute('aria-label', to.trim());
62
+ const anims = Array.from(to).map((ch, i) => {
63
+ const span = document.createElement('span');
64
+ span.setAttribute('aria-hidden', 'true');
65
+ span.style.display = 'inline-block';
66
+ span.textContent = /\d/.test(ch) ? (from[i] && from[i] !== ' ' ? from[i] : String((Number(ch) + 5) % 10)) : ch;
67
+ el.appendChild(span);
68
+ const a = ctx.animate(span, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(90deg)', offset: 0.5 }, { transform: 'rotateX(0)' }], { duration: o.duration, delay: i * o.stagger, easing: 'ease-in-out' });
69
+ setTimeout(() => (span.textContent = ch), i * o.stagger + o.duration / 2);
70
+ return a;
71
+ });
72
+ return Promise.all(anims.map((a) => a?.finished.catch(() => undefined))).then(() => {
73
+ el.textContent = to;
74
+ el.removeAttribute('aria-label');
75
+ });
76
+ },
77
+ },
78
+ {
79
+ name: 'stock-pulse',
80
+ kind: 'loop',
81
+ description: 'A soft urgency pulse — a glow ring in `color` — for low stock / last items (`color`, `period`).',
82
+ defaults: { color: 'rgba(239,68,68,.55)', period: 1400 },
83
+ reduced: 'skip',
84
+ run: (el, o, ctx) => {
85
+ const a = ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}` }, { boxShadow: '0 0 0 12px rgba(0,0,0,0)' }], { duration: o.period, iterations: Infinity, easing: 'ease-out' });
86
+ const stop = () => a?.cancel();
87
+ ctx.onCleanup(stop);
88
+ return stop;
89
+ },
90
+ },
91
+ {
92
+ name: 'sale-shine',
93
+ kind: 'hover',
94
+ description: 'A diagonal light sweep across the element (product cards, buy buttons) (`duration`).',
95
+ defaults: { duration: 700 },
96
+ reduced: 'skip',
97
+ run: (el, o, ctx) => {
98
+ const s = document.createElement('span');
99
+ s.setAttribute('aria-hidden', 'true');
100
+ Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', background: 'linear-gradient(115deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', borderRadius: 'inherit' });
101
+ if (getComputedStyle(el).position === 'static')
102
+ el.style.position = 'relative';
103
+ const prev = el.style.overflow;
104
+ el.style.overflow = 'hidden';
105
+ el.appendChild(s);
106
+ const a = ctx.animate(s, [{ transform: 'translateX(-100%)' }, { transform: 'translateX(100%)' }], { duration: o.duration, easing: 'ease-in-out' });
107
+ const end = () => (s.remove(), (el.style.overflow = prev));
108
+ if (a)
109
+ a.finished.then(end, end);
110
+ else
111
+ end();
112
+ return a?.finished.catch(() => undefined);
113
+ },
114
+ },
115
+ {
116
+ name: 'badge-pop',
117
+ kind: 'attention',
118
+ description: 'A sale badge pops in with a wobble (`duration`).',
119
+ defaults: { duration: 650 },
120
+ run: (el, o, ctx) => ctx.reduced
121
+ ? ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })
122
+ : ctx.animate(el, [{ transform: 'scale(0) rotate(-20deg)' }, { transform: 'scale(1.2) rotate(8deg)', offset: 0.5 }, { transform: 'scale(.95) rotate(-4deg)', offset: 0.75 }, { transform: 'none' }], { duration: o.duration, easing: 'ease-out' }),
123
+ },
124
+ ];
125
+ /** Register the 7.3 e-commerce pack (idempotent). */
126
+ function registerShopPack() {
127
+ registry.registerEffects(SHOP_FX);
128
+ }
129
+
130
+ exports.SHOP_FX = SHOP_FX;
131
+ exports.arcPath = arcPath;
132
+ exports.registerShopPack = registerShopPack;
133
+ //# sourceMappingURL=fx-shop.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-shop.cjs","sources":["../../src/components/fx2/shop.ts"],"sourcesContent":["/**\n * 7.3 — E-commerce motion (`motionary/fx/shop`, also\n * `motionary/components/fx-shop`):\n *\n * - `fly-to-cart` (click) — a ghost of the element (or its first `img`) flies\n * on an arc into the cart (`to`, default `[data-cart]`), shrinking; the cart\n * bumps when it lands.\n * - `price-flip` (enter) — the price flips like a split-flap display from\n * `data-from` (or a scramble) to its text.\n * - `stock-pulse` (loop) — a soft urgency pulse (glow ring) for low stock.\n * - `sale-shine` (hover) — a diagonal light sweep across the element.\n * - `badge-pop` (attention) — a sale badge pops in with a wobble.\n *\n * Reduced motion: fly-to-cart only bumps the cart with a fade, price-flip\n * sets the text, stock-pulse and sale-shine do nothing, badge-pop fades.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */\nexport function arcPath(ax: number, ay: number, bx: number, by: number, lift = 120, steps = 8): { x: number; y: number }[] {\n const cx = (ax + bx) / 2;\n const cy = Math.min(ay, by) - lift;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const t = i / steps;\n const u = 1 - t;\n return { x: u * u * ax + 2 * u * t * cx + t * t * bx, y: u * u * ay + 2 * u * t * cy + t * t * by };\n });\n}\n\nconst bump = (el: Element | null, ctx: EffectContext) =>\n el && ctx.animate(el, ctx.reduced ? [{ opacity: 0.5 }, { opacity: 1 }] : [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.35 }, { transform: 'scale(.92)', offset: 0.7 }, { transform: 'scale(1)' }], { duration: ctx.reduced ? 250 : 480, easing: 'ease-out' });\n\nexport const SHOP_FX: EffectDefinition[] = [\n {\n name: 'fly-to-cart',\n kind: 'click',\n description: 'A ghost of the element (or its first `img`) flies on an arc into the cart (`to` selector, default `[data-cart]`), shrinking; the cart bumps (`duration`, `lift`).',\n defaults: { to: '[data-cart]', duration: 750, lift: 120 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const cart = document.querySelector(o.to) as HTMLElement | null;\n if (!cart) return;\n if (ctx.reduced) return void bump(cart, ctx);\n const src = (el.querySelector('img') as HTMLElement | null) || el;\n const a = src.getBoundingClientRect();\n const b = cart.getBoundingClientRect();\n const ghost = src.cloneNode(true) as HTMLElement;\n ghost.removeAttribute('id');\n ghost.setAttribute('aria-hidden', 'true');\n Object.assign(ghost.style, { position: 'fixed', left: `${a.left}px`, top: `${a.top}px`, width: `${a.width}px`, height: `${a.height}px`, margin: '0', zIndex: '2147483000', pointerEvents: 'none', borderRadius: '12px', overflow: 'hidden' });\n document.body.appendChild(ghost);\n const pts = arcPath(0, 0, b.left + b.width / 2 - (a.left + a.width / 2), b.top + b.height / 2 - (a.top + a.height / 2), o.lift);\n const s = Math.max(0.12, Math.min(1, 28 / Math.max(a.width, a.height, 1)));\n const anim = ctx.animate(ghost, pts.map((p, i) => ({ transform: `translate(${p.x.toFixed(1)}px,${p.y.toFixed(1)}px) scale(${(1 - (1 - s) * (i / (pts.length - 1))).toFixed(3)})`, opacity: i === pts.length - 1 ? 0.6 : 1 })), { duration: o.duration, easing: 'cubic-bezier(.5,0,.75,.4)', fill: 'forwards' });\n const done = () => (ghost.remove(), bump(cart, ctx));\n if (anim) anim.finished.then(done, () => ghost.remove());\n else done();\n ctx.onCleanup(() => ghost.remove());\n return anim?.finished.catch(() => undefined);\n },\n },\n {\n name: 'price-flip',\n kind: 'enter',\n description: 'The price flips character by character like a split-flap display from `data-from` (or scrambled digits) to its text (`stagger`).',\n defaults: { stagger: 55, duration: 380 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const to = el.dataset.priceTo || el.textContent || '';\n el.dataset.priceTo = to;\n if (ctx.reduced) return void (el.textContent = to);\n const from = (el.dataset.from || '').padStart(to.length, ' ');\n el.textContent = '';\n el.setAttribute('aria-label', to.trim());\n const anims = Array.from(to).map((ch, i) => {\n const span = document.createElement('span');\n span.setAttribute('aria-hidden', 'true');\n span.style.display = 'inline-block';\n span.textContent = /\\d/.test(ch) ? (from[i] && from[i] !== ' ' ? from[i] : String((Number(ch) + 5) % 10)) : ch;\n el.appendChild(span);\n const a = ctx.animate(span, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(90deg)', offset: 0.5 }, { transform: 'rotateX(0)' }], { duration: o.duration, delay: i * o.stagger, easing: 'ease-in-out' });\n setTimeout(() => (span.textContent = ch), i * o.stagger + o.duration / 2);\n return a;\n });\n return Promise.all(anims.map((a) => a?.finished.catch(() => undefined))).then(() => {\n el.textContent = to;\n el.removeAttribute('aria-label');\n });\n },\n },\n {\n name: 'stock-pulse',\n kind: 'loop',\n description: 'A soft urgency pulse — a glow ring in `color` — for low stock / last items (`color`, `period`).',\n defaults: { color: 'rgba(239,68,68,.55)', period: 1400 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const a = ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}` }, { boxShadow: '0 0 0 12px rgba(0,0,0,0)' }], { duration: o.period, iterations: Infinity, easing: 'ease-out' });\n const stop = () => a?.cancel();\n ctx.onCleanup(stop);\n return stop;\n },\n },\n {\n name: 'sale-shine',\n kind: 'hover',\n description: 'A diagonal light sweep across the element (product cards, buy buttons) (`duration`).',\n defaults: { duration: 700 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const s = document.createElement('span');\n s.setAttribute('aria-hidden', 'true');\n Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', background: 'linear-gradient(115deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', borderRadius: 'inherit' });\n if (getComputedStyle(el).position === 'static') el.style.position = 'relative';\n const prev = el.style.overflow;\n el.style.overflow = 'hidden';\n el.appendChild(s);\n const a = ctx.animate(s, [{ transform: 'translateX(-100%)' }, { transform: 'translateX(100%)' }], { duration: o.duration, easing: 'ease-in-out' });\n const end = () => (s.remove(), (el.style.overflow = prev));\n if (a) a.finished.then(end, end);\n else end();\n return a?.finished.catch(() => undefined);\n },\n },\n {\n name: 'badge-pop',\n kind: 'attention',\n description: 'A sale badge pops in with a wobble (`duration`).',\n defaults: { duration: 650 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) =>\n ctx.reduced\n ? ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })\n : ctx.animate(el, [{ transform: 'scale(0) rotate(-20deg)' }, { transform: 'scale(1.2) rotate(8deg)', offset: 0.5 }, { transform: 'scale(.95) rotate(-4deg)', offset: 0.75 }, { transform: 'none' }], { duration: o.duration, easing: 'ease-out' }),\n },\n];\n\n/** Register the 7.3 e-commerce pack (idempotent). */\nexport function registerShopPack(): void {\n registerEffects(SHOP_FX);\n}\n"],"names":["registerEffects"],"mappings":"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"}
@@ -0,0 +1,70 @@
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
+ * 7.3 — E-commerce motion (`motionary/fx/shop`, also
46
+ * `motionary/components/fx-shop`):
47
+ *
48
+ * - `fly-to-cart` (click) — a ghost of the element (or its first `img`) flies
49
+ * on an arc into the cart (`to`, default `[data-cart]`), shrinking; the cart
50
+ * bumps when it lands.
51
+ * - `price-flip` (enter) — the price flips like a split-flap display from
52
+ * `data-from` (or a scramble) to its text.
53
+ * - `stock-pulse` (loop) — a soft urgency pulse (glow ring) for low stock.
54
+ * - `sale-shine` (hover) — a diagonal light sweep across the element.
55
+ * - `badge-pop` (attention) — a sale badge pops in with a wobble.
56
+ *
57
+ * Reduced motion: fly-to-cart only bumps the cart with a fade, price-flip
58
+ * sets the text, stock-pulse and sale-shine do nothing, badge-pop fades.
59
+ */
60
+
61
+ /** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */
62
+ declare function arcPath(ax: number, ay: number, bx: number, by: number, lift?: number, steps?: number): {
63
+ x: number;
64
+ y: number;
65
+ }[];
66
+ declare const SHOP_FX: EffectDefinition[];
67
+ /** Register the 7.3 e-commerce pack (idempotent). */
68
+ declare function registerShopPack(): void;
69
+
70
+ export { SHOP_FX, arcPath, registerShopPack };
@@ -0,0 +1,70 @@
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
+ * 7.3 — E-commerce motion (`motionary/fx/shop`, also
46
+ * `motionary/components/fx-shop`):
47
+ *
48
+ * - `fly-to-cart` (click) — a ghost of the element (or its first `img`) flies
49
+ * on an arc into the cart (`to`, default `[data-cart]`), shrinking; the cart
50
+ * bumps when it lands.
51
+ * - `price-flip` (enter) — the price flips like a split-flap display from
52
+ * `data-from` (or a scramble) to its text.
53
+ * - `stock-pulse` (loop) — a soft urgency pulse (glow ring) for low stock.
54
+ * - `sale-shine` (hover) — a diagonal light sweep across the element.
55
+ * - `badge-pop` (attention) — a sale badge pops in with a wobble.
56
+ *
57
+ * Reduced motion: fly-to-cart only bumps the cart with a fade, price-flip
58
+ * sets the text, stock-pulse and sale-shine do nothing, badge-pop fades.
59
+ */
60
+
61
+ /** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */
62
+ declare function arcPath(ax: number, ay: number, bx: number, by: number, lift?: number, steps?: number): {
63
+ x: number;
64
+ y: number;
65
+ }[];
66
+ declare const SHOP_FX: EffectDefinition[];
67
+ /** Register the 7.3 e-commerce pack (idempotent). */
68
+ declare function registerShopPack(): void;
69
+
70
+ export { SHOP_FX, arcPath, registerShopPack };
@@ -0,0 +1,129 @@
1
+ import { registerEffects } from '../chunks/registry-CyKExAmE.js';
2
+ import '../chunks/base-2-yYc93C.js';
3
+
4
+ /** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */
5
+ function arcPath(ax, ay, bx, by, lift = 120, steps = 8) {
6
+ const cx = (ax + bx) / 2;
7
+ const cy = Math.min(ay, by) - lift;
8
+ return Array.from({ length: steps + 1 }, (_, i) => {
9
+ const t = i / steps;
10
+ const u = 1 - t;
11
+ return { x: u * u * ax + 2 * u * t * cx + t * t * bx, y: u * u * ay + 2 * u * t * cy + t * t * by };
12
+ });
13
+ }
14
+ const bump = (el, ctx) => el && ctx.animate(el, ctx.reduced ? [{ opacity: 0.5 }, { opacity: 1 }] : [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.35 }, { transform: 'scale(.92)', offset: 0.7 }, { transform: 'scale(1)' }], { duration: ctx.reduced ? 250 : 480, easing: 'ease-out' });
15
+ const SHOP_FX = [
16
+ {
17
+ name: 'fly-to-cart',
18
+ kind: 'click',
19
+ description: 'A ghost of the element (or its first `img`) flies on an arc into the cart (`to` selector, default `[data-cart]`), shrinking; the cart bumps (`duration`, `lift`).',
20
+ defaults: { to: '[data-cart]', duration: 750, lift: 120 },
21
+ run: (el, o, ctx) => {
22
+ const cart = document.querySelector(o.to);
23
+ if (!cart)
24
+ return;
25
+ if (ctx.reduced)
26
+ return void bump(cart, ctx);
27
+ const src = el.querySelector('img') || el;
28
+ const a = src.getBoundingClientRect();
29
+ const b = cart.getBoundingClientRect();
30
+ const ghost = src.cloneNode(true);
31
+ ghost.removeAttribute('id');
32
+ ghost.setAttribute('aria-hidden', 'true');
33
+ Object.assign(ghost.style, { position: 'fixed', left: `${a.left}px`, top: `${a.top}px`, width: `${a.width}px`, height: `${a.height}px`, margin: '0', zIndex: '2147483000', pointerEvents: 'none', borderRadius: '12px', overflow: 'hidden' });
34
+ document.body.appendChild(ghost);
35
+ const pts = arcPath(0, 0, b.left + b.width / 2 - (a.left + a.width / 2), b.top + b.height / 2 - (a.top + a.height / 2), o.lift);
36
+ const s = Math.max(0.12, Math.min(1, 28 / Math.max(a.width, a.height, 1)));
37
+ const anim = ctx.animate(ghost, pts.map((p, i) => ({ transform: `translate(${p.x.toFixed(1)}px,${p.y.toFixed(1)}px) scale(${(1 - (1 - s) * (i / (pts.length - 1))).toFixed(3)})`, opacity: i === pts.length - 1 ? 0.6 : 1 })), { duration: o.duration, easing: 'cubic-bezier(.5,0,.75,.4)', fill: 'forwards' });
38
+ const done = () => (ghost.remove(), bump(cart, ctx));
39
+ if (anim)
40
+ anim.finished.then(done, () => ghost.remove());
41
+ else
42
+ done();
43
+ ctx.onCleanup(() => ghost.remove());
44
+ return anim?.finished.catch(() => undefined);
45
+ },
46
+ },
47
+ {
48
+ name: 'price-flip',
49
+ kind: 'enter',
50
+ description: 'The price flips character by character like a split-flap display from `data-from` (or scrambled digits) to its text (`stagger`).',
51
+ defaults: { stagger: 55, duration: 380 },
52
+ run: (el, o, ctx) => {
53
+ const to = el.dataset.priceTo || el.textContent || '';
54
+ el.dataset.priceTo = to;
55
+ if (ctx.reduced)
56
+ return void (el.textContent = to);
57
+ const from = (el.dataset.from || '').padStart(to.length, ' ');
58
+ el.textContent = '';
59
+ el.setAttribute('aria-label', to.trim());
60
+ const anims = Array.from(to).map((ch, i) => {
61
+ const span = document.createElement('span');
62
+ span.setAttribute('aria-hidden', 'true');
63
+ span.style.display = 'inline-block';
64
+ span.textContent = /\d/.test(ch) ? (from[i] && from[i] !== ' ' ? from[i] : String((Number(ch) + 5) % 10)) : ch;
65
+ el.appendChild(span);
66
+ const a = ctx.animate(span, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(90deg)', offset: 0.5 }, { transform: 'rotateX(0)' }], { duration: o.duration, delay: i * o.stagger, easing: 'ease-in-out' });
67
+ setTimeout(() => (span.textContent = ch), i * o.stagger + o.duration / 2);
68
+ return a;
69
+ });
70
+ return Promise.all(anims.map((a) => a?.finished.catch(() => undefined))).then(() => {
71
+ el.textContent = to;
72
+ el.removeAttribute('aria-label');
73
+ });
74
+ },
75
+ },
76
+ {
77
+ name: 'stock-pulse',
78
+ kind: 'loop',
79
+ description: 'A soft urgency pulse — a glow ring in `color` — for low stock / last items (`color`, `period`).',
80
+ defaults: { color: 'rgba(239,68,68,.55)', period: 1400 },
81
+ reduced: 'skip',
82
+ run: (el, o, ctx) => {
83
+ const a = ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}` }, { boxShadow: '0 0 0 12px rgba(0,0,0,0)' }], { duration: o.period, iterations: Infinity, easing: 'ease-out' });
84
+ const stop = () => a?.cancel();
85
+ ctx.onCleanup(stop);
86
+ return stop;
87
+ },
88
+ },
89
+ {
90
+ name: 'sale-shine',
91
+ kind: 'hover',
92
+ description: 'A diagonal light sweep across the element (product cards, buy buttons) (`duration`).',
93
+ defaults: { duration: 700 },
94
+ reduced: 'skip',
95
+ run: (el, o, ctx) => {
96
+ const s = document.createElement('span');
97
+ s.setAttribute('aria-hidden', 'true');
98
+ Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', background: 'linear-gradient(115deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', borderRadius: 'inherit' });
99
+ if (getComputedStyle(el).position === 'static')
100
+ el.style.position = 'relative';
101
+ const prev = el.style.overflow;
102
+ el.style.overflow = 'hidden';
103
+ el.appendChild(s);
104
+ const a = ctx.animate(s, [{ transform: 'translateX(-100%)' }, { transform: 'translateX(100%)' }], { duration: o.duration, easing: 'ease-in-out' });
105
+ const end = () => (s.remove(), (el.style.overflow = prev));
106
+ if (a)
107
+ a.finished.then(end, end);
108
+ else
109
+ end();
110
+ return a?.finished.catch(() => undefined);
111
+ },
112
+ },
113
+ {
114
+ name: 'badge-pop',
115
+ kind: 'attention',
116
+ description: 'A sale badge pops in with a wobble (`duration`).',
117
+ defaults: { duration: 650 },
118
+ run: (el, o, ctx) => ctx.reduced
119
+ ? ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })
120
+ : ctx.animate(el, [{ transform: 'scale(0) rotate(-20deg)' }, { transform: 'scale(1.2) rotate(8deg)', offset: 0.5 }, { transform: 'scale(.95) rotate(-4deg)', offset: 0.75 }, { transform: 'none' }], { duration: o.duration, easing: 'ease-out' }),
121
+ },
122
+ ];
123
+ /** Register the 7.3 e-commerce pack (idempotent). */
124
+ function registerShopPack() {
125
+ registerEffects(SHOP_FX);
126
+ }
127
+
128
+ export { SHOP_FX, arcPath, registerShopPack };
129
+ //# sourceMappingURL=fx-shop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-shop.js","sources":["../../src/components/fx2/shop.ts"],"sourcesContent":["/**\n * 7.3 — E-commerce motion (`motionary/fx/shop`, also\n * `motionary/components/fx-shop`):\n *\n * - `fly-to-cart` (click) — a ghost of the element (or its first `img`) flies\n * on an arc into the cart (`to`, default `[data-cart]`), shrinking; the cart\n * bumps when it lands.\n * - `price-flip` (enter) — the price flips like a split-flap display from\n * `data-from` (or a scramble) to its text.\n * - `stock-pulse` (loop) — a soft urgency pulse (glow ring) for low stock.\n * - `sale-shine` (hover) — a diagonal light sweep across the element.\n * - `badge-pop` (attention) — a sale badge pops in with a wobble.\n *\n * Reduced motion: fly-to-cart only bumps the cart with a fade, price-flip\n * sets the text, stock-pulse and sale-shine do nothing, badge-pop fades.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Quadratic-bezier arc points from a to b, lifted by `lift` px (7.3). */\nexport function arcPath(ax: number, ay: number, bx: number, by: number, lift = 120, steps = 8): { x: number; y: number }[] {\n const cx = (ax + bx) / 2;\n const cy = Math.min(ay, by) - lift;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const t = i / steps;\n const u = 1 - t;\n return { x: u * u * ax + 2 * u * t * cx + t * t * bx, y: u * u * ay + 2 * u * t * cy + t * t * by };\n });\n}\n\nconst bump = (el: Element | null, ctx: EffectContext) =>\n el && ctx.animate(el, ctx.reduced ? [{ opacity: 0.5 }, { opacity: 1 }] : [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.35 }, { transform: 'scale(.92)', offset: 0.7 }, { transform: 'scale(1)' }], { duration: ctx.reduced ? 250 : 480, easing: 'ease-out' });\n\nexport const SHOP_FX: EffectDefinition[] = [\n {\n name: 'fly-to-cart',\n kind: 'click',\n description: 'A ghost of the element (or its first `img`) flies on an arc into the cart (`to` selector, default `[data-cart]`), shrinking; the cart bumps (`duration`, `lift`).',\n defaults: { to: '[data-cart]', duration: 750, lift: 120 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const cart = document.querySelector(o.to) as HTMLElement | null;\n if (!cart) return;\n if (ctx.reduced) return void bump(cart, ctx);\n const src = (el.querySelector('img') as HTMLElement | null) || el;\n const a = src.getBoundingClientRect();\n const b = cart.getBoundingClientRect();\n const ghost = src.cloneNode(true) as HTMLElement;\n ghost.removeAttribute('id');\n ghost.setAttribute('aria-hidden', 'true');\n Object.assign(ghost.style, { position: 'fixed', left: `${a.left}px`, top: `${a.top}px`, width: `${a.width}px`, height: `${a.height}px`, margin: '0', zIndex: '2147483000', pointerEvents: 'none', borderRadius: '12px', overflow: 'hidden' });\n document.body.appendChild(ghost);\n const pts = arcPath(0, 0, b.left + b.width / 2 - (a.left + a.width / 2), b.top + b.height / 2 - (a.top + a.height / 2), o.lift);\n const s = Math.max(0.12, Math.min(1, 28 / Math.max(a.width, a.height, 1)));\n const anim = ctx.animate(ghost, pts.map((p, i) => ({ transform: `translate(${p.x.toFixed(1)}px,${p.y.toFixed(1)}px) scale(${(1 - (1 - s) * (i / (pts.length - 1))).toFixed(3)})`, opacity: i === pts.length - 1 ? 0.6 : 1 })), { duration: o.duration, easing: 'cubic-bezier(.5,0,.75,.4)', fill: 'forwards' });\n const done = () => (ghost.remove(), bump(cart, ctx));\n if (anim) anim.finished.then(done, () => ghost.remove());\n else done();\n ctx.onCleanup(() => ghost.remove());\n return anim?.finished.catch(() => undefined);\n },\n },\n {\n name: 'price-flip',\n kind: 'enter',\n description: 'The price flips character by character like a split-flap display from `data-from` (or scrambled digits) to its text (`stagger`).',\n defaults: { stagger: 55, duration: 380 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const to = el.dataset.priceTo || el.textContent || '';\n el.dataset.priceTo = to;\n if (ctx.reduced) return void (el.textContent = to);\n const from = (el.dataset.from || '').padStart(to.length, ' ');\n el.textContent = '';\n el.setAttribute('aria-label', to.trim());\n const anims = Array.from(to).map((ch, i) => {\n const span = document.createElement('span');\n span.setAttribute('aria-hidden', 'true');\n span.style.display = 'inline-block';\n span.textContent = /\\d/.test(ch) ? (from[i] && from[i] !== ' ' ? from[i] : String((Number(ch) + 5) % 10)) : ch;\n el.appendChild(span);\n const a = ctx.animate(span, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(90deg)', offset: 0.5 }, { transform: 'rotateX(0)' }], { duration: o.duration, delay: i * o.stagger, easing: 'ease-in-out' });\n setTimeout(() => (span.textContent = ch), i * o.stagger + o.duration / 2);\n return a;\n });\n return Promise.all(anims.map((a) => a?.finished.catch(() => undefined))).then(() => {\n el.textContent = to;\n el.removeAttribute('aria-label');\n });\n },\n },\n {\n name: 'stock-pulse',\n kind: 'loop',\n description: 'A soft urgency pulse — a glow ring in `color` — for low stock / last items (`color`, `period`).',\n defaults: { color: 'rgba(239,68,68,.55)', period: 1400 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const a = ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}` }, { boxShadow: '0 0 0 12px rgba(0,0,0,0)' }], { duration: o.period, iterations: Infinity, easing: 'ease-out' });\n const stop = () => a?.cancel();\n ctx.onCleanup(stop);\n return stop;\n },\n },\n {\n name: 'sale-shine',\n kind: 'hover',\n description: 'A diagonal light sweep across the element (product cards, buy buttons) (`duration`).',\n defaults: { duration: 700 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const s = document.createElement('span');\n s.setAttribute('aria-hidden', 'true');\n Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', background: 'linear-gradient(115deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', borderRadius: 'inherit' });\n if (getComputedStyle(el).position === 'static') el.style.position = 'relative';\n const prev = el.style.overflow;\n el.style.overflow = 'hidden';\n el.appendChild(s);\n const a = ctx.animate(s, [{ transform: 'translateX(-100%)' }, { transform: 'translateX(100%)' }], { duration: o.duration, easing: 'ease-in-out' });\n const end = () => (s.remove(), (el.style.overflow = prev));\n if (a) a.finished.then(end, end);\n else end();\n return a?.finished.catch(() => undefined);\n },\n },\n {\n name: 'badge-pop',\n kind: 'attention',\n description: 'A sale badge pops in with a wobble (`duration`).',\n defaults: { duration: 650 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) =>\n ctx.reduced\n ? ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })\n : ctx.animate(el, [{ transform: 'scale(0) rotate(-20deg)' }, { transform: 'scale(1.2) rotate(8deg)', offset: 0.5 }, { transform: 'scale(.95) rotate(-4deg)', offset: 0.75 }, { transform: 'none' }], { duration: o.duration, easing: 'ease-out' }),\n },\n];\n\n/** Register the 7.3 e-commerce pack (idempotent). */\nexport function registerShopPack(): void {\n registerEffects(SHOP_FX);\n}\n"],"names":[],"mappings":"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"}
@@ -2,9 +2,10 @@
2
2
 
3
3
  var base = require('../chunks/base-BaQV-2ha.cjs');
4
4
  var registry = require('../chunks/registry-DehBVRDV.cjs');
5
- var core = require('../chunks/core-BGAyaY6L.cjs');
6
- var fx = require('../chunks/fx-lBGVtQO1.cjs');
5
+ var builtins = require('../chunks/builtins-xalxV2d5.cjs');
6
+ require('../chunks/core-BGAyaY6L.cjs');
7
7
  require('./tokens.cjs');
8
+ require('../chunks/fx-lBGVtQO1.cjs');
8
9
 
9
10
  function defineFx(tag = 'usa-fx') {
10
11
  return base.defineElement(tag, (Base) => class UsaFx extends Base {
@@ -41,100 +42,6 @@ function defineFx(tag = 'usa-fx') {
41
42
  });
42
43
  }
43
44
 
44
- /**
45
- * 5.0 built-in effects, all registered through `registerEffect()`:
46
- * every timeline preset as an `enter` effect, attention seekers, and the
47
- * click effects (burst, confetti, shake, ripple).
48
- */
49
- const enter = Object.entries(core.TIMELINE_PRESETS).map(([name, frames]) => ({
50
- name,
51
- kind: 'enter',
52
- description: `Entrance: ${name} (same keyframes as the timeline preset).`,
53
- defaults: { duration: 600, delay: 0, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' },
54
- run: (el, o, ctx) => ctx.animate(el, ctx.reduced ? [{ opacity: 0 }, { opacity: 1 }] : frames, { duration: o.duration, delay: o.delay, easing: o.easing, fill: 'backwards' }),
55
- }));
56
- const A = (name, description, frames, duration = 700, easing = 'ease-in-out') => ({
57
- name,
58
- kind: 'attention',
59
- description,
60
- defaults: { duration, iterations: 1 },
61
- run: (el, o, ctx) => (ctx.reduced ? ctx.animate(el, [{ opacity: 1 }, { opacity: 0.6 }, { opacity: 1 }], { duration: 400 }) : ctx.animate(el, frames, { duration: o.duration, easing, iterations: o.iterations })),
62
- });
63
- const attention = [
64
- A('pulse', 'Gentle scale pulse.', [{ transform: 'scale(1)' }, { transform: 'scale(1.08)' }, { transform: 'scale(1)' }], 600),
65
- A('pop', 'Quick overshoot pop.', [{ transform: 'scale(1)' }, { transform: 'scale(1.18)', offset: 0.4 }, { transform: 'scale(0.96)', offset: 0.7 }, { transform: 'scale(1)' }], 450, 'cubic-bezier(0.34, 1.56, 0.64, 1)'),
66
- A('jelly', 'Rubbery squash-and-stretch.', [{ transform: 'scale(1,1)' }, { transform: 'scale(1.25,0.75)', offset: 0.3 }, { transform: 'scale(0.75,1.25)', offset: 0.4 }, { transform: 'scale(1.15,0.85)', offset: 0.5 }, { transform: 'scale(0.95,1.05)', offset: 0.65 }, { transform: 'scale(1.05,0.95)', offset: 0.75 }, { transform: 'scale(1,1)' }], 900),
67
- A('wiggle', 'Playful rotate wiggle.', [{ transform: 'rotate(0)' }, { transform: 'rotate(-8deg)', offset: 0.2 }, { transform: 'rotate(7deg)', offset: 0.4 }, { transform: 'rotate(-5deg)', offset: 0.6 }, { transform: 'rotate(3deg)', offset: 0.8 }, { transform: 'rotate(0)' }], 650),
68
- A('heartbeat', 'Double-beat heart pulse.', [{ transform: 'scale(1)' }, { transform: 'scale(1.2)', offset: 0.14 }, { transform: 'scale(1)', offset: 0.28 }, { transform: 'scale(1.2)', offset: 0.42 }, { transform: 'scale(1)', offset: 0.7 }], 1100),
69
- A('bounce', 'Hop up and settle with a squash.', [{ transform: 'translateY(0) scale(1,1)' }, { transform: 'translateY(-22px) scale(0.95,1.05)', offset: 0.35 }, { transform: 'translateY(0) scale(1.08,0.92)', offset: 0.6 }, { transform: 'translateY(-6px) scale(1,1)', offset: 0.8 }, { transform: 'translateY(0) scale(1,1)' }], 800),
70
- A('flash', 'Two soft flashes (well under 3 per second).', [{ opacity: 1 }, { opacity: 0.25, offset: 0.25 }, { opacity: 1, offset: 0.5 }, { opacity: 0.25, offset: 0.75 }, { opacity: 1 }], 1400),
71
- A('tada', 'Scale + shake celebration.', [{ transform: 'scale(1) rotate(0)' }, { transform: 'scale(0.9) rotate(-3deg)', offset: 0.1 }, { transform: 'scale(1.1) rotate(3deg)', offset: 0.3 }, { transform: 'scale(1.1) rotate(-3deg)', offset: 0.5 }, { transform: 'scale(1.1) rotate(3deg)', offset: 0.7 }, { transform: 'scale(1) rotate(0)' }], 1000),
72
- ];
73
- const click = [
74
- {
75
- name: 'burst',
76
- kind: 'click',
77
- description: 'Particle burst from the click point (or `x` / `y`, or the element center).',
78
- defaults: { count: 12 },
79
- run: (el, o, ctx) => {
80
- if (ctx.reduced)
81
- return;
82
- const r = el.getBoundingClientRect();
83
- const e = ctx.event;
84
- fx.burst(o.x ?? e?.clientX ?? r.left + r.width / 2, o.y ?? e?.clientY ?? r.top + r.height / 2, o);
85
- },
86
- },
87
- {
88
- name: 'confetti',
89
- kind: 'click',
90
- description: 'Confetti cannon from the element.',
91
- defaults: { count: 80 },
92
- run: (el, o, ctx) => {
93
- if (ctx.reduced)
94
- return;
95
- const r = el.getBoundingClientRect();
96
- fx.confetti({ x: r.left + r.width / 2, y: r.top + r.height / 2, ...o });
97
- },
98
- },
99
- {
100
- name: 'shake',
101
- kind: 'attention',
102
- description: 'Horizontal "no" shake (errors, wrong password).',
103
- defaults: { intensity: 8, duration: 480 },
104
- run: (el, o, ctx) => (ctx.reduced ? ctx.animate(el, [{ opacity: 1 }, { opacity: 0.5 }, { opacity: 1 }], { duration: 300 }) : fx.shake(el, o.intensity, o.duration)),
105
- },
106
- {
107
- name: 'ripple',
108
- kind: 'click',
109
- description: 'Material-style ink ripple from the pointer.',
110
- defaults: { color: 'currentColor', duration: 600 },
111
- run: (el, o, ctx) => {
112
- var _a;
113
- if (ctx.reduced)
114
- return;
115
- const r = el.getBoundingClientRect();
116
- const e = ctx.event;
117
- const d = Math.hypot(r.width, r.height) * 2;
118
- const dot = document.createElement('span');
119
- dot.setAttribute('aria-hidden', 'true');
120
- Object.assign(dot.style, { position: 'absolute', left: `${(e?.clientX ?? r.left + r.width / 2) - r.left - d / 2}px`, top: `${(e?.clientY ?? r.top + r.height / 2) - r.top - d / 2}px`, width: `${d}px`, height: `${d}px`, borderRadius: '50%', background: o.color, opacity: '0.25', pointerEvents: 'none' });
121
- if (getComputedStyle(el).position === 'static')
122
- el.style.position = 'relative';
123
- (_a = el.style).overflow || (_a.overflow = 'hidden');
124
- el.appendChild(dot);
125
- const a = ctx.animate(dot, [{ transform: 'scale(0)', opacity: 0.3 }, { transform: 'scale(1)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' });
126
- const done = () => dot.remove();
127
- if (a)
128
- a.finished.then(done, done);
129
- else
130
- done();
131
- return a;
132
- },
133
- },
134
- ];
135
- /** Every built-in 5.0 effect definition. */
136
- const BUILTIN_EFFECTS = [...enter, ...attention, ...click];
137
-
138
45
  /**
139
46
  * motionary/components/fx — unified plugin-style effects (5.0).
140
47
  * `registerEffect({ name, kind, run })`, `playEffect(el, name)`,
@@ -145,7 +52,7 @@ const BUILTIN_EFFECTS = [...enter, ...attention, ...click];
145
52
  */
146
53
  /** Register the built-in effects (idempotent; `defineFxComponents()` calls it). */
147
54
  function registerBuiltinEffects() {
148
- registry.registerEffects(BUILTIN_EFFECTS);
55
+ registry.registerEffects(builtins.BUILTIN_EFFECTS);
149
56
  }
150
57
  /** Register every component of this category under its default tag (+ the built-in effects). */
151
58
  function defineFxComponents() {
@@ -162,7 +69,7 @@ exports.listEffects = registry.listEffects;
162
69
  exports.playEffect = registry.playEffect;
163
70
  exports.registerEffect = registry.registerEffect;
164
71
  exports.registerEffects = registry.registerEffects;
165
- exports.BUILTIN_EFFECTS = BUILTIN_EFFECTS;
72
+ exports.BUILTIN_EFFECTS = builtins.BUILTIN_EFFECTS;
166
73
  exports.defineFx = defineFx;
167
74
  exports.defineFxComponents = defineFxComponents;
168
75
  exports.registerBuiltinEffects = registerBuiltinEffects;