@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
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
// Copyright (c) 2026 Amsterdam Data Labs
|
|
2
|
+
import { getMotionStyle, msToSeconds } from "./motion-styles";
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the user prefers reduced motion.
|
|
5
|
+
* Returns true if reduced motion is preferred, false otherwise.
|
|
6
|
+
*
|
|
7
|
+
* @returns Whether reduced motion is preferred
|
|
8
|
+
*/
|
|
9
|
+
function prefersReducedMotion() {
|
|
10
|
+
if (typeof window === "undefined")
|
|
11
|
+
return false;
|
|
12
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns empty props for reduced motion scenarios.
|
|
16
|
+
* Animations are disabled while maintaining component functionality.
|
|
17
|
+
*/
|
|
18
|
+
function getReducedMotionProps() {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// BUTTON PRESS PRESET
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Button Press Micro-Interaction
|
|
26
|
+
*
|
|
27
|
+
* Creates a subtle press effect where the element scales down slightly when clicked
|
|
28
|
+
* and springs back to its original size on release. Provides tactile feedback for
|
|
29
|
+
* interactive elements.
|
|
30
|
+
*
|
|
31
|
+
* @ai-hint Use buttonPress for clickable elements like buttons, cards, or list items
|
|
32
|
+
* that need tactile feedback. Best for primary actions and interactive controls.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* import { motion } from "motion/react";
|
|
37
|
+
* import { buttonPress } from "@enact-ui/animate";
|
|
38
|
+
*
|
|
39
|
+
* function Button({ children }) {
|
|
40
|
+
* const props = buttonPress.getProps("standard");
|
|
41
|
+
* return <motion.button {...props}>{children}</motion.button>;
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export const buttonPress = {
|
|
46
|
+
name: "buttonPress",
|
|
47
|
+
description: "Scale down slightly on press, spring back on release",
|
|
48
|
+
useCase: ["buttons", "clickable cards", "list items", "interactive elements", "call-to-action"],
|
|
49
|
+
getProps: (style) => {
|
|
50
|
+
if (prefersReducedMotion())
|
|
51
|
+
return getReducedMotionProps();
|
|
52
|
+
const config = getMotionStyle(style);
|
|
53
|
+
const scaleAmount = style === "subtle" ? 0.98 : style === "playful" ? 0.92 : 0.95;
|
|
54
|
+
return {
|
|
55
|
+
whileTap: {
|
|
56
|
+
scale: scaleAmount,
|
|
57
|
+
},
|
|
58
|
+
whileHover: {
|
|
59
|
+
scale: style === "subtle" ? 1.01 : 1.02,
|
|
60
|
+
},
|
|
61
|
+
transition: {
|
|
62
|
+
type: "spring",
|
|
63
|
+
stiffness: config.spring.stiffness,
|
|
64
|
+
damping: config.spring.damping,
|
|
65
|
+
mass: config.spring.mass,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// CARD HOVER PRESET
|
|
72
|
+
// =============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Card Hover Micro-Interaction
|
|
75
|
+
*
|
|
76
|
+
* Creates a subtle lift effect with shadow enhancement when hovering over card-like
|
|
77
|
+
* elements. Provides visual depth and indicates interactivity.
|
|
78
|
+
*
|
|
79
|
+
* @ai-hint Use cardHover for cards, tiles, or panels that are clickable or expandable.
|
|
80
|
+
* Creates a "lifting" effect that suggests the element can be interacted with.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* import { motion } from "motion/react";
|
|
85
|
+
* import { cardHover } from "@enact-ui/animate";
|
|
86
|
+
*
|
|
87
|
+
* function Card({ children }) {
|
|
88
|
+
* const props = cardHover.getProps("standard");
|
|
89
|
+
* return <motion.article {...props}>{children}</motion.article>;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export const cardHover = {
|
|
94
|
+
name: "cardHover",
|
|
95
|
+
description: "Subtle lift with shadow enhancement on hover",
|
|
96
|
+
useCase: ["cards", "tiles", "panels", "content blocks", "media items", "product listings"],
|
|
97
|
+
getProps: (style) => {
|
|
98
|
+
if (prefersReducedMotion())
|
|
99
|
+
return getReducedMotionProps();
|
|
100
|
+
const config = getMotionStyle(style);
|
|
101
|
+
const liftAmount = style === "subtle" ? -2 : style === "playful" ? -8 : -4;
|
|
102
|
+
const shadowIntensity = style === "subtle" ? 0.08 : style === "playful" ? 0.2 : 0.12;
|
|
103
|
+
return {
|
|
104
|
+
whileHover: {
|
|
105
|
+
y: liftAmount,
|
|
106
|
+
boxShadow: `0 ${Math.abs(liftAmount) * 2}px ${Math.abs(liftAmount) * 4}px rgba(0, 0, 0, ${shadowIntensity})`,
|
|
107
|
+
},
|
|
108
|
+
transition: {
|
|
109
|
+
type: "spring",
|
|
110
|
+
stiffness: config.spring.stiffness,
|
|
111
|
+
damping: config.spring.damping,
|
|
112
|
+
mass: config.spring.mass,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
// =============================================================================
|
|
118
|
+
// ICON SPIN PRESET
|
|
119
|
+
// =============================================================================
|
|
120
|
+
/**
|
|
121
|
+
* Icon Spin Micro-Interaction
|
|
122
|
+
*
|
|
123
|
+
* Performs a full 360-degree rotation, ideal for refresh icons, loading indicators,
|
|
124
|
+
* or interactive feedback on icon clicks.
|
|
125
|
+
*
|
|
126
|
+
* @ai-hint Use iconSpin for refresh buttons, sync icons, or loading states.
|
|
127
|
+
* Good for indicating an action is in progress or for playful icon interactions.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```tsx
|
|
131
|
+
* import { motion } from "motion/react";
|
|
132
|
+
* import { iconSpin } from "@enact-ui/animate";
|
|
133
|
+
*
|
|
134
|
+
* function RefreshButton() {
|
|
135
|
+
* const props = iconSpin.getProps("standard");
|
|
136
|
+
* return (
|
|
137
|
+
* <motion.button {...props}>
|
|
138
|
+
* <RefreshIcon />
|
|
139
|
+
* </motion.button>
|
|
140
|
+
* );
|
|
141
|
+
* }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export const iconSpin = {
|
|
145
|
+
name: "iconSpin",
|
|
146
|
+
description: "360 degree rotation animation",
|
|
147
|
+
useCase: ["refresh buttons", "sync icons", "loading indicators", "settings icons", "interactive icons"],
|
|
148
|
+
getProps: (style) => {
|
|
149
|
+
if (prefersReducedMotion())
|
|
150
|
+
return getReducedMotionProps();
|
|
151
|
+
const config = getMotionStyle(style);
|
|
152
|
+
return {
|
|
153
|
+
whileTap: {
|
|
154
|
+
rotate: 360,
|
|
155
|
+
},
|
|
156
|
+
whileHover: {
|
|
157
|
+
rotate: style === "playful" ? 15 : 5,
|
|
158
|
+
},
|
|
159
|
+
transition: {
|
|
160
|
+
type: "spring",
|
|
161
|
+
stiffness: config.spring.stiffness * 0.8,
|
|
162
|
+
damping: config.spring.damping,
|
|
163
|
+
mass: config.spring.mass,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// PULSE PRESET
|
|
170
|
+
// =============================================================================
|
|
171
|
+
/**
|
|
172
|
+
* Pulse Micro-Interaction
|
|
173
|
+
*
|
|
174
|
+
* Creates a breathing/pulsing scale animation. Can be used for attention-grabbing
|
|
175
|
+
* elements, loading states, or to indicate something is active/live.
|
|
176
|
+
*
|
|
177
|
+
* @ai-hint Use pulse for notifications, live indicators, or elements needing attention.
|
|
178
|
+
* The breathing effect draws the eye without being too distracting.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```tsx
|
|
182
|
+
* import { motion } from "motion/react";
|
|
183
|
+
* import { pulse } from "@enact-ui/animate";
|
|
184
|
+
*
|
|
185
|
+
* function LiveIndicator() {
|
|
186
|
+
* const props = pulse.getProps("standard");
|
|
187
|
+
* return <motion.span {...props} className="live-dot" />;
|
|
188
|
+
* }
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export const pulse = {
|
|
192
|
+
name: "pulse",
|
|
193
|
+
description: "Scale pulse animation with breathing effect",
|
|
194
|
+
useCase: ["notifications", "live indicators", "attention grabbers", "status badges", "loading states"],
|
|
195
|
+
getProps: (style) => {
|
|
196
|
+
if (prefersReducedMotion())
|
|
197
|
+
return getReducedMotionProps();
|
|
198
|
+
const config = getMotionStyle(style);
|
|
199
|
+
const scaleRange = style === "subtle" ? 1.03 : style === "playful" ? 1.12 : 1.06;
|
|
200
|
+
return {
|
|
201
|
+
initial: {
|
|
202
|
+
scale: 1,
|
|
203
|
+
},
|
|
204
|
+
animate: {
|
|
205
|
+
scale: [1, scaleRange, 1],
|
|
206
|
+
},
|
|
207
|
+
transition: {
|
|
208
|
+
duration: msToSeconds(config.duration.slow),
|
|
209
|
+
repeat: Infinity,
|
|
210
|
+
ease: config.easing.interactive,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
// =============================================================================
|
|
216
|
+
// SHAKE PRESET
|
|
217
|
+
// =============================================================================
|
|
218
|
+
/**
|
|
219
|
+
* Shake Micro-Interaction
|
|
220
|
+
*
|
|
221
|
+
* Horizontal shake animation commonly used for error states, invalid input,
|
|
222
|
+
* or to indicate that an action cannot be completed.
|
|
223
|
+
*
|
|
224
|
+
* @ai-hint Use shake for error states, invalid form inputs, or denied actions.
|
|
225
|
+
* The horizontal movement mimics the "no" head shake gesture.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```tsx
|
|
229
|
+
* import { motion } from "motion/react";
|
|
230
|
+
* import { shake } from "@enact-ui/animate";
|
|
231
|
+
*
|
|
232
|
+
* function FormInput({ error }) {
|
|
233
|
+
* const props = error ? shake.getProps("standard") : {};
|
|
234
|
+
* return <motion.input {...props} />;
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export const shake = {
|
|
239
|
+
name: "shake",
|
|
240
|
+
description: "Horizontal shake animation for error states",
|
|
241
|
+
useCase: ["error states", "invalid inputs", "denied actions", "form validation", "authentication failures"],
|
|
242
|
+
getProps: (style) => {
|
|
243
|
+
if (prefersReducedMotion())
|
|
244
|
+
return getReducedMotionProps();
|
|
245
|
+
const config = getMotionStyle(style);
|
|
246
|
+
const shakeDistance = style === "subtle" ? 4 : style === "playful" ? 12 : 8;
|
|
247
|
+
return {
|
|
248
|
+
initial: {
|
|
249
|
+
x: 0,
|
|
250
|
+
},
|
|
251
|
+
animate: {
|
|
252
|
+
x: [0, -shakeDistance, shakeDistance, -shakeDistance, shakeDistance, 0],
|
|
253
|
+
},
|
|
254
|
+
transition: {
|
|
255
|
+
duration: msToSeconds(config.duration.fast),
|
|
256
|
+
ease: config.easing.interactive,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
// =============================================================================
|
|
262
|
+
// WIGGLE PRESET
|
|
263
|
+
// =============================================================================
|
|
264
|
+
/**
|
|
265
|
+
* Wiggle Micro-Interaction
|
|
266
|
+
*
|
|
267
|
+
* Playful rotation wiggle animation. Great for drawing attention to elements
|
|
268
|
+
* in a fun, non-intrusive way. Often used in gamified interfaces or
|
|
269
|
+
* celebratory moments.
|
|
270
|
+
*
|
|
271
|
+
* @ai-hint Use wiggle for playful interfaces, gamification, or to draw attention
|
|
272
|
+
* to elements in a fun way. Works well for icons, badges, or decorative elements.
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```tsx
|
|
276
|
+
* import { motion } from "motion/react";
|
|
277
|
+
* import { wiggle } from "@enact-ui/animate";
|
|
278
|
+
*
|
|
279
|
+
* function AchievementBadge() {
|
|
280
|
+
* const props = wiggle.getProps("playful");
|
|
281
|
+
* return <motion.div {...props}><BadgeIcon /></motion.div>;
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export const wiggle = {
|
|
286
|
+
name: "wiggle",
|
|
287
|
+
description: "Playful rotation wiggle animation",
|
|
288
|
+
useCase: ["playful interfaces", "gamification", "attention indicators", "celebration elements", "decorative icons"],
|
|
289
|
+
getProps: (style) => {
|
|
290
|
+
if (prefersReducedMotion())
|
|
291
|
+
return getReducedMotionProps();
|
|
292
|
+
const config = getMotionStyle(style);
|
|
293
|
+
const wiggleAngle = style === "subtle" ? 3 : style === "playful" ? 12 : 6;
|
|
294
|
+
return {
|
|
295
|
+
whileHover: {
|
|
296
|
+
rotate: [0, -wiggleAngle, wiggleAngle, -wiggleAngle, wiggleAngle, 0],
|
|
297
|
+
},
|
|
298
|
+
transition: {
|
|
299
|
+
duration: msToSeconds(config.duration.normal),
|
|
300
|
+
ease: config.easing.interactive,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
// =============================================================================
|
|
306
|
+
// HEARTBEAT PRESET
|
|
307
|
+
// =============================================================================
|
|
308
|
+
/**
|
|
309
|
+
* Heartbeat Micro-Interaction
|
|
310
|
+
*
|
|
311
|
+
* Double-pulse heartbeat pattern that creates a realistic heartbeat effect.
|
|
312
|
+
* Perfect for health apps, like buttons, or emphasizing something "alive".
|
|
313
|
+
*
|
|
314
|
+
* @ai-hint Use heartbeat for health/fitness apps, like/love buttons, or to indicate
|
|
315
|
+
* something is active/alive. The double-pulse mimics a real heartbeat rhythm.
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```tsx
|
|
319
|
+
* import { motion } from "motion/react";
|
|
320
|
+
* import { heartbeat } from "@enact-ui/animate";
|
|
321
|
+
*
|
|
322
|
+
* function LikeButton({ isLiked }) {
|
|
323
|
+
* const props = isLiked ? heartbeat.getProps("playful") : {};
|
|
324
|
+
* return <motion.button {...props}><HeartIcon /></motion.button>;
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export const heartbeat = {
|
|
329
|
+
name: "heartbeat",
|
|
330
|
+
description: "Double-pulse heartbeat pattern animation",
|
|
331
|
+
useCase: ["like buttons", "health apps", "love reactions", "favorite indicators", "activity monitors"],
|
|
332
|
+
getProps: (style) => {
|
|
333
|
+
if (prefersReducedMotion())
|
|
334
|
+
return getReducedMotionProps();
|
|
335
|
+
const config = getMotionStyle(style);
|
|
336
|
+
const pulseScale = style === "subtle" ? 1.1 : style === "playful" ? 1.3 : 1.2;
|
|
337
|
+
return {
|
|
338
|
+
initial: {
|
|
339
|
+
scale: 1,
|
|
340
|
+
},
|
|
341
|
+
animate: {
|
|
342
|
+
scale: [1, pulseScale, 1, pulseScale * 0.95, 1],
|
|
343
|
+
},
|
|
344
|
+
transition: {
|
|
345
|
+
duration: msToSeconds(config.duration.slow * 1.5),
|
|
346
|
+
repeat: Infinity,
|
|
347
|
+
repeatDelay: msToSeconds(config.duration.normal),
|
|
348
|
+
ease: config.easing.interactive,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
// =============================================================================
|
|
354
|
+
// RUBBER BAND PRESET
|
|
355
|
+
// =============================================================================
|
|
356
|
+
/**
|
|
357
|
+
* Rubber Band Micro-Interaction
|
|
358
|
+
*
|
|
359
|
+
* Elastic stretch and snap back animation inspired by the classic rubber band effect.
|
|
360
|
+
* Creates a bouncy, playful feel that's perfect for attention-grabbing elements.
|
|
361
|
+
*
|
|
362
|
+
* @ai-hint Use rubberBand for emphasis animations, attention grabbers, or playful
|
|
363
|
+
* interfaces. The elastic effect creates a memorable, tactile impression.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```tsx
|
|
367
|
+
* import { motion } from "motion/react";
|
|
368
|
+
* import { rubberBand } from "@enact-ui/animate";
|
|
369
|
+
*
|
|
370
|
+
* function BouncyButton({ children }) {
|
|
371
|
+
* const props = rubberBand.getProps("playful");
|
|
372
|
+
* return <motion.button {...props}>{children}</motion.button>;
|
|
373
|
+
* }
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
export const rubberBand = {
|
|
377
|
+
name: "rubberBand",
|
|
378
|
+
description: "Elastic stretch and snap back animation",
|
|
379
|
+
useCase: ["emphasis animations", "attention grabbers", "playful buttons", "celebration effects", "interactive feedback"],
|
|
380
|
+
getProps: (style) => {
|
|
381
|
+
if (prefersReducedMotion())
|
|
382
|
+
return getReducedMotionProps();
|
|
383
|
+
const config = getMotionStyle(style);
|
|
384
|
+
const stretchX = style === "subtle" ? 1.05 : style === "playful" ? 1.25 : 1.15;
|
|
385
|
+
const stretchY = style === "subtle" ? 0.95 : style === "playful" ? 0.75 : 0.85;
|
|
386
|
+
return {
|
|
387
|
+
whileTap: {
|
|
388
|
+
scaleX: [1, stretchX, 0.95, 1.05, 1],
|
|
389
|
+
scaleY: [1, stretchY, 1.05, 0.95, 1],
|
|
390
|
+
},
|
|
391
|
+
whileHover: {
|
|
392
|
+
scaleX: 1.02,
|
|
393
|
+
scaleY: 0.98,
|
|
394
|
+
},
|
|
395
|
+
transition: {
|
|
396
|
+
type: "spring",
|
|
397
|
+
stiffness: config.spring.stiffness * 0.6,
|
|
398
|
+
damping: config.spring.damping * 0.5,
|
|
399
|
+
mass: config.spring.mass,
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
// =============================================================================
|
|
405
|
+
// SCALE PRESET (Micro-Interaction)
|
|
406
|
+
// =============================================================================
|
|
407
|
+
/**
|
|
408
|
+
* Scale Micro-Interaction
|
|
409
|
+
*
|
|
410
|
+
* Creates a scale animation effect for selection feedback. The element scales up
|
|
411
|
+
* briefly when activated, providing satisfying tactile feedback for toggles,
|
|
412
|
+
* checkboxes, and selection states.
|
|
413
|
+
*
|
|
414
|
+
* @ai-hint Use scale for checkboxes, toggles, radio buttons, or any selection
|
|
415
|
+
* feedback. The scale effect provides clear visual confirmation of state change.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```tsx
|
|
419
|
+
* import { motion } from "motion/react";
|
|
420
|
+
* import { scale } from "@enact-ui/animate";
|
|
421
|
+
*
|
|
422
|
+
* function Checkbox({ isSelected }) {
|
|
423
|
+
* const props = isSelected ? scale.getProps("standard") : {};
|
|
424
|
+
* return <motion.div {...props}>{isSelected && <Check />}</motion.div>;
|
|
425
|
+
* }
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
export const scale = {
|
|
429
|
+
name: "scale",
|
|
430
|
+
description: "Scale up animation for selection feedback",
|
|
431
|
+
useCase: ["checkboxes", "toggles", "radio buttons", "selection states", "activation feedback"],
|
|
432
|
+
getProps: (style) => {
|
|
433
|
+
if (prefersReducedMotion())
|
|
434
|
+
return getReducedMotionProps();
|
|
435
|
+
const config = getMotionStyle(style);
|
|
436
|
+
const scaleAmount = style === "subtle" ? 1.05 : style === "playful" ? 1.2 : 1.1;
|
|
437
|
+
return {
|
|
438
|
+
initial: {
|
|
439
|
+
scale: 0.8,
|
|
440
|
+
opacity: 0,
|
|
441
|
+
},
|
|
442
|
+
animate: {
|
|
443
|
+
scale: [0.8, scaleAmount, 1],
|
|
444
|
+
opacity: 1,
|
|
445
|
+
},
|
|
446
|
+
transition: {
|
|
447
|
+
type: "spring",
|
|
448
|
+
stiffness: config.spring.stiffness,
|
|
449
|
+
damping: config.spring.damping,
|
|
450
|
+
mass: config.spring.mass,
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
// =============================================================================
|
|
456
|
+
// SHIMMER PRESET
|
|
457
|
+
// =============================================================================
|
|
458
|
+
/**
|
|
459
|
+
* Shimmer Micro-Interaction
|
|
460
|
+
*
|
|
461
|
+
* Creates a gradient shimmer effect that slides across the element.
|
|
462
|
+
* Perfect for loading skeletons, progress indicators, or placeholder content.
|
|
463
|
+
*
|
|
464
|
+
* @ai-hint Use shimmer for skeleton loading states, progress bars, or placeholder
|
|
465
|
+
* content. Creates a polished "loading" appearance that indicates content is coming.
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```tsx
|
|
469
|
+
* import { motion } from "motion/react";
|
|
470
|
+
* import { shimmer } from "@enact-ui/animate";
|
|
471
|
+
*
|
|
472
|
+
* function SkeletonCard() {
|
|
473
|
+
* const props = shimmer.getProps("standard");
|
|
474
|
+
* return (
|
|
475
|
+
* <motion.div
|
|
476
|
+
* {...props}
|
|
477
|
+
* className="h-20 bg-gray-200 rounded overflow-hidden relative"
|
|
478
|
+
* style={{
|
|
479
|
+
* background: "linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)",
|
|
480
|
+
* backgroundSize: "200% 100%",
|
|
481
|
+
* }}
|
|
482
|
+
* />
|
|
483
|
+
* );
|
|
484
|
+
* }
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
487
|
+
export const shimmer = {
|
|
488
|
+
name: "shimmer",
|
|
489
|
+
description: "Gradient shimmer effect that slides across the element",
|
|
490
|
+
useCase: ["skeleton loading", "placeholder content", "progress indicators", "loading states", "content placeholders"],
|
|
491
|
+
getProps: (style) => {
|
|
492
|
+
if (prefersReducedMotion())
|
|
493
|
+
return getReducedMotionProps();
|
|
494
|
+
const config = getMotionStyle(style);
|
|
495
|
+
const duration = style === "subtle" ? 2 : style === "playful" ? 1.2 : 1.5;
|
|
496
|
+
return {
|
|
497
|
+
initial: {
|
|
498
|
+
backgroundPosition: "200% 0",
|
|
499
|
+
},
|
|
500
|
+
animate: {
|
|
501
|
+
backgroundPosition: ["-200% 0", "200% 0"],
|
|
502
|
+
},
|
|
503
|
+
transition: {
|
|
504
|
+
duration,
|
|
505
|
+
repeat: Infinity,
|
|
506
|
+
ease: config.easing.exit,
|
|
507
|
+
repeatDelay: 0.5,
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
// =============================================================================
|
|
513
|
+
// GLOW PULSE PRESET
|
|
514
|
+
// =============================================================================
|
|
515
|
+
/**
|
|
516
|
+
* Glow Pulse Micro-Interaction
|
|
517
|
+
*
|
|
518
|
+
* Creates a glowing pulse effect using box-shadow. Perfect for AI-generated
|
|
519
|
+
* content indicators, special items, or elements that need extra emphasis.
|
|
520
|
+
*
|
|
521
|
+
* @ai-hint Use glowPulse for AI content indicators, featured items, or elements
|
|
522
|
+
* needing premium emphasis. The glow effect creates a "magical" or "special" feel.
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```tsx
|
|
526
|
+
* import { motion } from "motion/react";
|
|
527
|
+
* import { glowPulse } from "@enact-ui/animate";
|
|
528
|
+
*
|
|
529
|
+
* function AIGeneratedBadge() {
|
|
530
|
+
* const props = glowPulse.getProps("standard");
|
|
531
|
+
* return <motion.span {...props} className="ai-badge">AI</motion.span>;
|
|
532
|
+
* }
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
export const glowPulse = {
|
|
536
|
+
name: "glowPulse",
|
|
537
|
+
description: "Glowing pulse effect for emphasis and AI indicators",
|
|
538
|
+
useCase: ["AI content indicators", "featured items", "premium elements", "special badges", "magical effects"],
|
|
539
|
+
getProps: (style) => {
|
|
540
|
+
if (prefersReducedMotion())
|
|
541
|
+
return getReducedMotionProps();
|
|
542
|
+
const config = getMotionStyle(style);
|
|
543
|
+
const glowIntensity = style === "subtle" ? 8 : style === "playful" ? 20 : 12;
|
|
544
|
+
const glowColor = "rgba(99, 102, 241, 0.6)"; // Indigo glow
|
|
545
|
+
return {
|
|
546
|
+
initial: {
|
|
547
|
+
boxShadow: `0 0 0 rgba(99, 102, 241, 0)`,
|
|
548
|
+
},
|
|
549
|
+
animate: {
|
|
550
|
+
boxShadow: [`0 0 0 rgba(99, 102, 241, 0)`, `0 0 ${glowIntensity}px ${glowColor}`, `0 0 0 rgba(99, 102, 241, 0)`],
|
|
551
|
+
},
|
|
552
|
+
transition: {
|
|
553
|
+
duration: msToSeconds(config.duration.slow * 1.5),
|
|
554
|
+
repeat: Infinity,
|
|
555
|
+
ease: config.easing.interactive,
|
|
556
|
+
},
|
|
557
|
+
};
|
|
558
|
+
},
|
|
559
|
+
};
|
|
560
|
+
// =============================================================================
|
|
561
|
+
// PROGRESS FILL PRESET
|
|
562
|
+
// =============================================================================
|
|
563
|
+
/**
|
|
564
|
+
* Progress Fill Micro-Interaction
|
|
565
|
+
*
|
|
566
|
+
* Animates width from 0% to the target value. Perfect for progress bars,
|
|
567
|
+
* completion indicators, and skill bars.
|
|
568
|
+
*
|
|
569
|
+
* Note: This preset returns a function that takes the target percentage
|
|
570
|
+
* and returns animation props. Use with scaleX transform for best performance.
|
|
571
|
+
*
|
|
572
|
+
* @ai-hint Use progressFill for progress bars, skill meters, or completion
|
|
573
|
+
* indicators. Animates smoothly from 0 to the target percentage.
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* ```tsx
|
|
577
|
+
* import { motion } from "motion/react";
|
|
578
|
+
* import { progressFill } from "@enact-ui/animate";
|
|
579
|
+
*
|
|
580
|
+
* function ProgressBar({ value }: { value: number }) {
|
|
581
|
+
* const props = progressFill.getProps("standard");
|
|
582
|
+
* return (
|
|
583
|
+
* <div className="h-2 bg-gray-200 rounded overflow-hidden">
|
|
584
|
+
* <motion.div
|
|
585
|
+
* {...props}
|
|
586
|
+
* className="h-full bg-blue-500 origin-left"
|
|
587
|
+
* style={{ width: `${value}%` }}
|
|
588
|
+
* />
|
|
589
|
+
* </div>
|
|
590
|
+
* );
|
|
591
|
+
* }
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
export const progressFill = {
|
|
595
|
+
name: "progressFill",
|
|
596
|
+
description: "Animated fill from 0% to target width for progress bars",
|
|
597
|
+
useCase: ["progress bars", "completion indicators", "skill bars", "loading progress", "data visualization"],
|
|
598
|
+
getProps: (style) => {
|
|
599
|
+
if (prefersReducedMotion())
|
|
600
|
+
return getReducedMotionProps();
|
|
601
|
+
const config = getMotionStyle(style);
|
|
602
|
+
const duration = style === "subtle" ? 0.6 : style === "playful" ? 1.2 : 0.8;
|
|
603
|
+
return {
|
|
604
|
+
initial: {
|
|
605
|
+
scaleX: 0,
|
|
606
|
+
},
|
|
607
|
+
animate: {
|
|
608
|
+
scaleX: 1,
|
|
609
|
+
},
|
|
610
|
+
transition: {
|
|
611
|
+
duration,
|
|
612
|
+
ease: config.easing.exit,
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
// =============================================================================
|
|
618
|
+
// PRESET COLLECTION
|
|
619
|
+
// =============================================================================
|
|
620
|
+
/**
|
|
621
|
+
* All available micro-interaction presets indexed by name.
|
|
622
|
+
*
|
|
623
|
+
* @ai-hint Use this collection to iterate over all presets or to access
|
|
624
|
+
* presets by name dynamically. Each preset adapts to the motion style.
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```tsx
|
|
628
|
+
* import { microInteractions } from "@enact-ui/animate";
|
|
629
|
+
*
|
|
630
|
+
* // Get a specific preset by name
|
|
631
|
+
* const pressProps = microInteractions.buttonPress.getProps("standard");
|
|
632
|
+
*
|
|
633
|
+
* // List all available presets
|
|
634
|
+
* Object.keys(microInteractions).forEach(name => {
|
|
635
|
+
* console.log(microInteractions[name].description);
|
|
636
|
+
* });
|
|
637
|
+
* ```
|
|
638
|
+
*/
|
|
639
|
+
// =============================================================================
|
|
640
|
+
// CHECKMARK DRAW PRESET
|
|
641
|
+
// =============================================================================
|
|
642
|
+
/**
|
|
643
|
+
* Checkmark Draw Micro-Interaction
|
|
644
|
+
*
|
|
645
|
+
* Animated checkmark draw effect, commonly used for success states,
|
|
646
|
+
* completed tasks, or confirmation feedback.
|
|
647
|
+
*
|
|
648
|
+
* @ai-hint Use checkmarkDraw for success confirmations, completed checkboxes,
|
|
649
|
+
* or any "done" state indication. The drawing animation provides satisfying feedback.
|
|
650
|
+
*
|
|
651
|
+
* @example
|
|
652
|
+
* ```tsx
|
|
653
|
+
* import { motion } from "motion/react";
|
|
654
|
+
* import { checkmarkDraw } from "@enact-ui/animate";
|
|
655
|
+
*
|
|
656
|
+
* function SuccessIcon() {
|
|
657
|
+
* const props = checkmarkDraw.getProps("standard");
|
|
658
|
+
* return <motion.svg {...props}><path d="M5 13l4 4L19 7" /></motion.svg>;
|
|
659
|
+
* }
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
export const checkmarkDraw = {
|
|
663
|
+
name: "checkmarkDraw",
|
|
664
|
+
description: "Animated checkmark draw effect for success states",
|
|
665
|
+
useCase: ["success confirmations", "completed tasks", "checkboxes", "form submissions", "achievement unlocks"],
|
|
666
|
+
getProps: (style) => {
|
|
667
|
+
if (prefersReducedMotion())
|
|
668
|
+
return getReducedMotionProps();
|
|
669
|
+
const config = getMotionStyle(style);
|
|
670
|
+
const duration = style === "subtle" ? config.duration.fast : style === "playful" ? config.duration.slow : config.duration.normal;
|
|
671
|
+
return {
|
|
672
|
+
initial: {
|
|
673
|
+
pathLength: 0,
|
|
674
|
+
opacity: 0,
|
|
675
|
+
},
|
|
676
|
+
animate: {
|
|
677
|
+
pathLength: 1,
|
|
678
|
+
opacity: 1,
|
|
679
|
+
},
|
|
680
|
+
transition: {
|
|
681
|
+
duration: msToSeconds(duration),
|
|
682
|
+
ease: config.easing.interactive,
|
|
683
|
+
},
|
|
684
|
+
};
|
|
685
|
+
},
|
|
686
|
+
};
|
|
687
|
+
// =============================================================================
|
|
688
|
+
// SUCCESS FLASH PRESET
|
|
689
|
+
// =============================================================================
|
|
690
|
+
/**
|
|
691
|
+
* Success Flash Micro-Interaction
|
|
692
|
+
*
|
|
693
|
+
* Brief highlight flash animation for success feedback. Creates a quick
|
|
694
|
+
* visual confirmation without being distracting.
|
|
695
|
+
*
|
|
696
|
+
* @ai-hint Use successFlash for brief success highlights, toast notifications,
|
|
697
|
+
* or inline success messages. The flash draws attention without lingering.
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* ```tsx
|
|
701
|
+
* import { motion } from "motion/react";
|
|
702
|
+
* import { successFlash } from "@enact-ui/animate";
|
|
703
|
+
*
|
|
704
|
+
* function SuccessMessage() {
|
|
705
|
+
* const props = successFlash.getProps("standard");
|
|
706
|
+
* return <motion.div {...props}>Saved!</motion.div>;
|
|
707
|
+
* }
|
|
708
|
+
* ```
|
|
709
|
+
*/
|
|
710
|
+
export const successFlash = {
|
|
711
|
+
name: "successFlash",
|
|
712
|
+
description: "Brief success highlight flash animation",
|
|
713
|
+
useCase: ["success toasts", "inline confirmations", "save indicators", "completion feedback", "achievement notifications"],
|
|
714
|
+
getProps: (style) => {
|
|
715
|
+
if (prefersReducedMotion())
|
|
716
|
+
return getReducedMotionProps();
|
|
717
|
+
const config = getMotionStyle(style);
|
|
718
|
+
const scale = style === "subtle" ? 1.02 : style === "playful" ? 1.08 : 1.05;
|
|
719
|
+
return {
|
|
720
|
+
initial: {
|
|
721
|
+
scale: 1,
|
|
722
|
+
backgroundColor: "transparent",
|
|
723
|
+
},
|
|
724
|
+
animate: {
|
|
725
|
+
scale: [1, scale, 1],
|
|
726
|
+
backgroundColor: ["transparent", "var(--color-surface-success-subtle)", "transparent"],
|
|
727
|
+
},
|
|
728
|
+
transition: {
|
|
729
|
+
duration: msToSeconds(config.duration.fast),
|
|
730
|
+
ease: config.easing.interactive,
|
|
731
|
+
},
|
|
732
|
+
};
|
|
733
|
+
},
|
|
734
|
+
};
|
|
735
|
+
// =============================================================================
|
|
736
|
+
// BADGE POP PRESET
|
|
737
|
+
// =============================================================================
|
|
738
|
+
/**
|
|
739
|
+
* Badge Pop Micro-Interaction
|
|
740
|
+
*
|
|
741
|
+
* Pop animation for badge count changes. Provides satisfying feedback
|
|
742
|
+
* when numbers update, drawing attention to the change.
|
|
743
|
+
*
|
|
744
|
+
* @ai-hint Use badgePop for notification badges, count indicators, or any
|
|
745
|
+
* numeric value that changes. The pop effect highlights the update.
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
* ```tsx
|
|
749
|
+
* import { motion } from "motion/react";
|
|
750
|
+
* import { badgePop } from "@enact-ui/animate";
|
|
751
|
+
*
|
|
752
|
+
* function NotificationBadge({ count }) {
|
|
753
|
+
* const props = badgePop.getProps("standard");
|
|
754
|
+
* return <motion.span {...props} key={count}>{count}</motion.span>;
|
|
755
|
+
* }
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
export const badgePop = {
|
|
759
|
+
name: "badgePop",
|
|
760
|
+
description: "Pop animation for badge count changes",
|
|
761
|
+
useCase: ["notification badges", "count indicators", "numeric updates", "inventory changes", "score updates"],
|
|
762
|
+
getProps: (style) => {
|
|
763
|
+
if (prefersReducedMotion())
|
|
764
|
+
return getReducedMotionProps();
|
|
765
|
+
const config = getMotionStyle(style);
|
|
766
|
+
const scale = style === "subtle" ? 1.15 : style === "playful" ? 1.4 : 1.25;
|
|
767
|
+
return {
|
|
768
|
+
initial: {
|
|
769
|
+
scale: 0,
|
|
770
|
+
opacity: 0,
|
|
771
|
+
},
|
|
772
|
+
animate: {
|
|
773
|
+
scale: [0, scale, 1],
|
|
774
|
+
opacity: [0, 1, 1],
|
|
775
|
+
},
|
|
776
|
+
transition: {
|
|
777
|
+
duration: msToSeconds(config.duration.fast),
|
|
778
|
+
ease: config.easing.interactive,
|
|
779
|
+
},
|
|
780
|
+
};
|
|
781
|
+
},
|
|
782
|
+
};
|
|
783
|
+
// =============================================================================
|
|
784
|
+
// PRESET COLLECTION
|
|
785
|
+
// =============================================================================
|
|
786
|
+
export const microInteractions = {
|
|
787
|
+
buttonPress,
|
|
788
|
+
cardHover,
|
|
789
|
+
iconSpin,
|
|
790
|
+
pulse,
|
|
791
|
+
scale,
|
|
792
|
+
shake,
|
|
793
|
+
wiggle,
|
|
794
|
+
heartbeat,
|
|
795
|
+
rubberBand,
|
|
796
|
+
shimmer,
|
|
797
|
+
glowPulse,
|
|
798
|
+
progressFill,
|
|
799
|
+
checkmarkDraw,
|
|
800
|
+
successFlash,
|
|
801
|
+
badgePop,
|
|
802
|
+
};
|
|
803
|
+
/**
|
|
804
|
+
* Gets a micro-interaction preset by name.
|
|
805
|
+
*
|
|
806
|
+
* @param name - The name of the preset to retrieve
|
|
807
|
+
* @returns The micro-interaction preset, or undefined if not found
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```ts
|
|
811
|
+
* const preset = getMicroInteraction("buttonPress");
|
|
812
|
+
* if (preset) {
|
|
813
|
+
* const props = preset.getProps("standard");
|
|
814
|
+
* }
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
817
|
+
export function getMicroInteraction(name) {
|
|
818
|
+
return microInteractions[name];
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Gets all micro-interaction preset names.
|
|
822
|
+
*
|
|
823
|
+
* @returns Array of all preset names
|
|
824
|
+
*
|
|
825
|
+
* @example
|
|
826
|
+
* ```ts
|
|
827
|
+
* const names = getMicroInteractionNames();
|
|
828
|
+
* // ["buttonPress", "cardHover", "iconSpin", ...]
|
|
829
|
+
* ```
|
|
830
|
+
*/
|
|
831
|
+
export function getMicroInteractionNames() {
|
|
832
|
+
return Object.keys(microInteractions);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Finds micro-interaction presets suitable for a given use case.
|
|
836
|
+
*
|
|
837
|
+
* @param useCase - The use case to search for (case-insensitive)
|
|
838
|
+
* @returns Array of presets that match the use case
|
|
839
|
+
*
|
|
840
|
+
* @ai-hint Use this function to find appropriate presets based on your component's
|
|
841
|
+
* purpose. It searches the useCase arrays of all presets for matches.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```ts
|
|
845
|
+
* const errorPresets = findPresetsForUseCase("error");
|
|
846
|
+
* // Returns [shake] preset since it includes "error states" in its use cases
|
|
847
|
+
*
|
|
848
|
+
* const buttonPresets = findPresetsForUseCase("button");
|
|
849
|
+
* // Returns [buttonPress, rubberBand] presets
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
export function findPresetsForUseCase(useCase) {
|
|
853
|
+
const searchTerm = useCase.toLowerCase();
|
|
854
|
+
return Object.values(microInteractions).filter((preset) => preset.useCase.some((uc) => uc.toLowerCase().includes(searchTerm)));
|
|
855
|
+
}
|
|
856
|
+
//# sourceMappingURL=micro-interactions.js.map
|