@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.
Files changed (82) hide show
  1. package/api-schema.json +206 -0
  2. package/dist/components/CountUp.d.ts +84 -0
  3. package/dist/components/CountUp.d.ts.map +1 -0
  4. package/dist/components/CountUp.js +68 -0
  5. package/dist/components/CountUp.js.map +1 -0
  6. package/dist/components/MotionDiv.d.ts +159 -0
  7. package/dist/components/MotionDiv.d.ts.map +1 -0
  8. package/dist/components/MotionDiv.js +162 -0
  9. package/dist/components/MotionDiv.js.map +1 -0
  10. package/dist/components/StaggerContainer.d.ts +136 -0
  11. package/dist/components/StaggerContainer.d.ts.map +1 -0
  12. package/dist/components/StaggerContainer.js +166 -0
  13. package/dist/components/StaggerContainer.js.map +1 -0
  14. package/dist/hooks/use-component-animation.d.ts +156 -0
  15. package/dist/hooks/use-component-animation.d.ts.map +1 -0
  16. package/dist/hooks/use-component-animation.js +231 -0
  17. package/dist/hooks/use-component-animation.js.map +1 -0
  18. package/dist/hooks/use-count-up.d.ts +111 -0
  19. package/dist/hooks/use-count-up.d.ts.map +1 -0
  20. package/dist/hooks/use-count-up.js +246 -0
  21. package/dist/hooks/use-count-up.js.map +1 -0
  22. package/dist/hooks/use-draw-path.d.ts +96 -0
  23. package/dist/hooks/use-draw-path.d.ts.map +1 -0
  24. package/dist/hooks/use-draw-path.js +227 -0
  25. package/dist/hooks/use-draw-path.js.map +1 -0
  26. package/dist/hooks/use-motion-preset.d.ts.map +1 -1
  27. package/dist/hooks/use-motion-preset.js +17 -16
  28. package/dist/hooks/use-motion-preset.js.map +1 -1
  29. package/dist/hooks/use-stagger.d.ts +174 -0
  30. package/dist/hooks/use-stagger.d.ts.map +1 -0
  31. package/dist/hooks/use-stagger.js +256 -0
  32. package/dist/hooks/use-stagger.js.map +1 -0
  33. package/dist/index.d.ts +17 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2442 -26
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.mjs +2335 -25
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/presets/component-presets.d.ts +246 -0
  40. package/dist/presets/component-presets.d.ts.map +1 -0
  41. package/dist/presets/component-presets.js +472 -0
  42. package/dist/presets/component-presets.js.map +1 -0
  43. package/dist/presets/micro-interactions.d.ts +451 -0
  44. package/dist/presets/micro-interactions.d.ts.map +1 -0
  45. package/dist/presets/micro-interactions.js +856 -0
  46. package/dist/presets/micro-interactions.js.map +1 -0
  47. package/dist/presets/motion-presets.d.ts.map +1 -1
  48. package/dist/presets/motion-presets.js +0 -1
  49. package/dist/presets/motion-presets.js.map +1 -1
  50. package/dist/presets/motion-styles.d.ts +186 -0
  51. package/dist/presets/motion-styles.d.ts.map +1 -0
  52. package/dist/presets/motion-styles.js +204 -0
  53. package/dist/presets/motion-styles.js.map +1 -0
  54. package/dist/presets/stagger-presets.d.ts +378 -0
  55. package/dist/presets/stagger-presets.d.ts.map +1 -0
  56. package/dist/presets/stagger-presets.js +582 -0
  57. package/dist/presets/stagger-presets.js.map +1 -0
  58. package/dist/showcase/motion-presets.demo.d.ts +25 -0
  59. package/dist/showcase/motion-presets.demo.d.ts.map +1 -0
  60. package/dist/showcase/motion-presets.demo.js +96 -0
  61. package/dist/showcase/motion-presets.demo.js.map +1 -0
  62. package/dist/showcase/motion-presets.story.d.ts +37 -0
  63. package/dist/showcase/motion-presets.story.d.ts.map +1 -0
  64. package/dist/showcase/motion-presets.story.js +151 -0
  65. package/dist/showcase/motion-presets.story.js.map +1 -0
  66. package/dist/utils/easing.d.ts +294 -0
  67. package/dist/utils/easing.d.ts.map +1 -0
  68. package/dist/utils/easing.js +265 -0
  69. package/dist/utils/easing.js.map +1 -0
  70. package/dist/utils/reduced-motion.d.ts +322 -0
  71. package/dist/utils/reduced-motion.d.ts.map +1 -0
  72. package/dist/utils/reduced-motion.js +362 -0
  73. package/dist/utils/reduced-motion.js.map +1 -0
  74. package/dist/utils/select-preset.d.ts +186 -0
  75. package/dist/utils/select-preset.d.ts.map +1 -0
  76. package/dist/utils/select-preset.js +320 -0
  77. package/dist/utils/select-preset.js.map +1 -0
  78. package/dist/utils/spring-configs.d.ts +187 -0
  79. package/dist/utils/spring-configs.d.ts.map +1 -0
  80. package/dist/utils/spring-configs.js +169 -0
  81. package/dist/utils/spring-configs.js.map +1 -0
  82. package/package.json +4 -3
@@ -0,0 +1,231 @@
1
+ // Copyright (c) 2026 Amsterdam Data Labs
2
+ "use client";
3
+ /**
4
+ * useComponentAnimation Hook
5
+ *
6
+ * Hook for applying component animation presets with motion style support.
7
+ * Provides a clean API for animating components with Motion library.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import { useEffect, useMemo, useState } from "react";
12
+ // =============================================================================
13
+ // Reduced Motion Detection
14
+ // =============================================================================
15
+ /**
16
+ * Hook to detect if user prefers reduced motion.
17
+ * Updates reactively when the preference changes.
18
+ */
19
+ function useReducedMotion() {
20
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(() => {
21
+ if (typeof window === "undefined")
22
+ return false;
23
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
24
+ });
25
+ useEffect(() => {
26
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
27
+ setPrefersReducedMotion(mediaQuery.matches);
28
+ const handler = (e) => {
29
+ setPrefersReducedMotion(e.matches);
30
+ };
31
+ mediaQuery.addEventListener("change", handler);
32
+ return () => mediaQuery.removeEventListener("change", handler);
33
+ }, []);
34
+ return prefersReducedMotion;
35
+ }
36
+ // =============================================================================
37
+ // Reduced Motion Variants
38
+ // =============================================================================
39
+ /**
40
+ * Creates disabled animation props (no animation).
41
+ */
42
+ function createDisabledProps(skipInitial) {
43
+ return {
44
+ initial: skipInitial ? false : { opacity: 1 },
45
+ animate: { opacity: 1 },
46
+ exit: { opacity: 1 },
47
+ transition: { type: "tween", duration: 0 },
48
+ };
49
+ }
50
+ // =============================================================================
51
+ // Main Hook
52
+ // =============================================================================
53
+ /**
54
+ * Hook for applying component animation presets.
55
+ *
56
+ * Provides Motion library compatible animation props that:
57
+ * - Apply the selected motion style (subtle, standard, bold, playful)
58
+ * - Support customization via options
59
+ *
60
+ * @param preset - The component animation preset to use
61
+ * @param style - The motion style to apply (defaults to "standard")
62
+ * @param options - Additional customization options
63
+ * @returns Animation props for Motion library components
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * import { motion } from "motion/react";
68
+ * import { useComponentAnimation, fadeIn } from "@enact-ui/animate";
69
+ *
70
+ * function MyComponent() {
71
+ * const animation = useComponentAnimation(fadeIn, "standard");
72
+ *
73
+ * return (
74
+ * <motion.div {...animation}>
75
+ * Content
76
+ * </motion.div>
77
+ * );
78
+ * }
79
+ * ```
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * // With AnimatePresence for exit animations
84
+ * import { AnimatePresence, motion } from "motion/react";
85
+ * import { useComponentAnimation, slideUp } from "@enact-ui/animate";
86
+ *
87
+ * function Modal({ isOpen, children }) {
88
+ * const animation = useComponentAnimation(slideUp, "bold");
89
+ *
90
+ * return (
91
+ * <AnimatePresence>
92
+ * {isOpen && (
93
+ * <motion.div {...animation}>
94
+ * {children}
95
+ * </motion.div>
96
+ * )}
97
+ * </AnimatePresence>
98
+ * );
99
+ * }
100
+ * ```
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * // With custom options
105
+ * const animation = useComponentAnimation(slideUp, "playful", {
106
+ * distance: 40,
107
+ * delay: 100,
108
+ * useSpring: true,
109
+ * });
110
+ * ```
111
+ */
112
+ export function useComponentAnimation(preset, style = "standard", options = {}) {
113
+ const { enabled = true, skipInitial = false, ...presetOptions } = options;
114
+ const prefersReducedMotion = useReducedMotion();
115
+ // Memoize presetOptions to avoid unnecessary re-renders
116
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Using JSON.stringify for deep comparison
117
+ const memoizedPresetOptions = useMemo(() => presetOptions, [JSON.stringify(presetOptions)]);
118
+ const animationProps = useMemo(() => {
119
+ if (!enabled) {
120
+ return createDisabledProps(skipInitial);
121
+ }
122
+ const props = preset.getProps(style, memoizedPresetOptions);
123
+ if (skipInitial) {
124
+ return {
125
+ ...props,
126
+ initial: false,
127
+ };
128
+ }
129
+ return props;
130
+ }, [preset, style, memoizedPresetOptions, enabled, skipInitial]);
131
+ return {
132
+ ...animationProps,
133
+ prefersReducedMotion,
134
+ isEnabled: enabled,
135
+ };
136
+ }
137
+ /**
138
+ * Hook for applying animation props with a delay.
139
+ *
140
+ * Useful for staggering animations without using variants.
141
+ *
142
+ * @param preset - The component animation preset to use
143
+ * @param style - The motion style to apply
144
+ * @param index - The index of this item (for calculating delay)
145
+ * @param options - Additional customization options
146
+ * @returns Animation props with calculated delay
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * function ListItem({ index, children }) {
151
+ * const animation = useDelayedAnimation(fadeIn, "standard", index, {
152
+ * delayMultiplier: 50, // 50ms between each item
153
+ * });
154
+ *
155
+ * return (
156
+ * <motion.li {...animation}>
157
+ * {children}
158
+ * </motion.li>
159
+ * );
160
+ * }
161
+ * ```
162
+ */
163
+ export function useDelayedAnimation(preset, style = "standard", index, options = {}) {
164
+ const { delayMultiplier = 50, maxDelay = 500, ...restOptions } = options;
165
+ const calculatedDelay = Math.min(index * delayMultiplier, maxDelay);
166
+ return useComponentAnimation(preset, style, {
167
+ ...restOptions,
168
+ delay: (restOptions.delay ?? 0) + calculatedDelay,
169
+ });
170
+ }
171
+ /**
172
+ * Hook that returns animation props as a function for use with variants.
173
+ *
174
+ * Useful when you need to pass animation config to Motion's variants system.
175
+ *
176
+ * @param preset - The component animation preset to use
177
+ * @param style - The motion style to apply
178
+ * @param options - Additional customization options
179
+ * @returns Object containing variants and transition
180
+ *
181
+ * @example
182
+ * ```tsx
183
+ * function Container({ children }) {
184
+ * const { variants, transition } = useAnimationVariants(fadeIn, "standard");
185
+ *
186
+ * return (
187
+ * <motion.div
188
+ * initial="initial"
189
+ * animate="animate"
190
+ * exit="exit"
191
+ * variants={variants}
192
+ * transition={transition}
193
+ * >
194
+ * {children}
195
+ * </motion.div>
196
+ * );
197
+ * }
198
+ * ```
199
+ */
200
+ export function useAnimationVariants(preset, style = "standard", options = {}) {
201
+ const { enabled = true, ...presetOptions } = options;
202
+ // Memoize presetOptions to avoid unnecessary re-renders
203
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Using JSON.stringify for deep comparison
204
+ const memoizedPresetOptions = useMemo(() => presetOptions, [JSON.stringify(presetOptions)]);
205
+ return useMemo(() => {
206
+ if (!enabled) {
207
+ return {
208
+ variants: {
209
+ initial: { opacity: 0 },
210
+ animate: { opacity: 1 },
211
+ exit: { opacity: 0 },
212
+ },
213
+ transition: { type: "tween", duration: 0.15 },
214
+ };
215
+ }
216
+ const props = preset.getProps(style, memoizedPresetOptions);
217
+ return {
218
+ variants: {
219
+ initial: props.initial,
220
+ animate: props.animate,
221
+ exit: (props.exit ?? props.initial),
222
+ },
223
+ transition: props.transition,
224
+ };
225
+ }, [preset, style, memoizedPresetOptions, enabled]);
226
+ }
227
+ // =============================================================================
228
+ // Re-exports for convenience
229
+ // =============================================================================
230
+ export { useReducedMotion };
231
+ //# sourceMappingURL=use-component-animation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-animation.js","sourceRoot":"","sources":["../../src/hooks/use-component-animation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import type { MotionStyle } from "../presets/motion-styles";
2
+ /**
3
+ * Easing function type for count-up animation.
4
+ */
5
+ export type CountUpEasing = "linear" | "easeOut" | "easeOutExpo" | "easeInOut" | "spring";
6
+ /**
7
+ * Options for the useCountUp hook.
8
+ */
9
+ export interface UseCountUpOptions {
10
+ /** Starting value. Defaults to 0. */
11
+ from?: number;
12
+ /** Target value to count to. Required. */
13
+ to: number;
14
+ /** Duration in milliseconds. Defaults to motion style duration. */
15
+ duration?: number;
16
+ /** Motion style to use for timing. Defaults to "standard". */
17
+ motionStyle?: MotionStyle;
18
+ /** Easing function. Defaults to "easeOutExpo". */
19
+ easing?: CountUpEasing;
20
+ /** Number of decimal places. Defaults to 0. */
21
+ decimals?: number;
22
+ /** Whether to use locale-specific formatting (e.g., 1,234). Defaults to true. */
23
+ useLocale?: boolean;
24
+ /** Locale for formatting. Defaults to browser locale. */
25
+ locale?: string;
26
+ /** Custom formatter function. Overrides decimals and locale settings. */
27
+ formatter?: (value: number) => string;
28
+ /** Delay before starting animation in ms. Defaults to 0. */
29
+ delay?: number;
30
+ /** Whether to start animation immediately. Defaults to true. */
31
+ autoStart?: boolean;
32
+ /** Callback when animation completes. */
33
+ onComplete?: () => void;
34
+ /** Callback on each value update. */
35
+ onUpdate?: (value: number) => void;
36
+ /** Prefix to add before the number (e.g., "$"). */
37
+ prefix?: string;
38
+ /** Suffix to add after the number (e.g., "%"). */
39
+ suffix?: string;
40
+ /** Whether animation is enabled. Defaults to true. */
41
+ enabled?: boolean;
42
+ }
43
+ /**
44
+ * Return type for the useCountUp hook.
45
+ */
46
+ export interface UseCountUpResult {
47
+ /** Current animated value (raw number). */
48
+ value: number;
49
+ /** Formatted display string with prefix/suffix. */
50
+ displayValue: string;
51
+ /** Whether animation is currently running. */
52
+ isAnimating: boolean;
53
+ /** Whether animation has completed. */
54
+ isComplete: boolean;
55
+ /** Start or restart the animation. */
56
+ start: () => void;
57
+ /** Pause the animation at current value. */
58
+ pause: () => void;
59
+ /** Resume a paused animation. */
60
+ resume: () => void;
61
+ /** Reset to starting value. */
62
+ reset: () => void;
63
+ /** Update the target value (will animate to new value). */
64
+ update: (newTo: number) => void;
65
+ /** Whether reduced motion is preferred. */
66
+ prefersReducedMotion: boolean;
67
+ }
68
+ /**
69
+ * Hook for animating numbers from one value to another.
70
+ *
71
+ * Features:
72
+ * - Configurable duration and easing
73
+ * - Respects reduced motion preferences
74
+ * - Locale-aware number formatting
75
+ * - Start/pause/resume/reset controls
76
+ * - Prefix and suffix support
77
+ * - Custom formatter support
78
+ *
79
+ * @param options - Configuration options for the animation
80
+ * @returns Object with current value, display string, and control functions
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * // Basic usage
85
+ * const { displayValue } = useCountUp({ to: 1000 });
86
+ * return <span>{displayValue}</span>;
87
+ *
88
+ * // With formatting
89
+ * const { displayValue } = useCountUp({
90
+ * to: 99.5,
91
+ * decimals: 1,
92
+ * suffix: "%",
93
+ * duration: 1500,
94
+ * });
95
+ *
96
+ * // Currency
97
+ * const { displayValue } = useCountUp({
98
+ * to: 1234567,
99
+ * prefix: "$",
100
+ * useLocale: true,
101
+ * });
102
+ *
103
+ * // Manual control
104
+ * const { displayValue, start, reset, isAnimating } = useCountUp({
105
+ * to: 500,
106
+ * autoStart: false,
107
+ * });
108
+ * ```
109
+ */
110
+ export declare function useCountUp(options: UseCountUpOptions): UseCountUpResult;
111
+ //# sourceMappingURL=use-count-up.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-count-up.d.ts","sourceRoot":"","sources":["../../src/hooks/use-count-up.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAO5D;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,kDAAkD;IAClD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,WAAW,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,sCAAsC;IACtC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,iCAAiC;IACjC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2DAA2D;IAC3D,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,2CAA2C;IAC3C,oBAAoB,EAAE,OAAO,CAAC;CACjC;AA8DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAyLvE"}
@@ -0,0 +1,246 @@
1
+ // Copyright (c) 2026 Amsterdam Data Labs
2
+ "use client";
3
+ /**
4
+ * useCountUp Hook
5
+ *
6
+ * Animates a number from a start value to an end value with configurable
7
+ * duration, easing, and formatting. Respects reduced motion preferences.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ import { useCallback, useEffect, useRef, useState } from "react";
12
+ import { getDuration } from "../presets/motion-styles";
13
+ // =============================================================================
14
+ // Easing Functions
15
+ // =============================================================================
16
+ const easingFunctions = {
17
+ linear: (t) => t,
18
+ easeOut: (t) => 1 - (1 - t) ** 3,
19
+ easeOutExpo: (t) => (t === 1 ? 1 : 1 - 2 ** (-10 * t)),
20
+ easeInOut: (t) => (t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2),
21
+ spring: (t) => {
22
+ const c4 = (2 * Math.PI) / 3;
23
+ return t === 0 ? 0 : t === 1 ? 1 : 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
24
+ },
25
+ };
26
+ // =============================================================================
27
+ // Reduced Motion Detection
28
+ // =============================================================================
29
+ function useReducedMotion() {
30
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(() => {
31
+ if (typeof window === "undefined")
32
+ return false;
33
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
34
+ });
35
+ useEffect(() => {
36
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
37
+ setPrefersReducedMotion(mediaQuery.matches);
38
+ const handler = (e) => {
39
+ setPrefersReducedMotion(e.matches);
40
+ };
41
+ mediaQuery.addEventListener("change", handler);
42
+ return () => mediaQuery.removeEventListener("change", handler);
43
+ }, []);
44
+ return prefersReducedMotion;
45
+ }
46
+ // =============================================================================
47
+ // Default Formatter
48
+ // =============================================================================
49
+ function createDefaultFormatter(decimals, useLocale, locale) {
50
+ return (value) => {
51
+ if (useLocale) {
52
+ return value.toLocaleString(locale, {
53
+ minimumFractionDigits: decimals,
54
+ maximumFractionDigits: decimals,
55
+ });
56
+ }
57
+ return value.toFixed(decimals);
58
+ };
59
+ }
60
+ // =============================================================================
61
+ // useCountUp Hook
62
+ // =============================================================================
63
+ /**
64
+ * Hook for animating numbers from one value to another.
65
+ *
66
+ * Features:
67
+ * - Configurable duration and easing
68
+ * - Respects reduced motion preferences
69
+ * - Locale-aware number formatting
70
+ * - Start/pause/resume/reset controls
71
+ * - Prefix and suffix support
72
+ * - Custom formatter support
73
+ *
74
+ * @param options - Configuration options for the animation
75
+ * @returns Object with current value, display string, and control functions
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * // Basic usage
80
+ * const { displayValue } = useCountUp({ to: 1000 });
81
+ * return <span>{displayValue}</span>;
82
+ *
83
+ * // With formatting
84
+ * const { displayValue } = useCountUp({
85
+ * to: 99.5,
86
+ * decimals: 1,
87
+ * suffix: "%",
88
+ * duration: 1500,
89
+ * });
90
+ *
91
+ * // Currency
92
+ * const { displayValue } = useCountUp({
93
+ * to: 1234567,
94
+ * prefix: "$",
95
+ * useLocale: true,
96
+ * });
97
+ *
98
+ * // Manual control
99
+ * const { displayValue, start, reset, isAnimating } = useCountUp({
100
+ * to: 500,
101
+ * autoStart: false,
102
+ * });
103
+ * ```
104
+ */
105
+ export function useCountUp(options) {
106
+ const { from = 0, to, duration: customDuration, motionStyle = "standard", easing = "easeOutExpo", decimals = 0, useLocale = true, locale, formatter: customFormatter, delay = 0, autoStart = true, onComplete, onUpdate, prefix = "", suffix = "", enabled = true, } = options;
107
+ // Get duration from motion style if not custom (use slow for count-up animations)
108
+ const duration = customDuration ?? getDuration(motionStyle, "slow");
109
+ // State
110
+ const [value, setValue] = useState(from);
111
+ const [isAnimating, setIsAnimating] = useState(false);
112
+ const [isComplete, setIsComplete] = useState(false);
113
+ // Refs for animation control
114
+ const animationRef = useRef(null);
115
+ const startTimeRef = useRef(null);
116
+ const pausedTimeRef = useRef(null);
117
+ const currentFromRef = useRef(from);
118
+ const currentToRef = useRef(to);
119
+ // Reduced motion
120
+ const prefersReducedMotion = useReducedMotion();
121
+ // Formatter
122
+ const formatter = customFormatter ?? createDefaultFormatter(decimals, useLocale, locale);
123
+ // Format display value
124
+ const displayValue = `${prefix}${formatter(value)}${suffix}`;
125
+ // Cancel animation
126
+ const cancelAnimation = useCallback(() => {
127
+ if (animationRef.current !== null) {
128
+ cancelAnimationFrame(animationRef.current);
129
+ animationRef.current = null;
130
+ }
131
+ }, []);
132
+ // Animation frame handler
133
+ const animate = useCallback((timestamp) => {
134
+ if (startTimeRef.current === null) {
135
+ startTimeRef.current = timestamp;
136
+ }
137
+ const elapsed = timestamp - startTimeRef.current;
138
+ const progress = Math.min(elapsed / duration, 1);
139
+ const easedProgress = easingFunctions[easing](progress);
140
+ const currentValue = currentFromRef.current + (currentToRef.current - currentFromRef.current) * easedProgress;
141
+ setValue(currentValue);
142
+ onUpdate?.(currentValue);
143
+ if (progress < 1) {
144
+ animationRef.current = requestAnimationFrame(animate);
145
+ }
146
+ else {
147
+ setIsAnimating(false);
148
+ setIsComplete(true);
149
+ onComplete?.();
150
+ }
151
+ }, [duration, easing, onComplete, onUpdate]);
152
+ // Start animation
153
+ const start = useCallback(() => {
154
+ if (!enabled) {
155
+ setValue(currentToRef.current);
156
+ setIsComplete(true);
157
+ return;
158
+ }
159
+ // Handle reduced motion - jump to end value immediately
160
+ if (prefersReducedMotion) {
161
+ setValue(currentToRef.current);
162
+ setIsComplete(true);
163
+ onComplete?.();
164
+ return;
165
+ }
166
+ cancelAnimation();
167
+ setIsComplete(false);
168
+ startTimeRef.current = null;
169
+ pausedTimeRef.current = null;
170
+ const startAnimation = () => {
171
+ setIsAnimating(true);
172
+ animationRef.current = requestAnimationFrame(animate);
173
+ };
174
+ if (delay > 0) {
175
+ setTimeout(startAnimation, delay);
176
+ }
177
+ else {
178
+ startAnimation();
179
+ }
180
+ }, [enabled, prefersReducedMotion, cancelAnimation, animate, delay, onComplete]);
181
+ // Pause animation
182
+ const pause = useCallback(() => {
183
+ if (isAnimating && animationRef.current !== null) {
184
+ pausedTimeRef.current = performance.now();
185
+ cancelAnimation();
186
+ setIsAnimating(false);
187
+ }
188
+ }, [isAnimating, cancelAnimation]);
189
+ // Resume animation
190
+ const resume = useCallback(() => {
191
+ if (!isAnimating && !isComplete && pausedTimeRef.current !== null && startTimeRef.current !== null) {
192
+ // Adjust start time to account for paused duration
193
+ const pausedDuration = performance.now() - pausedTimeRef.current;
194
+ startTimeRef.current += pausedDuration;
195
+ pausedTimeRef.current = null;
196
+ setIsAnimating(true);
197
+ animationRef.current = requestAnimationFrame(animate);
198
+ }
199
+ }, [isAnimating, isComplete, animate]);
200
+ // Reset to starting value
201
+ const reset = useCallback(() => {
202
+ cancelAnimation();
203
+ setValue(currentFromRef.current);
204
+ setIsAnimating(false);
205
+ setIsComplete(false);
206
+ startTimeRef.current = null;
207
+ pausedTimeRef.current = null;
208
+ }, [cancelAnimation]);
209
+ // Update target value
210
+ const update = useCallback((newTo) => {
211
+ currentFromRef.current = value;
212
+ currentToRef.current = newTo;
213
+ start();
214
+ }, [value, start]);
215
+ // Auto-start on mount - intentionally only runs once
216
+ // biome-ignore lint/correctness/useExhaustiveDependencies: We only want to start animation on mount, not on every dependency change
217
+ useEffect(() => {
218
+ if (autoStart) {
219
+ currentFromRef.current = from;
220
+ currentToRef.current = to;
221
+ start();
222
+ }
223
+ return () => {
224
+ cancelAnimation();
225
+ };
226
+ }, []);
227
+ // Update target when `to` prop changes
228
+ useEffect(() => {
229
+ if (to !== currentToRef.current && isComplete) {
230
+ update(to);
231
+ }
232
+ }, [to, isComplete, update]);
233
+ return {
234
+ value,
235
+ displayValue,
236
+ isAnimating,
237
+ isComplete,
238
+ start,
239
+ pause,
240
+ resume,
241
+ reset,
242
+ update,
243
+ prefersReducedMotion,
244
+ };
245
+ }
246
+ //# sourceMappingURL=use-count-up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-count-up.js","sourceRoot":"","sources":["../../src/hooks/use-count-up.ts"],"names":[],"mappings":"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"}