@nice2dev/icons 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/LICENSE +21 -0
  3. package/README.md +581 -0
  4. package/dist/cjs/NiceIconPicker.js +387 -0
  5. package/dist/cjs/NiceIconPicker.js.map +1 -0
  6. package/dist/cjs/NiceVectorEditor.js +675 -0
  7. package/dist/cjs/NiceVectorEditor.js.map +1 -0
  8. package/dist/cjs/animationControls.js +690 -0
  9. package/dist/cjs/animationControls.js.map +1 -0
  10. package/dist/cjs/createIcon.js +142 -0
  11. package/dist/cjs/createIcon.js.map +1 -0
  12. package/dist/cjs/figmaExport.js +288 -0
  13. package/dist/cjs/figmaExport.js.map +1 -0
  14. package/dist/cjs/icons/actions.js +257 -0
  15. package/dist/cjs/icons/actions.js.map +1 -0
  16. package/dist/cjs/icons/brand.js +128 -0
  17. package/dist/cjs/icons/brand.js.map +1 -0
  18. package/dist/cjs/icons/business.js +228 -0
  19. package/dist/cjs/icons/business.js.map +1 -0
  20. package/dist/cjs/icons/devtech.js +374 -0
  21. package/dist/cjs/icons/devtech.js.map +1 -0
  22. package/dist/cjs/icons/ecommerce.js +171 -0
  23. package/dist/cjs/icons/ecommerce.js.map +1 -0
  24. package/dist/cjs/icons/files.js +286 -0
  25. package/dist/cjs/icons/files.js.map +1 -0
  26. package/dist/cjs/icons/fintech.js +151 -0
  27. package/dist/cjs/icons/fintech.js.map +1 -0
  28. package/dist/cjs/icons/fun.js +124 -0
  29. package/dist/cjs/icons/fun.js.map +1 -0
  30. package/dist/cjs/icons/health.js +132 -0
  31. package/dist/cjs/icons/health.js.map +1 -0
  32. package/dist/cjs/icons/media.js +219 -0
  33. package/dist/cjs/icons/media.js.map +1 -0
  34. package/dist/cjs/icons/navigation.js +147 -0
  35. package/dist/cjs/icons/navigation.js.map +1 -0
  36. package/dist/cjs/icons/saas.js +141 -0
  37. package/dist/cjs/icons/saas.js.map +1 -0
  38. package/dist/cjs/icons/shapes.js +205 -0
  39. package/dist/cjs/icons/shapes.js.map +1 -0
  40. package/dist/cjs/icons/smarthome.js +141 -0
  41. package/dist/cjs/icons/smarthome.js.map +1 -0
  42. package/dist/cjs/icons/social.js +159 -0
  43. package/dist/cjs/icons/social.js.map +1 -0
  44. package/dist/cjs/icons/ui.js +262 -0
  45. package/dist/cjs/icons/ui.js.map +1 -0
  46. package/dist/cjs/icons/weather.js +187 -0
  47. package/dist/cjs/icons/weather.js.map +1 -0
  48. package/dist/cjs/index.js +362 -0
  49. package/dist/cjs/index.js.map +1 -0
  50. package/dist/cjs/nicetodev-icons.css +1 -0
  51. package/dist/cjs/smilAnimations.js +182 -0
  52. package/dist/cjs/smilAnimations.js.map +1 -0
  53. package/dist/cjs/types.js +47 -0
  54. package/dist/cjs/types.js.map +1 -0
  55. package/dist/esm/NiceIconPicker.js +385 -0
  56. package/dist/esm/NiceIconPicker.js.map +1 -0
  57. package/dist/esm/NiceVectorEditor.js +673 -0
  58. package/dist/esm/NiceVectorEditor.js.map +1 -0
  59. package/dist/esm/animationControls.js +680 -0
  60. package/dist/esm/animationControls.js.map +1 -0
  61. package/dist/esm/createIcon.js +140 -0
  62. package/dist/esm/createIcon.js.map +1 -0
  63. package/dist/esm/figmaExport.js +279 -0
  64. package/dist/esm/figmaExport.js.map +1 -0
  65. package/dist/esm/icons/actions.js +231 -0
  66. package/dist/esm/icons/actions.js.map +1 -0
  67. package/dist/esm/icons/brand.js +124 -0
  68. package/dist/esm/icons/brand.js.map +1 -0
  69. package/dist/esm/icons/business.js +209 -0
  70. package/dist/esm/icons/business.js.map +1 -0
  71. package/dist/esm/icons/devtech.js +342 -0
  72. package/dist/esm/icons/devtech.js.map +1 -0
  73. package/dist/esm/icons/ecommerce.js +154 -0
  74. package/dist/esm/icons/ecommerce.js.map +1 -0
  75. package/dist/esm/icons/files.js +254 -0
  76. package/dist/esm/icons/files.js.map +1 -0
  77. package/dist/esm/icons/fintech.js +136 -0
  78. package/dist/esm/icons/fintech.js.map +1 -0
  79. package/dist/esm/icons/fun.js +110 -0
  80. package/dist/esm/icons/fun.js.map +1 -0
  81. package/dist/esm/icons/health.js +118 -0
  82. package/dist/esm/icons/health.js.map +1 -0
  83. package/dist/esm/icons/media.js +195 -0
  84. package/dist/esm/icons/media.js.map +1 -0
  85. package/dist/esm/icons/navigation.js +132 -0
  86. package/dist/esm/icons/navigation.js.map +1 -0
  87. package/dist/esm/icons/saas.js +127 -0
  88. package/dist/esm/icons/saas.js.map +1 -0
  89. package/dist/esm/icons/shapes.js +182 -0
  90. package/dist/esm/icons/shapes.js.map +1 -0
  91. package/dist/esm/icons/smarthome.js +127 -0
  92. package/dist/esm/icons/smarthome.js.map +1 -0
  93. package/dist/esm/icons/social.js +150 -0
  94. package/dist/esm/icons/social.js.map +1 -0
  95. package/dist/esm/icons/ui.js +233 -0
  96. package/dist/esm/icons/ui.js.map +1 -0
  97. package/dist/esm/icons/weather.js +166 -0
  98. package/dist/esm/icons/weather.js.map +1 -0
  99. package/dist/esm/index.js +25 -0
  100. package/dist/esm/index.js.map +1 -0
  101. package/dist/esm/nicetodev-icons.css +1 -0
  102. package/dist/esm/smilAnimations.js +176 -0
  103. package/dist/esm/smilAnimations.js.map +1 -0
  104. package/dist/esm/types.js +44 -0
  105. package/dist/esm/types.js.map +1 -0
  106. package/dist/types/NiceIconPicker.d.ts +149 -0
  107. package/dist/types/NiceVectorEditor.d.ts +75 -0
  108. package/dist/types/animationControls.d.ts +307 -0
  109. package/dist/types/createIcon.d.ts +76 -0
  110. package/dist/types/figmaExport.d.ts +243 -0
  111. package/dist/types/icons/actions.d.ts +25 -0
  112. package/dist/types/icons/brand.d.ts +3 -0
  113. package/dist/types/icons/business.d.ts +25 -0
  114. package/dist/types/icons/devtech.d.ts +39 -0
  115. package/dist/types/icons/ecommerce.d.ts +16 -0
  116. package/dist/types/icons/files.d.ts +31 -0
  117. package/dist/types/icons/fintech.d.ts +14 -0
  118. package/dist/types/icons/fun.d.ts +13 -0
  119. package/dist/types/icons/health.d.ts +14 -0
  120. package/dist/types/icons/index.d.ts +17 -0
  121. package/dist/types/icons/media.d.ts +23 -0
  122. package/dist/types/icons/navigation.d.ts +14 -0
  123. package/dist/types/icons/saas.d.ts +13 -0
  124. package/dist/types/icons/shapes.d.ts +22 -0
  125. package/dist/types/icons/smarthome.d.ts +13 -0
  126. package/dist/types/icons/social.d.ts +18 -0
  127. package/dist/types/icons/ui.d.ts +28 -0
  128. package/dist/types/icons/weather.d.ts +20 -0
  129. package/dist/types/index.d.ts +69 -0
  130. package/dist/types/smilAnimations.d.ts +102 -0
  131. package/dist/types/types.d.ts +179 -0
  132. package/package.json +86 -0
@@ -0,0 +1,690 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+
6
+ /* ────────────────────────────────────────────────────────────────────────────
7
+ 2. HELPER FUNCTIONS
8
+ ───────────────────────────────────────────────────────────────────────────── */
9
+ /**
10
+ * Build CSS class for animation
11
+ */
12
+ function getAnimationClass(animation) {
13
+ return `ntd-anim-${animation}`;
14
+ }
15
+ /**
16
+ * Build inline animation style
17
+ */
18
+ function getAnimationStyle(animation, duration = 1000, easing = "ease-in-out", iterations = 1, delay = 0) {
19
+ const iterationValue = iterations < 0 ? "infinite" : iterations;
20
+ return {
21
+ animationName: `ntd-${animation}`,
22
+ animationDuration: `${duration}ms`,
23
+ animationTimingFunction: easing,
24
+ animationIterationCount: iterationValue,
25
+ animationDelay: `${delay}ms`,
26
+ animationFillMode: "forwards",
27
+ };
28
+ }
29
+ /**
30
+ * Check if config is a sequence
31
+ */
32
+ function isSequenceConfig(config) {
33
+ return typeof config === "object" && "steps" in config;
34
+ }
35
+ /* ────────────────────────────────────────────────────────────────────────────
36
+ 3. ANIMATION SEQUENCE HOOK
37
+ ───────────────────────────────────────────────────────────────────────────── */
38
+ /**
39
+ * Hook to manage animation sequences
40
+ */
41
+ function useAnimationSequence(config) {
42
+ const [currentStepIndex, setCurrentStepIndex] = React.useState(0);
43
+ const [loopIteration, setLoopIteration] = React.useState(0);
44
+ const [state, setState] = React.useState("idle");
45
+ const [direction, setDirection] = React.useState("forward");
46
+ const timeoutRef = React.useRef(null);
47
+ const startTimeRef = React.useRef(0);
48
+ const elapsedRef = React.useRef(0);
49
+ const steps = React.useMemo(() => {
50
+ if (config.direction === "reverse") {
51
+ return [...config.steps].reverse();
52
+ }
53
+ return config.steps;
54
+ }, [config.steps, config.direction]);
55
+ const currentStep = steps[currentStepIndex];
56
+ const clearTimer = React.useCallback(() => {
57
+ if (timeoutRef.current) {
58
+ clearTimeout(timeoutRef.current);
59
+ timeoutRef.current = null;
60
+ }
61
+ }, []);
62
+ const play = React.useCallback(() => {
63
+ if (state === "finished") {
64
+ // Reset if finished
65
+ setCurrentStepIndex(0);
66
+ setLoopIteration(0);
67
+ elapsedRef.current = 0;
68
+ }
69
+ setState("playing");
70
+ startTimeRef.current = Date.now();
71
+ }, [state]);
72
+ const pause = React.useCallback(() => {
73
+ if (state === "playing") {
74
+ clearTimer();
75
+ elapsedRef.current += Date.now() - startTimeRef.current;
76
+ setState("paused");
77
+ }
78
+ }, [state, clearTimer]);
79
+ const reset = React.useCallback(() => {
80
+ clearTimer();
81
+ setCurrentStepIndex(0);
82
+ setLoopIteration(0);
83
+ setDirection("forward");
84
+ elapsedRef.current = 0;
85
+ setState("idle");
86
+ }, [clearTimer]);
87
+ const goToStep = React.useCallback((index) => {
88
+ if (index >= 0 && index < steps.length) {
89
+ clearTimer();
90
+ setCurrentStepIndex(index);
91
+ elapsedRef.current = 0;
92
+ if (state === "playing") {
93
+ startTimeRef.current = Date.now();
94
+ }
95
+ }
96
+ }, [steps.length, clearTimer, state]);
97
+ const getProgress = React.useCallback(() => {
98
+ if (state === "idle")
99
+ return 0;
100
+ if (state === "finished")
101
+ return 1;
102
+ const stepProgress = currentStepIndex / steps.length;
103
+ return stepProgress;
104
+ }, [state, currentStepIndex, steps.length]);
105
+ // Handle step progression
106
+ React.useEffect(() => {
107
+ if (state !== "playing" || !currentStep)
108
+ return;
109
+ const stepDuration = (currentStep.duration || 1000) * (currentStep.iterations || 1);
110
+ const remainingTime = stepDuration - elapsedRef.current;
111
+ timeoutRef.current = setTimeout(() => {
112
+ elapsedRef.current = 0;
113
+ // Determine next step
114
+ let nextStepIndex;
115
+ if (config.direction === "alternate") {
116
+ if (direction === "forward") {
117
+ if (currentStepIndex >= steps.length - 1) {
118
+ setDirection("backward");
119
+ nextStepIndex = currentStepIndex - 1;
120
+ }
121
+ else {
122
+ nextStepIndex = currentStepIndex + 1;
123
+ }
124
+ }
125
+ else {
126
+ if (currentStepIndex <= 0) {
127
+ setDirection("forward");
128
+ nextStepIndex = currentStepIndex + 1;
129
+ }
130
+ else {
131
+ nextStepIndex = currentStepIndex - 1;
132
+ }
133
+ }
134
+ }
135
+ else {
136
+ nextStepIndex = currentStepIndex + 1;
137
+ }
138
+ // Check if sequence complete
139
+ if (nextStepIndex >= steps.length && config.direction !== "alternate") {
140
+ if (config.loop) {
141
+ const newIteraton = loopIteration + 1;
142
+ if (config.loopCount && newIteraton >= config.loopCount) {
143
+ setState("finished");
144
+ }
145
+ else {
146
+ setLoopIteration(newIteraton);
147
+ setCurrentStepIndex(0);
148
+ // Apply loop delay
149
+ if (config.loopDelay) {
150
+ setState("paused");
151
+ timeoutRef.current = setTimeout(() => {
152
+ setState("playing");
153
+ startTimeRef.current = Date.now();
154
+ }, config.loopDelay);
155
+ }
156
+ else {
157
+ startTimeRef.current = Date.now();
158
+ }
159
+ }
160
+ }
161
+ else {
162
+ setState("finished");
163
+ }
164
+ }
165
+ else if (nextStepIndex >= 0 && nextStepIndex < steps.length) {
166
+ setCurrentStepIndex(nextStepIndex);
167
+ startTimeRef.current = Date.now();
168
+ }
169
+ }, remainingTime + (currentStep.delay || 0));
170
+ return clearTimer;
171
+ }, [
172
+ state,
173
+ currentStep,
174
+ currentStepIndex,
175
+ steps.length,
176
+ direction,
177
+ config.loop,
178
+ config.loopCount,
179
+ config.loopDelay,
180
+ config.direction,
181
+ loopIteration,
182
+ clearTimer,
183
+ ]);
184
+ return {
185
+ currentStep,
186
+ currentStepIndex,
187
+ state,
188
+ loopIteration,
189
+ play,
190
+ pause,
191
+ reset,
192
+ goToStep,
193
+ getProgress,
194
+ };
195
+ }
196
+ /* ────────────────────────────────────────────────────────────────────────────
197
+ 4. ANIMATION CONTROLLER COMPONENT
198
+ ───────────────────────────────────────────────────────────────────────────── */
199
+ /**
200
+ * Animation Controller component
201
+ *
202
+ * Wraps an icon and provides play/pause/reset controls.
203
+ *
204
+ * @example
205
+ * ```tsx
206
+ * const ref = useRef<AnimationControllerHandle>(null);
207
+ *
208
+ * <AnimationController
209
+ * ref={ref}
210
+ * animation="spin"
211
+ * autoPlay={false}
212
+ * >
213
+ * <NiceIcon name="loading" />
214
+ * </AnimationController>
215
+ *
216
+ * <button onClick={() => ref.current?.play()}>Play</button>
217
+ * <button onClick={() => ref.current?.pause()}>Pause</button>
218
+ * <button onClick={() => ref.current?.reset()}>Reset</button>
219
+ * ```
220
+ *
221
+ * @example Sequence
222
+ * ```tsx
223
+ * <AnimationController
224
+ * animation={{
225
+ * steps: [
226
+ * { animation: 'bounce', duration: 500 },
227
+ * { animation: 'spin', duration: 1000 },
228
+ * { animation: 'pulse', duration: 800 },
229
+ * ],
230
+ * loop: true,
231
+ * loopCount: 3
232
+ * }}
233
+ * autoPlay
234
+ * >
235
+ * <NiceIcon name="star" />
236
+ * </AnimationController>
237
+ * ```
238
+ */
239
+ const AnimationController = React.forwardRef(function AnimationController(props, ref) {
240
+ const { children, animation, autoPlay = false, playState: externalPlayState, onStart, onEnd, onStepChange, onPause, onResume, className, style, } = props;
241
+ // Determine if sequence or single animation
242
+ const isSequence = isSequenceConfig(animation);
243
+ // For single animations
244
+ const [singleState, setSingleState] = React.useState(autoPlay ? "playing" : "idle");
245
+ const singleIterationRef = React.useRef(0);
246
+ // For sequences
247
+ const sequenceConfig = isSequence
248
+ ? animation
249
+ : { steps: [{ animation, duration: 1000 }] };
250
+ const sequence = useAnimationSequence(sequenceConfig);
251
+ // Unified state
252
+ const state = isSequence ? sequence.state : singleState;
253
+ const currentStepIndex = isSequence ? sequence.currentStepIndex : 0;
254
+ // Handle external playState control
255
+ React.useEffect(() => {
256
+ if (externalPlayState !== undefined) {
257
+ if (isSequence) {
258
+ if (externalPlayState === "playing")
259
+ sequence.play();
260
+ else if (externalPlayState === "paused")
261
+ sequence.pause();
262
+ else if (externalPlayState === "idle")
263
+ sequence.reset();
264
+ }
265
+ else {
266
+ setSingleState(externalPlayState);
267
+ }
268
+ }
269
+ }, [externalPlayState, isSequence, sequence]);
270
+ // Auto-play
271
+ React.useEffect(() => {
272
+ if (autoPlay) {
273
+ if (isSequence) {
274
+ sequence.play();
275
+ }
276
+ else {
277
+ setSingleState("playing");
278
+ }
279
+ onStart === null || onStart === void 0 ? void 0 : onStart();
280
+ }
281
+ // eslint-disable-next-line react-hooks/exhaustive-deps
282
+ }, []);
283
+ // Step change callback
284
+ const prevStepRef = React.useRef(currentStepIndex);
285
+ React.useEffect(() => {
286
+ if (prevStepRef.current !== currentStepIndex && isSequence) {
287
+ const step = sequenceConfig.steps[currentStepIndex];
288
+ onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(currentStepIndex, step);
289
+ }
290
+ prevStepRef.current = currentStepIndex;
291
+ }, [currentStepIndex, isSequence, sequenceConfig.steps, onStepChange]);
292
+ // State change callbacks
293
+ const prevStateRef = React.useRef(state);
294
+ React.useEffect(() => {
295
+ if (prevStateRef.current !== state) {
296
+ if (state === "playing" && prevStateRef.current === "paused") {
297
+ onResume === null || onResume === void 0 ? void 0 : onResume();
298
+ }
299
+ else if (state === "paused" && prevStateRef.current === "playing") {
300
+ onPause === null || onPause === void 0 ? void 0 : onPause();
301
+ }
302
+ else if (state === "finished") {
303
+ onEnd === null || onEnd === void 0 ? void 0 : onEnd();
304
+ }
305
+ else if (state === "playing" && prevStateRef.current === "idle") {
306
+ onStart === null || onStart === void 0 ? void 0 : onStart();
307
+ }
308
+ }
309
+ prevStateRef.current = state;
310
+ }, [state, onStart, onEnd, onPause, onResume]);
311
+ // Imperative handle
312
+ React.useImperativeHandle(ref, () => ({
313
+ play: () => {
314
+ if (isSequence) {
315
+ sequence.play();
316
+ }
317
+ else {
318
+ setSingleState("playing");
319
+ singleIterationRef.current++;
320
+ }
321
+ onStart === null || onStart === void 0 ? void 0 : onStart();
322
+ },
323
+ pause: () => {
324
+ if (isSequence) {
325
+ sequence.pause();
326
+ }
327
+ else {
328
+ setSingleState("paused");
329
+ }
330
+ onPause === null || onPause === void 0 ? void 0 : onPause();
331
+ },
332
+ reset: () => {
333
+ if (isSequence) {
334
+ sequence.reset();
335
+ }
336
+ else {
337
+ setSingleState("idle");
338
+ singleIterationRef.current++;
339
+ }
340
+ },
341
+ goToStep: (index) => {
342
+ if (isSequence) {
343
+ sequence.goToStep(index);
344
+ }
345
+ },
346
+ getState: () => state,
347
+ getCurrentStep: () => currentStepIndex,
348
+ getProgress: () => {
349
+ if (isSequence) {
350
+ return sequence.getProgress();
351
+ }
352
+ return state === "playing" ? 0.5 : state === "finished" ? 1 : 0;
353
+ },
354
+ }));
355
+ // Build animation styles
356
+ const animationStyles = React.useMemo(() => {
357
+ if (state === "idle") {
358
+ return {};
359
+ }
360
+ if (state === "paused") {
361
+ return { animationPlayState: "paused" };
362
+ }
363
+ if (isSequence && sequence.currentStep) {
364
+ const step = sequence.currentStep;
365
+ return getAnimationStyle(step.animation, step.duration, step.easing, step.iterations, step.delay);
366
+ }
367
+ if (!isSequence) {
368
+ return getAnimationStyle(animation, 1000, "ease-in-out", -1);
369
+ }
370
+ return {};
371
+ }, [state, isSequence, sequence.currentStep, animation]);
372
+ // Animation class
373
+ const animationClass = state === "playing" || state === "paused"
374
+ ? isSequence && sequence.currentStep
375
+ ? getAnimationClass(sequence.currentStep.animation)
376
+ : getAnimationClass(animation)
377
+ : "";
378
+ // Clone child with animation props
379
+ const animatedChild = React.cloneElement(children, {
380
+ className: `${children.props.className || ""} ${animationClass}`.trim(),
381
+ style: {
382
+ ...children.props.style,
383
+ ...animationStyles,
384
+ },
385
+ key: isSequence
386
+ ? `seq-${currentStepIndex}-${sequence.loopIteration}`
387
+ : `single-${singleIterationRef.current}`,
388
+ });
389
+ return (jsxRuntime.jsx("span", { className: `ntd-animation-controller ntd-animation-${state} ${className || ""}`.trim(), style: style, children: animatedChild }));
390
+ });
391
+ /* ────────────────────────────────────────────────────────────────────────────
392
+ 5. INTERACTIVE ICON COMPONENT
393
+ ───────────────────────────────────────────────────────────────────────────── */
394
+ /**
395
+ * Interactive icon wrapper with hover/click/focus triggers
396
+ *
397
+ * @example
398
+ * ```tsx
399
+ * <InteractiveIcon
400
+ * config={{
401
+ * trigger: 'hover',
402
+ * enterAnimation: 'bounce',
403
+ * leaveAnimation: 'fadeOut',
404
+ * }}
405
+ * >
406
+ * <NiceIcon name="heart" />
407
+ * </InteractiveIcon>
408
+ * ```
409
+ *
410
+ * @example Click
411
+ * ```tsx
412
+ * <InteractiveIcon
413
+ * config={{
414
+ * trigger: 'click',
415
+ * enterAnimation: 'pulse',
416
+ * once: true,
417
+ * }}
418
+ * >
419
+ * <NiceIcon name="notification" />
420
+ * </InteractiveIcon>
421
+ * ```
422
+ */
423
+ const InteractiveIcon = React.forwardRef(function InteractiveIcon(props, ref) {
424
+ const { children, config, disabled = false, onInteractionStart, onInteractionEnd, className, style, } = props;
425
+ const [isActive, setIsActive] = React.useState(false);
426
+ const [isLeaving, setIsLeaving] = React.useState(false);
427
+ const [hasPlayed, setHasPlayed] = React.useState(false);
428
+ const wrapperRef = React.useRef(null);
429
+ const timeoutRef = React.useRef(null);
430
+ // Merge refs
431
+ const setRefs = React.useCallback((node) => {
432
+ wrapperRef.current =
433
+ node;
434
+ if (typeof ref === "function") {
435
+ ref(node);
436
+ }
437
+ else if (ref) {
438
+ ref.current = node;
439
+ }
440
+ }, [ref]);
441
+ // Clear any pending timeouts
442
+ const clearTimer = React.useCallback(() => {
443
+ if (timeoutRef.current) {
444
+ clearTimeout(timeoutRef.current);
445
+ timeoutRef.current = null;
446
+ }
447
+ }, []);
448
+ React.useEffect(() => clearTimer, [clearTimer]);
449
+ // Handle activation
450
+ const activate = React.useCallback(() => {
451
+ if (disabled)
452
+ return;
453
+ if (config.once && hasPlayed)
454
+ return;
455
+ clearTimer();
456
+ setIsLeaving(false);
457
+ if (config.delay) {
458
+ timeoutRef.current = setTimeout(() => {
459
+ setIsActive(true);
460
+ setHasPlayed(true);
461
+ onInteractionStart === null || onInteractionStart === void 0 ? void 0 : onInteractionStart();
462
+ }, config.delay);
463
+ }
464
+ else {
465
+ setIsActive(true);
466
+ setHasPlayed(true);
467
+ onInteractionStart === null || onInteractionStart === void 0 ? void 0 : onInteractionStart();
468
+ }
469
+ }, [disabled, config.once, config.delay, hasPlayed, clearTimer, onInteractionStart]);
470
+ // Handle deactivation
471
+ const deactivate = React.useCallback(() => {
472
+ if (!isActive)
473
+ return;
474
+ clearTimer();
475
+ if (config.leaveAnimation) {
476
+ setIsLeaving(true);
477
+ setIsActive(false);
478
+ timeoutRef.current = setTimeout(() => {
479
+ setIsLeaving(false);
480
+ onInteractionEnd === null || onInteractionEnd === void 0 ? void 0 : onInteractionEnd();
481
+ }, config.leaveDuration || 300);
482
+ }
483
+ else {
484
+ setIsActive(false);
485
+ onInteractionEnd === null || onInteractionEnd === void 0 ? void 0 : onInteractionEnd();
486
+ }
487
+ }, [isActive, config.leaveAnimation, config.leaveDuration, clearTimer, onInteractionEnd]);
488
+ // Visibility observer
489
+ React.useEffect(() => {
490
+ var _a;
491
+ if (config.trigger !== "visible" || !wrapperRef.current)
492
+ return;
493
+ const threshold = (_a = config.visibilityThreshold) !== null && _a !== void 0 ? _a : 0.5;
494
+ const observer = new IntersectionObserver(([entry]) => {
495
+ if (entry.isIntersecting) {
496
+ activate();
497
+ }
498
+ else if (!config.once) {
499
+ deactivate();
500
+ }
501
+ }, { threshold });
502
+ observer.observe(wrapperRef.current);
503
+ return () => observer.disconnect();
504
+ }, [config.trigger, config.visibilityThreshold, config.once, activate, deactivate]);
505
+ // Event handlers
506
+ const handleMouseEnter = config.trigger === "hover" ? activate : undefined;
507
+ const handleMouseLeave = config.trigger === "hover" ? deactivate : undefined;
508
+ const handleClick = config.trigger === "click" ? activate : undefined;
509
+ const handleFocus = config.trigger === "focus" ? activate : undefined;
510
+ const handleBlur = config.trigger === "focus" ? deactivate : undefined;
511
+ // Build animation props
512
+ const currentAnimation = isActive
513
+ ? config.enterAnimation
514
+ : isLeaving
515
+ ? config.leaveAnimation
516
+ : undefined;
517
+ const animationDuration = isActive
518
+ ? config.enterDuration
519
+ : config.leaveDuration;
520
+ const animationStyles = currentAnimation
521
+ ? getAnimationStyle(currentAnimation, animationDuration || 300)
522
+ : {};
523
+ const animationClass = currentAnimation
524
+ ? getAnimationClass(currentAnimation)
525
+ : "";
526
+ // Clone with animation
527
+ const animatedChild = React.cloneElement(children, {
528
+ className: `${children.props.className || ""} ${animationClass}`.trim(),
529
+ style: {
530
+ ...children.props.style,
531
+ ...animationStyles,
532
+ },
533
+ });
534
+ return (jsxRuntime.jsx("span", { ref: setRefs, className: `ntd-interactive-icon ${isActive ? "ntd-active" : ""} ${isLeaving ? "ntd-leaving" : ""} ${disabled ? "ntd-disabled" : ""} ${className || ""}`.trim(), style: {
535
+ display: "inline-flex",
536
+ cursor: disabled ? "default" : config.trigger === "click" ? "pointer" : undefined,
537
+ ...style,
538
+ }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: handleClick, onFocus: handleFocus, onBlur: handleBlur, tabIndex: config.trigger === "focus" ? 0 : undefined, role: config.trigger === "click" ? "button" : undefined, children: animatedChild }));
539
+ });
540
+ /* ────────────────────────────────────────────────────────────────────────────
541
+ 6. UTILITY FUNCTIONS
542
+ ───────────────────────────────────────────────────────────────────────────── */
543
+ /**
544
+ * Create an animation sequence configuration
545
+ *
546
+ * @example
547
+ * ```tsx
548
+ * const seq = createAnimationSequence([
549
+ * { animation: 'shake', duration: 300 },
550
+ * { animation: 'pulse', duration: 500 },
551
+ * { animation: 'bounce', duration: 400 },
552
+ * ], { loop: true, loopCount: 2 });
553
+ * ```
554
+ */
555
+ function createAnimationSequence(steps, options) {
556
+ var _a, _b;
557
+ return {
558
+ steps,
559
+ loop: (_a = options === null || options === void 0 ? void 0 : options.loop) !== null && _a !== void 0 ? _a : false,
560
+ loopCount: options === null || options === void 0 ? void 0 : options.loopCount,
561
+ loopDelay: options === null || options === void 0 ? void 0 : options.loopDelay,
562
+ direction: (_b = options === null || options === void 0 ? void 0 : options.direction) !== null && _b !== void 0 ? _b : "normal",
563
+ };
564
+ }
565
+ /**
566
+ * Create an interactive config for hover effect
567
+ */
568
+ function createHoverAnimation(enterAnimation, leaveAnimation, options) {
569
+ var _a, _b;
570
+ return {
571
+ trigger: "hover",
572
+ enterAnimation,
573
+ leaveAnimation,
574
+ enterDuration: (_a = options === null || options === void 0 ? void 0 : options.enterDuration) !== null && _a !== void 0 ? _a : 300,
575
+ leaveDuration: (_b = options === null || options === void 0 ? void 0 : options.leaveDuration) !== null && _b !== void 0 ? _b : 200,
576
+ delay: options === null || options === void 0 ? void 0 : options.delay,
577
+ };
578
+ }
579
+ /**
580
+ * Create an interactive config for click effect
581
+ */
582
+ function createClickAnimation(animation, options) {
583
+ var _a, _b;
584
+ return {
585
+ trigger: "click",
586
+ enterAnimation: animation,
587
+ enterDuration: (_a = options === null || options === void 0 ? void 0 : options.duration) !== null && _a !== void 0 ? _a : 500,
588
+ once: (_b = options === null || options === void 0 ? void 0 : options.once) !== null && _b !== void 0 ? _b : false,
589
+ delay: options === null || options === void 0 ? void 0 : options.delay,
590
+ };
591
+ }
592
+ /**
593
+ * Create an interactive config for visibility trigger
594
+ */
595
+ function createVisibilityAnimation(animation, options) {
596
+ var _a, _b, _c;
597
+ return {
598
+ trigger: "visible",
599
+ enterAnimation: animation,
600
+ enterDuration: (_a = options === null || options === void 0 ? void 0 : options.duration) !== null && _a !== void 0 ? _a : 600,
601
+ once: (_b = options === null || options === void 0 ? void 0 : options.once) !== null && _b !== void 0 ? _b : true,
602
+ visibilityThreshold: (_c = options === null || options === void 0 ? void 0 : options.threshold) !== null && _c !== void 0 ? _c : 0.5,
603
+ };
604
+ }
605
+ /* ────────────────────────────────────────────────────────────────────────────
606
+ 7. PRESET SEQUENCES
607
+ ───────────────────────────────────────────────────────────────────────────── */
608
+ /**
609
+ * Preset animation sequences for common use cases
610
+ */
611
+ const PRESET_SEQUENCES = {
612
+ /** Attention grabber: bounce → shake → pulse */
613
+ attention: createAnimationSequence([
614
+ { animation: "bounce", duration: 400 },
615
+ { animation: "shake", duration: 300 },
616
+ { animation: "pulse", duration: 500 },
617
+ ]),
618
+ /** Success animation: pop → bounce */
619
+ success: createAnimationSequence([
620
+ { animation: "pop", duration: 200 },
621
+ { animation: "bounce", duration: 500 },
622
+ ]),
623
+ /** Error animation: shake → pulse */
624
+ error: createAnimationSequence([
625
+ { animation: "shake", duration: 500, iterations: 2 },
626
+ { animation: "pulse", duration: 300 },
627
+ ]),
628
+ /** Loading sequence: spin → pulse (looping) */
629
+ loading: createAnimationSequence([
630
+ { animation: "spin", duration: 1000 },
631
+ { animation: "pulse", duration: 500 },
632
+ ], { loop: true }),
633
+ /** Celebration: bounce → tada → heartbeat */
634
+ celebrate: createAnimationSequence([
635
+ { animation: "bounce", duration: 500 },
636
+ { animation: "tada", duration: 800 },
637
+ { animation: "heartbeat", duration: 600 },
638
+ ]),
639
+ /** Notification: swing → bounce */
640
+ notification: createAnimationSequence([
641
+ { animation: "swing", duration: 600 },
642
+ { animation: "bounce", duration: 400 },
643
+ ]),
644
+ /** Gentle: pulse → breathe */
645
+ gentle: createAnimationSequence([
646
+ { animation: "pulse", duration: 800 },
647
+ { animation: "breathe", duration: 1500 },
648
+ ], { loop: true }),
649
+ /** Reveal: fade-in → pop */
650
+ reveal: createAnimationSequence([
651
+ { animation: "fade-in", duration: 300 },
652
+ { animation: "pop", duration: 200 },
653
+ ]),
654
+ };
655
+ /**
656
+ * Preset interactive configs
657
+ */
658
+ const PRESET_INTERACTIONS = {
659
+ /** Bounce on hover */
660
+ hoverBounce: createHoverAnimation("bounce"),
661
+ /** Pulse on hover */
662
+ hoverPulse: createHoverAnimation("pulse"),
663
+ /** Spin on hover */
664
+ hoverSpin: createHoverAnimation("spin"),
665
+ /** Shake on hover */
666
+ hoverShake: createHoverAnimation("shake"),
667
+ /** Pop on click */
668
+ clickPop: createClickAnimation("pop", { once: true }),
669
+ /** Bounce on click */
670
+ clickBounce: createClickAnimation("bounce"),
671
+ /** Tada on click */
672
+ clickTada: createClickAnimation("tada"),
673
+ /** FadeIn on visible */
674
+ visibleFadeIn: createVisibilityAnimation("fade-in", { once: true }),
675
+ /** Bounce on visible */
676
+ visibleBounce: createVisibilityAnimation("bounce", { once: true }),
677
+ /** Scale in on visible */
678
+ visibleScaleIn: createVisibilityAnimation("scale-in", { once: true }),
679
+ };
680
+
681
+ exports.AnimationController = AnimationController;
682
+ exports.InteractiveIcon = InteractiveIcon;
683
+ exports.PRESET_INTERACTIONS = PRESET_INTERACTIONS;
684
+ exports.PRESET_SEQUENCES = PRESET_SEQUENCES;
685
+ exports.createAnimationSequence = createAnimationSequence;
686
+ exports.createClickAnimation = createClickAnimation;
687
+ exports.createHoverAnimation = createHoverAnimation;
688
+ exports.createVisibilityAnimation = createVisibilityAnimation;
689
+ exports.useAnimationSequence = useAnimationSequence;
690
+ //# sourceMappingURL=animationControls.js.map