@enact-ui/animate 0.1.0 → 0.2.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/api-schema.json +206 -0
- package/dist/components/CountUp.d.ts +84 -0
- package/dist/components/CountUp.d.ts.map +1 -0
- package/dist/components/CountUp.js +68 -0
- package/dist/components/CountUp.js.map +1 -0
- package/dist/components/MotionDiv.d.ts +159 -0
- package/dist/components/MotionDiv.d.ts.map +1 -0
- package/dist/components/MotionDiv.js +162 -0
- package/dist/components/MotionDiv.js.map +1 -0
- package/dist/components/StaggerContainer.d.ts +136 -0
- package/dist/components/StaggerContainer.d.ts.map +1 -0
- package/dist/components/StaggerContainer.js +166 -0
- package/dist/components/StaggerContainer.js.map +1 -0
- package/dist/hooks/use-component-animation.d.ts +156 -0
- package/dist/hooks/use-component-animation.d.ts.map +1 -0
- package/dist/hooks/use-component-animation.js +231 -0
- package/dist/hooks/use-component-animation.js.map +1 -0
- package/dist/hooks/use-count-up.d.ts +111 -0
- package/dist/hooks/use-count-up.d.ts.map +1 -0
- package/dist/hooks/use-count-up.js +246 -0
- package/dist/hooks/use-count-up.js.map +1 -0
- package/dist/hooks/use-draw-path.d.ts +96 -0
- package/dist/hooks/use-draw-path.d.ts.map +1 -0
- package/dist/hooks/use-draw-path.js +227 -0
- package/dist/hooks/use-draw-path.js.map +1 -0
- package/dist/hooks/use-motion-preset.d.ts.map +1 -1
- package/dist/hooks/use-motion-preset.js +17 -16
- package/dist/hooks/use-motion-preset.js.map +1 -1
- package/dist/hooks/use-stagger.d.ts +174 -0
- package/dist/hooks/use-stagger.d.ts.map +1 -0
- package/dist/hooks/use-stagger.js +256 -0
- package/dist/hooks/use-stagger.js.map +1 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2442 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2335 -25
- package/dist/index.mjs.map +1 -1
- package/dist/presets/component-presets.d.ts +246 -0
- package/dist/presets/component-presets.d.ts.map +1 -0
- package/dist/presets/component-presets.js +472 -0
- package/dist/presets/component-presets.js.map +1 -0
- package/dist/presets/micro-interactions.d.ts +451 -0
- package/dist/presets/micro-interactions.d.ts.map +1 -0
- package/dist/presets/micro-interactions.js +856 -0
- package/dist/presets/micro-interactions.js.map +1 -0
- package/dist/presets/motion-presets.d.ts.map +1 -1
- package/dist/presets/motion-presets.js +0 -1
- package/dist/presets/motion-presets.js.map +1 -1
- package/dist/presets/motion-styles.d.ts +186 -0
- package/dist/presets/motion-styles.d.ts.map +1 -0
- package/dist/presets/motion-styles.js +204 -0
- package/dist/presets/motion-styles.js.map +1 -0
- package/dist/presets/stagger-presets.d.ts +378 -0
- package/dist/presets/stagger-presets.d.ts.map +1 -0
- package/dist/presets/stagger-presets.js +582 -0
- package/dist/presets/stagger-presets.js.map +1 -0
- package/dist/showcase/motion-presets.demo.d.ts +25 -0
- package/dist/showcase/motion-presets.demo.d.ts.map +1 -0
- package/dist/showcase/motion-presets.demo.js +96 -0
- package/dist/showcase/motion-presets.demo.js.map +1 -0
- package/dist/showcase/motion-presets.story.d.ts +37 -0
- package/dist/showcase/motion-presets.story.d.ts.map +1 -0
- package/dist/showcase/motion-presets.story.js +151 -0
- package/dist/showcase/motion-presets.story.js.map +1 -0
- package/dist/utils/easing.d.ts +294 -0
- package/dist/utils/easing.d.ts.map +1 -0
- package/dist/utils/easing.js +265 -0
- package/dist/utils/easing.js.map +1 -0
- package/dist/utils/reduced-motion.d.ts +322 -0
- package/dist/utils/reduced-motion.d.ts.map +1 -0
- package/dist/utils/reduced-motion.js +362 -0
- package/dist/utils/reduced-motion.js.map +1 -0
- package/dist/utils/select-preset.d.ts +186 -0
- package/dist/utils/select-preset.d.ts.map +1 -0
- package/dist/utils/select-preset.js +320 -0
- package/dist/utils/select-preset.js.map +1 -0
- package/dist/utils/spring-configs.d.ts +187 -0
- package/dist/utils/spring-configs.d.ts.map +1 -0
- package/dist/utils/spring-configs.js +169 -0
- package/dist/utils/spring-configs.js.map +1 -0
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,819 @@
|
|
|
1
|
+
// src/hooks/use-count-up.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/presets/motion-styles.ts
|
|
5
|
+
var subtleStyle = {
|
|
6
|
+
name: "Subtle",
|
|
7
|
+
description: "Gentle, minimal animations ideal for professional UIs",
|
|
8
|
+
duration: {
|
|
9
|
+
fast: 150,
|
|
10
|
+
normal: 200,
|
|
11
|
+
slow: 300
|
|
12
|
+
},
|
|
13
|
+
spring: {
|
|
14
|
+
stiffness: 400,
|
|
15
|
+
damping: 35,
|
|
16
|
+
mass: 0.8
|
|
17
|
+
},
|
|
18
|
+
easing: {
|
|
19
|
+
enter: "easeOut",
|
|
20
|
+
exit: "easeIn",
|
|
21
|
+
interactive: "easeInOut"
|
|
22
|
+
},
|
|
23
|
+
staggerDelay: 30
|
|
24
|
+
};
|
|
25
|
+
var standardStyle = {
|
|
26
|
+
name: "Standard",
|
|
27
|
+
description: "Balanced, professional animations for general use",
|
|
28
|
+
duration: {
|
|
29
|
+
fast: 200,
|
|
30
|
+
normal: 300,
|
|
31
|
+
slow: 400
|
|
32
|
+
},
|
|
33
|
+
spring: {
|
|
34
|
+
stiffness: 300,
|
|
35
|
+
damping: 28,
|
|
36
|
+
mass: 1
|
|
37
|
+
},
|
|
38
|
+
easing: {
|
|
39
|
+
enter: "easeOut",
|
|
40
|
+
exit: "easeIn",
|
|
41
|
+
interactive: "easeInOut"
|
|
42
|
+
},
|
|
43
|
+
staggerDelay: 50
|
|
44
|
+
};
|
|
45
|
+
var boldStyle = {
|
|
46
|
+
name: "Bold",
|
|
47
|
+
description: "Dramatic, attention-grabbing animations for emphasis",
|
|
48
|
+
duration: {
|
|
49
|
+
fast: 250,
|
|
50
|
+
normal: 400,
|
|
51
|
+
slow: 600
|
|
52
|
+
},
|
|
53
|
+
spring: {
|
|
54
|
+
stiffness: 250,
|
|
55
|
+
damping: 22,
|
|
56
|
+
mass: 1.2
|
|
57
|
+
},
|
|
58
|
+
easing: {
|
|
59
|
+
enter: "easeOut",
|
|
60
|
+
exit: "easeIn",
|
|
61
|
+
interactive: "easeInOut"
|
|
62
|
+
},
|
|
63
|
+
staggerDelay: 80
|
|
64
|
+
};
|
|
65
|
+
var playfulStyle = {
|
|
66
|
+
name: "Playful",
|
|
67
|
+
description: "Bouncy, fun animations with elastic spring physics",
|
|
68
|
+
duration: {
|
|
69
|
+
fast: 200,
|
|
70
|
+
normal: 350,
|
|
71
|
+
slow: 500
|
|
72
|
+
},
|
|
73
|
+
spring: {
|
|
74
|
+
stiffness: 200,
|
|
75
|
+
damping: 15,
|
|
76
|
+
mass: 1
|
|
77
|
+
},
|
|
78
|
+
easing: {
|
|
79
|
+
enter: "easeOut",
|
|
80
|
+
exit: "easeIn",
|
|
81
|
+
interactive: "easeInOut"
|
|
82
|
+
},
|
|
83
|
+
staggerDelay: 60
|
|
84
|
+
};
|
|
85
|
+
var motionStyles = {
|
|
86
|
+
subtle: subtleStyle,
|
|
87
|
+
standard: standardStyle,
|
|
88
|
+
bold: boldStyle,
|
|
89
|
+
playful: playfulStyle
|
|
90
|
+
};
|
|
91
|
+
function getMotionStyle(style) {
|
|
92
|
+
return motionStyles[style];
|
|
93
|
+
}
|
|
94
|
+
function getSpringConfig(style) {
|
|
95
|
+
return motionStyles[style].spring;
|
|
96
|
+
}
|
|
97
|
+
function getDuration(style, speed) {
|
|
98
|
+
return motionStyles[style].duration[speed];
|
|
99
|
+
}
|
|
100
|
+
function msToSeconds(ms) {
|
|
101
|
+
return ms / 1e3;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/hooks/use-count-up.ts
|
|
105
|
+
var easingFunctions = {
|
|
106
|
+
linear: (t) => t,
|
|
107
|
+
easeOut: (t) => 1 - (1 - t) ** 3,
|
|
108
|
+
easeOutExpo: (t) => t === 1 ? 1 : 1 - 2 ** (-10 * t),
|
|
109
|
+
easeInOut: (t) => t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2,
|
|
110
|
+
spring: (t) => {
|
|
111
|
+
const c4 = 2 * Math.PI / 3;
|
|
112
|
+
return t === 0 ? 0 : t === 1 ? 1 : 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
function useReducedMotion() {
|
|
116
|
+
const [prefersReducedMotion2, setPrefersReducedMotion] = useState(() => {
|
|
117
|
+
if (typeof window === "undefined") return false;
|
|
118
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
119
|
+
});
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
122
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
123
|
+
const handler = (e) => {
|
|
124
|
+
setPrefersReducedMotion(e.matches);
|
|
125
|
+
};
|
|
126
|
+
mediaQuery.addEventListener("change", handler);
|
|
127
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
128
|
+
}, []);
|
|
129
|
+
return prefersReducedMotion2;
|
|
130
|
+
}
|
|
131
|
+
function createDefaultFormatter(decimals, useLocale, locale) {
|
|
132
|
+
return (value) => {
|
|
133
|
+
if (useLocale) {
|
|
134
|
+
return value.toLocaleString(locale, {
|
|
135
|
+
minimumFractionDigits: decimals,
|
|
136
|
+
maximumFractionDigits: decimals
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return value.toFixed(decimals);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function useCountUp(options) {
|
|
143
|
+
const {
|
|
144
|
+
from = 0,
|
|
145
|
+
to,
|
|
146
|
+
duration: customDuration,
|
|
147
|
+
motionStyle = "standard",
|
|
148
|
+
easing = "easeOutExpo",
|
|
149
|
+
decimals = 0,
|
|
150
|
+
useLocale = true,
|
|
151
|
+
locale,
|
|
152
|
+
formatter: customFormatter,
|
|
153
|
+
delay = 0,
|
|
154
|
+
autoStart = true,
|
|
155
|
+
onComplete,
|
|
156
|
+
onUpdate,
|
|
157
|
+
prefix = "",
|
|
158
|
+
suffix = "",
|
|
159
|
+
enabled = true
|
|
160
|
+
} = options;
|
|
161
|
+
const duration = customDuration ?? getDuration(motionStyle, "slow");
|
|
162
|
+
const [value, setValue] = useState(from);
|
|
163
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
164
|
+
const [isComplete, setIsComplete] = useState(false);
|
|
165
|
+
const animationRef = useRef(null);
|
|
166
|
+
const startTimeRef = useRef(null);
|
|
167
|
+
const pausedTimeRef = useRef(null);
|
|
168
|
+
const currentFromRef = useRef(from);
|
|
169
|
+
const currentToRef = useRef(to);
|
|
170
|
+
const prefersReducedMotion2 = useReducedMotion();
|
|
171
|
+
const formatter = customFormatter ?? createDefaultFormatter(decimals, useLocale, locale);
|
|
172
|
+
const displayValue = `${prefix}${formatter(value)}${suffix}`;
|
|
173
|
+
const cancelAnimation = useCallback(() => {
|
|
174
|
+
if (animationRef.current !== null) {
|
|
175
|
+
cancelAnimationFrame(animationRef.current);
|
|
176
|
+
animationRef.current = null;
|
|
177
|
+
}
|
|
178
|
+
}, []);
|
|
179
|
+
const animate = useCallback(
|
|
180
|
+
(timestamp) => {
|
|
181
|
+
if (startTimeRef.current === null) {
|
|
182
|
+
startTimeRef.current = timestamp;
|
|
183
|
+
}
|
|
184
|
+
const elapsed = timestamp - startTimeRef.current;
|
|
185
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
186
|
+
const easedProgress = easingFunctions[easing](progress);
|
|
187
|
+
const currentValue = currentFromRef.current + (currentToRef.current - currentFromRef.current) * easedProgress;
|
|
188
|
+
setValue(currentValue);
|
|
189
|
+
onUpdate?.(currentValue);
|
|
190
|
+
if (progress < 1) {
|
|
191
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
192
|
+
} else {
|
|
193
|
+
setIsAnimating(false);
|
|
194
|
+
setIsComplete(true);
|
|
195
|
+
onComplete?.();
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
[duration, easing, onComplete, onUpdate]
|
|
199
|
+
);
|
|
200
|
+
const start = useCallback(() => {
|
|
201
|
+
if (!enabled) {
|
|
202
|
+
setValue(currentToRef.current);
|
|
203
|
+
setIsComplete(true);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (prefersReducedMotion2) {
|
|
207
|
+
setValue(currentToRef.current);
|
|
208
|
+
setIsComplete(true);
|
|
209
|
+
onComplete?.();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
cancelAnimation();
|
|
213
|
+
setIsComplete(false);
|
|
214
|
+
startTimeRef.current = null;
|
|
215
|
+
pausedTimeRef.current = null;
|
|
216
|
+
const startAnimation = () => {
|
|
217
|
+
setIsAnimating(true);
|
|
218
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
219
|
+
};
|
|
220
|
+
if (delay > 0) {
|
|
221
|
+
setTimeout(startAnimation, delay);
|
|
222
|
+
} else {
|
|
223
|
+
startAnimation();
|
|
224
|
+
}
|
|
225
|
+
}, [enabled, prefersReducedMotion2, cancelAnimation, animate, delay, onComplete]);
|
|
226
|
+
const pause = useCallback(() => {
|
|
227
|
+
if (isAnimating && animationRef.current !== null) {
|
|
228
|
+
pausedTimeRef.current = performance.now();
|
|
229
|
+
cancelAnimation();
|
|
230
|
+
setIsAnimating(false);
|
|
231
|
+
}
|
|
232
|
+
}, [isAnimating, cancelAnimation]);
|
|
233
|
+
const resume = useCallback(() => {
|
|
234
|
+
if (!isAnimating && !isComplete && pausedTimeRef.current !== null && startTimeRef.current !== null) {
|
|
235
|
+
const pausedDuration = performance.now() - pausedTimeRef.current;
|
|
236
|
+
startTimeRef.current += pausedDuration;
|
|
237
|
+
pausedTimeRef.current = null;
|
|
238
|
+
setIsAnimating(true);
|
|
239
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
240
|
+
}
|
|
241
|
+
}, [isAnimating, isComplete, animate]);
|
|
242
|
+
const reset = useCallback(() => {
|
|
243
|
+
cancelAnimation();
|
|
244
|
+
setValue(currentFromRef.current);
|
|
245
|
+
setIsAnimating(false);
|
|
246
|
+
setIsComplete(false);
|
|
247
|
+
startTimeRef.current = null;
|
|
248
|
+
pausedTimeRef.current = null;
|
|
249
|
+
}, [cancelAnimation]);
|
|
250
|
+
const update = useCallback(
|
|
251
|
+
(newTo) => {
|
|
252
|
+
currentFromRef.current = value;
|
|
253
|
+
currentToRef.current = newTo;
|
|
254
|
+
start();
|
|
255
|
+
},
|
|
256
|
+
[value, start]
|
|
257
|
+
);
|
|
258
|
+
useEffect(() => {
|
|
259
|
+
if (autoStart) {
|
|
260
|
+
currentFromRef.current = from;
|
|
261
|
+
currentToRef.current = to;
|
|
262
|
+
start();
|
|
263
|
+
}
|
|
264
|
+
return () => {
|
|
265
|
+
cancelAnimation();
|
|
266
|
+
};
|
|
267
|
+
}, []);
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (to !== currentToRef.current && isComplete) {
|
|
270
|
+
update(to);
|
|
271
|
+
}
|
|
272
|
+
}, [to, isComplete, update]);
|
|
273
|
+
return {
|
|
274
|
+
value,
|
|
275
|
+
displayValue,
|
|
276
|
+
isAnimating,
|
|
277
|
+
isComplete,
|
|
278
|
+
start,
|
|
279
|
+
pause,
|
|
280
|
+
resume,
|
|
281
|
+
reset,
|
|
282
|
+
update,
|
|
283
|
+
prefersReducedMotion: prefersReducedMotion2
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/components/CountUp.tsx
|
|
288
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
289
|
+
var CountUp = ({
|
|
290
|
+
to,
|
|
291
|
+
from = 0,
|
|
292
|
+
duration,
|
|
293
|
+
motionStyle = "standard",
|
|
294
|
+
easing = "easeOutExpo",
|
|
295
|
+
decimals = 0,
|
|
296
|
+
useLocale = true,
|
|
297
|
+
locale,
|
|
298
|
+
formatter,
|
|
299
|
+
delay = 0,
|
|
300
|
+
autoStart = true,
|
|
301
|
+
onComplete,
|
|
302
|
+
onUpdate,
|
|
303
|
+
prefix = "",
|
|
304
|
+
suffix = "",
|
|
305
|
+
enabled = true,
|
|
306
|
+
children,
|
|
307
|
+
...spanProps
|
|
308
|
+
}) => {
|
|
309
|
+
const hookOptions = {
|
|
310
|
+
from,
|
|
311
|
+
to,
|
|
312
|
+
motionStyle,
|
|
313
|
+
easing,
|
|
314
|
+
decimals,
|
|
315
|
+
useLocale,
|
|
316
|
+
delay,
|
|
317
|
+
autoStart,
|
|
318
|
+
prefix,
|
|
319
|
+
suffix,
|
|
320
|
+
enabled,
|
|
321
|
+
// Only include optional props if they are defined
|
|
322
|
+
...duration !== void 0 && { duration },
|
|
323
|
+
...locale !== void 0 && { locale },
|
|
324
|
+
...formatter !== void 0 && { formatter },
|
|
325
|
+
...onComplete !== void 0 && { onComplete },
|
|
326
|
+
...onUpdate !== void 0 && { onUpdate }
|
|
327
|
+
};
|
|
328
|
+
const { value, displayValue, isAnimating } = useCountUp(hookOptions);
|
|
329
|
+
if (typeof children === "function") {
|
|
330
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children({ value, displayValue, isAnimating }) });
|
|
331
|
+
}
|
|
332
|
+
return /* @__PURE__ */ jsx("span", { ...spanProps, children: displayValue });
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/components/MotionDiv.tsx
|
|
336
|
+
import { motion } from "motion/react";
|
|
337
|
+
|
|
338
|
+
// src/hooks/use-component-animation.ts
|
|
339
|
+
import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
340
|
+
function useReducedMotion2() {
|
|
341
|
+
const [prefersReducedMotion2, setPrefersReducedMotion] = useState2(() => {
|
|
342
|
+
if (typeof window === "undefined") return false;
|
|
343
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
344
|
+
});
|
|
345
|
+
useEffect2(() => {
|
|
346
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
347
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
348
|
+
const handler = (e) => {
|
|
349
|
+
setPrefersReducedMotion(e.matches);
|
|
350
|
+
};
|
|
351
|
+
mediaQuery.addEventListener("change", handler);
|
|
352
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
353
|
+
}, []);
|
|
354
|
+
return prefersReducedMotion2;
|
|
355
|
+
}
|
|
356
|
+
function createDisabledProps(skipInitial) {
|
|
357
|
+
return {
|
|
358
|
+
initial: skipInitial ? false : { opacity: 1 },
|
|
359
|
+
animate: { opacity: 1 },
|
|
360
|
+
exit: { opacity: 1 },
|
|
361
|
+
transition: { type: "tween", duration: 0 }
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function useComponentAnimation(preset, style = "standard", options = {}) {
|
|
365
|
+
const { enabled = true, skipInitial = false, ...presetOptions } = options;
|
|
366
|
+
const prefersReducedMotion2 = useReducedMotion2();
|
|
367
|
+
const memoizedPresetOptions = useMemo(() => presetOptions, [JSON.stringify(presetOptions)]);
|
|
368
|
+
const animationProps = useMemo(() => {
|
|
369
|
+
if (!enabled) {
|
|
370
|
+
return createDisabledProps(skipInitial);
|
|
371
|
+
}
|
|
372
|
+
const props = preset.getProps(style, memoizedPresetOptions);
|
|
373
|
+
if (skipInitial) {
|
|
374
|
+
return {
|
|
375
|
+
...props,
|
|
376
|
+
initial: false
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return props;
|
|
380
|
+
}, [preset, style, memoizedPresetOptions, enabled, skipInitial]);
|
|
381
|
+
return {
|
|
382
|
+
...animationProps,
|
|
383
|
+
prefersReducedMotion: prefersReducedMotion2,
|
|
384
|
+
isEnabled: enabled
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function useDelayedAnimation(preset, style = "standard", index, options = {}) {
|
|
388
|
+
const { delayMultiplier = 50, maxDelay = 500, ...restOptions } = options;
|
|
389
|
+
const calculatedDelay = Math.min(index * delayMultiplier, maxDelay);
|
|
390
|
+
return useComponentAnimation(preset, style, {
|
|
391
|
+
...restOptions,
|
|
392
|
+
delay: (restOptions.delay ?? 0) + calculatedDelay
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
function useAnimationVariants(preset, style = "standard", options = {}) {
|
|
396
|
+
const { enabled = true, ...presetOptions } = options;
|
|
397
|
+
const memoizedPresetOptions = useMemo(() => presetOptions, [JSON.stringify(presetOptions)]);
|
|
398
|
+
return useMemo(() => {
|
|
399
|
+
if (!enabled) {
|
|
400
|
+
return {
|
|
401
|
+
variants: {
|
|
402
|
+
initial: { opacity: 0 },
|
|
403
|
+
animate: { opacity: 1 },
|
|
404
|
+
exit: { opacity: 0 }
|
|
405
|
+
},
|
|
406
|
+
transition: { type: "tween", duration: 0.15 }
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
const props = preset.getProps(style, memoizedPresetOptions);
|
|
410
|
+
return {
|
|
411
|
+
variants: {
|
|
412
|
+
initial: props.initial,
|
|
413
|
+
animate: props.animate,
|
|
414
|
+
exit: props.exit ?? props.initial
|
|
415
|
+
},
|
|
416
|
+
transition: props.transition
|
|
417
|
+
};
|
|
418
|
+
}, [preset, style, memoizedPresetOptions, enabled]);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/components/MotionDiv.tsx
|
|
422
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
423
|
+
function MotionDiv({
|
|
424
|
+
preset,
|
|
425
|
+
exit: exitPreset,
|
|
426
|
+
as = "div",
|
|
427
|
+
motionStyle = "standard",
|
|
428
|
+
presetOptions,
|
|
429
|
+
enabled = true,
|
|
430
|
+
skipInitial = false,
|
|
431
|
+
children,
|
|
432
|
+
...motionProps
|
|
433
|
+
}) {
|
|
434
|
+
const animation = useComponentAnimation(preset, motionStyle, {
|
|
435
|
+
...presetOptions,
|
|
436
|
+
enabled,
|
|
437
|
+
skipInitial
|
|
438
|
+
});
|
|
439
|
+
const exitAnimation = exitPreset && typeof exitPreset === "object" && "getProps" in exitPreset && typeof exitPreset.getProps === "function" ? exitPreset.getProps(motionStyle, presetOptions) : null;
|
|
440
|
+
const { prefersReducedMotion: prefersReducedMotion2, isEnabled, ...animationProps } = animation;
|
|
441
|
+
const exitValue = exitAnimation ? exitAnimation.initial : void 0;
|
|
442
|
+
const MotionComponent = motion[as];
|
|
443
|
+
const finalProps = {
|
|
444
|
+
...motionProps,
|
|
445
|
+
...animationProps,
|
|
446
|
+
...exitValue !== void 0 && { exit: exitValue },
|
|
447
|
+
"data-reduced-motion": prefersReducedMotion2,
|
|
448
|
+
"data-animation-enabled": isEnabled
|
|
449
|
+
};
|
|
450
|
+
return /* @__PURE__ */ jsx2(MotionComponent, { ...finalProps, children });
|
|
451
|
+
}
|
|
452
|
+
function createMotionProps(preset, style = "standard", options) {
|
|
453
|
+
return preset.getProps(style, options);
|
|
454
|
+
}
|
|
455
|
+
function createAccessibleMotionProps(preset, style = "standard", options) {
|
|
456
|
+
return preset.getProps(style, options);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// src/components/StaggerContainer.tsx
|
|
460
|
+
import { Children, cloneElement, isValidElement } from "react";
|
|
461
|
+
|
|
462
|
+
// src/hooks/use-stagger.ts
|
|
463
|
+
import { useMemo as useMemo2 } from "react";
|
|
464
|
+
function calculateDelay(index, total, direction, baseDelay) {
|
|
465
|
+
switch (direction) {
|
|
466
|
+
case "forward":
|
|
467
|
+
return index * baseDelay;
|
|
468
|
+
case "reverse":
|
|
469
|
+
return (total - 1 - index) * baseDelay;
|
|
470
|
+
case "center": {
|
|
471
|
+
const center = (total - 1) / 2;
|
|
472
|
+
const distanceFromCenter = Math.abs(index - center);
|
|
473
|
+
return distanceFromCenter * baseDelay;
|
|
474
|
+
}
|
|
475
|
+
case "edges": {
|
|
476
|
+
const center = (total - 1) / 2;
|
|
477
|
+
const distanceFromCenter = Math.abs(index - center);
|
|
478
|
+
const maxDistance = center;
|
|
479
|
+
return (maxDistance - distanceFromCenter) * baseDelay;
|
|
480
|
+
}
|
|
481
|
+
case "random":
|
|
482
|
+
return Math.random() * total * baseDelay * 0.5;
|
|
483
|
+
default:
|
|
484
|
+
return index * baseDelay;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function useStagger(style = "standard", options = {}) {
|
|
488
|
+
const { direction = "forward", totalItems = 10, delayMultiplier, maxDelay = 1e3, useSpring = true, getDelay: customGetDelay } = options;
|
|
489
|
+
const styleConfig = getMotionStyle(style);
|
|
490
|
+
const baseDelay = delayMultiplier ?? styleConfig.staggerDelay;
|
|
491
|
+
const result = useMemo2(() => {
|
|
492
|
+
const getDelayForIndex = (index) => {
|
|
493
|
+
if (customGetDelay) {
|
|
494
|
+
return Math.min(customGetDelay(index, totalItems), maxDelay);
|
|
495
|
+
}
|
|
496
|
+
return Math.min(calculateDelay(index, totalItems, direction, baseDelay), maxDelay);
|
|
497
|
+
};
|
|
498
|
+
const containerVariants = {
|
|
499
|
+
hidden: { opacity: 0 },
|
|
500
|
+
visible: {
|
|
501
|
+
opacity: 1,
|
|
502
|
+
transition: {
|
|
503
|
+
staggerChildren: msToSeconds(baseDelay),
|
|
504
|
+
delayChildren: 0,
|
|
505
|
+
when: "beforeChildren"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
const itemTransition = useSpring ? {
|
|
510
|
+
type: "spring",
|
|
511
|
+
stiffness: styleConfig.spring.stiffness,
|
|
512
|
+
damping: styleConfig.spring.damping,
|
|
513
|
+
mass: styleConfig.spring.mass
|
|
514
|
+
} : {
|
|
515
|
+
type: "tween",
|
|
516
|
+
duration: msToSeconds(styleConfig.duration.normal),
|
|
517
|
+
ease: [0.25, 0.1, 0.25, 1]
|
|
518
|
+
};
|
|
519
|
+
const itemVariants = {
|
|
520
|
+
hidden: {
|
|
521
|
+
opacity: 0,
|
|
522
|
+
y: 20
|
|
523
|
+
},
|
|
524
|
+
visible: (custom) => ({
|
|
525
|
+
opacity: 1,
|
|
526
|
+
y: 0,
|
|
527
|
+
transition: {
|
|
528
|
+
...itemTransition,
|
|
529
|
+
delay: msToSeconds(getDelayForIndex(custom))
|
|
530
|
+
}
|
|
531
|
+
})
|
|
532
|
+
};
|
|
533
|
+
const containerProps = {
|
|
534
|
+
initial: "hidden",
|
|
535
|
+
animate: "visible",
|
|
536
|
+
exit: "hidden",
|
|
537
|
+
variants: containerVariants
|
|
538
|
+
};
|
|
539
|
+
const getItemProps = (index) => ({
|
|
540
|
+
variants: itemVariants,
|
|
541
|
+
custom: index
|
|
542
|
+
});
|
|
543
|
+
return {
|
|
544
|
+
containerVariants,
|
|
545
|
+
itemVariants,
|
|
546
|
+
containerProps,
|
|
547
|
+
getItemProps
|
|
548
|
+
};
|
|
549
|
+
}, [direction, totalItems, baseDelay, maxDelay, useSpring, customGetDelay, styleConfig]);
|
|
550
|
+
return result;
|
|
551
|
+
}
|
|
552
|
+
function gridStagger(columns, baseDelay = 50) {
|
|
553
|
+
return (index) => {
|
|
554
|
+
const row = Math.floor(index / columns);
|
|
555
|
+
const col = index % columns;
|
|
556
|
+
return (row + col) * baseDelay;
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
function waveStagger(amplitude = 100, frequency = 0.5, baseDelay = 30) {
|
|
560
|
+
return (index) => {
|
|
561
|
+
const wave = Math.sin(index * frequency) * amplitude;
|
|
562
|
+
return index * baseDelay + Math.abs(wave);
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
function cascadeStagger(baseDelay = 80, acceleration = 0.8) {
|
|
566
|
+
return (index) => {
|
|
567
|
+
const factor = acceleration ** index;
|
|
568
|
+
return baseDelay * (1 - factor) * (1 / (1 - acceleration));
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function explodeStagger(baseDelay = 20) {
|
|
572
|
+
return (index, total) => {
|
|
573
|
+
const center = (total - 1) / 2;
|
|
574
|
+
const distance = Math.abs(index - center);
|
|
575
|
+
return distance * baseDelay;
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// src/components/StaggerContainer.tsx
|
|
580
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
581
|
+
function StaggerItem({ children, index, variants }) {
|
|
582
|
+
if (!isValidElement(children)) {
|
|
583
|
+
return children;
|
|
584
|
+
}
|
|
585
|
+
const motionProps = {
|
|
586
|
+
variants,
|
|
587
|
+
custom: index,
|
|
588
|
+
initial: "hidden",
|
|
589
|
+
animate: "visible",
|
|
590
|
+
exit: "hidden"
|
|
591
|
+
};
|
|
592
|
+
return cloneElement(children, motionProps);
|
|
593
|
+
}
|
|
594
|
+
function StaggerContainer({
|
|
595
|
+
children,
|
|
596
|
+
style = "standard",
|
|
597
|
+
direction = "forward",
|
|
598
|
+
delay,
|
|
599
|
+
maxDelay = 1e3,
|
|
600
|
+
useSpring = true,
|
|
601
|
+
getDelay,
|
|
602
|
+
className,
|
|
603
|
+
as: Element = "div",
|
|
604
|
+
animate = true
|
|
605
|
+
}) {
|
|
606
|
+
const childArray = Children.toArray(children);
|
|
607
|
+
const totalItems = childArray.length;
|
|
608
|
+
const staggerOptions = {
|
|
609
|
+
direction,
|
|
610
|
+
totalItems,
|
|
611
|
+
...delay !== void 0 && { delayMultiplier: delay },
|
|
612
|
+
maxDelay,
|
|
613
|
+
useSpring,
|
|
614
|
+
...getDelay !== void 0 && { getDelay }
|
|
615
|
+
};
|
|
616
|
+
const { itemVariants } = useStagger(style, staggerOptions);
|
|
617
|
+
if (!animate) {
|
|
618
|
+
return /* @__PURE__ */ jsx3(Element, { className, children });
|
|
619
|
+
}
|
|
620
|
+
return /* @__PURE__ */ jsx3(Element, { className, children: childArray.map((child, index) => {
|
|
621
|
+
if (!isValidElement(child)) {
|
|
622
|
+
return child;
|
|
623
|
+
}
|
|
624
|
+
return /* @__PURE__ */ jsx3(StaggerItem, { index, variants: itemVariants, children: child }, child.key ?? index);
|
|
625
|
+
}) });
|
|
626
|
+
}
|
|
627
|
+
function withStagger(WrappedComponent) {
|
|
628
|
+
return function StaggerWrapper({
|
|
629
|
+
style = "standard",
|
|
630
|
+
direction = "forward",
|
|
631
|
+
delay,
|
|
632
|
+
maxDelay,
|
|
633
|
+
useSpring,
|
|
634
|
+
getDelay,
|
|
635
|
+
children,
|
|
636
|
+
...props
|
|
637
|
+
}) {
|
|
638
|
+
const staggerProps = {
|
|
639
|
+
children: /* @__PURE__ */ jsx3(WrappedComponent, { ...props, children }),
|
|
640
|
+
style,
|
|
641
|
+
direction,
|
|
642
|
+
...delay !== void 0 && { delay },
|
|
643
|
+
...maxDelay !== void 0 && { maxDelay },
|
|
644
|
+
...useSpring !== void 0 && { useSpring },
|
|
645
|
+
...getDelay !== void 0 && { getDelay }
|
|
646
|
+
};
|
|
647
|
+
return /* @__PURE__ */ jsx3(StaggerContainer, { ...staggerProps });
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/hooks/use-draw-path.ts
|
|
652
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
653
|
+
var easingFunctions2 = {
|
|
654
|
+
linear: (t) => t,
|
|
655
|
+
easeOut: (t) => 1 - (1 - t) ** 3,
|
|
656
|
+
easeOutExpo: (t) => t === 1 ? 1 : 1 - 2 ** (-10 * t),
|
|
657
|
+
easeInOut: (t) => t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2,
|
|
658
|
+
spring: (t) => {
|
|
659
|
+
const c4 = 2 * Math.PI / 3;
|
|
660
|
+
return t === 0 ? 0 : t === 1 ? 1 : 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
function useReducedMotion3() {
|
|
664
|
+
const [prefersReducedMotion2, setPrefersReducedMotion] = useState3(() => {
|
|
665
|
+
if (typeof window === "undefined") return false;
|
|
666
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
667
|
+
});
|
|
668
|
+
useEffect3(() => {
|
|
669
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
670
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
671
|
+
const handler = (e) => {
|
|
672
|
+
setPrefersReducedMotion(e.matches);
|
|
673
|
+
};
|
|
674
|
+
mediaQuery.addEventListener("change", handler);
|
|
675
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
676
|
+
}, []);
|
|
677
|
+
return prefersReducedMotion2;
|
|
678
|
+
}
|
|
679
|
+
function useDrawPath(options) {
|
|
680
|
+
const {
|
|
681
|
+
from = 0,
|
|
682
|
+
to,
|
|
683
|
+
duration: customDuration,
|
|
684
|
+
motionStyle = "standard",
|
|
685
|
+
easing = "easeOutExpo",
|
|
686
|
+
delay = 0,
|
|
687
|
+
autoStart = true,
|
|
688
|
+
onComplete,
|
|
689
|
+
onUpdate,
|
|
690
|
+
enabled = true
|
|
691
|
+
} = options;
|
|
692
|
+
const duration = customDuration ?? getDuration(motionStyle, "slow");
|
|
693
|
+
const [pathLength, setPathLength] = useState3(from);
|
|
694
|
+
const [isAnimating, setIsAnimating] = useState3(false);
|
|
695
|
+
const [isComplete, setIsComplete] = useState3(false);
|
|
696
|
+
const animationRef = useRef2(null);
|
|
697
|
+
const startTimeRef = useRef2(null);
|
|
698
|
+
const pausedTimeRef = useRef2(null);
|
|
699
|
+
const currentFromRef = useRef2(from);
|
|
700
|
+
const currentToRef = useRef2(to);
|
|
701
|
+
const prefersReducedMotion2 = useReducedMotion3();
|
|
702
|
+
const cancelAnimation = useCallback2(() => {
|
|
703
|
+
if (animationRef.current !== null) {
|
|
704
|
+
cancelAnimationFrame(animationRef.current);
|
|
705
|
+
animationRef.current = null;
|
|
706
|
+
}
|
|
707
|
+
}, []);
|
|
708
|
+
const animate = useCallback2(
|
|
709
|
+
(timestamp) => {
|
|
710
|
+
if (startTimeRef.current === null) {
|
|
711
|
+
startTimeRef.current = timestamp;
|
|
712
|
+
}
|
|
713
|
+
const elapsed = timestamp - startTimeRef.current;
|
|
714
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
715
|
+
const easedProgress = easingFunctions2[easing](progress);
|
|
716
|
+
const currentPathLength = currentFromRef.current + (currentToRef.current - currentFromRef.current) * easedProgress;
|
|
717
|
+
setPathLength(currentPathLength);
|
|
718
|
+
onUpdate?.(currentPathLength);
|
|
719
|
+
if (progress < 1) {
|
|
720
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
721
|
+
} else {
|
|
722
|
+
setIsAnimating(false);
|
|
723
|
+
setIsComplete(true);
|
|
724
|
+
onComplete?.();
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
[duration, easing, onComplete, onUpdate]
|
|
728
|
+
);
|
|
729
|
+
const start = useCallback2(() => {
|
|
730
|
+
if (!enabled) {
|
|
731
|
+
setPathLength(currentToRef.current);
|
|
732
|
+
setIsComplete(true);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (prefersReducedMotion2) {
|
|
736
|
+
setPathLength(currentToRef.current);
|
|
737
|
+
setIsComplete(true);
|
|
738
|
+
onComplete?.();
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
cancelAnimation();
|
|
742
|
+
setIsComplete(false);
|
|
743
|
+
startTimeRef.current = null;
|
|
744
|
+
pausedTimeRef.current = null;
|
|
745
|
+
const startAnimation = () => {
|
|
746
|
+
setIsAnimating(true);
|
|
747
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
748
|
+
};
|
|
749
|
+
if (delay > 0) {
|
|
750
|
+
setTimeout(startAnimation, delay);
|
|
751
|
+
} else {
|
|
752
|
+
startAnimation();
|
|
753
|
+
}
|
|
754
|
+
}, [enabled, prefersReducedMotion2, cancelAnimation, animate, delay, onComplete]);
|
|
755
|
+
const pause = useCallback2(() => {
|
|
756
|
+
if (isAnimating && animationRef.current !== null) {
|
|
757
|
+
pausedTimeRef.current = performance.now();
|
|
758
|
+
cancelAnimation();
|
|
759
|
+
setIsAnimating(false);
|
|
760
|
+
}
|
|
761
|
+
}, [isAnimating, cancelAnimation]);
|
|
762
|
+
const resume = useCallback2(() => {
|
|
763
|
+
if (!isAnimating && !isComplete && pausedTimeRef.current !== null && startTimeRef.current !== null) {
|
|
764
|
+
const pausedDuration = performance.now() - pausedTimeRef.current;
|
|
765
|
+
startTimeRef.current += pausedDuration;
|
|
766
|
+
pausedTimeRef.current = null;
|
|
767
|
+
setIsAnimating(true);
|
|
768
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
769
|
+
}
|
|
770
|
+
}, [isAnimating, isComplete, animate]);
|
|
771
|
+
const reset = useCallback2(() => {
|
|
772
|
+
cancelAnimation();
|
|
773
|
+
setPathLength(currentFromRef.current);
|
|
774
|
+
setIsAnimating(false);
|
|
775
|
+
setIsComplete(false);
|
|
776
|
+
startTimeRef.current = null;
|
|
777
|
+
pausedTimeRef.current = null;
|
|
778
|
+
}, [cancelAnimation]);
|
|
779
|
+
const update = useCallback2(
|
|
780
|
+
(newTo) => {
|
|
781
|
+
currentFromRef.current = pathLength;
|
|
782
|
+
currentToRef.current = newTo;
|
|
783
|
+
start();
|
|
784
|
+
},
|
|
785
|
+
[pathLength, start]
|
|
786
|
+
);
|
|
787
|
+
useEffect3(() => {
|
|
788
|
+
if (autoStart) {
|
|
789
|
+
currentFromRef.current = from;
|
|
790
|
+
currentToRef.current = to;
|
|
791
|
+
start();
|
|
792
|
+
}
|
|
793
|
+
return () => {
|
|
794
|
+
cancelAnimation();
|
|
795
|
+
};
|
|
796
|
+
}, []);
|
|
797
|
+
useEffect3(() => {
|
|
798
|
+
if (to !== currentToRef.current && isComplete) {
|
|
799
|
+
update(to);
|
|
800
|
+
}
|
|
801
|
+
}, [to, isComplete, update]);
|
|
802
|
+
return {
|
|
803
|
+
pathLength,
|
|
804
|
+
isAnimating,
|
|
805
|
+
isComplete,
|
|
806
|
+
start,
|
|
807
|
+
pause,
|
|
808
|
+
resume,
|
|
809
|
+
reset,
|
|
810
|
+
update,
|
|
811
|
+
prefersReducedMotion: prefersReducedMotion2
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
1
815
|
// src/hooks/use-motion-preset.ts
|
|
2
|
-
import { useEffect, useMemo, useState } from "react";
|
|
816
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
|
|
3
817
|
|
|
4
818
|
// src/presets/motion-presets.ts
|
|
5
819
|
var ambientPaths = {
|
|
@@ -53,29 +867,27 @@ function applyMotionPreset(preset, baseConfig) {
|
|
|
53
867
|
}
|
|
54
868
|
|
|
55
869
|
// src/hooks/use-motion-preset.ts
|
|
56
|
-
var DEFAULT_CSS_VARS = {
|
|
57
|
-
durationMultiplier: 1,
|
|
58
|
-
opacityMin: 0.35,
|
|
59
|
-
opacityMax: 0.6
|
|
60
|
-
};
|
|
61
870
|
function readCSSVariables() {
|
|
62
871
|
if (typeof window === "undefined") {
|
|
63
|
-
|
|
872
|
+
throw new Error("useMotionPreset/readCSSVariables requires a browser environment");
|
|
64
873
|
}
|
|
65
874
|
const root = document.documentElement;
|
|
66
875
|
const styles = getComputedStyle(root);
|
|
67
|
-
const
|
|
876
|
+
const parseMotionVar = (value) => {
|
|
68
877
|
const parsed = parseFloat(value);
|
|
69
|
-
|
|
878
|
+
if (Number.isNaN(parsed)) {
|
|
879
|
+
throw new Error("Motion CSS variable could not be parsed as a number");
|
|
880
|
+
}
|
|
881
|
+
return parsed;
|
|
70
882
|
};
|
|
71
883
|
return {
|
|
72
|
-
durationMultiplier:
|
|
73
|
-
opacityMin:
|
|
74
|
-
opacityMax:
|
|
884
|
+
durationMultiplier: parseMotionVar(styles.getPropertyValue("--motion-duration-multiplier")),
|
|
885
|
+
opacityMin: parseMotionVar(styles.getPropertyValue("--motion-opacity-min")),
|
|
886
|
+
opacityMax: parseMotionVar(styles.getPropertyValue("--motion-opacity-max"))
|
|
75
887
|
};
|
|
76
888
|
}
|
|
77
|
-
function computePathsMotion(preset, cssVars,
|
|
78
|
-
if (
|
|
889
|
+
function computePathsMotion(preset, cssVars, prefersReducedMotion2) {
|
|
890
|
+
if (prefersReducedMotion2) {
|
|
79
891
|
return {
|
|
80
892
|
baseDuration: 0,
|
|
81
893
|
opacity: [cssVars.opacityMin, cssVars.opacityMin, cssVars.opacityMin],
|
|
@@ -98,8 +910,8 @@ function computePathsMotion(preset, cssVars, prefersReducedMotion) {
|
|
|
98
910
|
prefersReducedMotion: false
|
|
99
911
|
};
|
|
100
912
|
}
|
|
101
|
-
function computeRaysMotion(preset, cssVars,
|
|
102
|
-
if (
|
|
913
|
+
function computeRaysMotion(preset, cssVars, prefersReducedMotion2) {
|
|
914
|
+
if (prefersReducedMotion2) {
|
|
103
915
|
return {
|
|
104
916
|
cycleDuration: 0,
|
|
105
917
|
intensity: 0,
|
|
@@ -115,19 +927,24 @@ function computeRaysMotion(preset, cssVars, prefersReducedMotion) {
|
|
|
115
927
|
};
|
|
116
928
|
}
|
|
117
929
|
function useMotionPreset(component, preset) {
|
|
118
|
-
const [
|
|
930
|
+
const [prefersReducedMotion2, setPrefersReducedMotion] = useState4(() => {
|
|
119
931
|
if (typeof window === "undefined") return false;
|
|
120
932
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
121
933
|
});
|
|
122
|
-
const [cssVars, setCssVars] =
|
|
123
|
-
|
|
934
|
+
const [cssVars, setCssVars] = useState4(() => {
|
|
935
|
+
if (typeof window === "undefined") {
|
|
936
|
+
throw new Error("useMotionPreset requires a browser environment");
|
|
937
|
+
}
|
|
938
|
+
return readCSSVariables();
|
|
939
|
+
});
|
|
940
|
+
useEffect4(() => {
|
|
124
941
|
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
125
942
|
setPrefersReducedMotion(mediaQuery.matches);
|
|
126
943
|
const handler = (e) => setPrefersReducedMotion(e.matches);
|
|
127
944
|
mediaQuery.addEventListener("change", handler);
|
|
128
945
|
return () => mediaQuery.removeEventListener("change", handler);
|
|
129
946
|
}, []);
|
|
130
|
-
|
|
947
|
+
useEffect4(() => {
|
|
131
948
|
setCssVars(readCSSVariables());
|
|
132
949
|
const observer = new MutationObserver(() => {
|
|
133
950
|
setCssVars(readCSSVariables());
|
|
@@ -138,20 +955,1513 @@ function useMotionPreset(component, preset) {
|
|
|
138
955
|
});
|
|
139
956
|
return () => observer.disconnect();
|
|
140
957
|
}, []);
|
|
141
|
-
return
|
|
958
|
+
return useMemo3(() => {
|
|
142
959
|
if (component === "paths") {
|
|
143
960
|
const presetConfig2 = getPreset(preset, "paths");
|
|
144
|
-
return computePathsMotion(presetConfig2, cssVars,
|
|
961
|
+
return computePathsMotion(presetConfig2, cssVars, prefersReducedMotion2);
|
|
145
962
|
}
|
|
146
963
|
const presetConfig = getPreset(preset, "rays");
|
|
147
|
-
return computeRaysMotion(presetConfig, cssVars,
|
|
148
|
-
}, [component, preset, cssVars,
|
|
964
|
+
return computeRaysMotion(presetConfig, cssVars, prefersReducedMotion2);
|
|
965
|
+
}, [component, preset, cssVars, prefersReducedMotion2]);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/presets/component-presets.ts
|
|
969
|
+
function createTweenTransition(style, options) {
|
|
970
|
+
const duration = options?.duration ?? getDuration(style, "normal");
|
|
971
|
+
return {
|
|
972
|
+
type: "tween",
|
|
973
|
+
duration: msToSeconds(duration),
|
|
974
|
+
ease: [0.25, 0.1, 0.25, 1],
|
|
975
|
+
// cubic-bezier ease-out
|
|
976
|
+
delay: options?.delay ? msToSeconds(options.delay) : 0
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
function createSpringTransition(style, options) {
|
|
980
|
+
const spring = getSpringConfig(style);
|
|
981
|
+
return {
|
|
982
|
+
type: "spring",
|
|
983
|
+
stiffness: spring.stiffness,
|
|
984
|
+
damping: spring.damping,
|
|
985
|
+
mass: spring.mass,
|
|
986
|
+
delay: options?.delay ? msToSeconds(options.delay) : 0
|
|
987
|
+
};
|
|
149
988
|
}
|
|
989
|
+
function getTransition(style, preferSpring, options) {
|
|
990
|
+
const useSpring = options?.useSpring ?? preferSpring;
|
|
991
|
+
return useSpring ? createSpringTransition(style, options) : createTweenTransition(style, options);
|
|
992
|
+
}
|
|
993
|
+
var fadeIn = {
|
|
994
|
+
metadata: {
|
|
995
|
+
id: "fadeIn",
|
|
996
|
+
name: "Fade In",
|
|
997
|
+
description: "Smooth opacity transition from invisible to visible",
|
|
998
|
+
useCase: ["entrance", "reveal"],
|
|
999
|
+
context: ["tooltip", "dropdown", "modal", "notification"],
|
|
1000
|
+
intensity: 2,
|
|
1001
|
+
hasMovement: false
|
|
1002
|
+
},
|
|
1003
|
+
getProps: (style, options) => ({
|
|
1004
|
+
initial: { opacity: 0 },
|
|
1005
|
+
animate: { opacity: 1 },
|
|
1006
|
+
exit: { opacity: 0 },
|
|
1007
|
+
transition: createTweenTransition(style, options)
|
|
1008
|
+
})
|
|
1009
|
+
};
|
|
1010
|
+
var fadeOut = {
|
|
1011
|
+
metadata: {
|
|
1012
|
+
id: "fadeOut",
|
|
1013
|
+
name: "Fade Out",
|
|
1014
|
+
description: "Smooth opacity transition from visible to invisible",
|
|
1015
|
+
useCase: ["exit"],
|
|
1016
|
+
context: ["tooltip", "dropdown", "modal", "notification"],
|
|
1017
|
+
intensity: 2,
|
|
1018
|
+
hasMovement: false
|
|
1019
|
+
},
|
|
1020
|
+
getProps: (style, options) => ({
|
|
1021
|
+
initial: { opacity: 1 },
|
|
1022
|
+
animate: { opacity: 0 },
|
|
1023
|
+
transition: createTweenTransition(style, options)
|
|
1024
|
+
})
|
|
1025
|
+
};
|
|
1026
|
+
var DEFAULT_SLIDE_DISTANCE = 20;
|
|
1027
|
+
var slideUp = {
|
|
1028
|
+
metadata: {
|
|
1029
|
+
id: "slideUp",
|
|
1030
|
+
name: "Slide Up",
|
|
1031
|
+
description: "Element slides upward while fading in",
|
|
1032
|
+
useCase: ["entrance", "reveal"],
|
|
1033
|
+
context: ["modal", "card", "list-item", "notification"],
|
|
1034
|
+
intensity: 3,
|
|
1035
|
+
hasMovement: true,
|
|
1036
|
+
direction: "up"
|
|
1037
|
+
},
|
|
1038
|
+
getProps: (style, options) => {
|
|
1039
|
+
const distance = options?.distance ?? DEFAULT_SLIDE_DISTANCE;
|
|
1040
|
+
return {
|
|
1041
|
+
initial: { opacity: 0, y: distance },
|
|
1042
|
+
animate: { opacity: 1, y: 0 },
|
|
1043
|
+
exit: { opacity: 0, y: distance },
|
|
1044
|
+
transition: getTransition(style, true, options)
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
var slideDown = {
|
|
1049
|
+
metadata: {
|
|
1050
|
+
id: "slideDown",
|
|
1051
|
+
name: "Slide Down",
|
|
1052
|
+
description: "Element slides downward while fading in",
|
|
1053
|
+
useCase: ["entrance", "reveal"],
|
|
1054
|
+
context: ["dropdown", "tooltip", "notification"],
|
|
1055
|
+
intensity: 3,
|
|
1056
|
+
hasMovement: true,
|
|
1057
|
+
direction: "down"
|
|
1058
|
+
},
|
|
1059
|
+
getProps: (style, options) => {
|
|
1060
|
+
const distance = options?.distance ?? DEFAULT_SLIDE_DISTANCE;
|
|
1061
|
+
return {
|
|
1062
|
+
initial: { opacity: 0, y: -distance },
|
|
1063
|
+
animate: { opacity: 1, y: 0 },
|
|
1064
|
+
exit: { opacity: 0, y: -distance },
|
|
1065
|
+
transition: getTransition(style, true, options)
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
var slideLeft = {
|
|
1070
|
+
metadata: {
|
|
1071
|
+
id: "slideLeft",
|
|
1072
|
+
name: "Slide Left",
|
|
1073
|
+
description: "Element slides leftward while fading in",
|
|
1074
|
+
useCase: ["entrance", "transition"],
|
|
1075
|
+
context: ["drawer", "page", "section"],
|
|
1076
|
+
intensity: 3,
|
|
1077
|
+
hasMovement: true,
|
|
1078
|
+
direction: "left"
|
|
1079
|
+
},
|
|
1080
|
+
getProps: (style, options) => {
|
|
1081
|
+
const distance = options?.distance ?? DEFAULT_SLIDE_DISTANCE;
|
|
1082
|
+
return {
|
|
1083
|
+
initial: { opacity: 0, x: distance },
|
|
1084
|
+
animate: { opacity: 1, x: 0 },
|
|
1085
|
+
exit: { opacity: 0, x: -distance },
|
|
1086
|
+
transition: getTransition(style, true, options)
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
var slideRight = {
|
|
1091
|
+
metadata: {
|
|
1092
|
+
id: "slideRight",
|
|
1093
|
+
name: "Slide Right",
|
|
1094
|
+
description: "Element slides rightward while fading in",
|
|
1095
|
+
useCase: ["entrance", "transition"],
|
|
1096
|
+
context: ["drawer", "page", "section"],
|
|
1097
|
+
intensity: 3,
|
|
1098
|
+
hasMovement: true,
|
|
1099
|
+
direction: "right"
|
|
1100
|
+
},
|
|
1101
|
+
getProps: (style, options) => {
|
|
1102
|
+
const distance = options?.distance ?? DEFAULT_SLIDE_DISTANCE;
|
|
1103
|
+
return {
|
|
1104
|
+
initial: { opacity: 0, x: -distance },
|
|
1105
|
+
animate: { opacity: 1, x: 0 },
|
|
1106
|
+
exit: { opacity: 0, x: distance },
|
|
1107
|
+
transition: getTransition(style, true, options)
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
var DEFAULT_SCALE_FROM = 0.95;
|
|
1112
|
+
var DEFAULT_ZOOM_SCALE = 0.5;
|
|
1113
|
+
var scale = {
|
|
1114
|
+
metadata: {
|
|
1115
|
+
id: "scale",
|
|
1116
|
+
name: "Scale",
|
|
1117
|
+
description: "Subtle scale transition with fade",
|
|
1118
|
+
useCase: ["entrance", "emphasis"],
|
|
1119
|
+
context: ["modal", "card", "notification"],
|
|
1120
|
+
intensity: 3,
|
|
1121
|
+
hasMovement: true,
|
|
1122
|
+
direction: "in"
|
|
1123
|
+
},
|
|
1124
|
+
getProps: (style, options) => {
|
|
1125
|
+
const scaleFrom = options?.scale ?? DEFAULT_SCALE_FROM;
|
|
1126
|
+
return {
|
|
1127
|
+
initial: { opacity: 0, scale: scaleFrom },
|
|
1128
|
+
animate: { opacity: 1, scale: 1 },
|
|
1129
|
+
exit: { opacity: 0, scale: scaleFrom },
|
|
1130
|
+
transition: getTransition(style, true, options)
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
var zoomIn = {
|
|
1135
|
+
metadata: {
|
|
1136
|
+
id: "zoomIn",
|
|
1137
|
+
name: "Zoom In",
|
|
1138
|
+
description: "Dramatic zoom from small to full size",
|
|
1139
|
+
useCase: ["entrance", "emphasis"],
|
|
1140
|
+
context: ["hero", "modal", "card"],
|
|
1141
|
+
intensity: 4,
|
|
1142
|
+
hasMovement: true,
|
|
1143
|
+
direction: "in"
|
|
1144
|
+
},
|
|
1145
|
+
getProps: (style, options) => {
|
|
1146
|
+
const scaleFrom = options?.scale ?? DEFAULT_ZOOM_SCALE;
|
|
1147
|
+
return {
|
|
1148
|
+
initial: { opacity: 0, scale: scaleFrom },
|
|
1149
|
+
animate: { opacity: 1, scale: 1 },
|
|
1150
|
+
exit: { opacity: 0, scale: scaleFrom },
|
|
1151
|
+
transition: getTransition(style, true, options)
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
var zoomOut = {
|
|
1156
|
+
metadata: {
|
|
1157
|
+
id: "zoomOut",
|
|
1158
|
+
name: "Zoom Out",
|
|
1159
|
+
description: "Scale from larger to normal size",
|
|
1160
|
+
useCase: ["entrance", "emphasis"],
|
|
1161
|
+
context: ["hero", "modal"],
|
|
1162
|
+
intensity: 4,
|
|
1163
|
+
hasMovement: true,
|
|
1164
|
+
direction: "out"
|
|
1165
|
+
},
|
|
1166
|
+
getProps: (style, options) => {
|
|
1167
|
+
const scaleTo = options?.scale ?? 1.1;
|
|
1168
|
+
return {
|
|
1169
|
+
initial: { opacity: 0, scale: scaleTo },
|
|
1170
|
+
animate: { opacity: 1, scale: 1 },
|
|
1171
|
+
exit: { opacity: 0, scale: scaleTo },
|
|
1172
|
+
transition: getTransition(style, true, options)
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
var DEFAULT_ROTATION = 10;
|
|
1177
|
+
var rotate = {
|
|
1178
|
+
metadata: {
|
|
1179
|
+
id: "rotate",
|
|
1180
|
+
name: "Rotate",
|
|
1181
|
+
description: "Subtle rotation animation with fade",
|
|
1182
|
+
useCase: ["entrance", "emphasis"],
|
|
1183
|
+
context: ["card", "notification"],
|
|
1184
|
+
intensity: 4,
|
|
1185
|
+
hasMovement: true
|
|
1186
|
+
},
|
|
1187
|
+
getProps: (style, options) => {
|
|
1188
|
+
const rotation = options?.rotation ?? DEFAULT_ROTATION;
|
|
1189
|
+
return {
|
|
1190
|
+
initial: { opacity: 0, rotate: -rotation },
|
|
1191
|
+
animate: { opacity: 1, rotate: 0 },
|
|
1192
|
+
exit: { opacity: 0, rotate: rotation },
|
|
1193
|
+
transition: getTransition(style, true, options)
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
var slideUpScale = {
|
|
1198
|
+
metadata: {
|
|
1199
|
+
id: "slideUpScale",
|
|
1200
|
+
name: "Slide Up & Scale",
|
|
1201
|
+
description: "Combines upward slide with subtle scale",
|
|
1202
|
+
useCase: ["entrance", "emphasis"],
|
|
1203
|
+
context: ["hero", "card", "section"],
|
|
1204
|
+
intensity: 4,
|
|
1205
|
+
hasMovement: true,
|
|
1206
|
+
direction: "up"
|
|
1207
|
+
},
|
|
1208
|
+
getProps: (style, options) => {
|
|
1209
|
+
const distance = options?.distance ?? DEFAULT_SLIDE_DISTANCE;
|
|
1210
|
+
const scaleFrom = options?.scale ?? 0.98;
|
|
1211
|
+
return {
|
|
1212
|
+
initial: { opacity: 0, y: distance, scale: scaleFrom },
|
|
1213
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1214
|
+
exit: { opacity: 0, y: distance, scale: scaleFrom },
|
|
1215
|
+
transition: getTransition(style, true, options)
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
var flip = {
|
|
1220
|
+
metadata: {
|
|
1221
|
+
id: "flip",
|
|
1222
|
+
name: "Flip",
|
|
1223
|
+
description: "3D flip animation on the X axis",
|
|
1224
|
+
useCase: ["entrance", "transition"],
|
|
1225
|
+
context: ["card"],
|
|
1226
|
+
intensity: 5,
|
|
1227
|
+
hasMovement: true
|
|
1228
|
+
},
|
|
1229
|
+
getProps: (style, options) => {
|
|
1230
|
+
const rotation = options?.rotation ?? 90;
|
|
1231
|
+
return {
|
|
1232
|
+
initial: { opacity: 0, rotateX: rotation },
|
|
1233
|
+
animate: { opacity: 1, rotateX: 0 },
|
|
1234
|
+
exit: { opacity: 0, rotateX: -rotation },
|
|
1235
|
+
transition: getTransition(style, true, options)
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
var expand = {
|
|
1240
|
+
metadata: {
|
|
1241
|
+
id: "expand",
|
|
1242
|
+
name: "Expand",
|
|
1243
|
+
description: "Height expansion animation",
|
|
1244
|
+
useCase: ["entrance", "reveal"],
|
|
1245
|
+
context: ["section"],
|
|
1246
|
+
intensity: 2,
|
|
1247
|
+
hasMovement: true,
|
|
1248
|
+
direction: "down"
|
|
1249
|
+
},
|
|
1250
|
+
getProps: (style, options) => ({
|
|
1251
|
+
initial: { opacity: 0, height: 0 },
|
|
1252
|
+
animate: { opacity: 1, height: "auto" },
|
|
1253
|
+
exit: { opacity: 0, height: 0 },
|
|
1254
|
+
transition: createTweenTransition(style, options)
|
|
1255
|
+
})
|
|
1256
|
+
};
|
|
1257
|
+
var componentPresets = {
|
|
1258
|
+
fadeIn,
|
|
1259
|
+
fadeOut,
|
|
1260
|
+
slideUp,
|
|
1261
|
+
slideDown,
|
|
1262
|
+
slideLeft,
|
|
1263
|
+
slideRight,
|
|
1264
|
+
scale,
|
|
1265
|
+
zoomIn,
|
|
1266
|
+
zoomOut,
|
|
1267
|
+
rotate,
|
|
1268
|
+
slideUpScale,
|
|
1269
|
+
flip,
|
|
1270
|
+
expand
|
|
1271
|
+
};
|
|
1272
|
+
function getComponentPreset(name) {
|
|
1273
|
+
return componentPresets[name];
|
|
1274
|
+
}
|
|
1275
|
+
function getPresetsByUseCase(useCase) {
|
|
1276
|
+
return Object.values(componentPresets).filter((preset) => preset.metadata.useCase.includes(useCase));
|
|
1277
|
+
}
|
|
1278
|
+
function getPresetsByContext(context) {
|
|
1279
|
+
return Object.values(componentPresets).filter((preset) => preset.metadata.context.includes(context));
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// src/presets/micro-interactions.ts
|
|
1283
|
+
function prefersReducedMotion() {
|
|
1284
|
+
if (typeof window === "undefined") return false;
|
|
1285
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1286
|
+
}
|
|
1287
|
+
function getReducedMotionProps() {
|
|
1288
|
+
return {};
|
|
1289
|
+
}
|
|
1290
|
+
var buttonPress = {
|
|
1291
|
+
name: "buttonPress",
|
|
1292
|
+
description: "Scale down slightly on press, spring back on release",
|
|
1293
|
+
useCase: ["buttons", "clickable cards", "list items", "interactive elements", "call-to-action"],
|
|
1294
|
+
getProps: (style) => {
|
|
1295
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1296
|
+
const config = getMotionStyle(style);
|
|
1297
|
+
const scaleAmount = style === "subtle" ? 0.98 : style === "playful" ? 0.92 : 0.95;
|
|
1298
|
+
return {
|
|
1299
|
+
whileTap: {
|
|
1300
|
+
scale: scaleAmount
|
|
1301
|
+
},
|
|
1302
|
+
whileHover: {
|
|
1303
|
+
scale: style === "subtle" ? 1.01 : 1.02
|
|
1304
|
+
},
|
|
1305
|
+
transition: {
|
|
1306
|
+
type: "spring",
|
|
1307
|
+
stiffness: config.spring.stiffness,
|
|
1308
|
+
damping: config.spring.damping,
|
|
1309
|
+
mass: config.spring.mass
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
var cardHover = {
|
|
1315
|
+
name: "cardHover",
|
|
1316
|
+
description: "Subtle lift with shadow enhancement on hover",
|
|
1317
|
+
useCase: ["cards", "tiles", "panels", "content blocks", "media items", "product listings"],
|
|
1318
|
+
getProps: (style) => {
|
|
1319
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1320
|
+
const config = getMotionStyle(style);
|
|
1321
|
+
const liftAmount = style === "subtle" ? -2 : style === "playful" ? -8 : -4;
|
|
1322
|
+
const shadowIntensity = style === "subtle" ? 0.08 : style === "playful" ? 0.2 : 0.12;
|
|
1323
|
+
return {
|
|
1324
|
+
whileHover: {
|
|
1325
|
+
y: liftAmount,
|
|
1326
|
+
boxShadow: `0 ${Math.abs(liftAmount) * 2}px ${Math.abs(liftAmount) * 4}px rgba(0, 0, 0, ${shadowIntensity})`
|
|
1327
|
+
},
|
|
1328
|
+
transition: {
|
|
1329
|
+
type: "spring",
|
|
1330
|
+
stiffness: config.spring.stiffness,
|
|
1331
|
+
damping: config.spring.damping,
|
|
1332
|
+
mass: config.spring.mass
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
var iconSpin = {
|
|
1338
|
+
name: "iconSpin",
|
|
1339
|
+
description: "360 degree rotation animation",
|
|
1340
|
+
useCase: ["refresh buttons", "sync icons", "loading indicators", "settings icons", "interactive icons"],
|
|
1341
|
+
getProps: (style) => {
|
|
1342
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1343
|
+
const config = getMotionStyle(style);
|
|
1344
|
+
return {
|
|
1345
|
+
whileTap: {
|
|
1346
|
+
rotate: 360
|
|
1347
|
+
},
|
|
1348
|
+
whileHover: {
|
|
1349
|
+
rotate: style === "playful" ? 15 : 5
|
|
1350
|
+
},
|
|
1351
|
+
transition: {
|
|
1352
|
+
type: "spring",
|
|
1353
|
+
stiffness: config.spring.stiffness * 0.8,
|
|
1354
|
+
damping: config.spring.damping,
|
|
1355
|
+
mass: config.spring.mass
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
var pulse = {
|
|
1361
|
+
name: "pulse",
|
|
1362
|
+
description: "Scale pulse animation with breathing effect",
|
|
1363
|
+
useCase: ["notifications", "live indicators", "attention grabbers", "status badges", "loading states"],
|
|
1364
|
+
getProps: (style) => {
|
|
1365
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1366
|
+
const config = getMotionStyle(style);
|
|
1367
|
+
const scaleRange = style === "subtle" ? 1.03 : style === "playful" ? 1.12 : 1.06;
|
|
1368
|
+
return {
|
|
1369
|
+
initial: {
|
|
1370
|
+
scale: 1
|
|
1371
|
+
},
|
|
1372
|
+
animate: {
|
|
1373
|
+
scale: [1, scaleRange, 1]
|
|
1374
|
+
},
|
|
1375
|
+
transition: {
|
|
1376
|
+
duration: msToSeconds(config.duration.slow),
|
|
1377
|
+
repeat: Infinity,
|
|
1378
|
+
ease: config.easing.interactive
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
1383
|
+
var shake = {
|
|
1384
|
+
name: "shake",
|
|
1385
|
+
description: "Horizontal shake animation for error states",
|
|
1386
|
+
useCase: ["error states", "invalid inputs", "denied actions", "form validation", "authentication failures"],
|
|
1387
|
+
getProps: (style) => {
|
|
1388
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1389
|
+
const config = getMotionStyle(style);
|
|
1390
|
+
const shakeDistance = style === "subtle" ? 4 : style === "playful" ? 12 : 8;
|
|
1391
|
+
return {
|
|
1392
|
+
initial: {
|
|
1393
|
+
x: 0
|
|
1394
|
+
},
|
|
1395
|
+
animate: {
|
|
1396
|
+
x: [0, -shakeDistance, shakeDistance, -shakeDistance, shakeDistance, 0]
|
|
1397
|
+
},
|
|
1398
|
+
transition: {
|
|
1399
|
+
duration: msToSeconds(config.duration.fast),
|
|
1400
|
+
ease: config.easing.interactive
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
var wiggle = {
|
|
1406
|
+
name: "wiggle",
|
|
1407
|
+
description: "Playful rotation wiggle animation",
|
|
1408
|
+
useCase: ["playful interfaces", "gamification", "attention indicators", "celebration elements", "decorative icons"],
|
|
1409
|
+
getProps: (style) => {
|
|
1410
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1411
|
+
const config = getMotionStyle(style);
|
|
1412
|
+
const wiggleAngle = style === "subtle" ? 3 : style === "playful" ? 12 : 6;
|
|
1413
|
+
return {
|
|
1414
|
+
whileHover: {
|
|
1415
|
+
rotate: [0, -wiggleAngle, wiggleAngle, -wiggleAngle, wiggleAngle, 0]
|
|
1416
|
+
},
|
|
1417
|
+
transition: {
|
|
1418
|
+
duration: msToSeconds(config.duration.normal),
|
|
1419
|
+
ease: config.easing.interactive
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
var heartbeat = {
|
|
1425
|
+
name: "heartbeat",
|
|
1426
|
+
description: "Double-pulse heartbeat pattern animation",
|
|
1427
|
+
useCase: ["like buttons", "health apps", "love reactions", "favorite indicators", "activity monitors"],
|
|
1428
|
+
getProps: (style) => {
|
|
1429
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1430
|
+
const config = getMotionStyle(style);
|
|
1431
|
+
const pulseScale = style === "subtle" ? 1.1 : style === "playful" ? 1.3 : 1.2;
|
|
1432
|
+
return {
|
|
1433
|
+
initial: {
|
|
1434
|
+
scale: 1
|
|
1435
|
+
},
|
|
1436
|
+
animate: {
|
|
1437
|
+
scale: [1, pulseScale, 1, pulseScale * 0.95, 1]
|
|
1438
|
+
},
|
|
1439
|
+
transition: {
|
|
1440
|
+
duration: msToSeconds(config.duration.slow * 1.5),
|
|
1441
|
+
repeat: Infinity,
|
|
1442
|
+
repeatDelay: msToSeconds(config.duration.normal),
|
|
1443
|
+
ease: config.easing.interactive
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
var rubberBand = {
|
|
1449
|
+
name: "rubberBand",
|
|
1450
|
+
description: "Elastic stretch and snap back animation",
|
|
1451
|
+
useCase: ["emphasis animations", "attention grabbers", "playful buttons", "celebration effects", "interactive feedback"],
|
|
1452
|
+
getProps: (style) => {
|
|
1453
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1454
|
+
const config = getMotionStyle(style);
|
|
1455
|
+
const stretchX = style === "subtle" ? 1.05 : style === "playful" ? 1.25 : 1.15;
|
|
1456
|
+
const stretchY = style === "subtle" ? 0.95 : style === "playful" ? 0.75 : 0.85;
|
|
1457
|
+
return {
|
|
1458
|
+
whileTap: {
|
|
1459
|
+
scaleX: [1, stretchX, 0.95, 1.05, 1],
|
|
1460
|
+
scaleY: [1, stretchY, 1.05, 0.95, 1]
|
|
1461
|
+
},
|
|
1462
|
+
whileHover: {
|
|
1463
|
+
scaleX: 1.02,
|
|
1464
|
+
scaleY: 0.98
|
|
1465
|
+
},
|
|
1466
|
+
transition: {
|
|
1467
|
+
type: "spring",
|
|
1468
|
+
stiffness: config.spring.stiffness * 0.6,
|
|
1469
|
+
damping: config.spring.damping * 0.5,
|
|
1470
|
+
mass: config.spring.mass
|
|
1471
|
+
}
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
var scale2 = {
|
|
1476
|
+
name: "scale",
|
|
1477
|
+
description: "Scale up animation for selection feedback",
|
|
1478
|
+
useCase: ["checkboxes", "toggles", "radio buttons", "selection states", "activation feedback"],
|
|
1479
|
+
getProps: (style) => {
|
|
1480
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1481
|
+
const config = getMotionStyle(style);
|
|
1482
|
+
const scaleAmount = style === "subtle" ? 1.05 : style === "playful" ? 1.2 : 1.1;
|
|
1483
|
+
return {
|
|
1484
|
+
initial: {
|
|
1485
|
+
scale: 0.8,
|
|
1486
|
+
opacity: 0
|
|
1487
|
+
},
|
|
1488
|
+
animate: {
|
|
1489
|
+
scale: [0.8, scaleAmount, 1],
|
|
1490
|
+
opacity: 1
|
|
1491
|
+
},
|
|
1492
|
+
transition: {
|
|
1493
|
+
type: "spring",
|
|
1494
|
+
stiffness: config.spring.stiffness,
|
|
1495
|
+
damping: config.spring.damping,
|
|
1496
|
+
mass: config.spring.mass
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1501
|
+
var shimmer = {
|
|
1502
|
+
name: "shimmer",
|
|
1503
|
+
description: "Gradient shimmer effect that slides across the element",
|
|
1504
|
+
useCase: ["skeleton loading", "placeholder content", "progress indicators", "loading states", "content placeholders"],
|
|
1505
|
+
getProps: (style) => {
|
|
1506
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1507
|
+
const config = getMotionStyle(style);
|
|
1508
|
+
const duration = style === "subtle" ? 2 : style === "playful" ? 1.2 : 1.5;
|
|
1509
|
+
return {
|
|
1510
|
+
initial: {
|
|
1511
|
+
backgroundPosition: "200% 0"
|
|
1512
|
+
},
|
|
1513
|
+
animate: {
|
|
1514
|
+
backgroundPosition: ["-200% 0", "200% 0"]
|
|
1515
|
+
},
|
|
1516
|
+
transition: {
|
|
1517
|
+
duration,
|
|
1518
|
+
repeat: Infinity,
|
|
1519
|
+
ease: config.easing.exit,
|
|
1520
|
+
repeatDelay: 0.5
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
var glowPulse = {
|
|
1526
|
+
name: "glowPulse",
|
|
1527
|
+
description: "Glowing pulse effect for emphasis and AI indicators",
|
|
1528
|
+
useCase: ["AI content indicators", "featured items", "premium elements", "special badges", "magical effects"],
|
|
1529
|
+
getProps: (style) => {
|
|
1530
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1531
|
+
const config = getMotionStyle(style);
|
|
1532
|
+
const glowIntensity = style === "subtle" ? 8 : style === "playful" ? 20 : 12;
|
|
1533
|
+
const glowColor = "rgba(99, 102, 241, 0.6)";
|
|
1534
|
+
return {
|
|
1535
|
+
initial: {
|
|
1536
|
+
boxShadow: `0 0 0 rgba(99, 102, 241, 0)`
|
|
1537
|
+
},
|
|
1538
|
+
animate: {
|
|
1539
|
+
boxShadow: [`0 0 0 rgba(99, 102, 241, 0)`, `0 0 ${glowIntensity}px ${glowColor}`, `0 0 0 rgba(99, 102, 241, 0)`]
|
|
1540
|
+
},
|
|
1541
|
+
transition: {
|
|
1542
|
+
duration: msToSeconds(config.duration.slow * 1.5),
|
|
1543
|
+
repeat: Infinity,
|
|
1544
|
+
ease: config.easing.interactive
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
var progressFill = {
|
|
1550
|
+
name: "progressFill",
|
|
1551
|
+
description: "Animated fill from 0% to target width for progress bars",
|
|
1552
|
+
useCase: ["progress bars", "completion indicators", "skill bars", "loading progress", "data visualization"],
|
|
1553
|
+
getProps: (style) => {
|
|
1554
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1555
|
+
const config = getMotionStyle(style);
|
|
1556
|
+
const duration = style === "subtle" ? 0.6 : style === "playful" ? 1.2 : 0.8;
|
|
1557
|
+
return {
|
|
1558
|
+
initial: {
|
|
1559
|
+
scaleX: 0
|
|
1560
|
+
},
|
|
1561
|
+
animate: {
|
|
1562
|
+
scaleX: 1
|
|
1563
|
+
},
|
|
1564
|
+
transition: {
|
|
1565
|
+
duration,
|
|
1566
|
+
ease: config.easing.exit
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
var checkmarkDraw = {
|
|
1572
|
+
name: "checkmarkDraw",
|
|
1573
|
+
description: "Animated checkmark draw effect for success states",
|
|
1574
|
+
useCase: ["success confirmations", "completed tasks", "checkboxes", "form submissions", "achievement unlocks"],
|
|
1575
|
+
getProps: (style) => {
|
|
1576
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1577
|
+
const config = getMotionStyle(style);
|
|
1578
|
+
const duration = style === "subtle" ? config.duration.fast : style === "playful" ? config.duration.slow : config.duration.normal;
|
|
1579
|
+
return {
|
|
1580
|
+
initial: {
|
|
1581
|
+
pathLength: 0,
|
|
1582
|
+
opacity: 0
|
|
1583
|
+
},
|
|
1584
|
+
animate: {
|
|
1585
|
+
pathLength: 1,
|
|
1586
|
+
opacity: 1
|
|
1587
|
+
},
|
|
1588
|
+
transition: {
|
|
1589
|
+
duration: msToSeconds(duration),
|
|
1590
|
+
ease: config.easing.interactive
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
var successFlash = {
|
|
1596
|
+
name: "successFlash",
|
|
1597
|
+
description: "Brief success highlight flash animation",
|
|
1598
|
+
useCase: ["success toasts", "inline confirmations", "save indicators", "completion feedback", "achievement notifications"],
|
|
1599
|
+
getProps: (style) => {
|
|
1600
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1601
|
+
const config = getMotionStyle(style);
|
|
1602
|
+
const scale3 = style === "subtle" ? 1.02 : style === "playful" ? 1.08 : 1.05;
|
|
1603
|
+
return {
|
|
1604
|
+
initial: {
|
|
1605
|
+
scale: 1,
|
|
1606
|
+
backgroundColor: "transparent"
|
|
1607
|
+
},
|
|
1608
|
+
animate: {
|
|
1609
|
+
scale: [1, scale3, 1],
|
|
1610
|
+
backgroundColor: ["transparent", "var(--color-surface-success-subtle)", "transparent"]
|
|
1611
|
+
},
|
|
1612
|
+
transition: {
|
|
1613
|
+
duration: msToSeconds(config.duration.fast),
|
|
1614
|
+
ease: config.easing.interactive
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
var badgePop = {
|
|
1620
|
+
name: "badgePop",
|
|
1621
|
+
description: "Pop animation for badge count changes",
|
|
1622
|
+
useCase: ["notification badges", "count indicators", "numeric updates", "inventory changes", "score updates"],
|
|
1623
|
+
getProps: (style) => {
|
|
1624
|
+
if (prefersReducedMotion()) return getReducedMotionProps();
|
|
1625
|
+
const config = getMotionStyle(style);
|
|
1626
|
+
const scale3 = style === "subtle" ? 1.15 : style === "playful" ? 1.4 : 1.25;
|
|
1627
|
+
return {
|
|
1628
|
+
initial: {
|
|
1629
|
+
scale: 0,
|
|
1630
|
+
opacity: 0
|
|
1631
|
+
},
|
|
1632
|
+
animate: {
|
|
1633
|
+
scale: [0, scale3, 1],
|
|
1634
|
+
opacity: [0, 1, 1]
|
|
1635
|
+
},
|
|
1636
|
+
transition: {
|
|
1637
|
+
duration: msToSeconds(config.duration.fast),
|
|
1638
|
+
ease: config.easing.interactive
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
var microInteractions = {
|
|
1644
|
+
buttonPress,
|
|
1645
|
+
cardHover,
|
|
1646
|
+
iconSpin,
|
|
1647
|
+
pulse,
|
|
1648
|
+
scale: scale2,
|
|
1649
|
+
shake,
|
|
1650
|
+
wiggle,
|
|
1651
|
+
heartbeat,
|
|
1652
|
+
rubberBand,
|
|
1653
|
+
shimmer,
|
|
1654
|
+
glowPulse,
|
|
1655
|
+
progressFill,
|
|
1656
|
+
checkmarkDraw,
|
|
1657
|
+
successFlash,
|
|
1658
|
+
badgePop
|
|
1659
|
+
};
|
|
1660
|
+
function getMicroInteraction(name) {
|
|
1661
|
+
return microInteractions[name];
|
|
1662
|
+
}
|
|
1663
|
+
function getMicroInteractionNames() {
|
|
1664
|
+
return Object.keys(microInteractions);
|
|
1665
|
+
}
|
|
1666
|
+
function findPresetsForUseCase(useCase) {
|
|
1667
|
+
const searchTerm = useCase.toLowerCase();
|
|
1668
|
+
return Object.values(microInteractions).filter((preset) => preset.useCase.some((uc) => uc.toLowerCase().includes(searchTerm)));
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// src/presets/stagger-presets.ts
|
|
1672
|
+
function createBaseItemVariants(style) {
|
|
1673
|
+
const config = getMotionStyle(style);
|
|
1674
|
+
return {
|
|
1675
|
+
hidden: {
|
|
1676
|
+
opacity: 0,
|
|
1677
|
+
y: 20
|
|
1678
|
+
},
|
|
1679
|
+
visible: {
|
|
1680
|
+
opacity: 1,
|
|
1681
|
+
y: 0,
|
|
1682
|
+
transition: {
|
|
1683
|
+
type: "spring",
|
|
1684
|
+
stiffness: config.spring.stiffness,
|
|
1685
|
+
damping: config.spring.damping,
|
|
1686
|
+
mass: config.spring.mass
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
var staggerSequential = {
|
|
1692
|
+
name: "Sequential",
|
|
1693
|
+
description: "Items animate one after another from top to bottom",
|
|
1694
|
+
useCase: ["Navigation menus", "Vertical lists", "Table rows", "Form fields", "Sidebar items"],
|
|
1695
|
+
getDelay(index, _total, style) {
|
|
1696
|
+
const config = getMotionStyle(style);
|
|
1697
|
+
return msToSeconds(config.staggerDelay * index);
|
|
1698
|
+
},
|
|
1699
|
+
getContainerVariants(style) {
|
|
1700
|
+
const config = getMotionStyle(style);
|
|
1701
|
+
return {
|
|
1702
|
+
hidden: { opacity: 0 },
|
|
1703
|
+
visible: {
|
|
1704
|
+
opacity: 1,
|
|
1705
|
+
transition: {
|
|
1706
|
+
staggerChildren: msToSeconds(config.staggerDelay),
|
|
1707
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
},
|
|
1712
|
+
getItemVariants: createBaseItemVariants
|
|
1713
|
+
};
|
|
1714
|
+
var staggerReverse = {
|
|
1715
|
+
name: "Reverse",
|
|
1716
|
+
description: "Items animate from bottom to top",
|
|
1717
|
+
useCase: ["Toast notifications", "Chat messages (newest first)", "Bottom-anchored content", "Rising effect animations", "Upward reveals"],
|
|
1718
|
+
getDelay(index, total, style) {
|
|
1719
|
+
const config = getMotionStyle(style);
|
|
1720
|
+
const reverseIndex = total - 1 - index;
|
|
1721
|
+
return msToSeconds(config.staggerDelay * reverseIndex);
|
|
1722
|
+
},
|
|
1723
|
+
getContainerVariants(style) {
|
|
1724
|
+
const config = getMotionStyle(style);
|
|
1725
|
+
return {
|
|
1726
|
+
hidden: { opacity: 0 },
|
|
1727
|
+
visible: {
|
|
1728
|
+
opacity: 1,
|
|
1729
|
+
transition: {
|
|
1730
|
+
staggerChildren: msToSeconds(config.staggerDelay),
|
|
1731
|
+
staggerDirection: -1,
|
|
1732
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
},
|
|
1737
|
+
getItemVariants(style) {
|
|
1738
|
+
const config = getMotionStyle(style);
|
|
1739
|
+
return {
|
|
1740
|
+
hidden: {
|
|
1741
|
+
opacity: 0,
|
|
1742
|
+
y: -20
|
|
1743
|
+
},
|
|
1744
|
+
visible: {
|
|
1745
|
+
opacity: 1,
|
|
1746
|
+
y: 0,
|
|
1747
|
+
transition: {
|
|
1748
|
+
type: "spring",
|
|
1749
|
+
stiffness: config.spring.stiffness,
|
|
1750
|
+
damping: config.spring.damping,
|
|
1751
|
+
mass: config.spring.mass
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
var staggerCenter = {
|
|
1758
|
+
name: "Center",
|
|
1759
|
+
description: "Items animate from center outward",
|
|
1760
|
+
useCase: ["Hero sections", "Featured content", "Pricing cards", "Centered navigation", "Focus-based reveals"],
|
|
1761
|
+
getDelay(index, total, style) {
|
|
1762
|
+
const config = getMotionStyle(style);
|
|
1763
|
+
const centerIndex = (total - 1) / 2;
|
|
1764
|
+
const distanceFromCenter = Math.abs(index - centerIndex);
|
|
1765
|
+
return msToSeconds(config.staggerDelay * distanceFromCenter);
|
|
1766
|
+
},
|
|
1767
|
+
getContainerVariants(style) {
|
|
1768
|
+
const config = getMotionStyle(style);
|
|
1769
|
+
return {
|
|
1770
|
+
hidden: { opacity: 0 },
|
|
1771
|
+
visible: {
|
|
1772
|
+
opacity: 1,
|
|
1773
|
+
transition: {
|
|
1774
|
+
staggerChildren: msToSeconds(config.staggerDelay),
|
|
1775
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
},
|
|
1780
|
+
getItemVariants(style) {
|
|
1781
|
+
const config = getMotionStyle(style);
|
|
1782
|
+
return {
|
|
1783
|
+
hidden: {
|
|
1784
|
+
opacity: 0,
|
|
1785
|
+
scale: 0.8
|
|
1786
|
+
},
|
|
1787
|
+
visible: {
|
|
1788
|
+
opacity: 1,
|
|
1789
|
+
scale: 1,
|
|
1790
|
+
transition: {
|
|
1791
|
+
type: "spring",
|
|
1792
|
+
stiffness: config.spring.stiffness,
|
|
1793
|
+
damping: config.spring.damping,
|
|
1794
|
+
mass: config.spring.mass
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
};
|
|
1800
|
+
var staggerRandom = {
|
|
1801
|
+
name: "Random",
|
|
1802
|
+
description: "Items animate in random order",
|
|
1803
|
+
useCase: ["Photo galleries", "Tag clouds", "Creative portfolios", "Playful interfaces", "Organic reveals"],
|
|
1804
|
+
getDelay(index, total, style) {
|
|
1805
|
+
const config = getMotionStyle(style);
|
|
1806
|
+
const seed = index * 7919 % total / total;
|
|
1807
|
+
const maxDelay = config.staggerDelay * total;
|
|
1808
|
+
return msToSeconds(seed * maxDelay);
|
|
1809
|
+
},
|
|
1810
|
+
getContainerVariants(style) {
|
|
1811
|
+
const config = getMotionStyle(style);
|
|
1812
|
+
return {
|
|
1813
|
+
hidden: { opacity: 0 },
|
|
1814
|
+
visible: {
|
|
1815
|
+
opacity: 1,
|
|
1816
|
+
transition: {
|
|
1817
|
+
staggerChildren: msToSeconds(config.staggerDelay * 0.3),
|
|
1818
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
},
|
|
1823
|
+
getItemVariants(style) {
|
|
1824
|
+
const config = getMotionStyle(style);
|
|
1825
|
+
return {
|
|
1826
|
+
hidden: {
|
|
1827
|
+
opacity: 0,
|
|
1828
|
+
scale: 0.9,
|
|
1829
|
+
rotate: -5
|
|
1830
|
+
},
|
|
1831
|
+
visible: {
|
|
1832
|
+
opacity: 1,
|
|
1833
|
+
scale: 1,
|
|
1834
|
+
rotate: 0,
|
|
1835
|
+
transition: {
|
|
1836
|
+
type: "spring",
|
|
1837
|
+
stiffness: config.spring.stiffness,
|
|
1838
|
+
damping: config.spring.damping,
|
|
1839
|
+
mass: config.spring.mass
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
var staggerGrid = {
|
|
1846
|
+
name: "Grid",
|
|
1847
|
+
description: "2D diagonal wave pattern for grid layouts",
|
|
1848
|
+
useCase: ["Image galleries", "Card grids", "Dashboard widgets", "Product catalogs", "Portfolio items"],
|
|
1849
|
+
getDelay(index, _total, style, columns = 4) {
|
|
1850
|
+
const config = getMotionStyle(style);
|
|
1851
|
+
const row = Math.floor(index / columns);
|
|
1852
|
+
const col = index % columns;
|
|
1853
|
+
const diagonalIndex = row + col;
|
|
1854
|
+
return msToSeconds(config.staggerDelay * diagonalIndex);
|
|
1855
|
+
},
|
|
1856
|
+
getContainerVariants(style) {
|
|
1857
|
+
const config = getMotionStyle(style);
|
|
1858
|
+
return {
|
|
1859
|
+
hidden: { opacity: 0 },
|
|
1860
|
+
visible: {
|
|
1861
|
+
opacity: 1,
|
|
1862
|
+
transition: {
|
|
1863
|
+
staggerChildren: msToSeconds(config.staggerDelay * 0.8),
|
|
1864
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
};
|
|
1868
|
+
},
|
|
1869
|
+
getItemVariants(style) {
|
|
1870
|
+
const config = getMotionStyle(style);
|
|
1871
|
+
return {
|
|
1872
|
+
hidden: {
|
|
1873
|
+
opacity: 0,
|
|
1874
|
+
scale: 0.9,
|
|
1875
|
+
y: 10
|
|
1876
|
+
},
|
|
1877
|
+
visible: {
|
|
1878
|
+
opacity: 1,
|
|
1879
|
+
scale: 1,
|
|
1880
|
+
y: 0,
|
|
1881
|
+
transition: {
|
|
1882
|
+
type: "spring",
|
|
1883
|
+
stiffness: config.spring.stiffness,
|
|
1884
|
+
damping: config.spring.damping,
|
|
1885
|
+
mass: config.spring.mass
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
};
|
|
1891
|
+
var staggerWave = {
|
|
1892
|
+
name: "Wave",
|
|
1893
|
+
description: "Sine-wave based stagger pattern for organic motion",
|
|
1894
|
+
useCase: ["Audio visualizers", "Timeline animations", "Organic reveals", "Music interfaces", "Flowing sequences"],
|
|
1895
|
+
getDelay(index, total, style) {
|
|
1896
|
+
const config = getMotionStyle(style);
|
|
1897
|
+
const wavePosition = index / total * Math.PI * 2;
|
|
1898
|
+
const waveOffset = (Math.sin(wavePosition) + 1) / 2;
|
|
1899
|
+
const baseDelay = config.staggerDelay * index;
|
|
1900
|
+
const waveDelay = config.staggerDelay * waveOffset * 2;
|
|
1901
|
+
return msToSeconds(baseDelay + waveDelay);
|
|
1902
|
+
},
|
|
1903
|
+
getContainerVariants(style) {
|
|
1904
|
+
const config = getMotionStyle(style);
|
|
1905
|
+
return {
|
|
1906
|
+
hidden: { opacity: 0 },
|
|
1907
|
+
visible: {
|
|
1908
|
+
opacity: 1,
|
|
1909
|
+
transition: {
|
|
1910
|
+
staggerChildren: msToSeconds(config.staggerDelay * 0.6),
|
|
1911
|
+
delayChildren: msToSeconds(config.duration.fast * 0.5)
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
},
|
|
1916
|
+
getItemVariants(style) {
|
|
1917
|
+
const config = getMotionStyle(style);
|
|
1918
|
+
return {
|
|
1919
|
+
hidden: {
|
|
1920
|
+
opacity: 0,
|
|
1921
|
+
y: 15,
|
|
1922
|
+
x: -5
|
|
1923
|
+
},
|
|
1924
|
+
visible: {
|
|
1925
|
+
opacity: 1,
|
|
1926
|
+
y: 0,
|
|
1927
|
+
x: 0,
|
|
1928
|
+
transition: {
|
|
1929
|
+
type: "spring",
|
|
1930
|
+
stiffness: config.spring.stiffness,
|
|
1931
|
+
damping: config.spring.damping,
|
|
1932
|
+
mass: config.spring.mass
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
};
|
|
1938
|
+
var staggerCascade = {
|
|
1939
|
+
name: "Cascade",
|
|
1940
|
+
description: "Fast initial items, progressively slower later ones",
|
|
1941
|
+
useCase: ["Long lists", "Data tables", "Search results", "Infinite scroll content", "Progressive reveals"],
|
|
1942
|
+
getDelay(index, total, style) {
|
|
1943
|
+
const config = getMotionStyle(style);
|
|
1944
|
+
const normalizedIndex = index / Math.max(total - 1, 1);
|
|
1945
|
+
const cascadeFactor = Math.sqrt(normalizedIndex);
|
|
1946
|
+
const maxDuration = config.staggerDelay * total;
|
|
1947
|
+
return msToSeconds(cascadeFactor * maxDuration);
|
|
1948
|
+
},
|
|
1949
|
+
getContainerVariants(style) {
|
|
1950
|
+
const config = getMotionStyle(style);
|
|
1951
|
+
return {
|
|
1952
|
+
hidden: { opacity: 0 },
|
|
1953
|
+
visible: {
|
|
1954
|
+
opacity: 1,
|
|
1955
|
+
transition: {
|
|
1956
|
+
staggerChildren: msToSeconds(config.staggerDelay * 0.4),
|
|
1957
|
+
delayChildren: msToSeconds(config.duration.fast * 0.3)
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
},
|
|
1962
|
+
getItemVariants(style) {
|
|
1963
|
+
const config = getMotionStyle(style);
|
|
1964
|
+
return {
|
|
1965
|
+
hidden: {
|
|
1966
|
+
opacity: 0,
|
|
1967
|
+
x: -10
|
|
1968
|
+
},
|
|
1969
|
+
visible: {
|
|
1970
|
+
opacity: 1,
|
|
1971
|
+
x: 0,
|
|
1972
|
+
transition: {
|
|
1973
|
+
type: "spring",
|
|
1974
|
+
stiffness: config.spring.stiffness + 50,
|
|
1975
|
+
// Slightly snappier
|
|
1976
|
+
damping: config.spring.damping + 5,
|
|
1977
|
+
mass: config.spring.mass * 0.9
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
var staggerPresets = {
|
|
1984
|
+
sequential: staggerSequential,
|
|
1985
|
+
reverse: staggerReverse,
|
|
1986
|
+
center: staggerCenter,
|
|
1987
|
+
random: staggerRandom,
|
|
1988
|
+
grid: staggerGrid,
|
|
1989
|
+
wave: staggerWave,
|
|
1990
|
+
cascade: staggerCascade
|
|
1991
|
+
};
|
|
1992
|
+
function getStaggerPreset(name) {
|
|
1993
|
+
const preset = staggerPresets[name];
|
|
1994
|
+
if (!preset) {
|
|
1995
|
+
throw new Error(`Unknown stagger preset: ${name}. Available: ${Object.keys(staggerPresets).join(", ")}`);
|
|
1996
|
+
}
|
|
1997
|
+
return preset;
|
|
1998
|
+
}
|
|
1999
|
+
function calculateStaggerDelays(preset, total, style) {
|
|
2000
|
+
const staggerPreset = getStaggerPreset(preset);
|
|
2001
|
+
return Array.from({ length: total }, (_, index) => staggerPreset.getDelay(index, total, style));
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/utils/easing.ts
|
|
2005
|
+
var linear = [0, 0, 1, 1];
|
|
2006
|
+
var easeIn = [0.4, 0, 1, 1];
|
|
2007
|
+
var easeOut = [0, 0, 0.2, 1];
|
|
2008
|
+
var easeInOut = [0.4, 0, 0.2, 1];
|
|
2009
|
+
var easeOutQuart = [0.25, 1, 0.5, 1];
|
|
2010
|
+
var easeInOutCubic = [0.65, 0, 0.35, 1];
|
|
2011
|
+
var easeOutBack = [0.34, 1.56, 0.64, 1];
|
|
2012
|
+
var easeOutExpo = [0.16, 1, 0.3, 1];
|
|
2013
|
+
var easeInOutQuint = [0.83, 0, 0.17, 1];
|
|
2014
|
+
function createTween(duration, ease) {
|
|
2015
|
+
return {
|
|
2016
|
+
type: "tween",
|
|
2017
|
+
duration,
|
|
2018
|
+
ease: ease ?? easeOut
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
function createTweenFromParams(params) {
|
|
2022
|
+
const result = {
|
|
2023
|
+
type: "tween",
|
|
2024
|
+
duration: params.duration
|
|
2025
|
+
};
|
|
2026
|
+
if (params.ease !== void 0) {
|
|
2027
|
+
return { ...result, ease: params.ease };
|
|
2028
|
+
}
|
|
2029
|
+
return result;
|
|
2030
|
+
}
|
|
2031
|
+
var durations = {
|
|
2032
|
+
/** Micro-interactions: hover states, small toggles (100ms) */
|
|
2033
|
+
instant: 0.1,
|
|
2034
|
+
/** Quick feedback: button clicks, checkboxes (200ms) */
|
|
2035
|
+
fast: 0.2,
|
|
2036
|
+
/** Standard transitions: most UI elements (300ms) */
|
|
2037
|
+
normal: 0.3,
|
|
2038
|
+
/** Emphasized transitions: modals, drawers (400ms) */
|
|
2039
|
+
slow: 0.4,
|
|
2040
|
+
/** Dramatic transitions: page changes, reveals (600ms) */
|
|
2041
|
+
slower: 0.6
|
|
2042
|
+
};
|
|
2043
|
+
var easingPresets = {
|
|
2044
|
+
linear,
|
|
2045
|
+
easeIn,
|
|
2046
|
+
easeOut,
|
|
2047
|
+
easeInOut,
|
|
2048
|
+
easeOutQuart,
|
|
2049
|
+
easeInOutCubic,
|
|
2050
|
+
easeOutBack,
|
|
2051
|
+
easeOutExpo,
|
|
2052
|
+
easeInOutQuint
|
|
2053
|
+
};
|
|
2054
|
+
var tweenPresets = {
|
|
2055
|
+
/** Quick fade for hover states and micro-interactions */
|
|
2056
|
+
instant: createTween(durations.instant, easeOut),
|
|
2057
|
+
/** Snappy transition for interactive elements */
|
|
2058
|
+
fast: createTween(durations.fast, easeOut),
|
|
2059
|
+
/** Balanced transition for most UI elements */
|
|
2060
|
+
normal: createTween(durations.normal, easeOutQuart),
|
|
2061
|
+
/** Smooth transition for modals and overlays */
|
|
2062
|
+
slow: createTween(durations.slow, easeOutQuart),
|
|
2063
|
+
/** Dramatic transition for page-level changes */
|
|
2064
|
+
slower: createTween(durations.slower, easeInOutCubic)
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2067
|
+
// src/utils/reduced-motion.ts
|
|
2068
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
2069
|
+
var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
|
|
2070
|
+
var INSTANT_TRANSITION = {
|
|
2071
|
+
duration: 0,
|
|
2072
|
+
delay: 0
|
|
2073
|
+
};
|
|
2074
|
+
function getReducedMotionVariant(normalVariant, reducedVariant, prefersReducedMotion2) {
|
|
2075
|
+
return prefersReducedMotion2 ? reducedVariant : normalVariant;
|
|
2076
|
+
}
|
|
2077
|
+
function filterVariantForReducedMotion(variant, options) {
|
|
2078
|
+
const { preserveOpacity = true, preserveColors = true } = options;
|
|
2079
|
+
const filtered = {};
|
|
2080
|
+
for (const [key, value] of Object.entries(variant)) {
|
|
2081
|
+
const isOpacityProperty = key === "opacity";
|
|
2082
|
+
const isColorProperty = key === "color" || key === "backgroundColor" || key === "borderColor" || key === "fill" || key === "stroke";
|
|
2083
|
+
if (preserveOpacity && isOpacityProperty || preserveColors && isColorProperty) {
|
|
2084
|
+
filtered[key] = value;
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
return filtered;
|
|
2088
|
+
}
|
|
2089
|
+
function createReducedMotionProps(props, prefersReducedMotion2, options = {}) {
|
|
2090
|
+
if (!prefersReducedMotion2) {
|
|
2091
|
+
return props;
|
|
2092
|
+
}
|
|
2093
|
+
const { preserveOpacity = true, preserveColors = true, reducedTransition } = options;
|
|
2094
|
+
const transition = reducedTransition ?? INSTANT_TRANSITION;
|
|
2095
|
+
const processVariant = (variant) => {
|
|
2096
|
+
if (variant === void 0 || typeof variant === "string" || typeof variant === "boolean") {
|
|
2097
|
+
return variant;
|
|
2098
|
+
}
|
|
2099
|
+
return filterVariantForReducedMotion(variant, { preserveOpacity, preserveColors });
|
|
2100
|
+
};
|
|
2101
|
+
const processVariants = (variants) => {
|
|
2102
|
+
if (!variants) {
|
|
2103
|
+
return void 0;
|
|
2104
|
+
}
|
|
2105
|
+
const processed = {};
|
|
2106
|
+
for (const [key, variant] of Object.entries(variants)) {
|
|
2107
|
+
processed[key] = filterVariantForReducedMotion(variant, { preserveOpacity, preserveColors });
|
|
2108
|
+
}
|
|
2109
|
+
return processed;
|
|
2110
|
+
};
|
|
2111
|
+
const processNonBooleanVariant = (variant) => {
|
|
2112
|
+
if (variant === void 0 || typeof variant === "string") {
|
|
2113
|
+
return variant;
|
|
2114
|
+
}
|
|
2115
|
+
return filterVariantForReducedMotion(variant, { preserveOpacity, preserveColors });
|
|
2116
|
+
};
|
|
2117
|
+
return {
|
|
2118
|
+
...props,
|
|
2119
|
+
initial: processVariant(props.initial),
|
|
2120
|
+
animate: processNonBooleanVariant(props.animate),
|
|
2121
|
+
exit: processNonBooleanVariant(props.exit),
|
|
2122
|
+
variants: processVariants(props.variants),
|
|
2123
|
+
transition,
|
|
2124
|
+
// Disable hover/tap/focus animations in reduced motion mode
|
|
2125
|
+
// as they often involve movement
|
|
2126
|
+
whileHover: void 0,
|
|
2127
|
+
whileTap: void 0,
|
|
2128
|
+
whileFocus: void 0,
|
|
2129
|
+
whileDrag: void 0,
|
|
2130
|
+
whileInView: processNonBooleanVariant(props.whileInView)
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
function checkReducedMotion() {
|
|
2134
|
+
if (typeof window === "undefined") {
|
|
2135
|
+
return false;
|
|
2136
|
+
}
|
|
2137
|
+
return window.matchMedia(REDUCED_MOTION_QUERY).matches;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
// src/utils/select-preset.ts
|
|
2141
|
+
function calculateMatchScore(preset, criteria) {
|
|
2142
|
+
let score = 0;
|
|
2143
|
+
let factors = 0;
|
|
2144
|
+
if (criteria.useCase) {
|
|
2145
|
+
factors++;
|
|
2146
|
+
if (preset.metadata.useCase.includes(criteria.useCase)) {
|
|
2147
|
+
score += 1;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
if (criteria.context) {
|
|
2151
|
+
factors++;
|
|
2152
|
+
if (preset.metadata.context.includes(criteria.context)) {
|
|
2153
|
+
score += 1;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
if (criteria.maxIntensity !== void 0) {
|
|
2157
|
+
factors++;
|
|
2158
|
+
if (preset.metadata.intensity <= criteria.maxIntensity) {
|
|
2159
|
+
score += 1;
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
if (criteria.minIntensity !== void 0) {
|
|
2163
|
+
factors++;
|
|
2164
|
+
if (preset.metadata.intensity >= criteria.minIntensity) {
|
|
2165
|
+
score += 1;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
if (criteria.preferMovement !== void 0) {
|
|
2169
|
+
factors++;
|
|
2170
|
+
if (preset.metadata.hasMovement === criteria.preferMovement) {
|
|
2171
|
+
score += 1;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
if (criteria.direction && preset.metadata.direction) {
|
|
2175
|
+
factors++;
|
|
2176
|
+
if (preset.metadata.direction === criteria.direction) {
|
|
2177
|
+
score += 1;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
if (criteria.prioritizeAccessibility) {
|
|
2181
|
+
factors++;
|
|
2182
|
+
score += (5 - preset.metadata.intensity) / 5;
|
|
2183
|
+
}
|
|
2184
|
+
return factors > 0 ? score / factors : 0;
|
|
2185
|
+
}
|
|
2186
|
+
function determineStyle(criteria) {
|
|
2187
|
+
if (criteria.style) {
|
|
2188
|
+
return criteria.style;
|
|
2189
|
+
}
|
|
2190
|
+
if (criteria.prioritizeAccessibility) {
|
|
2191
|
+
return "subtle";
|
|
2192
|
+
}
|
|
2193
|
+
if (criteria.context === "hero" || criteria.context === "page") {
|
|
2194
|
+
return "bold";
|
|
2195
|
+
}
|
|
2196
|
+
if (criteria.context === "tooltip" || criteria.context === "dropdown") {
|
|
2197
|
+
return "subtle";
|
|
2198
|
+
}
|
|
2199
|
+
return "standard";
|
|
2200
|
+
}
|
|
2201
|
+
function generateReasoning(preset, criteria, score) {
|
|
2202
|
+
const reasons = [];
|
|
2203
|
+
if (criteria.useCase && preset.metadata.useCase.includes(criteria.useCase)) {
|
|
2204
|
+
reasons.push(`matches use case "${criteria.useCase}"`);
|
|
2205
|
+
}
|
|
2206
|
+
if (criteria.context && preset.metadata.context.includes(criteria.context)) {
|
|
2207
|
+
reasons.push(`suitable for "${criteria.context}" context`);
|
|
2208
|
+
}
|
|
2209
|
+
if (criteria.direction && preset.metadata.direction === criteria.direction) {
|
|
2210
|
+
reasons.push(`provides "${criteria.direction}" movement`);
|
|
2211
|
+
}
|
|
2212
|
+
if (criteria.prioritizeAccessibility && preset.metadata.intensity <= 2) {
|
|
2213
|
+
reasons.push("has low intensity for accessibility");
|
|
2214
|
+
}
|
|
2215
|
+
if (reasons.length === 0) {
|
|
2216
|
+
reasons.push("general-purpose animation");
|
|
2217
|
+
}
|
|
2218
|
+
return `Selected "${preset.metadata.name}" (${Math.round(score * 100)}% match): ${reasons.join(", ")}.`;
|
|
2219
|
+
}
|
|
2220
|
+
function selectPreset(criteria) {
|
|
2221
|
+
const allPresets = Object.entries(componentPresets);
|
|
2222
|
+
const scoredPresets = allPresets.map(([name, preset]) => ({
|
|
2223
|
+
name,
|
|
2224
|
+
preset,
|
|
2225
|
+
score: calculateMatchScore(preset, criteria)
|
|
2226
|
+
}));
|
|
2227
|
+
scoredPresets.sort((a, b) => b.score - a.score);
|
|
2228
|
+
const best = scoredPresets[0];
|
|
2229
|
+
const style = determineStyle(criteria);
|
|
2230
|
+
if (!best) {
|
|
2231
|
+
throw new Error("selectPreset: no presets available; cannot select a preset.");
|
|
2232
|
+
}
|
|
2233
|
+
const alternatives = scoredPresets.slice(1, 4).filter((p) => p.score > 0.3).map((p) => p.name);
|
|
2234
|
+
return {
|
|
2235
|
+
preset: best.preset,
|
|
2236
|
+
presetName: best.name,
|
|
2237
|
+
style,
|
|
2238
|
+
confidence: best.score,
|
|
2239
|
+
reasoning: generateReasoning(best.preset, criteria, best.score),
|
|
2240
|
+
alternatives
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
function getRecommendations(context, options = {}) {
|
|
2244
|
+
const { maxResults = 5, minScore = 0.3 } = options;
|
|
2245
|
+
const contextPresets = getPresetsByContext(context);
|
|
2246
|
+
const recommendations = contextPresets.map((preset) => {
|
|
2247
|
+
const name = Object.entries(componentPresets).find(([_, p]) => p === preset)?.[0];
|
|
2248
|
+
const contextFit = preset.metadata.context.indexOf(context) === 0 ? 1 : 0.7;
|
|
2249
|
+
const intensityFit = 1 - Math.abs(preset.metadata.intensity - 3) / 4;
|
|
2250
|
+
const score = (contextFit + intensityFit) / 2;
|
|
2251
|
+
return {
|
|
2252
|
+
preset,
|
|
2253
|
+
name,
|
|
2254
|
+
reason: `${preset.metadata.description}. Ideal for ${preset.metadata.context.slice(0, 2).join(", ")}.`,
|
|
2255
|
+
score
|
|
2256
|
+
};
|
|
2257
|
+
});
|
|
2258
|
+
return recommendations.filter((r) => r.score >= minScore).sort((a, b) => b.score - a.score).slice(0, maxResults);
|
|
2259
|
+
}
|
|
2260
|
+
function getDefaultPreset(context) {
|
|
2261
|
+
const defaults = {
|
|
2262
|
+
modal: "scale",
|
|
2263
|
+
dropdown: "slideDown",
|
|
2264
|
+
tooltip: "fadeIn",
|
|
2265
|
+
drawer: "slideRight",
|
|
2266
|
+
card: "fadeIn",
|
|
2267
|
+
"list-item": "slideUp",
|
|
2268
|
+
notification: "slideRight",
|
|
2269
|
+
page: "fadeIn",
|
|
2270
|
+
section: "slideUp",
|
|
2271
|
+
hero: "slideUpScale"
|
|
2272
|
+
};
|
|
2273
|
+
return componentPresets[defaults[context]];
|
|
2274
|
+
}
|
|
2275
|
+
function suggestAnimations(context, style = "standard") {
|
|
2276
|
+
const entranceResult = selectPreset({
|
|
2277
|
+
useCase: "entrance",
|
|
2278
|
+
context,
|
|
2279
|
+
style
|
|
2280
|
+
});
|
|
2281
|
+
const exitResult = selectPreset({
|
|
2282
|
+
useCase: "exit",
|
|
2283
|
+
context,
|
|
2284
|
+
style
|
|
2285
|
+
});
|
|
2286
|
+
return {
|
|
2287
|
+
entrance: entranceResult.preset,
|
|
2288
|
+
entranceName: entranceResult.presetName,
|
|
2289
|
+
exit: exitResult.preset,
|
|
2290
|
+
exitName: exitResult.presetName,
|
|
2291
|
+
style
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
function getAllPresetNames() {
|
|
2295
|
+
return Object.keys(componentPresets);
|
|
2296
|
+
}
|
|
2297
|
+
function getAllContexts() {
|
|
2298
|
+
return ["modal", "dropdown", "tooltip", "drawer", "card", "list-item", "notification", "page", "section", "hero"];
|
|
2299
|
+
}
|
|
2300
|
+
function getAllUseCases() {
|
|
2301
|
+
return ["entrance", "exit", "transition", "emphasis", "reveal"];
|
|
2302
|
+
}
|
|
2303
|
+
function getPresetMetadata(name) {
|
|
2304
|
+
return componentPresets[name].metadata;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
// src/utils/spring-configs.ts
|
|
2308
|
+
var springGentle = {
|
|
2309
|
+
type: "spring",
|
|
2310
|
+
stiffness: 200,
|
|
2311
|
+
damping: 30,
|
|
2312
|
+
mass: 1
|
|
2313
|
+
};
|
|
2314
|
+
var springSnappy = {
|
|
2315
|
+
type: "spring",
|
|
2316
|
+
stiffness: 400,
|
|
2317
|
+
damping: 30,
|
|
2318
|
+
mass: 0.8
|
|
2319
|
+
};
|
|
2320
|
+
var springBouncy = {
|
|
2321
|
+
type: "spring",
|
|
2322
|
+
stiffness: 300,
|
|
2323
|
+
damping: 15,
|
|
2324
|
+
mass: 1
|
|
2325
|
+
};
|
|
2326
|
+
var springStiff = {
|
|
2327
|
+
type: "spring",
|
|
2328
|
+
stiffness: 500,
|
|
2329
|
+
damping: 35,
|
|
2330
|
+
mass: 0.6
|
|
2331
|
+
};
|
|
2332
|
+
function createSpring(stiffness, damping, mass) {
|
|
2333
|
+
return {
|
|
2334
|
+
type: "spring",
|
|
2335
|
+
stiffness,
|
|
2336
|
+
damping,
|
|
2337
|
+
mass
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
function createSpringFromParams(params) {
|
|
2341
|
+
return {
|
|
2342
|
+
type: "spring",
|
|
2343
|
+
stiffness: params.stiffness,
|
|
2344
|
+
damping: params.damping,
|
|
2345
|
+
mass: params.mass
|
|
2346
|
+
};
|
|
2347
|
+
}
|
|
2348
|
+
var springPresets = {
|
|
2349
|
+
gentle: springGentle,
|
|
2350
|
+
snappy: springSnappy,
|
|
2351
|
+
bouncy: springBouncy,
|
|
2352
|
+
stiff: springStiff
|
|
2353
|
+
};
|
|
150
2354
|
export {
|
|
2355
|
+
CountUp,
|
|
2356
|
+
INSTANT_TRANSITION,
|
|
2357
|
+
MotionDiv,
|
|
2358
|
+
REDUCED_MOTION_QUERY,
|
|
2359
|
+
StaggerContainer,
|
|
151
2360
|
ambientPaths,
|
|
152
2361
|
applyMotionPreset,
|
|
2362
|
+
badgePop,
|
|
2363
|
+
boldStyle,
|
|
2364
|
+
buttonPress,
|
|
2365
|
+
calculateStaggerDelays,
|
|
2366
|
+
cardHover,
|
|
2367
|
+
cascadeStagger,
|
|
2368
|
+
checkReducedMotion,
|
|
2369
|
+
checkmarkDraw,
|
|
2370
|
+
componentPresets,
|
|
2371
|
+
createAccessibleMotionProps,
|
|
2372
|
+
createMotionProps,
|
|
2373
|
+
createReducedMotionProps,
|
|
2374
|
+
createSpring,
|
|
2375
|
+
createSpringFromParams,
|
|
2376
|
+
createTween,
|
|
2377
|
+
createTweenFromParams,
|
|
2378
|
+
durations,
|
|
2379
|
+
easeIn,
|
|
2380
|
+
easeInOut,
|
|
2381
|
+
easeInOutCubic,
|
|
2382
|
+
easeInOutQuint,
|
|
2383
|
+
easeOut,
|
|
2384
|
+
easeOutBack,
|
|
2385
|
+
easeOutExpo,
|
|
2386
|
+
easeOutQuart,
|
|
2387
|
+
easingPresets,
|
|
2388
|
+
expand,
|
|
2389
|
+
explodeStagger,
|
|
2390
|
+
fadeIn,
|
|
2391
|
+
fadeOut,
|
|
2392
|
+
findPresetsForUseCase,
|
|
2393
|
+
flip,
|
|
2394
|
+
getAllContexts,
|
|
2395
|
+
getAllPresetNames,
|
|
2396
|
+
getAllUseCases,
|
|
2397
|
+
getComponentPreset,
|
|
2398
|
+
getDefaultPreset,
|
|
2399
|
+
getDuration,
|
|
2400
|
+
getMicroInteraction,
|
|
2401
|
+
getMicroInteractionNames,
|
|
2402
|
+
getMotionStyle,
|
|
153
2403
|
getPreset,
|
|
2404
|
+
getPresetMetadata,
|
|
2405
|
+
getPresetsByContext,
|
|
2406
|
+
getPresetsByUseCase,
|
|
2407
|
+
getRecommendations,
|
|
2408
|
+
getReducedMotionVariant,
|
|
2409
|
+
getSpringConfig,
|
|
2410
|
+
getStaggerPreset,
|
|
2411
|
+
glowPulse,
|
|
2412
|
+
gridStagger,
|
|
2413
|
+
heartbeat,
|
|
2414
|
+
iconSpin,
|
|
154
2415
|
lightRays,
|
|
155
|
-
|
|
2416
|
+
linear,
|
|
2417
|
+
microInteractions,
|
|
2418
|
+
motionStyles,
|
|
2419
|
+
msToSeconds,
|
|
2420
|
+
playfulStyle,
|
|
2421
|
+
progressFill,
|
|
2422
|
+
pulse,
|
|
2423
|
+
rotate,
|
|
2424
|
+
rubberBand,
|
|
2425
|
+
scale,
|
|
2426
|
+
scale2 as scaleMicro,
|
|
2427
|
+
selectPreset,
|
|
2428
|
+
shake,
|
|
2429
|
+
shimmer,
|
|
2430
|
+
slideDown,
|
|
2431
|
+
slideLeft,
|
|
2432
|
+
slideRight,
|
|
2433
|
+
slideUp,
|
|
2434
|
+
slideUpScale,
|
|
2435
|
+
springBouncy,
|
|
2436
|
+
springGentle,
|
|
2437
|
+
springPresets,
|
|
2438
|
+
springSnappy,
|
|
2439
|
+
springStiff,
|
|
2440
|
+
staggerCascade,
|
|
2441
|
+
staggerCenter,
|
|
2442
|
+
staggerGrid,
|
|
2443
|
+
staggerPresets,
|
|
2444
|
+
staggerRandom,
|
|
2445
|
+
staggerReverse,
|
|
2446
|
+
staggerSequential,
|
|
2447
|
+
staggerWave,
|
|
2448
|
+
standardStyle,
|
|
2449
|
+
subtleStyle,
|
|
2450
|
+
successFlash,
|
|
2451
|
+
suggestAnimations,
|
|
2452
|
+
tweenPresets,
|
|
2453
|
+
useAnimationVariants,
|
|
2454
|
+
useComponentAnimation,
|
|
2455
|
+
useCountUp,
|
|
2456
|
+
useDelayedAnimation,
|
|
2457
|
+
useDrawPath,
|
|
2458
|
+
useMotionPreset,
|
|
2459
|
+
useReducedMotion2 as useReducedMotion,
|
|
2460
|
+
useStagger,
|
|
2461
|
+
waveStagger,
|
|
2462
|
+
wiggle,
|
|
2463
|
+
withStagger,
|
|
2464
|
+
zoomIn,
|
|
2465
|
+
zoomOut
|
|
156
2466
|
};
|
|
157
2467
|
//# sourceMappingURL=index.mjs.map
|