@tarsis/toolkit 0.6.5 → 0.7.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 (78) hide show
  1. package/dist/Container-BVX2MW1U.cjs +138 -0
  2. package/dist/Container-BirkN1fA.js +119 -0
  3. package/dist/SelectBase-BC6WKZVF.cjs +448 -0
  4. package/dist/SelectBase-DPcXvMTa.js +399 -0
  5. package/dist/Slot-SOe-b2n6.cjs +77 -0
  6. package/dist/Slot-z71j7q57.js +65 -0
  7. package/dist/animation-BFpILbqb.js +102 -0
  8. package/dist/animation-BauloIgQ.cjs +119 -0
  9. package/dist/assets-BMqH4phf.cjs +52 -0
  10. package/dist/assets-huTvlamy.js +29 -0
  11. package/dist/audio/fail.mp3 +0 -0
  12. package/dist/audio/fail.ogg +0 -0
  13. package/dist/audio/hover.mp3 +0 -0
  14. package/dist/audio/hover.ogg +0 -0
  15. package/dist/audio/lock/fail.mp3 +0 -0
  16. package/dist/audio/lock/fail.ogg +0 -0
  17. package/dist/audio/lock/hover.mp3 +0 -0
  18. package/dist/audio/lock/hover.ogg +0 -0
  19. package/dist/audio/lock/prev-next.mp3 +0 -0
  20. package/dist/audio/lock/prev-next.ogg +0 -0
  21. package/dist/audio/lock/select.mp3 +0 -0
  22. package/dist/audio/lock/select.ogg +0 -0
  23. package/dist/audio/lock/success.mp3 +0 -0
  24. package/dist/audio/lock/success.ogg +0 -0
  25. package/dist/audio/prev-next.mp3 +0 -0
  26. package/dist/audio/prev-next.ogg +0 -0
  27. package/dist/audio/select.mp3 +0 -0
  28. package/dist/audio/select.ogg +0 -0
  29. package/dist/audio/success.mp3 +0 -0
  30. package/dist/audio/success.ogg +0 -0
  31. package/dist/chunk-CKQMccvm.cjs +28 -0
  32. package/dist/fonts/orbitron/orbitron-black.fnt +426 -0
  33. package/dist/fonts/orbitron/orbitron-black.png +0 -0
  34. package/dist/fonts/orbitron-black.fnt +426 -0
  35. package/dist/fonts/orbitron-black.png +0 -0
  36. package/dist/gl-B0NhVYRl.cjs +177 -0
  37. package/dist/gl-BipoEx9s.js +171 -0
  38. package/dist/hooks.cjs +661 -24
  39. package/dist/hooks.d.ts +72 -0
  40. package/dist/hooks.js +635 -1
  41. package/dist/index.cjs +26708 -384
  42. package/dist/index.d.ts +913 -27
  43. package/dist/index.js +26282 -3
  44. package/dist/layout.cjs +5 -0
  45. package/dist/layout.d.ts +45 -0
  46. package/dist/layout.js +2 -0
  47. package/dist/primitives.cjs +13 -0
  48. package/dist/primitives.d.ts +178 -0
  49. package/dist/primitives.js +3 -0
  50. package/dist/server.cjs +25 -0
  51. package/dist/server.d.ts +70 -0
  52. package/dist/server.js +2 -0
  53. package/dist/styles.css +3872 -2798
  54. package/dist/tokens-B2AxRYyF.js +434 -0
  55. package/dist/tokens-DlMougUi.cjs +469 -0
  56. package/dist/tokens.cjs +12 -0
  57. package/dist/tokens.d.ts +435 -0
  58. package/dist/tokens.js +3 -0
  59. package/dist/useMergeRefs-BM2-gSLn.js +16 -0
  60. package/dist/useMergeRefs-C_l6omwU.cjs +28 -0
  61. package/dist/utils-BGgmkNY4.cjs +330 -0
  62. package/dist/utils-Dw5El_3G.js +222 -0
  63. package/dist/utils.cjs +44 -38
  64. package/dist/utils.d.ts +75 -0
  65. package/dist/utils.js +3 -1
  66. package/dist/values-BTw18-W5.js +138 -0
  67. package/dist/values-BqSJ0h9o.cjs +275 -0
  68. package/package.json +88 -36
  69. package/dist/gl-Bp3e3vph.js +0 -3258
  70. package/dist/gl-Duf2UKsB.cjs +0 -3262
  71. package/dist/index-BcIzOPR7.cjs +0 -116866
  72. package/dist/index-BjG_vCX_.js +0 -3910
  73. package/dist/index-ZBjz1bHI.cjs +0 -3912
  74. package/dist/index-ss50SEnC.js +0 -116503
  75. package/dist/svg-BT_esDTZ.cjs +0 -236
  76. package/dist/svg-CQLdTbLk.js +0 -205
  77. package/dist/useWindowReady-6kIdYolB.cjs +0 -9317
  78. package/dist/useWindowReady-tUs-ONyG.js +0 -9224
package/dist/hooks.cjs CHANGED
@@ -1,24 +1,661 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
5
- const useWindowReady = require('./useWindowReady-6kIdYolB.cjs');
6
-
7
-
8
-
9
- exports.useAnimatedText = useWindowReady.useAnimatedText;
10
- exports.useBowser = useWindowReady.useBowser;
11
- exports.useDebounce = useWindowReady.useDebounce;
12
- exports.useEffectEvent = useWindowReady.useEffectEvent;
13
- exports.useInterval = useWindowReady.useInterval;
14
- exports.useLiveRef = useWindowReady.useLiveRef;
15
- exports.useMatchMedia = useWindowReady.useMatchMedia;
16
- exports.useOklch = useWindowReady.useOklch;
17
- exports.useOutsideClick = useWindowReady.useOutsideClick;
18
- exports.usePreviousRender = useWindowReady.usePreviousRender;
19
- exports.usePreviousState = useWindowReady.usePreviousState;
20
- exports.useRaf = useWindowReady.useRaf;
21
- exports.useThrottle = useWindowReady.useThrottle;
22
- exports.useTimeout = useWindowReady.useTimeout;
23
- exports.useUniversalLayoutEffect = useWindowReady.useUniversalLayoutEffect;
24
- exports.useWindowReady = useWindowReady.useWindowReady;
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_chunk = require("./chunk-CKQMccvm.cjs");
3
+ const require_useMergeRefs = require("./useMergeRefs-C_l6omwU.cjs");
4
+ let react = require("react");
5
+ react = require_chunk.__toESM(react);
6
+ let gsap = require("gsap");
7
+ gsap = require_chunk.__toESM(gsap);
8
+ let motion_react = require("motion/react");
9
+ let bowser = require("bowser");
10
+ bowser = require_chunk.__toESM(bowser);
11
+ //#region src/hooks/usePrevious.ts
12
+ var usePreviousState = (value) => {
13
+ const previousRef = (0, react.useRef)(void 0);
14
+ const currentRef = (0, react.useRef)(void 0);
15
+ (0, react.useEffect)(() => {
16
+ if (value !== currentRef.current) {
17
+ previousRef.current = currentRef.current;
18
+ currentRef.current = value;
19
+ }
20
+ }, [value]);
21
+ return previousRef.current;
22
+ };
23
+ var usePreviousRender = (value) => {
24
+ const previousRef = (0, react.useRef)(void 0);
25
+ (0, react.useEffect)(() => {
26
+ previousRef.current = value;
27
+ }, [value]);
28
+ return previousRef.current;
29
+ };
30
+ //#endregion
31
+ //#region src/hooks/useAnimatedText/useAnimatedText.ts
32
+ function useAnimatedText(text, delimiter) {
33
+ const resolvedDelimiter = delimiter === "word" ? " " : "";
34
+ const animatedCursor = (0, motion_react.useMotionValue)(0);
35
+ const [cursor, setCursor] = (0, react.useState)(0);
36
+ const prevText = usePreviousRender(text);
37
+ const isSameText = text.startsWith(prevText ?? "");
38
+ const mountedRef = (0, react.useRef)(true);
39
+ (0, react.useEffect)(() => {
40
+ mountedRef.current = true;
41
+ return () => {
42
+ mountedRef.current = false;
43
+ };
44
+ }, []);
45
+ (0, react.useEffect)(() => {
46
+ if (!isSameText && mountedRef.current) {
47
+ animatedCursor.jump(0);
48
+ requestAnimationFrame(() => {
49
+ if (mountedRef.current) setCursor(0);
50
+ });
51
+ }
52
+ }, [isSameText, animatedCursor]);
53
+ (0, react.useEffect)(() => {
54
+ if (!mountedRef.current) return;
55
+ const controls = (0, motion_react.animate)(animatedCursor, text.split(resolvedDelimiter).length, {
56
+ duration: 3,
57
+ ease: "easeOut",
58
+ onUpdate(latest) {
59
+ if (mountedRef.current) setCursor(Math.floor(latest));
60
+ }
61
+ });
62
+ return () => {
63
+ controls.stop();
64
+ };
65
+ }, [
66
+ animatedCursor,
67
+ isSameText,
68
+ text,
69
+ resolvedDelimiter
70
+ ]);
71
+ return text.split(resolvedDelimiter).slice(0, cursor).join(resolvedDelimiter);
72
+ }
73
+ //#endregion
74
+ //#region src/hooks/useControllableState.ts
75
+ function useControllableState(controlledValue, defaultValue, onChange) {
76
+ const isControlled = controlledValue !== void 0;
77
+ const isControlledRef = (0, react.useRef)(isControlled);
78
+ const [internalValue, setInternalValue] = (0, react.useState)(defaultValue);
79
+ (0, react.useEffect)(() => {
80
+ if (process.env.NODE_ENV !== "production") {
81
+ if (isControlledRef.current !== isControlled) console.warn("Component switched between controlled and uncontrolled. Decide between using a controlled or uncontrolled value for the lifetime of the component.");
82
+ }
83
+ isControlledRef.current = isControlled;
84
+ });
85
+ return [isControlled ? controlledValue : internalValue, (0, react.useCallback)((next) => {
86
+ const resolve = (prev) => typeof next === "function" ? next(prev) : next;
87
+ if (!isControlledRef.current) setInternalValue((prev) => {
88
+ const nextValue = resolve(prev);
89
+ onChange?.(nextValue);
90
+ return nextValue;
91
+ });
92
+ else onChange?.(resolve(controlledValue));
93
+ }, [onChange, controlledValue])];
94
+ }
95
+ //#endregion
96
+ //#region src/hooks/useBowser.ts
97
+ var useBowser = () => {
98
+ const [browser] = (0, react.useState)(() => typeof window === "undefined" ? null : bowser.default.parse(window.navigator.userAgent));
99
+ const [parser] = (0, react.useState)(() => typeof window === "undefined" ? null : bowser.default.getParser(window.navigator.userAgent));
100
+ return (0, react.useMemo)(() => {
101
+ if (!parser || !browser) return null;
102
+ const browserName = parser.getBrowser().name;
103
+ const isDesktop = browser.platform.type === "desktop";
104
+ return {
105
+ isMobile: browser.platform.type === "mobile",
106
+ isDesktop,
107
+ isIOS: browser.os.name?.toLowerCase() === "ios",
108
+ isMacOS: browser.platform.type?.toLocaleLowerCase() === "desktop" && browser.platform.vendor?.toLowerCase() === "apple" && browser.os.name?.toLocaleLowerCase() === "macos",
109
+ isSafari: browserName ? Boolean(browserName.toLowerCase().match(/safari/)) : false,
110
+ isFirefox: browserName ? Boolean(browserName.toLowerCase().match(/firefox/)) : false,
111
+ isChrome: browserName ? Boolean(browserName.toLowerCase().match(/chrome/)) : false
112
+ };
113
+ }, [browser, parser]);
114
+ };
115
+ //#endregion
116
+ //#region src/hooks/useLiveRef.ts
117
+ var useLiveRef = (value) => {
118
+ const ref = (0, react.useRef)(value);
119
+ ref.current = value;
120
+ return ref;
121
+ };
122
+ //#endregion
123
+ //#region src/hooks/useDebounce.ts
124
+ /**
125
+ * Custom hook that debounces a callback function to delay its execution until after
126
+ * a specified wait time has elapsed since the last time it was invoked.
127
+ *
128
+ * Debouncing ensures that the callback is only executed once after a series of rapid calls,
129
+ * waiting for a pause in the calls before executing.
130
+ *
131
+ * @param callback - The function to debounce
132
+ * @param delay - The delay time (in milliseconds) to wait before executing the callback
133
+ * @param options - Optional configuration object
134
+ * @param options.maxWait - Maximum time before function must be invoked
135
+ * @param options.leading - If true, invoke on the leading edge
136
+ * @returns A debounced version of the callback function with a `cancel` method
137
+ *
138
+ * @example
139
+ * ```tsx
140
+ * const debouncedSearch = useDebounce((query: string) => {
141
+ * console.log('Searching for:', query)
142
+ * }, 300)
143
+ *
144
+ * return <input onChange={(e) => debouncedSearch(e.target.value)} />
145
+ * ```
146
+ *
147
+ * @example
148
+ * ```tsx
149
+ * // With maxWait and leading options
150
+ * const debouncedSearch = useDebounce(
151
+ * (query: string) => console.log('Searching for:', query),
152
+ * 300,
153
+ * { maxWait: 1000, leading: true }
154
+ * )
155
+ * ```
156
+ *
157
+ * @example
158
+ * ```tsx
159
+ * // Cancel pending debounced call
160
+ * const debouncedSearch = useDebounce((query: string) => {
161
+ * console.log('Searching for:', query)
162
+ * }, 300)
163
+ *
164
+ * debouncedSearch('test')
165
+ * debouncedSearch.cancel() // Cancels the pending call
166
+ * ```
167
+ */
168
+ var useDebounce = (callback, delay, { maxWait, leading = false } = {}) => {
169
+ const timeoutRef = (0, react.useRef)(null);
170
+ const maxTimeoutMetadataRef = (0, react.useRef)(null);
171
+ const callbackRef = useLiveRef(callback);
172
+ const clearTimers = (0, react.useCallback)(() => {
173
+ if (timeoutRef.current) {
174
+ clearTimeout(timeoutRef.current);
175
+ timeoutRef.current = null;
176
+ }
177
+ if (maxTimeoutMetadataRef.current) {
178
+ clearTimeout(maxTimeoutMetadataRef.current.timeout);
179
+ maxTimeoutMetadataRef.current = null;
180
+ }
181
+ }, []);
182
+ const cancel = (0, react.useCallback)(() => {
183
+ clearTimers();
184
+ }, [clearTimers]);
185
+ const invokeCallback = (0, react.useCallback)((args) => {
186
+ clearTimers();
187
+ callbackRef.current(...args);
188
+ }, [clearTimers, callbackRef]);
189
+ (0, react.useEffect)(() => {
190
+ return clearTimers;
191
+ }, [clearTimers]);
192
+ const debounced = (0, react.useCallback)((...args) => {
193
+ const isNewCycle = timeoutRef.current === null;
194
+ if (leading && isNewCycle) callbackRef.current(...args);
195
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
196
+ if (maxWait && !maxTimeoutMetadataRef.current) maxTimeoutMetadataRef.current = {
197
+ timeout: setTimeout(() => {
198
+ if (maxTimeoutMetadataRef.current) invokeCallback(maxTimeoutMetadataRef.current.args);
199
+ }, maxWait),
200
+ args
201
+ };
202
+ else if (maxTimeoutMetadataRef.current) maxTimeoutMetadataRef.current.args = args;
203
+ timeoutRef.current = setTimeout(() => {
204
+ invokeCallback(args);
205
+ }, delay);
206
+ }, [
207
+ delay,
208
+ maxWait,
209
+ leading,
210
+ invokeCallback,
211
+ callbackRef
212
+ ]);
213
+ return Object.assign(debounced, { cancel });
214
+ };
215
+ //#endregion
216
+ //#region src/hooks/useEffectEvent.ts
217
+ /**
218
+ * Universal layout effect that uses useLayoutEffect in browser environments
219
+ * and falls back to useEffect in SSR environments
220
+ */
221
+ var useUniversalLayoutEffect = typeof window === "undefined" ? react.default.useEffect : react.default.useLayoutEffect;
222
+ /**
223
+ * Use `toString()` to prevent bundlers from trying to `import { useInsertionEffect } from 'react';`
224
+ * @see https://github.com/radix-ui/primitives/blob/main/packages/react/id/src/id.tsx
225
+ */
226
+ var useInsertionEffect = react.default["useInsertionEffect".toString()] || useUniversalLayoutEffect;
227
+ function useEffectEvent(callback) {
228
+ const ref = react.default.useRef(() => {
229
+ throw new Error("Cannot call an event handler while rendering.");
230
+ });
231
+ useInsertionEffect(() => {
232
+ ref.current = callback;
233
+ }, [callback]);
234
+ return react.default.useCallback((...args) => {
235
+ return ref.current?.(...args);
236
+ }, []);
237
+ }
238
+ //#endregion
239
+ //#region src/hooks/useInterval.ts
240
+ var DEFAULT_DEPENDENCIES$1 = [];
241
+ /**
242
+ * Custom hook that manages an interval with automatic cleanup.
243
+ * Provides a reliable way to handle intervals that are properly cleaned up
244
+ * on component unmount or when dependencies change.
245
+ *
246
+ * @param callback - The function to execute on each interval
247
+ * @param delay - The delay in milliseconds (null to clear the interval)
248
+ * @param deps - Optional dependency array. If provided, interval restarts when deps change.
249
+ * If not provided, callback updates via ref without restarting interval.
250
+ *
251
+ * @example
252
+ * ```tsx
253
+ * // Runs continuously, callback updates via ref
254
+ * useInterval(() => {
255
+ * console.log('This runs every second')
256
+ * }, 1000)
257
+ *
258
+ * // Restarts interval when count changes
259
+ * useInterval(() => {
260
+ * console.log('Count:', count)
261
+ * }, 1000, [count])
262
+ * ```
263
+ */
264
+ var useInterval = (callback, delay = null, deps = DEFAULT_DEPENDENCIES$1) => {
265
+ const intervalRef = (0, react.useRef)(null);
266
+ const callbackRef = (0, react.useRef)(callback);
267
+ (0, react.useEffect)(() => {
268
+ callbackRef.current = callback;
269
+ }, [callback]);
270
+ (0, react.useEffect)(() => {
271
+ if (delay === null) return;
272
+ intervalRef.current = setInterval(() => {
273
+ callbackRef.current();
274
+ }, delay);
275
+ return () => {
276
+ if (intervalRef.current) {
277
+ clearInterval(intervalRef.current);
278
+ intervalRef.current = null;
279
+ }
280
+ };
281
+ }, [delay, ...deps]);
282
+ };
283
+ //#endregion
284
+ //#region src/hooks/useMatchMedia.ts
285
+ var hasMatchMedia = () => {
286
+ return typeof window?.matchMedia === "function";
287
+ };
288
+ var useMatchMedia = (query) => {
289
+ const [matches, setMatches] = (0, react.useState)(() => {
290
+ if (!hasMatchMedia()) return null;
291
+ try {
292
+ return window.matchMedia(query).matches;
293
+ } catch {
294
+ return null;
295
+ }
296
+ });
297
+ const matchMedia = (0, react.useMemo)(() => {
298
+ if (!hasMatchMedia()) return null;
299
+ try {
300
+ return window.matchMedia(query);
301
+ } catch {
302
+ return null;
303
+ }
304
+ }, [query]);
305
+ const handleChange = (0, react.useCallback)((event) => {
306
+ setMatches(event.matches);
307
+ }, []);
308
+ (0, react.useEffect)(() => {
309
+ if (!matchMedia) return;
310
+ requestAnimationFrame(() => {
311
+ setMatches(matchMedia.matches);
312
+ });
313
+ if (matchMedia.addEventListener) {
314
+ matchMedia.addEventListener("change", handleChange);
315
+ return () => matchMedia.removeEventListener("change", handleChange);
316
+ }
317
+ const legacyHandler = (event) => {
318
+ handleChange(event);
319
+ };
320
+ matchMedia.addListener(legacyHandler);
321
+ return () => matchMedia.removeListener(legacyHandler);
322
+ }, [matchMedia, handleChange]);
323
+ return matches;
324
+ };
325
+ //#endregion
326
+ //#region src/hooks/useOklch.ts
327
+ var globalCounterRef = { current: 0 };
328
+ var useOklch = () => {
329
+ const hasSetP3Ref = (0, react.useRef)(false);
330
+ (0, react.useEffect)(() => {
331
+ if (typeof window === "undefined") return;
332
+ globalCounterRef.current += 1;
333
+ hasSetP3Ref.current = true;
334
+ document.body.dataset.p3 = "false";
335
+ return () => {
336
+ globalCounterRef.current -= 1;
337
+ if (globalCounterRef.current < 1 && hasSetP3Ref.current) {
338
+ document.body.dataset.p3 = void 0;
339
+ hasSetP3Ref.current = false;
340
+ }
341
+ };
342
+ }, []);
343
+ };
344
+ //#endregion
345
+ //#region src/hooks/useOutsideClick.ts
346
+ /**
347
+ * Custom hook that detects clicks outside of a specified element and triggers a callback.
348
+ *
349
+ * Useful for implementing dropdown menus, modals, or any component that should close
350
+ * when the user clicks outside of it.
351
+ *
352
+ * @param ref - React ref object pointing to the element to monitor
353
+ * @param callback - Function to call when a click occurs outside the element
354
+ * @param isActive - Whether the outside click detection should be active (default: true)
355
+ *
356
+ * @example
357
+ * ```tsx
358
+ * const ref = useRef<HTMLDivElement>(null)
359
+ * const [isOpen, setIsOpen] = useState(false)
360
+ *
361
+ * useOutsideClick(ref, () => setIsOpen(false), isOpen)
362
+ *
363
+ * return <div ref={ref}>...</div>
364
+ * ```
365
+ */
366
+ var useOutsideClick = (ref, callback, isActive = true) => {
367
+ const liveCallbackRef = useLiveRef(callback);
368
+ (0, react.useEffect)(() => {
369
+ if (!isActive) return;
370
+ const handleClick = (event) => {
371
+ if (ref.current && !ref.current.contains(event.target)) liveCallbackRef.current();
372
+ };
373
+ document.addEventListener("pointerdown", handleClick, true);
374
+ return () => {
375
+ document.removeEventListener("pointerdown", handleClick, true);
376
+ };
377
+ }, [
378
+ ref,
379
+ isActive,
380
+ liveCallbackRef
381
+ ]);
382
+ };
383
+ //#endregion
384
+ //#region src/hooks/useRaf.ts
385
+ /**
386
+ * Custom hook that provides a requestAnimationFrame-based callback execution.
387
+ * Useful for performance-critical animations and continuous updates that should
388
+ * be synchronized with the browser's refresh rate.
389
+ *
390
+ * The callback will be executed on the next animation frame, and can be
391
+ * controlled with an enabled flag for conditional execution.
392
+ *
393
+ * @param callback - The function to execute on each animation frame
394
+ * @param enabled - Whether the animation loop should be active (default: true)
395
+ * @returns A function to manually trigger the animation frame callback
396
+ *
397
+ * @example
398
+ * ```tsx
399
+ * const animate = useRaf(() => {
400
+ * // Animation logic here
401
+ * console.log('Animation frame')
402
+ * }, isAnimating)
403
+ *
404
+ * // Manually trigger
405
+ * animate()
406
+ * ```
407
+ */
408
+ var useRaf = (callback, enabled = true) => {
409
+ const rafIdRef = (0, react.useRef)(null);
410
+ const isRunningRef = (0, react.useRef)(false);
411
+ const enabledRef = useLiveRef(enabled);
412
+ const cleanup = (0, react.useCallback)(() => {
413
+ if (rafIdRef.current) {
414
+ cancelAnimationFrame(rafIdRef.current);
415
+ rafIdRef.current = null;
416
+ }
417
+ isRunningRef.current = false;
418
+ }, []);
419
+ const animate = (0, react.useCallback)(() => {
420
+ if (!enabledRef.current) return;
421
+ cleanup();
422
+ isRunningRef.current = true;
423
+ const loop = () => {
424
+ if (!enabledRef.current || !isRunningRef.current) {
425
+ isRunningRef.current = false;
426
+ return;
427
+ }
428
+ callback();
429
+ rafIdRef.current = requestAnimationFrame(loop);
430
+ };
431
+ rafIdRef.current = requestAnimationFrame(loop);
432
+ }, [
433
+ callback,
434
+ cleanup,
435
+ enabledRef
436
+ ]);
437
+ (0, react.useEffect)(() => {
438
+ if (enabled) animate();
439
+ else cleanup();
440
+ return cleanup;
441
+ }, [
442
+ enabled,
443
+ animate,
444
+ cleanup
445
+ ]);
446
+ return animate;
447
+ };
448
+ //#endregion
449
+ //#region src/hooks/useThrottle.ts
450
+ /**
451
+ * Custom hook that throttles a callback function to limit how often it can be invoked.
452
+ *
453
+ * Throttling ensures that the callback is executed at most once per specified time interval,
454
+ * regardless of how many times the throttled function is called.
455
+ *
456
+ * @param callback - The function to throttle
457
+ * @param delay - The minimum time interval (in milliseconds) between executions
458
+ * @returns A throttled version of the callback function
459
+ *
460
+ * @example
461
+ * ```tsx
462
+ * const throttledClick = useThrottle(() => {
463
+ * console.log('Button clicked')
464
+ * }, 500)
465
+ *
466
+ * return <button onClick={throttledClick}>Click me</button>
467
+ * ```
468
+ */
469
+ var useThrottle = (callback, delay) => {
470
+ const lastExecuted = (0, react.useRef)(0);
471
+ const timeoutRef = (0, react.useRef)(null);
472
+ (0, react.useEffect)(() => {
473
+ return () => {
474
+ if (timeoutRef.current) {
475
+ clearTimeout(timeoutRef.current);
476
+ timeoutRef.current = null;
477
+ }
478
+ };
479
+ }, [callback, delay]);
480
+ return (0, react.useCallback)((...args) => {
481
+ const now = Date.now();
482
+ if (now - lastExecuted.current >= delay) {
483
+ callback(...args);
484
+ lastExecuted.current = now;
485
+ } else {
486
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
487
+ timeoutRef.current = setTimeout(() => {
488
+ callback(...args);
489
+ lastExecuted.current = Date.now();
490
+ timeoutRef.current = null;
491
+ }, delay - (now - lastExecuted.current));
492
+ }
493
+ }, [callback, delay]);
494
+ };
495
+ //#endregion
496
+ //#region src/hooks/useTimeout.ts
497
+ var DEFAULT_DEPENDENCIES = [];
498
+ /**
499
+ * Custom hook that manages a timeout with automatic cleanup.
500
+ * Provides a reliable way to handle timeouts that are properly cleaned up
501
+ * on component unmount or when dependencies change.
502
+ *
503
+ * @param callback - The function to execute after the delay
504
+ * @param delay - The delay in milliseconds (null to clear the timeout)
505
+ * @param deps - Optional dependency array. If provided, timeout restarts when deps change.
506
+ * If not provided, callback updates via ref without restarting timeout.
507
+ *
508
+ * @example
509
+ * ```tsx
510
+ * // Runs once, callback updates via ref
511
+ * useTimeout(() => {
512
+ * console.log('This runs after 1 second')
513
+ * }, 1000)
514
+ *
515
+ * // Restarts timeout when count changes
516
+ * useTimeout(() => {
517
+ * console.log('Count:', count)
518
+ * }, 1000, [count])
519
+ * ```
520
+ */
521
+ var useTimeout = (callback, delay = null, deps = DEFAULT_DEPENDENCIES) => {
522
+ const timeoutRef = (0, react.useRef)(null);
523
+ const callbackRef = (0, react.useRef)(callback);
524
+ (0, react.useEffect)(() => {
525
+ callbackRef.current = callback;
526
+ }, [callback]);
527
+ (0, react.useEffect)(() => {
528
+ if (delay === null) return;
529
+ timeoutRef.current = setTimeout(() => {
530
+ callbackRef.current();
531
+ }, delay);
532
+ return () => {
533
+ if (timeoutRef.current) {
534
+ clearTimeout(timeoutRef.current);
535
+ timeoutRef.current = null;
536
+ }
537
+ };
538
+ }, [delay, ...deps]);
539
+ };
540
+ //#endregion
541
+ //#region src/hooks/useWindowReady.tsx
542
+ var useWindowReady = () => {
543
+ const [ready, setReady] = (0, react.useState)(false);
544
+ (0, react.useEffect)(() => {
545
+ const timer = setTimeout(() => setReady(true), 0);
546
+ return () => clearTimeout(timer);
547
+ }, []);
548
+ return ready;
549
+ };
550
+ //#endregion
551
+ //#region src/hooks/useReducedMotion.ts
552
+ var QUERY = "(prefers-reduced-motion: reduce)";
553
+ function useReducedMotion() {
554
+ const [reduced, setReduced] = (0, react.useState)(() => {
555
+ if (typeof window === "undefined") return false;
556
+ return window.matchMedia(QUERY).matches;
557
+ });
558
+ (0, react.useEffect)(() => {
559
+ const mql = window.matchMedia(QUERY);
560
+ const handler = (e) => setReduced(e.matches);
561
+ mql.addEventListener("change", handler);
562
+ return () => mql.removeEventListener("change", handler);
563
+ }, []);
564
+ return reduced;
565
+ }
566
+ //#endregion
567
+ //#region src/hooks/useGsapContext.ts
568
+ /**
569
+ * Creates a GSAP context scoped to the given ref.
570
+ * All animations created inside the callback are automatically
571
+ * reverted on unmount — preventing DOM leak bugs.
572
+ */
573
+ function useGsapContext(scope, callback, deps = []) {
574
+ const ctxRef = (0, react.useRef)(null);
575
+ (0, react.useEffect)(() => {
576
+ if (!scope.current) return;
577
+ const ctx = gsap.default.context((context) => {
578
+ const typedContext = context;
579
+ ctxRef.current = typedContext;
580
+ const cleanup = callback(typedContext);
581
+ if (typeof cleanup === "function") typedContext.add(cleanup);
582
+ }, scope.current);
583
+ ctxRef.current = ctx;
584
+ return () => {
585
+ ctx.revert();
586
+ ctxRef.current = null;
587
+ };
588
+ }, [scope, ...deps]);
589
+ return ctxRef;
590
+ }
591
+ //#endregion
592
+ //#region src/hooks/useFormField.ts
593
+ function useFormField(options = {}) {
594
+ const { id: externalId, hasError = false, hasHint = false } = options;
595
+ const autoId = (0, react.useId)();
596
+ const fieldId = externalId ?? autoId;
597
+ const ids = (0, react.useMemo)(() => ({
598
+ fieldId,
599
+ labelId: `${fieldId}-label`,
600
+ errorId: `${fieldId}-error`,
601
+ hintId: `${fieldId}-hint`,
602
+ descriptionId: `${fieldId}-description`
603
+ }), [fieldId]);
604
+ const describedBy = (0, react.useMemo)(() => {
605
+ const parts = [];
606
+ if (hasError) parts.push(ids.errorId);
607
+ if (hasHint && !hasError) parts.push(ids.hintId);
608
+ return parts.length > 0 ? parts.join(" ") : void 0;
609
+ }, [
610
+ hasError,
611
+ hasHint,
612
+ ids.errorId,
613
+ ids.hintId
614
+ ]);
615
+ return (0, react.useMemo)(() => ({
616
+ ids,
617
+ labelProps: {
618
+ htmlFor: fieldId,
619
+ id: ids.labelId
620
+ },
621
+ fieldProps: {
622
+ id: fieldId,
623
+ "aria-describedby": describedBy,
624
+ "aria-invalid": hasError || void 0,
625
+ "aria-errormessage": hasError ? ids.errorId : void 0
626
+ },
627
+ errorProps: {
628
+ id: ids.errorId,
629
+ role: "alert"
630
+ },
631
+ hintProps: { id: ids.hintId }
632
+ }), [
633
+ ids,
634
+ fieldId,
635
+ describedBy,
636
+ hasError
637
+ ]);
638
+ }
639
+ //#endregion
640
+ exports.mergeRefs = require_useMergeRefs.mergeRefs;
641
+ exports.useAnimatedText = useAnimatedText;
642
+ exports.useBowser = useBowser;
643
+ exports.useControllableState = useControllableState;
644
+ exports.useDebounce = useDebounce;
645
+ exports.useEffectEvent = useEffectEvent;
646
+ exports.useFormField = useFormField;
647
+ exports.useGsapContext = useGsapContext;
648
+ exports.useInterval = useInterval;
649
+ exports.useLiveRef = useLiveRef;
650
+ exports.useMatchMedia = useMatchMedia;
651
+ exports.useMergeRefs = require_useMergeRefs.useMergeRefs;
652
+ exports.useOklch = useOklch;
653
+ exports.useOutsideClick = useOutsideClick;
654
+ exports.usePreviousRender = usePreviousRender;
655
+ exports.usePreviousState = usePreviousState;
656
+ exports.useRaf = useRaf;
657
+ exports.useReducedMotion = useReducedMotion;
658
+ exports.useThrottle = useThrottle;
659
+ exports.useTimeout = useTimeout;
660
+ exports.useUniversalLayoutEffect = useUniversalLayoutEffect;
661
+ exports.useWindowReady = useWindowReady;