@ts-hooks-kit/core 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,2574 @@
1
+ "use strict";
2
+ //#region rolldown:runtime
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+
24
+ //#endregion
25
+ const react = __toESM(require("react"));
26
+
27
+ //#region src/useAsync/useAsync.ts
28
+ /**
29
+ * Custom hook that manages the state of an async function.
30
+ * @template T - The type of the resolved value.
31
+ * @param {() => Promise<T>} asyncFn - The async function to execute.
32
+ * @param {unknown[]} [deps] - Dependencies that trigger re-execution when changed.
33
+ * @returns {UseAsyncState<T>} The state of the async operation.
34
+ * @public
35
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-async)
36
+ * @example
37
+ * ```tsx
38
+ * const { value, error, loading, retry } = useAsync(async () => {
39
+ * const response = await fetch('/api/data');
40
+ * return response.json();
41
+ * }, []);
42
+ * ```
43
+ */
44
+ function useAsync(asyncFn, deps = []) {
45
+ const [state, setState] = (0, react.useState)({
46
+ loading: true,
47
+ value: void 0,
48
+ error: void 0
49
+ });
50
+ const asyncFnRef = (0, react.useRef)(asyncFn);
51
+ const isMountedRef = (0, react.useRef)(true);
52
+ (0, react.useEffect)(() => {
53
+ asyncFnRef.current = asyncFn;
54
+ }, [asyncFn]);
55
+ const execute = (0, react.useCallback)(async () => {
56
+ setState((prev) => ({
57
+ ...prev,
58
+ loading: true,
59
+ error: void 0
60
+ }));
61
+ try {
62
+ const result = await asyncFnRef.current();
63
+ if (isMountedRef.current) setState({
64
+ loading: false,
65
+ value: result,
66
+ error: void 0
67
+ });
68
+ } catch (err) {
69
+ if (isMountedRef.current) setState({
70
+ loading: false,
71
+ value: void 0,
72
+ error: err instanceof Error ? err : new Error(String(err))
73
+ });
74
+ }
75
+ }, deps);
76
+ const retry = (0, react.useCallback)(() => {
77
+ execute();
78
+ }, [execute]);
79
+ (0, react.useEffect)(() => {
80
+ isMountedRef.current = true;
81
+ execute();
82
+ return () => {
83
+ isMountedRef.current = false;
84
+ };
85
+ }, [execute]);
86
+ return {
87
+ loading: state.loading,
88
+ value: state.value,
89
+ error: state.error,
90
+ retry
91
+ };
92
+ }
93
+
94
+ //#endregion
95
+ //#region src/useBoolean/useBoolean.ts
96
+ /**
97
+ * Custom hook that handles boolean state with useful utility functions.
98
+ * @param {boolean} [defaultValue] - The initial value for the boolean state (default is `false`).
99
+ * @returns {UseBooleanReturn} An object containing the boolean state value and utility functions to manipulate the state.
100
+ * @throws Will throw an error if `defaultValue` is an invalid boolean value.
101
+ * @public
102
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-boolean)
103
+ * @example
104
+ * ```tsx
105
+ * const { value, setTrue, setFalse, toggle } = useBoolean(true);
106
+ * ```
107
+ */
108
+ function useBoolean(defaultValue = false) {
109
+ if (typeof defaultValue !== "boolean") throw new Error("defaultValue must be `true` or `false`");
110
+ const [value, setValue] = (0, react.useState)(defaultValue);
111
+ const setTrue = (0, react.useCallback)(() => {
112
+ setValue(true);
113
+ }, []);
114
+ const setFalse = (0, react.useCallback)(() => {
115
+ setValue(false);
116
+ }, []);
117
+ const toggle = (0, react.useCallback)(() => {
118
+ setValue((x) => !x);
119
+ }, []);
120
+ return {
121
+ value,
122
+ setValue,
123
+ setTrue,
124
+ setFalse,
125
+ toggle
126
+ };
127
+ }
128
+
129
+ //#endregion
130
+ //#region src/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.ts
131
+ /**
132
+ * Custom hook that uses either `useLayoutEffect` or `useEffect` based on the environment (client-side or server-side).
133
+ * @param {Function} effect - The effect function to be executed.
134
+ * @param {Array<any>} [dependencies] - An array of dependencies for the effect (optional).
135
+ * @public
136
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect)
137
+ * @example
138
+ * ```tsx
139
+ * useIsomorphicLayoutEffect(() => {
140
+ * // Code to be executed during the layout phase on the client side
141
+ * }, [dependency1, dependency2]);
142
+ * ```
143
+ */
144
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
145
+
146
+ //#endregion
147
+ //#region src/useEventListener/useEventListener.ts
148
+ /**
149
+ * Custom hook that attaches event listeners to DOM elements, the window, or media query lists.
150
+ * @template KW - The type of event for window events.
151
+ * @template KH - The type of event for HTML or SVG element events.
152
+ * @template KM - The type of event for media query list events.
153
+ * @template T - The type of the DOM element (default is `HTMLElement`).
154
+ * @param {KW | KH | KM} eventName - The name of the event to listen for.
155
+ * @param {(event: WindowEventMap[KW] | HTMLElementEventMap[KH] | SVGElementEventMap[KH] | MediaQueryListEventMap[KM] | Event) => void} handler - The event handler function.
156
+ * @param {RefObject<T>} [element] - The DOM element or media query list to attach the event listener to (optional).
157
+ * @param {boolean | AddEventListenerOptions} [options] - An options object that specifies characteristics about the event listener (optional).
158
+ * @public
159
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-event-listener)
160
+ * @example
161
+ * ```tsx
162
+ * // Example 1: Attach a window event listener
163
+ * useEventListener('resize', handleResize);
164
+ * ```
165
+ * @example
166
+ * ```tsx
167
+ * // Example 2: Attach a document event listener with options
168
+ * const elementRef = useRef(document);
169
+ * useEventListener('click', handleClick, elementRef, { capture: true });
170
+ * ```
171
+ * @example
172
+ * ```tsx
173
+ * // Example 3: Attach an element event listener
174
+ * const buttonRef = useRef<HTMLButtonElement>(null);
175
+ * useEventListener('click', handleButtonClick, buttonRef);
176
+ * ```
177
+ */
178
+ function useEventListener(eventName, handler, element, options) {
179
+ const savedHandler = (0, react.useRef)(handler);
180
+ useIsomorphicLayoutEffect(() => {
181
+ savedHandler.current = handler;
182
+ }, [handler]);
183
+ (0, react.useEffect)(() => {
184
+ const targetElement = element?.current ?? window;
185
+ if (!(targetElement && targetElement.addEventListener)) return;
186
+ const listener = (event) => {
187
+ savedHandler.current(event);
188
+ };
189
+ targetElement.addEventListener(eventName, listener, options);
190
+ return () => {
191
+ targetElement.removeEventListener(eventName, listener, options);
192
+ };
193
+ }, [
194
+ eventName,
195
+ element,
196
+ options
197
+ ]);
198
+ }
199
+
200
+ //#endregion
201
+ //#region src/useClickAnyWhere/useClickAnyWhere.ts
202
+ /**
203
+ * Custom hook that handles click events anywhere on the document.
204
+ * @param {Function} handler - The function to be called when a click event is detected anywhere on the document.
205
+ * @public
206
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-click-any-where)
207
+ * @example
208
+ * ```tsx
209
+ * const handleClick = (event) => {
210
+ * console.log('Document clicked!', event);
211
+ * };
212
+ *
213
+ * // Attach click event handler to document
214
+ * useClickAnywhere(handleClick);
215
+ * ```
216
+ */
217
+ function useClickAnyWhere(handler) {
218
+ useEventListener("click", (event) => {
219
+ handler(event);
220
+ });
221
+ }
222
+
223
+ //#endregion
224
+ //#region src/useCopyToClipboard/useCopyToClipboard.ts
225
+ /**
226
+ * Custom hook that copies text to the clipboard using the [`Clipboard API`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API).
227
+ * @returns {[CopiedValue, CopyFn]} An tuple containing the copied text and a function to copy text to the clipboard.
228
+ * @public
229
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-copy-to-clipboard)
230
+ * @example
231
+ * ```tsx
232
+ * const [copiedText, copyToClipboard] = useCopyToClipboard();
233
+ * const textToCopy = 'Hello, world!';
234
+ *
235
+ * // Attempt to copy text to the clipboard
236
+ * copyToClipboard(textToCopy)
237
+ * .then(success => {
238
+ * if (success) {
239
+ * console.log(`Text "${textToCopy}" copied to clipboard successfully.`);
240
+ * } else {
241
+ * console.error('Failed to copy text to clipboard.');
242
+ * }
243
+ * });
244
+ * ```
245
+ */
246
+ function useCopyToClipboard() {
247
+ const [copiedText, setCopiedText] = (0, react.useState)(null);
248
+ const copy = (0, react.useCallback)(async (text) => {
249
+ if (!navigator?.clipboard) {
250
+ console.warn("Clipboard not supported");
251
+ return false;
252
+ }
253
+ try {
254
+ await navigator.clipboard.writeText(text);
255
+ setCopiedText(text);
256
+ return true;
257
+ } catch (error) {
258
+ console.warn("Copy failed", error);
259
+ setCopiedText(null);
260
+ return false;
261
+ }
262
+ }, []);
263
+ return [copiedText, copy];
264
+ }
265
+
266
+ //#endregion
267
+ //#region src/useCounter/useCounter.ts
268
+ /**
269
+ * Custom hook that manages a counter with increment, decrement, reset, and setCount functionalities.
270
+ * @param {number} [initialValue] - The initial value for the counter.
271
+ * @returns {UseCounterReturn} An object containing the current count and functions to interact with the counter.
272
+ * @public
273
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-counter)
274
+ * @example
275
+ * ```tsx
276
+ * const { count, increment, decrement, reset, setCount } = useCounter(5);
277
+ * ```
278
+ */
279
+ function useCounter(initialValue) {
280
+ const [count, setCount] = (0, react.useState)(initialValue ?? 0);
281
+ const increment = (0, react.useCallback)(() => {
282
+ setCount((x) => x + 1);
283
+ }, []);
284
+ const decrement = (0, react.useCallback)(() => {
285
+ setCount((x) => x - 1);
286
+ }, []);
287
+ const reset = (0, react.useCallback)(() => {
288
+ setCount(initialValue ?? 0);
289
+ }, [initialValue]);
290
+ return {
291
+ count,
292
+ increment,
293
+ decrement,
294
+ reset,
295
+ setCount
296
+ };
297
+ }
298
+
299
+ //#endregion
300
+ //#region src/useInterval/useInterval.ts
301
+ /**
302
+ * Custom hook that creates an interval that invokes a callback function at a specified delay using the [`setInterval API`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval).
303
+ * @param {() => void} callback - The function to be invoked at each interval.
304
+ * @param {number | null} delay - The time, in milliseconds, between each invocation of the callback. Use `null` to clear the interval.
305
+ * @public
306
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-interval)
307
+ * @example
308
+ * ```tsx
309
+ * const handleInterval = () => {
310
+ * // Code to be executed at each interval
311
+ * };
312
+ * useInterval(handleInterval, 1000);
313
+ * ```
314
+ */
315
+ function useInterval(callback, delay) {
316
+ const savedCallback = (0, react.useRef)(callback);
317
+ useIsomorphicLayoutEffect(() => {
318
+ savedCallback.current = callback;
319
+ }, [callback]);
320
+ (0, react.useEffect)(() => {
321
+ if (delay === null) return;
322
+ const id = setInterval(() => {
323
+ savedCallback.current();
324
+ }, delay);
325
+ return () => {
326
+ clearInterval(id);
327
+ };
328
+ }, [delay]);
329
+ }
330
+
331
+ //#endregion
332
+ //#region src/useCountdown/useCountdown.ts
333
+ /**
334
+ * Custom hook that manages countdown.
335
+ * @param {CountdownOptions} countdownOptions - The countdown's options.
336
+ * @returns {[number, CountdownControllers]} An array containing the countdown's count and its controllers.
337
+ * @public
338
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-countdown)
339
+ * @example
340
+ * ```tsx
341
+ * const [counter, { start, stop, reset }] = useCountdown({
342
+ * countStart: 10,
343
+ * intervalMs: 1000,
344
+ * isIncrement: false,
345
+ * });
346
+ * ```
347
+ */
348
+ function useCountdown({ countStart, countStop = 0, intervalMs = 1e3, isIncrement = false }) {
349
+ const { count, increment, decrement, reset: resetCounter } = useCounter(countStart);
350
+ const { value: isCountdownRunning, setTrue: startCountdown, setFalse: stopCountdown } = useBoolean(false);
351
+ const resetCountdown = (0, react.useCallback)(() => {
352
+ stopCountdown();
353
+ resetCounter();
354
+ }, [stopCountdown, resetCounter]);
355
+ const countdownCallback = (0, react.useCallback)(() => {
356
+ if (count === countStop) {
357
+ stopCountdown();
358
+ return;
359
+ }
360
+ if (isIncrement) increment();
361
+ else decrement();
362
+ }, [
363
+ count,
364
+ countStop,
365
+ decrement,
366
+ increment,
367
+ isIncrement,
368
+ stopCountdown
369
+ ]);
370
+ useInterval(countdownCallback, isCountdownRunning ? intervalMs : null);
371
+ return [count, {
372
+ startCountdown,
373
+ stopCountdown,
374
+ resetCountdown
375
+ }];
376
+ }
377
+
378
+ //#endregion
379
+ //#region src/useEventCallback/useEventCallback.ts
380
+ function useEventCallback(fn) {
381
+ const ref = (0, react.useRef)(() => {
382
+ throw new Error("Cannot call an event handler while rendering.");
383
+ });
384
+ useIsomorphicLayoutEffect(() => {
385
+ ref.current = fn;
386
+ }, [fn]);
387
+ return (0, react.useCallback)((...args) => ref.current?.(...args), [ref]);
388
+ }
389
+
390
+ //#endregion
391
+ //#region src/useLocalStorage/useLocalStorage.ts
392
+ const IS_SERVER$6 = typeof window === "undefined";
393
+ /**
394
+ * Custom hook that uses the [`localStorage API`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to persist state across page reloads.
395
+ * @template T - The type of the state to be stored in local storage.
396
+ * @param {string} key - The key under which the value will be stored in local storage.
397
+ * @param {T | (() => T)} initialValue - The initial value of the state or a function that returns the initial value.
398
+ * @param {UseLocalStorageOptions<T>} [options] - Options for customizing the behavior of serialization and deserialization (optional).
399
+ * @returns {[T, Dispatch<SetStateAction<T>>, () => void]} A tuple containing the stored value, a function to set the value and a function to remove the key from storage.
400
+ * @public
401
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-local-storage)
402
+ * @example
403
+ * ```tsx
404
+ * const [count, setCount, removeCount] = useLocalStorage('count', 0);
405
+ * // Access the `count` value, the `setCount` function to update it and `removeCount` function to remove the key from storage.
406
+ * ```
407
+ */
408
+ function useLocalStorage(key, initialValue, options = {}) {
409
+ const { initializeWithValue = true } = options;
410
+ const serializer = (0, react.useCallback)((value) => {
411
+ if (options.serializer) return options.serializer(value);
412
+ return JSON.stringify(value);
413
+ }, [options]);
414
+ const deserializer = (0, react.useCallback)((value) => {
415
+ if (options.deserializer) return options.deserializer(value);
416
+ if (value === "undefined") return void 0;
417
+ const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
418
+ let parsed;
419
+ try {
420
+ parsed = JSON.parse(value);
421
+ } catch (error) {
422
+ console.error("Error parsing JSON:", error);
423
+ return defaultValue;
424
+ }
425
+ return parsed;
426
+ }, [options, initialValue]);
427
+ const readValue = (0, react.useCallback)(() => {
428
+ const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;
429
+ if (IS_SERVER$6) return initialValueToUse;
430
+ try {
431
+ const raw = window.localStorage.getItem(key);
432
+ return raw ? deserializer(raw) : initialValueToUse;
433
+ } catch (error) {
434
+ console.warn(`Error reading localStorage key “${key}”:`, error);
435
+ return initialValueToUse;
436
+ }
437
+ }, [
438
+ initialValue,
439
+ key,
440
+ deserializer
441
+ ]);
442
+ const [storedValue, setStoredValue] = (0, react.useState)(() => {
443
+ if (initializeWithValue) return readValue();
444
+ return initialValue instanceof Function ? initialValue() : initialValue;
445
+ });
446
+ const setValue = useEventCallback((value) => {
447
+ if (IS_SERVER$6) console.warn(`Tried setting localStorage key “${key}” even though environment is not a client`);
448
+ try {
449
+ const newValue = value instanceof Function ? value(readValue()) : value;
450
+ window.localStorage.setItem(key, serializer(newValue));
451
+ setStoredValue(newValue);
452
+ window.dispatchEvent(new StorageEvent("local-storage", { key }));
453
+ } catch (error) {
454
+ console.warn(`Error setting localStorage key “${key}”:`, error);
455
+ }
456
+ });
457
+ const removeValue = useEventCallback(() => {
458
+ if (IS_SERVER$6) console.warn(`Tried removing localStorage key “${key}” even though environment is not a client`);
459
+ const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
460
+ window.localStorage.removeItem(key);
461
+ setStoredValue(defaultValue);
462
+ window.dispatchEvent(new StorageEvent("local-storage", { key }));
463
+ });
464
+ (0, react.useEffect)(() => {
465
+ setStoredValue(readValue());
466
+ }, [key]);
467
+ const handleStorageChange = (0, react.useCallback)((event) => {
468
+ if (event.key && event.key !== key) return;
469
+ setStoredValue(readValue());
470
+ }, [key, readValue]);
471
+ useEventListener("storage", handleStorageChange);
472
+ useEventListener("local-storage", handleStorageChange);
473
+ return [
474
+ storedValue,
475
+ setValue,
476
+ removeValue
477
+ ];
478
+ }
479
+
480
+ //#endregion
481
+ //#region src/useMediaQuery/useMediaQuery.ts
482
+ const IS_SERVER$5 = typeof window === "undefined";
483
+ /**
484
+ * Custom hook that tracks the state of a media query using the [`Match Media API`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia).
485
+ * @param {string} query - The media query to track.
486
+ * @param {?UseMediaQueryOptions} [options] - The options for customizing the behavior of the hook (optional).
487
+ * @returns {boolean} The current state of the media query (true if the query matches, false otherwise).
488
+ * @public
489
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-media-query)
490
+ * @example
491
+ * ```tsx
492
+ * const isSmallScreen = useMediaQuery('(max-width: 600px)');
493
+ * // Use `isSmallScreen` to conditionally apply styles or logic based on the screen size.
494
+ * ```
495
+ */
496
+ function useMediaQuery(query, { defaultValue = false, initializeWithValue = true } = {}) {
497
+ const getMatches = (query$1) => {
498
+ if (IS_SERVER$5) return defaultValue;
499
+ return window.matchMedia(query$1).matches;
500
+ };
501
+ const [matches, setMatches] = (0, react.useState)(() => {
502
+ if (initializeWithValue) return getMatches(query);
503
+ return defaultValue;
504
+ });
505
+ function handleChange() {
506
+ setMatches(getMatches(query));
507
+ }
508
+ useIsomorphicLayoutEffect(() => {
509
+ const matchMedia = window.matchMedia(query);
510
+ handleChange();
511
+ if (matchMedia.addListener) matchMedia.addListener(handleChange);
512
+ else matchMedia.addEventListener("change", handleChange);
513
+ return () => {
514
+ if (matchMedia.removeListener) matchMedia.removeListener(handleChange);
515
+ else matchMedia.removeEventListener("change", handleChange);
516
+ };
517
+ }, [query]);
518
+ return matches;
519
+ }
520
+
521
+ //#endregion
522
+ //#region src/useDarkMode/useDarkMode.ts
523
+ const COLOR_SCHEME_QUERY$1 = "(prefers-color-scheme: dark)";
524
+ const LOCAL_STORAGE_KEY$1 = "usehooks-ts-dark-mode";
525
+ /**
526
+ * Custom hook that returns the current state of the dark mode.
527
+ * @param {?DarkModeOptions} [options] - The initial value of the dark mode, default `false`.
528
+ * @returns {DarkModeReturn} An object containing the dark mode's state and its controllers.
529
+ * @public
530
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-dark-mode)
531
+ * @example
532
+ * ```tsx
533
+ * const { isDarkMode, toggle, enable, disable, set } = useDarkMode({ defaultValue: true });
534
+ * ```
535
+ */
536
+ function useDarkMode(options = {}) {
537
+ const { defaultValue, localStorageKey = LOCAL_STORAGE_KEY$1, initializeWithValue = true } = options;
538
+ const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY$1, {
539
+ initializeWithValue,
540
+ defaultValue
541
+ });
542
+ const [isDarkMode, setDarkMode] = useLocalStorage(localStorageKey, defaultValue ?? isDarkOS ?? false, { initializeWithValue });
543
+ useIsomorphicLayoutEffect(() => {
544
+ if (isDarkOS !== isDarkMode) setDarkMode(isDarkOS);
545
+ }, [isDarkOS]);
546
+ return {
547
+ isDarkMode,
548
+ toggle: () => {
549
+ setDarkMode((prev) => !prev);
550
+ },
551
+ enable: () => {
552
+ setDarkMode(true);
553
+ },
554
+ disable: () => {
555
+ setDarkMode(false);
556
+ },
557
+ set: (value) => {
558
+ setDarkMode(value);
559
+ }
560
+ };
561
+ }
562
+
563
+ //#endregion
564
+ //#region src/utils/debounce.ts
565
+ /**
566
+ * Creates a debounced version of a function.
567
+ * @param func The function to debounce
568
+ * @param delay The delay in milliseconds
569
+ * @param options Debounce options
570
+ * @returns Debounced function with cancel and flush methods
571
+ */
572
+ function debounce(func, delay, options = {}) {
573
+ const { leading = false, trailing = true, maxWait } = options;
574
+ let timeoutId = null;
575
+ let maxTimeoutId = null;
576
+ let lastArgs = null;
577
+ let lastResult;
578
+ let lastCallTime = null;
579
+ const clearTimeouts = () => {
580
+ if (timeoutId) {
581
+ clearTimeout(timeoutId);
582
+ timeoutId = null;
583
+ }
584
+ if (maxTimeoutId) {
585
+ clearTimeout(maxTimeoutId);
586
+ maxTimeoutId = null;
587
+ }
588
+ };
589
+ const invokeFunc = (args) => {
590
+ lastArgs = null;
591
+ lastCallTime = null;
592
+ lastResult = func(...args);
593
+ return lastResult;
594
+ };
595
+ const remainingWait = (time) => {
596
+ const timeSinceLastCall = time - (lastCallTime ?? 0);
597
+ return delay - timeSinceLastCall;
598
+ };
599
+ const shouldInvoke = (time) => {
600
+ const timeSinceLastCall = time - (lastCallTime ?? 0);
601
+ return lastCallTime === null || timeSinceLastCall >= delay || timeSinceLastCall < 0;
602
+ };
603
+ const trailingEdge = () => {
604
+ timeoutId = null;
605
+ if (trailing && lastArgs) return invokeFunc(lastArgs);
606
+ lastArgs = null;
607
+ lastCallTime = null;
608
+ return void 0;
609
+ };
610
+ const timerExpired = () => {
611
+ const time = Date.now();
612
+ if (shouldInvoke(time)) return trailingEdge();
613
+ const timeWaiting = remainingWait(time);
614
+ timeoutId = setTimeout(timerExpired, timeWaiting);
615
+ return void 0;
616
+ };
617
+ const debounced = (...args) => {
618
+ const time = Date.now();
619
+ const isInvoking = shouldInvoke(time);
620
+ lastArgs = args;
621
+ if (isInvoking) {
622
+ clearTimeouts();
623
+ if (lastCallTime === null) {
624
+ lastCallTime = time;
625
+ timeoutId = setTimeout(timerExpired, delay);
626
+ if (leading) return invokeFunc(args);
627
+ return void 0;
628
+ }
629
+ lastCallTime = time;
630
+ return lastResult;
631
+ }
632
+ if (timeoutId) clearTimeout(timeoutId);
633
+ if (maxWait && !maxTimeoutId && lastCallTime !== null) {
634
+ const timeSinceLastCall = time - lastCallTime;
635
+ const timeUntilMaxWait = maxWait - timeSinceLastCall;
636
+ maxTimeoutId = setTimeout(() => {
637
+ maxTimeoutId = null;
638
+ if (lastArgs) invokeFunc(lastArgs);
639
+ }, timeUntilMaxWait);
640
+ }
641
+ const timeWaiting = remainingWait(time);
642
+ timeoutId = setTimeout(timerExpired, timeWaiting);
643
+ return lastResult;
644
+ };
645
+ debounced.cancel = () => {
646
+ clearTimeouts();
647
+ lastArgs = null;
648
+ lastCallTime = null;
649
+ };
650
+ debounced.flush = () => {
651
+ if (timeoutId || maxTimeoutId) {
652
+ clearTimeouts();
653
+ if (lastArgs) return invokeFunc(lastArgs);
654
+ }
655
+ return lastResult;
656
+ };
657
+ return debounced;
658
+ }
659
+
660
+ //#endregion
661
+ //#region src/useUnmount/useUnmount.ts
662
+ /**
663
+ * Custom hook that runs a cleanup function when the component is unmounted.
664
+ * @param {() => void} func - The cleanup function to be executed on unmount.
665
+ * @public
666
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-unmount)
667
+ * @example
668
+ * ```tsx
669
+ * useUnmount(() => {
670
+ * // Cleanup logic here
671
+ * });
672
+ * ```
673
+ */
674
+ function useUnmount(func) {
675
+ const funcRef = (0, react.useRef)(func);
676
+ funcRef.current = func;
677
+ (0, react.useEffect)(() => () => {
678
+ funcRef.current();
679
+ }, []);
680
+ }
681
+
682
+ //#endregion
683
+ //#region src/useDebounceCallback/useDebounceCallback.ts
684
+ /**
685
+ * Custom hook that creates a debounced version of a callback function.
686
+ * @template T - Type of the original callback function.
687
+ * @param {T} func - The callback function to be debounced.
688
+ * @param {number} delay - The delay in milliseconds before the callback is invoked (default is `500` milliseconds).
689
+ * @param {DebounceOptions} [options] - Options to control the behavior of the debounced function.
690
+ * @returns {DebouncedState<T>} A debounced version of the original callback along with control functions.
691
+ * @public
692
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-debounce-callback)
693
+ * @example
694
+ * ```tsx
695
+ * const debouncedCallback = useDebounceCallback(
696
+ * (searchTerm) => {
697
+ * // Perform search after user stops typing for 500 milliseconds
698
+ * searchApi(searchTerm);
699
+ * },
700
+ * 500
701
+ * );
702
+ *
703
+ * // Later in the component
704
+ * debouncedCallback('react hooks'); // Will invoke the callback after 500 milliseconds of inactivity.
705
+ * ```
706
+ */
707
+ function useDebounceCallback(func, delay = 500, options) {
708
+ const debouncedFunc = (0, react.useRef)(null);
709
+ useUnmount(() => {
710
+ if (debouncedFunc.current) debouncedFunc.current.cancel();
711
+ });
712
+ const debounced = (0, react.useMemo)(() => {
713
+ const debouncedFuncInstance = debounce(func, delay, options);
714
+ const wrappedFunc = (...args) => {
715
+ return debouncedFuncInstance(...args);
716
+ };
717
+ wrappedFunc.cancel = () => {
718
+ debouncedFuncInstance.cancel();
719
+ };
720
+ wrappedFunc.isPending = () => {
721
+ return !!debouncedFunc.current;
722
+ };
723
+ wrappedFunc.flush = () => {
724
+ return debouncedFuncInstance.flush();
725
+ };
726
+ return wrappedFunc;
727
+ }, [
728
+ func,
729
+ delay,
730
+ options
731
+ ]);
732
+ (0, react.useEffect)(() => {
733
+ debouncedFunc.current = debounce(func, delay, options);
734
+ }, [
735
+ func,
736
+ delay,
737
+ options
738
+ ]);
739
+ return debounced;
740
+ }
741
+
742
+ //#endregion
743
+ //#region src/useDebounceValue/useDebounceValue.ts
744
+ /**
745
+ * Custom hook that returns a debounced version of the provided value, along with a function to update it.
746
+ * @template T - The type of the value.
747
+ * @param {T | (() => T)} initialValue - The value to be debounced.
748
+ * @param {number} delay - The delay in milliseconds before the value is updated (default is 500ms).
749
+ * @param {object} [options] - Optional configurations for the debouncing behavior.
750
+ * @returns {[T, DebouncedState<(value: T) => void>]} An array containing the debounced value and the function to update it.
751
+ * @public
752
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-debounce-value)
753
+ * @example
754
+ * ```tsx
755
+ * const [debouncedValue, updateDebouncedValue] = useDebounceValue(inputValue, 500, { leading: true });
756
+ * ```
757
+ */
758
+ function useDebounceValue(initialValue, delay, options) {
759
+ const eq = options?.equalityFn ?? ((left, right) => left === right);
760
+ const unwrappedInitialValue = initialValue instanceof Function ? initialValue() : initialValue;
761
+ const [debouncedValue, setDebouncedValue] = (0, react.useState)(unwrappedInitialValue);
762
+ const previousValueRef = (0, react.useRef)(unwrappedInitialValue);
763
+ const updateDebouncedValue = useDebounceCallback(setDebouncedValue, delay, options);
764
+ if (!eq(previousValueRef.current, unwrappedInitialValue)) {
765
+ updateDebouncedValue(unwrappedInitialValue);
766
+ previousValueRef.current = unwrappedInitialValue;
767
+ }
768
+ return [debouncedValue, updateDebouncedValue];
769
+ }
770
+
771
+ //#endregion
772
+ //#region src/useDisclosure/useDisclosure.ts
773
+ /**
774
+ * Custom hook for managing boolean disclosure state (modals, popovers, drawers, etc.).
775
+ * @param {boolean} [initialState=false] - The initial open state.
776
+ * @param {UseDisclosureOptions} [options] - Optional callbacks for open/close events.
777
+ * @returns {UseDisclosureReturn} A tuple containing the open state and control actions.
778
+ * @public
779
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-disclosure)
780
+ * @example
781
+ * ```tsx
782
+ * const [opened, { open, close, toggle }] = useDisclosure(false, {
783
+ * onOpen: () => console.log('Opened'),
784
+ * onClose: () => console.log('Closed'),
785
+ * });
786
+ *
787
+ * return (
788
+ * <>
789
+ * <button onClick={open}>Open Modal</button>
790
+ * <Modal opened={opened} onClose={close}>
791
+ * <button onClick={close}>Close</button>
792
+ * </Modal>
793
+ * </>
794
+ * );
795
+ * ```
796
+ */
797
+ function useDisclosure(initialState = false, options = {}) {
798
+ const { onOpen, onClose } = options;
799
+ const [opened, setOpened] = (0, react.useState)(initialState);
800
+ const open = (0, react.useCallback)(() => {
801
+ setOpened((isOpen) => {
802
+ if (!isOpen) {
803
+ onOpen?.();
804
+ return true;
805
+ }
806
+ return isOpen;
807
+ });
808
+ }, [onOpen]);
809
+ const close = (0, react.useCallback)(() => {
810
+ setOpened((isOpen) => {
811
+ if (isOpen) {
812
+ onClose?.();
813
+ return false;
814
+ }
815
+ return isOpen;
816
+ });
817
+ }, [onClose]);
818
+ const toggle = (0, react.useCallback)(() => {
819
+ setOpened((isOpen) => {
820
+ if (isOpen) onClose?.();
821
+ else onOpen?.();
822
+ return !isOpen;
823
+ });
824
+ }, [onClose, onOpen]);
825
+ return [opened, {
826
+ open,
827
+ close,
828
+ toggle
829
+ }];
830
+ }
831
+
832
+ //#endregion
833
+ //#region src/useDocumentTitle/useDocumentTitle.ts
834
+ /**
835
+ * Custom hook that sets the document title.
836
+ * @param {string} title - The title to set.
837
+ * @param {?UseDocumentTitleOptions} [options] - The options.
838
+ * @public
839
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-document-title)
840
+ * @example
841
+ * ```tsx
842
+ * useDocumentTitle('My new title');
843
+ * ```
844
+ */
845
+ function useDocumentTitle(title, options = {}) {
846
+ const { preserveTitleOnUnmount = true } = options;
847
+ const defaultTitle = (0, react.useRef)(null);
848
+ useIsomorphicLayoutEffect(() => {
849
+ defaultTitle.current = window.document.title;
850
+ }, []);
851
+ useIsomorphicLayoutEffect(() => {
852
+ window.document.title = title;
853
+ }, [title]);
854
+ useUnmount(() => {
855
+ if (!preserveTitleOnUnmount && defaultTitle.current) window.document.title = defaultTitle.current;
856
+ });
857
+ }
858
+
859
+ //#endregion
860
+ //#region src/useGeolocation/useGeolocation.ts
861
+ /**
862
+ * Custom hook that provides access to the browser's geolocation API.
863
+ * @param {UseGeolocationOptions} [options] - Options for geolocation and hook behavior.
864
+ * @returns {UseGeolocationState} The current geolocation state.
865
+ * @public
866
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-geolocation)
867
+ * @example
868
+ * ```tsx
869
+ * const { latitude, longitude, loading, error } = useGeolocation({
870
+ * enableHighAccuracy: true,
871
+ * timeout: 5000,
872
+ * });
873
+ *
874
+ * if (loading) return <div>Loading location...</div>;
875
+ * if (error) return <div>Error: {error.message}</div>;
876
+ * return <div>Location: {latitude}, {longitude}</div>;
877
+ * ```
878
+ */
879
+ function useGeolocation(options = {}) {
880
+ const { enableHighAccuracy = false, timeout = Infinity, maximumAge = 0, enabled = true } = options;
881
+ const [state, setState] = (0, react.useState)({
882
+ latitude: void 0,
883
+ longitude: void 0,
884
+ accuracy: void 0,
885
+ altitude: void 0,
886
+ altitudeAccuracy: void 0,
887
+ heading: void 0,
888
+ speed: void 0,
889
+ timestamp: void 0,
890
+ loading: true,
891
+ error: void 0
892
+ });
893
+ (0, react.useEffect)(() => {
894
+ if (!enabled) {
895
+ setState((prev) => ({
896
+ ...prev,
897
+ loading: false
898
+ }));
899
+ return;
900
+ }
901
+ if (!navigator.geolocation) {
902
+ setState((prev) => ({
903
+ ...prev,
904
+ loading: false,
905
+ error: new Error("Geolocation is not supported")
906
+ }));
907
+ return;
908
+ }
909
+ let isMounted = true;
910
+ const onSuccess = (position) => {
911
+ if (!isMounted) return;
912
+ setState({
913
+ latitude: position.coords.latitude,
914
+ longitude: position.coords.longitude,
915
+ accuracy: position.coords.accuracy,
916
+ altitude: position.coords.altitude,
917
+ altitudeAccuracy: position.coords.altitudeAccuracy,
918
+ heading: position.coords.heading,
919
+ speed: position.coords.speed,
920
+ timestamp: position.timestamp,
921
+ loading: false,
922
+ error: void 0
923
+ });
924
+ };
925
+ const onError = (error) => {
926
+ if (!isMounted) return;
927
+ setState((prev) => ({
928
+ ...prev,
929
+ loading: false,
930
+ error
931
+ }));
932
+ };
933
+ navigator.geolocation.getCurrentPosition(onSuccess, onError, {
934
+ enableHighAccuracy,
935
+ timeout,
936
+ maximumAge
937
+ });
938
+ return () => {
939
+ isMounted = false;
940
+ };
941
+ }, [
942
+ enableHighAccuracy,
943
+ enabled,
944
+ maximumAge,
945
+ timeout
946
+ ]);
947
+ return state;
948
+ }
949
+
950
+ //#endregion
951
+ //#region src/useHover/useHover.ts
952
+ /**
953
+ * Custom hook that tracks whether a DOM element is being hovered over.
954
+ * @template T - The type of the DOM element. Defaults to `HTMLElement`.
955
+ * @param {RefObject<T>} elementRef - The ref object for the DOM element to track.
956
+ * @returns {boolean} A boolean value indicating whether the element is being hovered over.
957
+ * @public
958
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-hover)
959
+ * @example
960
+ * ```tsx
961
+ * const buttonRef = useRef<HTMLButtonElement>(null);
962
+ * const isHovered = useHover(buttonRef);
963
+ * // Access the isHovered variable to determine if the button is being hovered over.
964
+ * ```
965
+ */
966
+ function useHover(elementRef) {
967
+ const [value, setValue] = (0, react.useState)(false);
968
+ const handleMouseEnter = () => {
969
+ setValue(true);
970
+ };
971
+ const handleMouseLeave = () => {
972
+ setValue(false);
973
+ };
974
+ useEventListener("mouseenter", handleMouseEnter, elementRef);
975
+ useEventListener("mouseleave", handleMouseLeave, elementRef);
976
+ return value;
977
+ }
978
+
979
+ //#endregion
980
+ //#region src/useIdle/useIdle.ts
981
+ /**
982
+ * Default events that indicate user activity.
983
+ */
984
+ const DEFAULT_EVENTS = [
985
+ "mousemove",
986
+ "mousedown",
987
+ "resize",
988
+ "keydown",
989
+ "touchstart",
990
+ "wheel"
991
+ ];
992
+ /**
993
+ * Custom hook that tracks whether the user is idle (no activity for a specified time).
994
+ * @param {number} timeout - The time in milliseconds of inactivity before considering the user idle.
995
+ * @param {UseIdleOptions} [options] - Options for customizing the hook behavior.
996
+ * @returns {IdleState} The current idle state and last activity timestamp.
997
+ * @public
998
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-idle)
999
+ * @example
1000
+ * ```tsx
1001
+ * const { idle, lastActive } = useIdle(5000);
1002
+ *
1003
+ * return (
1004
+ * <div>
1005
+ * <p>{idle ? 'User is idle' : 'User is active'}</p>
1006
+ * <p>Last active: {new Date(lastActive).toLocaleString()}</p>
1007
+ * </div>
1008
+ * );
1009
+ * ```
1010
+ */
1011
+ function useIdle(timeout, options = {}) {
1012
+ const { events = DEFAULT_EVENTS, initialIdle = false } = options;
1013
+ const [state, setState] = (0, react.useState)({
1014
+ idle: initialIdle,
1015
+ lastActive: Date.now()
1016
+ });
1017
+ const timerRef = (0, react.useRef)(null);
1018
+ (0, react.useEffect)(() => {
1019
+ const resetIdle = () => {
1020
+ if (timerRef.current) clearTimeout(timerRef.current);
1021
+ setState({
1022
+ idle: false,
1023
+ lastActive: Date.now()
1024
+ });
1025
+ timerRef.current = setTimeout(() => {
1026
+ setState((prev) => ({
1027
+ ...prev,
1028
+ idle: true
1029
+ }));
1030
+ }, timeout);
1031
+ };
1032
+ events.forEach((event) => {
1033
+ window.addEventListener(event, resetIdle);
1034
+ });
1035
+ timerRef.current = setTimeout(() => {
1036
+ setState((prev) => ({
1037
+ ...prev,
1038
+ idle: true
1039
+ }));
1040
+ }, timeout);
1041
+ return () => {
1042
+ events.forEach((event) => {
1043
+ window.removeEventListener(event, resetIdle);
1044
+ });
1045
+ if (timerRef.current) clearTimeout(timerRef.current);
1046
+ };
1047
+ }, [timeout, events]);
1048
+ return state;
1049
+ }
1050
+
1051
+ //#endregion
1052
+ //#region src/useIntersectionObserver/useIntersectionObserver.ts
1053
+ /**
1054
+ * Custom hook that tracks the intersection of a DOM element with its containing element or the viewport using the [`Intersection Observer API`](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
1055
+ * @param {UseIntersectionObserverOptions} options - The options for the Intersection Observer.
1056
+ * @returns {IntersectionReturn} The ref callback, a boolean indicating if the element is intersecting, and the intersection observer entry.
1057
+ * @public
1058
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-intersection-observer)
1059
+ * @example
1060
+ * ```tsx
1061
+ * // Example 1
1062
+ * const [ref, isIntersecting, entry] = useIntersectionObserver({ threshold: 0.5 });
1063
+ * ```
1064
+ *
1065
+ * ```tsx
1066
+ * // Example 2
1067
+ * const { ref, isIntersecting, entry } = useIntersectionObserver({ threshold: 0.5 });
1068
+ * ```
1069
+ */
1070
+ function useIntersectionObserver({ threshold = 0, root = null, rootMargin = "0%", freezeOnceVisible = false, initialIsIntersecting = false, onChange } = {}) {
1071
+ const [ref, setRef] = (0, react.useState)(null);
1072
+ const [state, setState] = (0, react.useState)(() => ({
1073
+ isIntersecting: initialIsIntersecting,
1074
+ entry: void 0
1075
+ }));
1076
+ const callbackRef = (0, react.useRef)(void 0);
1077
+ callbackRef.current = onChange;
1078
+ const frozen = state.entry?.isIntersecting && freezeOnceVisible;
1079
+ (0, react.useEffect)(() => {
1080
+ if (!ref) return;
1081
+ if (!("IntersectionObserver" in window)) return;
1082
+ if (frozen) return;
1083
+ let unobserve;
1084
+ const observer = new IntersectionObserver((entries) => {
1085
+ const thresholds = Array.isArray(observer.thresholds) ? observer.thresholds : [observer.thresholds];
1086
+ entries.forEach((entry) => {
1087
+ const isIntersecting = entry.isIntersecting && thresholds.some((threshold$1) => entry.intersectionRatio >= threshold$1);
1088
+ setState({
1089
+ isIntersecting,
1090
+ entry
1091
+ });
1092
+ if (callbackRef.current) callbackRef.current(isIntersecting, entry);
1093
+ if (isIntersecting && freezeOnceVisible && unobserve) {
1094
+ unobserve();
1095
+ unobserve = void 0;
1096
+ }
1097
+ });
1098
+ }, {
1099
+ threshold,
1100
+ root,
1101
+ rootMargin
1102
+ });
1103
+ observer.observe(ref);
1104
+ return () => {
1105
+ observer.disconnect();
1106
+ };
1107
+ }, [
1108
+ ref,
1109
+ JSON.stringify(threshold),
1110
+ root,
1111
+ rootMargin,
1112
+ frozen,
1113
+ freezeOnceVisible
1114
+ ]);
1115
+ const prevRef = (0, react.useRef)(null);
1116
+ (0, react.useEffect)(() => {
1117
+ if (!ref && state.entry?.target && !freezeOnceVisible && !frozen && prevRef.current !== state.entry.target) {
1118
+ prevRef.current = state.entry.target;
1119
+ setState({
1120
+ isIntersecting: initialIsIntersecting,
1121
+ entry: void 0
1122
+ });
1123
+ }
1124
+ }, [
1125
+ ref,
1126
+ state.entry,
1127
+ freezeOnceVisible,
1128
+ frozen,
1129
+ initialIsIntersecting
1130
+ ]);
1131
+ const result = [
1132
+ setRef,
1133
+ !!state.isIntersecting,
1134
+ state.entry
1135
+ ];
1136
+ result.ref = result[0];
1137
+ result.isIntersecting = result[1];
1138
+ result.entry = result[2];
1139
+ return result;
1140
+ }
1141
+
1142
+ //#endregion
1143
+ //#region src/useIsClient/useIsClient.ts
1144
+ /**
1145
+ * Custom hook that determines if the code is running on the client side (in the browser).
1146
+ * @returns {boolean} A boolean value indicating whether the code is running on the client side.
1147
+ * @public
1148
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-is-client)
1149
+ * @example
1150
+ * ```tsx
1151
+ * const isClient = useIsClient();
1152
+ * // Use isClient to conditionally render or execute code specific to the client side.
1153
+ * ```
1154
+ */
1155
+ function useIsClient() {
1156
+ const [isClient, setClient] = (0, react.useState)(false);
1157
+ (0, react.useEffect)(() => {
1158
+ setClient(true);
1159
+ }, []);
1160
+ return isClient;
1161
+ }
1162
+
1163
+ //#endregion
1164
+ //#region src/useIsMounted/useIsMounted.ts
1165
+ /**
1166
+ * Custom hook that determines if the component is currently mounted.
1167
+ * @returns {() => boolean} A function that returns a boolean value indicating whether the component is mounted.
1168
+ * @public
1169
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-is-mounted)
1170
+ * @example
1171
+ * ```tsx
1172
+ * const isComponentMounted = useIsMounted();
1173
+ * // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.
1174
+ * ```
1175
+ */
1176
+ function useIsMounted() {
1177
+ const isMounted = (0, react.useRef)(false);
1178
+ (0, react.useEffect)(() => {
1179
+ isMounted.current = true;
1180
+ return () => {
1181
+ isMounted.current = false;
1182
+ };
1183
+ }, []);
1184
+ return (0, react.useCallback)(() => isMounted.current, []);
1185
+ }
1186
+
1187
+ //#endregion
1188
+ //#region src/useList/useList.ts
1189
+ /**
1190
+ * Custom hook that manages a list state with setter actions.
1191
+ * @template T - The type of elements in the list.
1192
+ * @param {T[]} [initialValue] - The initial array of values for the list (optional).
1193
+ * @returns {UseListReturn<T>} A tuple containing the list state and actions to interact with the list.
1194
+ * @public
1195
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-list)
1196
+ * @example
1197
+ * ```tsx
1198
+ * const [list, listActions] = useList<number>([1, 2, 3]);
1199
+ * // Access the `list` array and use `listActions` to push, updateAt, removeAt, or reset values.
1200
+ * ```
1201
+ */
1202
+ function useList(initialValue = []) {
1203
+ const initialListRef = (0, react.useRef)(initialValue);
1204
+ const [list, setList] = (0, react.useState)(initialValue);
1205
+ const set = (0, react.useCallback)((newList) => {
1206
+ setList(newList);
1207
+ }, []);
1208
+ const push = (0, react.useCallback)((...values) => {
1209
+ setList((prev) => [...prev, ...values]);
1210
+ }, []);
1211
+ const updateAt = (0, react.useCallback)((index, value) => {
1212
+ setList((prev) => {
1213
+ if (index < 0 || index >= prev.length) return prev;
1214
+ const copy = [...prev];
1215
+ copy[index] = value;
1216
+ return copy;
1217
+ });
1218
+ }, []);
1219
+ const insertAt = (0, react.useCallback)((index, value) => {
1220
+ setList((prev) => {
1221
+ if (index < 0 || index > prev.length) return prev;
1222
+ const copy = [...prev];
1223
+ copy.splice(index, 0, value);
1224
+ return copy;
1225
+ });
1226
+ }, []);
1227
+ const removeAt = (0, react.useCallback)((index) => {
1228
+ setList((prev) => {
1229
+ if (index < 0 || index >= prev.length) return prev;
1230
+ const copy = [...prev];
1231
+ copy.splice(index, 1);
1232
+ return copy;
1233
+ });
1234
+ }, []);
1235
+ const clear = (0, react.useCallback)(() => {
1236
+ setList([]);
1237
+ }, []);
1238
+ const reset = (0, react.useCallback)(() => {
1239
+ setList([...initialListRef.current]);
1240
+ }, []);
1241
+ const actions = {
1242
+ set,
1243
+ push,
1244
+ updateAt,
1245
+ insertAt,
1246
+ removeAt,
1247
+ clear,
1248
+ reset
1249
+ };
1250
+ return [list, actions];
1251
+ }
1252
+
1253
+ //#endregion
1254
+ //#region src/useMap/useMap.ts
1255
+ /**
1256
+ * Custom hook that manages a key-value [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) state with setter actions.
1257
+ * @template K - The type of keys in the map.
1258
+ * @template V - The type of values in the map.
1259
+ * @param {MapOrEntries<K, V>} [initialState] - The initial state of the map as a Map or an array of key-value pairs (optional).
1260
+ * @returns {UseMapReturn<K, V>} A tuple containing the map state and actions to interact with the map.
1261
+ * @public
1262
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-map)
1263
+ * @example
1264
+ * ```tsx
1265
+ * const [map, mapActions] = useMap();
1266
+ * // Access the `map` state and use `mapActions` to set, remove, or reset entries.
1267
+ * ```
1268
+ */
1269
+ function useMap(initialState = new Map()) {
1270
+ const [map, setMap] = (0, react.useState)(new Map(initialState));
1271
+ const actions = {
1272
+ set: (0, react.useCallback)((key, value) => {
1273
+ setMap((prev) => {
1274
+ const copy = new Map(prev);
1275
+ copy.set(key, value);
1276
+ return copy;
1277
+ });
1278
+ }, []),
1279
+ setAll: (0, react.useCallback)((entries) => {
1280
+ setMap(() => new Map(entries));
1281
+ }, []),
1282
+ remove: (0, react.useCallback)((key) => {
1283
+ setMap((prev) => {
1284
+ const copy = new Map(prev);
1285
+ copy.delete(key);
1286
+ return copy;
1287
+ });
1288
+ }, []),
1289
+ reset: (0, react.useCallback)(() => {
1290
+ setMap(() => new Map());
1291
+ }, [])
1292
+ };
1293
+ return [map, actions];
1294
+ }
1295
+
1296
+ //#endregion
1297
+ //#region src/useMemoizedFn/useMemoizedFn.ts
1298
+ /**
1299
+ * Custom hook that returns a memoized version of a function that never changes reference.
1300
+ * The returned function will always call the latest version of the callback, but its
1301
+ * identity (reference) will remain stable across renders.
1302
+ *
1303
+ * This is useful when you need to pass a callback to a dependency array or child component
1304
+ * without causing unnecessary re-renders.
1305
+ *
1306
+ * @template T - The type of the function being memoized.
1307
+ * @param {T} fn - The function to memoize.
1308
+ * @returns {T} A memoized function with stable reference.
1309
+ * @public
1310
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-memoized-fn)
1311
+ * @example
1312
+ * ```tsx
1313
+ * const stableCallback = useMemoizedFn((value) => {
1314
+ * console.log(value);
1315
+ * });
1316
+ *
1317
+ * // stableCallback can be safely used in useEffect deps without causing infinite loops
1318
+ * useEffect(() => {
1319
+ * stableCallback(someValue);
1320
+ * }, [stableCallback]);
1321
+ * ```
1322
+ */
1323
+ function useMemoizedFn(fn) {
1324
+ const fnRef = (0, react.useRef)(fn);
1325
+ fnRef.current = fn;
1326
+ const memoizedFn = (0, react.useCallback)((...args) => {
1327
+ return fnRef.current(...args);
1328
+ }, []);
1329
+ return memoizedFn;
1330
+ }
1331
+
1332
+ //#endregion
1333
+ //#region src/useNetwork/useNetwork.ts
1334
+ /**
1335
+ * Custom hook that tracks the browser's network connection status.
1336
+ * @returns {NetworkState} The current network state including online status and connection info.
1337
+ * @public
1338
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-network)
1339
+ * @example
1340
+ * ```tsx
1341
+ * const { online, effectiveType, downlink } = useNetwork();
1342
+ *
1343
+ * return (
1344
+ * <div>
1345
+ * <p>Status: {online ? 'Online' : 'Offline'}</p>
1346
+ * <p>Connection: {effectiveType}</p>
1347
+ * <p>Speed: {downlink} Mbps</p>
1348
+ * </div>
1349
+ * );
1350
+ * ```
1351
+ */
1352
+ function useNetwork() {
1353
+ const [state, setState] = (0, react.useState)({
1354
+ online: typeof navigator !== "undefined" ? navigator.onLine : true,
1355
+ effectiveType: void 0,
1356
+ downlink: void 0,
1357
+ downlinkMax: void 0,
1358
+ type: void 0,
1359
+ rtt: void 0,
1360
+ saveData: void 0
1361
+ });
1362
+ (0, react.useEffect)(() => {
1363
+ const handleOnline = () => {
1364
+ setState((prev) => ({
1365
+ ...prev,
1366
+ online: true
1367
+ }));
1368
+ };
1369
+ const handleOffline = () => {
1370
+ setState((prev) => ({
1371
+ ...prev,
1372
+ online: false
1373
+ }));
1374
+ };
1375
+ const updateConnectionInfo = () => {
1376
+ const connection$1 = navigator.connection;
1377
+ if (connection$1) setState({
1378
+ online: navigator.onLine,
1379
+ effectiveType: connection$1.effectiveType,
1380
+ downlink: connection$1.downlink,
1381
+ downlinkMax: connection$1.downlinkMax,
1382
+ type: connection$1.type,
1383
+ rtt: connection$1.rtt,
1384
+ saveData: connection$1.saveData
1385
+ });
1386
+ };
1387
+ window.addEventListener("online", handleOnline);
1388
+ window.addEventListener("offline", handleOffline);
1389
+ const connection = navigator.connection;
1390
+ if (connection) {
1391
+ connection.addEventListener("change", updateConnectionInfo);
1392
+ updateConnectionInfo();
1393
+ }
1394
+ return () => {
1395
+ window.removeEventListener("online", handleOnline);
1396
+ window.removeEventListener("offline", handleOffline);
1397
+ if (connection) connection.removeEventListener("change", updateConnectionInfo);
1398
+ };
1399
+ }, []);
1400
+ return state;
1401
+ }
1402
+
1403
+ //#endregion
1404
+ //#region src/useOnClickOutside/useOnClickOutside.ts
1405
+ /**
1406
+ * Custom hook that handles clicks outside a specified element.
1407
+ * @template T - The type of the element's reference.
1408
+ * @param {RefObject<T | null> | RefObject<T | null>[]} ref - The React ref object(s) representing the element(s) to watch for outside clicks.
1409
+ * @param {(event: MouseEvent | TouchEvent | FocusEvent) => void} handler - The callback function to be executed when a click outside the element occurs.
1410
+ * @param {EventType} [eventType] - The mouse event type to listen for (optional, default is 'mousedown').
1411
+ * @param {?AddEventListenerOptions} [eventListenerOptions] - The options object to be passed to the `addEventListener` method (optional).
1412
+ * @returns {void}
1413
+ * @public
1414
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-on-click-outside)
1415
+ * @example
1416
+ * ```tsx
1417
+ * const containerRef = useRef(null);
1418
+ * useOnClickOutside([containerRef], () => {
1419
+ * // Handle clicks outside the container.
1420
+ * });
1421
+ * ```
1422
+ */
1423
+ function useOnClickOutside(ref, handler, eventType = "mousedown", eventListenerOptions = {}) {
1424
+ useEventListener(eventType, (event) => {
1425
+ const target = event.target;
1426
+ if (!target || !target.isConnected) return;
1427
+ const isOutside = Array.isArray(ref) ? ref.filter((r) => Boolean(r.current)).every((r) => r.current && !r.current.contains(target)) : ref.current && !ref.current.contains(target);
1428
+ if (isOutside) handler(event);
1429
+ }, void 0, eventListenerOptions);
1430
+ }
1431
+
1432
+ //#endregion
1433
+ //#region src/usePageLeave/usePageLeave.ts
1434
+ /**
1435
+ * Custom hook that invokes a callback when the user's mouse leaves the page.
1436
+ * @param {() => void} handler - The callback function to invoke when the mouse leaves the page.
1437
+ * @public
1438
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-page-leave)
1439
+ * @example
1440
+ * ```tsx
1441
+ * usePageLeave(() => {
1442
+ * console.log('User is leaving the page');
1443
+ * // Show "Don't leave!" modal or save draft
1444
+ * });
1445
+ * ```
1446
+ */
1447
+ function usePageLeave(handler) {
1448
+ (0, react.useEffect)(() => {
1449
+ if (!handler) return;
1450
+ const handleMouseLeave = () => {
1451
+ handler();
1452
+ };
1453
+ document.addEventListener("mouseleave", handleMouseLeave);
1454
+ return () => {
1455
+ document.removeEventListener("mouseleave", handleMouseLeave);
1456
+ };
1457
+ }, [handler]);
1458
+ }
1459
+
1460
+ //#endregion
1461
+ //#region src/usePagination/usePagination.ts
1462
+ const DOTS = "dots";
1463
+ /**
1464
+ * Custom hook for managing pagination logic.
1465
+ * Returns page navigation functions and a range array suitable for pagination UI.
1466
+ * @param {UsePaginationOptions} options - Pagination configuration options.
1467
+ * @returns {UsePaginationReturn} The pagination state and navigation functions.
1468
+ * @public
1469
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-pagination)
1470
+ * @example
1471
+ * ```tsx
1472
+ * const { activePage, setPage, next, prev, range } = usePagination({
1473
+ * total: 20,
1474
+ * siblings: 1,
1475
+ * boundaries: 1,
1476
+ * });
1477
+ *
1478
+ * // range = [1, 'dots', 4, 5, 6, 'dots', 20]
1479
+ * ```
1480
+ */
1481
+ function usePagination(options) {
1482
+ const { total, siblings = 1, boundaries = 1, initialPage = 1, page: controlledPage, onChange } = options;
1483
+ const [internalPage, setInternalPage] = (0, react.useState)(initialPage);
1484
+ const activePage = controlledPage ?? internalPage;
1485
+ const setPage = (0, react.useCallback)((page) => {
1486
+ const validPage = Math.max(1, Math.min(page, total));
1487
+ if (validPage !== activePage) {
1488
+ if (controlledPage === void 0) setInternalPage(validPage);
1489
+ onChange?.(validPage);
1490
+ }
1491
+ }, [
1492
+ activePage,
1493
+ controlledPage,
1494
+ onChange,
1495
+ total
1496
+ ]);
1497
+ const next = (0, react.useCallback)(() => {
1498
+ setPage(activePage + 1);
1499
+ }, [activePage, setPage]);
1500
+ const prev = (0, react.useCallback)(() => {
1501
+ setPage(activePage - 1);
1502
+ }, [activePage, setPage]);
1503
+ const isFirst = activePage === 1;
1504
+ const isLast = activePage === total;
1505
+ const range = (0, react.useMemo)(() => {
1506
+ const range$1 = [];
1507
+ const totalVisible = siblings * 2 + 3 + boundaries * 2;
1508
+ if (totalVisible >= total) for (let i = 1; i <= total; i++) range$1.push(i);
1509
+ else {
1510
+ const leftBoundaryEnd = boundaries;
1511
+ for (let i = 1; i <= leftBoundaryEnd; i++) range$1.push(i);
1512
+ const leftSibling = Math.max(activePage - siblings, boundaries + 1);
1513
+ const rightSibling = Math.min(activePage + siblings, total - boundaries);
1514
+ const showLeftDots = leftSibling > boundaries + 1;
1515
+ const showRightDots = rightSibling < total - boundaries;
1516
+ if (showLeftDots) range$1.push(DOTS);
1517
+ for (let i = leftSibling; i <= rightSibling; i++) range$1.push(i);
1518
+ if (showRightDots) range$1.push(DOTS);
1519
+ const rightBoundaryStart = total - boundaries + 1;
1520
+ for (let i = rightBoundaryStart; i <= total; i++) range$1.push(i);
1521
+ }
1522
+ return range$1;
1523
+ }, [
1524
+ activePage,
1525
+ boundaries,
1526
+ siblings,
1527
+ total
1528
+ ]);
1529
+ return {
1530
+ activePage,
1531
+ range,
1532
+ setPage,
1533
+ next,
1534
+ prev,
1535
+ first: isFirst,
1536
+ last: isLast
1537
+ };
1538
+ }
1539
+
1540
+ //#endregion
1541
+ //#region src/usePermission/usePermission.ts
1542
+ /**
1543
+ * Custom hook that tracks the state of a browser permission.
1544
+ * @param {PermissionName} permissionName - The name of the permission to track.
1545
+ * @returns {PermissionState} The current state of the permission.
1546
+ * @public
1547
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-permission)
1548
+ * @example
1549
+ * ```tsx
1550
+ * const { state, supported } = usePermission('camera');
1551
+ *
1552
+ * if (!supported) return <div>Permissions API not supported</div>;
1553
+ * if (state === 'denied') return <div>Camera access denied</div>;
1554
+ * return <Camera />;
1555
+ * ```
1556
+ */
1557
+ function usePermission(permissionName) {
1558
+ const [state, setState] = (0, react.useState)({
1559
+ state: "prompt",
1560
+ supported: true
1561
+ });
1562
+ const permissionStatusRef = (0, react.useRef)(null);
1563
+ (0, react.useEffect)(() => {
1564
+ if (!navigator.permissions) {
1565
+ setState({
1566
+ state: "unsupported",
1567
+ supported: false
1568
+ });
1569
+ return;
1570
+ }
1571
+ let isMounted = true;
1572
+ const queryPermission = async () => {
1573
+ try {
1574
+ const status = await navigator.permissions.query({ name: permissionName });
1575
+ if (!isMounted) return;
1576
+ permissionStatusRef.current = status;
1577
+ const updateState = () => {
1578
+ if (isMounted) setState({
1579
+ state: status.state,
1580
+ supported: true
1581
+ });
1582
+ };
1583
+ updateState();
1584
+ status.addEventListener("change", updateState);
1585
+ return () => {
1586
+ status.removeEventListener("change", updateState);
1587
+ };
1588
+ } catch {
1589
+ if (isMounted) setState({
1590
+ state: "unsupported",
1591
+ supported: false
1592
+ });
1593
+ }
1594
+ };
1595
+ queryPermission();
1596
+ return () => {
1597
+ isMounted = false;
1598
+ };
1599
+ }, [permissionName]);
1600
+ return state;
1601
+ }
1602
+
1603
+ //#endregion
1604
+ //#region src/usePrevious/usePrevious.ts
1605
+ function usePrevious(value, initialValue) {
1606
+ const ref = (0, react.useRef)(initialValue);
1607
+ (0, react.useEffect)(() => {
1608
+ ref.current = value;
1609
+ }, [value]);
1610
+ return ref.current;
1611
+ }
1612
+
1613
+ //#endregion
1614
+ //#region src/useQueue/useQueue.ts
1615
+ /**
1616
+ * Custom hook that manages a FIFO (First In, First Out) queue state with setter actions.
1617
+ * @template T - The type of elements in the queue.
1618
+ * @param {T[]} [initialValue] - The initial array of values for the queue (optional).
1619
+ * @returns {UseQueueReturn<T>} A tuple containing the queue state and actions to interact with the queue.
1620
+ * @public
1621
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-queue)
1622
+ * @example
1623
+ * ```tsx
1624
+ * const [queue, queueActions] = useQueue<number>([1, 2, 3]);
1625
+ * // Access the `queue` array and use `queueActions` to add, remove, or clear values.
1626
+ * ```
1627
+ */
1628
+ function useQueue(initialValue = []) {
1629
+ const queueRef = (0, react.useRef)(initialValue);
1630
+ const [, setTick] = (0, react.useState)(0);
1631
+ const update = (0, react.useCallback)(() => {
1632
+ setTick((t) => t + 1);
1633
+ }, []);
1634
+ const add = (0, react.useCallback)((value) => {
1635
+ queueRef.current = [...queueRef.current, value];
1636
+ update();
1637
+ }, [update]);
1638
+ const remove = (0, react.useCallback)(() => {
1639
+ if (queueRef.current.length === 0) return void 0;
1640
+ const [first, ...rest] = queueRef.current;
1641
+ queueRef.current = rest;
1642
+ update();
1643
+ return first;
1644
+ }, [update]);
1645
+ const clear = (0, react.useCallback)(() => {
1646
+ queueRef.current = [];
1647
+ update();
1648
+ }, [update]);
1649
+ const actions = (0, react.useMemo)(() => ({
1650
+ add,
1651
+ remove,
1652
+ clear,
1653
+ get first() {
1654
+ return queueRef.current[0];
1655
+ },
1656
+ get last() {
1657
+ return queueRef.current[queueRef.current.length - 1];
1658
+ },
1659
+ get size() {
1660
+ return queueRef.current.length;
1661
+ }
1662
+ }), [
1663
+ add,
1664
+ clear,
1665
+ remove
1666
+ ]);
1667
+ return [queueRef.current, actions];
1668
+ }
1669
+
1670
+ //#endregion
1671
+ //#region src/useReadLocalStorage/useReadLocalStorage.ts
1672
+ const IS_SERVER$4 = typeof window === "undefined";
1673
+ /**
1674
+ * Custom hook that reads a value from [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), closely related to [`useLocalStorage()`](https://usehooks-ts.com/react-hook/use-local-storage).
1675
+ * @template T - The type of the stored value.
1676
+ * @param {string} key - The key associated with the value in local storage.
1677
+ * @param {Options<T>} [options] - Additional options for reading the value (optional).
1678
+ * @returns {T | null | undefined} The stored value, or null if the key is not present or an error occurs.
1679
+ * @public
1680
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-read-local-storage)
1681
+ * @example
1682
+ * ```tsx
1683
+ * const storedData = useReadLocalStorage('myKey');
1684
+ * // Access the stored data from local storage.
1685
+ * ```
1686
+ */
1687
+ function useReadLocalStorage(key, options = {}) {
1688
+ let { initializeWithValue = true } = options;
1689
+ if (IS_SERVER$4) initializeWithValue = false;
1690
+ const deserializer = (0, react.useCallback)((value) => {
1691
+ if (options.deserializer) return options.deserializer(value);
1692
+ if (value === "undefined") return void 0;
1693
+ let parsed;
1694
+ try {
1695
+ parsed = JSON.parse(value);
1696
+ } catch (error) {
1697
+ console.error("Error parsing JSON:", error);
1698
+ return null;
1699
+ }
1700
+ return parsed;
1701
+ }, [options]);
1702
+ const readValue = (0, react.useCallback)(() => {
1703
+ if (IS_SERVER$4) return null;
1704
+ try {
1705
+ const raw = window.localStorage.getItem(key);
1706
+ return raw ? deserializer(raw) : null;
1707
+ } catch (error) {
1708
+ console.warn(`Error reading localStorage key “${key}”:`, error);
1709
+ return null;
1710
+ }
1711
+ }, [key, deserializer]);
1712
+ const [storedValue, setStoredValue] = (0, react.useState)(() => {
1713
+ if (initializeWithValue) return readValue();
1714
+ return void 0;
1715
+ });
1716
+ (0, react.useEffect)(() => {
1717
+ setStoredValue(readValue());
1718
+ }, [key]);
1719
+ const handleStorageChange = (0, react.useCallback)((event) => {
1720
+ if (event.key && event.key !== key) return;
1721
+ setStoredValue(readValue());
1722
+ }, [key, readValue]);
1723
+ useEventListener("storage", handleStorageChange);
1724
+ useEventListener("local-storage", handleStorageChange);
1725
+ return storedValue;
1726
+ }
1727
+
1728
+ //#endregion
1729
+ //#region src/useResizeObserver/useResizeObserver.ts
1730
+ const initialSize = {
1731
+ width: void 0,
1732
+ height: void 0
1733
+ };
1734
+ /**
1735
+ * Custom hook that observes the size of an element using the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
1736
+ * @template T - The type of the element to observe.
1737
+ * @param {UseResizeObserverOptions<T>} options - The options for the ResizeObserver.
1738
+ * @returns {Size} - The size of the observed element.
1739
+ * @public
1740
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-resize-observer)
1741
+ * @example
1742
+ * ```tsx
1743
+ * const myRef = useRef(null);
1744
+ * const { width = 0, height = 0 } = useResizeObserver({
1745
+ * ref: myRef,
1746
+ * box: 'content-box',
1747
+ * });
1748
+ *
1749
+ * <div ref={myRef}>Hello, world!</div>
1750
+ * ```
1751
+ */
1752
+ function useResizeObserver(options) {
1753
+ const { ref, box = "content-box" } = options;
1754
+ const [{ width, height }, setSize] = (0, react.useState)(initialSize);
1755
+ const isMounted = useIsMounted();
1756
+ const previousSize = (0, react.useRef)({ ...initialSize });
1757
+ const onResize = (0, react.useRef)(void 0);
1758
+ onResize.current = options.onResize;
1759
+ (0, react.useEffect)(() => {
1760
+ if (!ref.current) return;
1761
+ if (typeof window === "undefined" || !("ResizeObserver" in window)) return;
1762
+ const observer = new ResizeObserver(([entry]) => {
1763
+ if (!entry) return;
1764
+ const boxProp = box === "border-box" ? "borderBoxSize" : box === "device-pixel-content-box" ? "devicePixelContentBoxSize" : "contentBoxSize";
1765
+ const newWidth = extractSize(entry, boxProp, "inlineSize");
1766
+ const newHeight = extractSize(entry, boxProp, "blockSize");
1767
+ const hasChanged = previousSize.current.width !== newWidth || previousSize.current.height !== newHeight;
1768
+ if (hasChanged) {
1769
+ const newSize = {
1770
+ width: newWidth,
1771
+ height: newHeight
1772
+ };
1773
+ previousSize.current.width = newWidth;
1774
+ previousSize.current.height = newHeight;
1775
+ if (onResize.current) onResize.current(newSize);
1776
+ else if (isMounted()) setSize(newSize);
1777
+ }
1778
+ });
1779
+ observer.observe(ref.current, { box });
1780
+ return () => {
1781
+ observer.disconnect();
1782
+ };
1783
+ }, [
1784
+ box,
1785
+ ref,
1786
+ isMounted
1787
+ ]);
1788
+ return {
1789
+ width,
1790
+ height
1791
+ };
1792
+ }
1793
+ function extractSize(entry, box, sizeType) {
1794
+ if (!entry[box]) {
1795
+ if (box === "contentBoxSize") return entry.contentRect[sizeType === "inlineSize" ? "width" : "height"];
1796
+ return void 0;
1797
+ }
1798
+ return Array.isArray(entry[box]) ? entry[box][0][sizeType] : entry[box][sizeType];
1799
+ }
1800
+
1801
+ //#endregion
1802
+ //#region src/useScreen/useScreen.ts
1803
+ const IS_SERVER$3 = typeof window === "undefined";
1804
+ /**
1805
+ * Custom hook that tracks the [`screen`](https://developer.mozilla.org/en-US/docs/Web/API/Window/screen) dimensions and properties.
1806
+ * @param {?UseScreenOptions} [options] - The options for customizing the behavior of the hook (optional).
1807
+ * @returns {Screen | undefined} The current `Screen` object representing the screen dimensions and properties, or `undefined` if not available.
1808
+ * @public
1809
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-screen)
1810
+ * @example
1811
+ * ```tsx
1812
+ * const currentScreen = useScreen();
1813
+ * // Access properties of the current screen, such as width and height.
1814
+ * ```
1815
+ */
1816
+ function useScreen(options = {}) {
1817
+ let { initializeWithValue = true } = options;
1818
+ if (IS_SERVER$3) initializeWithValue = false;
1819
+ const readScreen = () => {
1820
+ if (IS_SERVER$3) return void 0;
1821
+ return window.screen;
1822
+ };
1823
+ const [screen, setScreen] = (0, react.useState)(() => {
1824
+ if (initializeWithValue) return readScreen();
1825
+ return void 0;
1826
+ });
1827
+ const debouncedSetScreen = useDebounceCallback(setScreen, options.debounceDelay);
1828
+ function handleSize() {
1829
+ const newScreen = readScreen();
1830
+ const setSize = options.debounceDelay ? debouncedSetScreen : setScreen;
1831
+ if (newScreen) {
1832
+ const { width, height, availHeight, availWidth, colorDepth, orientation, pixelDepth } = newScreen;
1833
+ setSize({
1834
+ width,
1835
+ height,
1836
+ availHeight,
1837
+ availWidth,
1838
+ colorDepth,
1839
+ orientation,
1840
+ pixelDepth
1841
+ });
1842
+ }
1843
+ }
1844
+ useEventListener("resize", handleSize);
1845
+ useIsomorphicLayoutEffect(() => {
1846
+ handleSize();
1847
+ }, []);
1848
+ return screen;
1849
+ }
1850
+
1851
+ //#endregion
1852
+ //#region src/useScript/useScript.ts
1853
+ const cachedScriptStatuses = new Map();
1854
+ /**
1855
+ * Gets the script element with the specified source URL.
1856
+ * @param {string} src - The source URL of the script to get.
1857
+ * @returns {{ node: HTMLScriptElement | null, status: UseScriptStatus | undefined }} The script element and its loading status.
1858
+ * @public
1859
+ * @example
1860
+ * ```tsx
1861
+ * const script = getScriptNode(src);
1862
+ * ```
1863
+ */
1864
+ function getScriptNode(src) {
1865
+ const node = document.querySelector(`script[src="${src}"]`);
1866
+ const status = node?.getAttribute("data-status");
1867
+ return {
1868
+ node,
1869
+ status
1870
+ };
1871
+ }
1872
+ /**
1873
+ * Custom hook that dynamically loads scripts and tracking their loading status.
1874
+ * @param {string | null} src - The source URL of the script to load. Set to `null` or omit to prevent loading (optional).
1875
+ * @param {UseScriptOptions} [options] - Additional options for controlling script loading (optional).
1876
+ * @returns {UseScriptStatus} The status of the script loading, which can be one of 'idle', 'loading', 'ready', or 'error'.
1877
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-script)
1878
+ * @example
1879
+ * const scriptStatus = useScript('https://example.com/script.js', { removeOnUnmount: true });
1880
+ * // Access the status of the script loading (e.g., 'loading', 'ready', 'error').
1881
+ */
1882
+ function useScript(src, options) {
1883
+ const [status, setStatus] = (0, react.useState)(() => {
1884
+ if (!src || options?.shouldPreventLoad) return "idle";
1885
+ if (typeof window === "undefined") return "loading";
1886
+ return cachedScriptStatuses.get(src) ?? "loading";
1887
+ });
1888
+ (0, react.useEffect)(() => {
1889
+ if (!src || options?.shouldPreventLoad) return;
1890
+ const cachedScriptStatus = cachedScriptStatuses.get(src);
1891
+ if (cachedScriptStatus === "ready" || cachedScriptStatus === "error") {
1892
+ setStatus(cachedScriptStatus);
1893
+ return;
1894
+ }
1895
+ const script = getScriptNode(src);
1896
+ let scriptNode = script.node;
1897
+ if (!scriptNode) {
1898
+ scriptNode = document.createElement("script");
1899
+ scriptNode.src = src;
1900
+ scriptNode.async = true;
1901
+ if (options?.id) scriptNode.id = options.id;
1902
+ scriptNode.setAttribute("data-status", "loading");
1903
+ document.body.appendChild(scriptNode);
1904
+ const setAttributeFromEvent = (event) => {
1905
+ const scriptStatus = event.type === "load" ? "ready" : "error";
1906
+ scriptNode?.setAttribute("data-status", scriptStatus);
1907
+ };
1908
+ scriptNode.addEventListener("load", setAttributeFromEvent);
1909
+ scriptNode.addEventListener("error", setAttributeFromEvent);
1910
+ } else setStatus(script.status ?? cachedScriptStatus ?? "loading");
1911
+ const setStateFromEvent = (event) => {
1912
+ const newStatus = event.type === "load" ? "ready" : "error";
1913
+ setStatus(newStatus);
1914
+ cachedScriptStatuses.set(src, newStatus);
1915
+ };
1916
+ scriptNode.addEventListener("load", setStateFromEvent);
1917
+ scriptNode.addEventListener("error", setStateFromEvent);
1918
+ return () => {
1919
+ if (scriptNode) {
1920
+ scriptNode.removeEventListener("load", setStateFromEvent);
1921
+ scriptNode.removeEventListener("error", setStateFromEvent);
1922
+ }
1923
+ if (scriptNode && options?.removeOnUnmount) {
1924
+ scriptNode.remove();
1925
+ cachedScriptStatuses.delete(src);
1926
+ }
1927
+ };
1928
+ }, [
1929
+ src,
1930
+ options?.shouldPreventLoad,
1931
+ options?.removeOnUnmount,
1932
+ options?.id
1933
+ ]);
1934
+ return status;
1935
+ }
1936
+
1937
+ //#endregion
1938
+ //#region src/useScrollLock/useScrollLock.ts
1939
+ const IS_SERVER$2 = typeof window === "undefined";
1940
+ /**
1941
+ * A custom hook that locks and unlocks scroll.
1942
+ * @param {UseScrollLockOptions} [options] - Options to configure the hook, by default it will lock the scroll automatically.
1943
+ * @returns {UseScrollLockReturn} - An object containing the lock and unlock functions.
1944
+ * @public
1945
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-scroll-lock)
1946
+ * @example
1947
+ * ```tsx
1948
+ * // Lock the scroll when the modal is mounted, and unlock it when it's unmounted
1949
+ * useScrollLock()
1950
+ * ```
1951
+ * @example
1952
+ * ```tsx
1953
+ * // Manually lock and unlock the scroll
1954
+ * const { lock, unlock } = useScrollLock({ autoLock: false })
1955
+ *
1956
+ * return (
1957
+ * <div>
1958
+ * <button onClick={lock}>Lock</button>
1959
+ * <button onClick={unlock}>Unlock</button>
1960
+ * </div>
1961
+ * )
1962
+ * ```
1963
+ */
1964
+ function useScrollLock(options = {}) {
1965
+ const { autoLock = true, lockTarget, widthReflow = true } = options;
1966
+ const [isLocked, setIsLocked] = (0, react.useState)(false);
1967
+ const target = (0, react.useRef)(null);
1968
+ const originalStyle = (0, react.useRef)(null);
1969
+ const lock = () => {
1970
+ if (target.current) {
1971
+ const { overflow, paddingRight } = target.current.style;
1972
+ originalStyle.current = {
1973
+ overflow,
1974
+ paddingRight
1975
+ };
1976
+ if (widthReflow) {
1977
+ const offsetWidth = target.current === document.body ? window.innerWidth : target.current.offsetWidth;
1978
+ const currentPaddingRight = parseInt(window.getComputedStyle(target.current).paddingRight, 10) || 0;
1979
+ const scrollbarWidth = offsetWidth - target.current.scrollWidth;
1980
+ target.current.style.paddingRight = `${scrollbarWidth + currentPaddingRight}px`;
1981
+ }
1982
+ target.current.style.overflow = "hidden";
1983
+ setIsLocked(true);
1984
+ }
1985
+ };
1986
+ const unlock = () => {
1987
+ if (target.current && originalStyle.current) {
1988
+ target.current.style.overflow = originalStyle.current.overflow;
1989
+ if (widthReflow) target.current.style.paddingRight = originalStyle.current.paddingRight;
1990
+ }
1991
+ setIsLocked(false);
1992
+ };
1993
+ useIsomorphicLayoutEffect(() => {
1994
+ if (IS_SERVER$2) return;
1995
+ if (lockTarget) target.current = typeof lockTarget === "string" ? document.querySelector(lockTarget) : lockTarget;
1996
+ if (!target.current) target.current = document.body;
1997
+ if (autoLock) lock();
1998
+ return () => {
1999
+ unlock();
2000
+ };
2001
+ }, [
2002
+ autoLock,
2003
+ lockTarget,
2004
+ widthReflow
2005
+ ]);
2006
+ return {
2007
+ isLocked,
2008
+ lock,
2009
+ unlock
2010
+ };
2011
+ }
2012
+
2013
+ //#endregion
2014
+ //#region src/useSessionStorage/useSessionStorage.ts
2015
+ const IS_SERVER$1 = typeof window === "undefined";
2016
+ /**
2017
+ * Custom hook that uses the [`sessionStorage API`](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) to persist state across page reloads.
2018
+ * @template T - The type of the state to be stored in session storage.
2019
+ * @param {string} key - The key under which the value will be stored in session storage.
2020
+ * @param {T | (() => T)} initialValue - The initial value of the state or a function that returns the initial value.
2021
+ * @param {?UseSessionStorageOptions<T>} [options] - Options for customizing the behavior of serialization and deserialization (optional).
2022
+ * @returns {[T, Dispatch<SetStateAction<T>>, () => void]} A tuple containing the stored value, a function to set the value and a function to remove the key from storage.
2023
+ * @public
2024
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-session-storage)
2025
+ * @example
2026
+ * ```tsx
2027
+ * const [count, setCount, removeCount] = useSessionStorage('count', 0);
2028
+ * // Access the `count` value, the `setCount` function to update it and `removeCount` function to remove the key from storage.
2029
+ * ```
2030
+ */
2031
+ function useSessionStorage(key, initialValue, options = {}) {
2032
+ const { initializeWithValue = true } = options;
2033
+ const serializer = (0, react.useCallback)((value) => {
2034
+ if (options.serializer) return options.serializer(value);
2035
+ return JSON.stringify(value);
2036
+ }, [options]);
2037
+ const deserializer = (0, react.useCallback)((value) => {
2038
+ if (options.deserializer) return options.deserializer(value);
2039
+ if (value === "undefined") return void 0;
2040
+ const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
2041
+ let parsed;
2042
+ try {
2043
+ parsed = JSON.parse(value);
2044
+ } catch (error) {
2045
+ console.error("Error parsing JSON:", error);
2046
+ return defaultValue;
2047
+ }
2048
+ return parsed;
2049
+ }, [options, initialValue]);
2050
+ const readValue = (0, react.useCallback)(() => {
2051
+ const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;
2052
+ if (IS_SERVER$1) return initialValueToUse;
2053
+ try {
2054
+ const raw = window.sessionStorage.getItem(key);
2055
+ return raw ? deserializer(raw) : initialValueToUse;
2056
+ } catch (error) {
2057
+ console.warn(`Error reading sessionStorage key “${key}”:`, error);
2058
+ return initialValueToUse;
2059
+ }
2060
+ }, [
2061
+ initialValue,
2062
+ key,
2063
+ deserializer
2064
+ ]);
2065
+ const [storedValue, setStoredValue] = (0, react.useState)(() => {
2066
+ if (initializeWithValue) return readValue();
2067
+ return initialValue instanceof Function ? initialValue() : initialValue;
2068
+ });
2069
+ const setValue = useEventCallback((value) => {
2070
+ if (IS_SERVER$1) console.warn(`Tried setting sessionStorage key “${key}” even though environment is not a client`);
2071
+ try {
2072
+ const newValue = value instanceof Function ? value(readValue()) : value;
2073
+ window.sessionStorage.setItem(key, serializer(newValue));
2074
+ setStoredValue(newValue);
2075
+ window.dispatchEvent(new StorageEvent("session-storage", { key }));
2076
+ } catch (error) {
2077
+ console.warn(`Error setting sessionStorage key “${key}”:`, error);
2078
+ }
2079
+ });
2080
+ const removeValue = useEventCallback(() => {
2081
+ if (IS_SERVER$1) console.warn(`Tried removing sessionStorage key “${key}” even though environment is not a client`);
2082
+ const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
2083
+ window.sessionStorage.removeItem(key);
2084
+ setStoredValue(defaultValue);
2085
+ window.dispatchEvent(new StorageEvent("session-storage", { key }));
2086
+ });
2087
+ (0, react.useEffect)(() => {
2088
+ setStoredValue(readValue());
2089
+ }, [key]);
2090
+ const handleStorageChange = (0, react.useCallback)((event) => {
2091
+ if (event.key && event.key !== key) return;
2092
+ setStoredValue(readValue());
2093
+ }, [key, readValue]);
2094
+ useEventListener("storage", handleStorageChange);
2095
+ useEventListener("session-storage", handleStorageChange);
2096
+ return [
2097
+ storedValue,
2098
+ setValue,
2099
+ removeValue
2100
+ ];
2101
+ }
2102
+
2103
+ //#endregion
2104
+ //#region src/useSet/useSet.ts
2105
+ /**
2106
+ * Custom hook that manages a [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) state with setter actions.
2107
+ * @template T - The type of elements in the set.
2108
+ * @param {Set<T> | T[]} [initialValue] - The initial value of the set as a Set or an array of values (optional).
2109
+ * @returns {UseSetReturn<T>} A tuple containing the set state and actions to interact with the set.
2110
+ * @public
2111
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-set)
2112
+ * @example
2113
+ * ```tsx
2114
+ * const [set, setActions] = useSet<string>(['hello']);
2115
+ * // Access the `set` state and use `setActions` to add, remove, toggle, or reset values.
2116
+ * ```
2117
+ */
2118
+ function useSet(initialValue = []) {
2119
+ const initialSet = initialValue instanceof Set ? initialValue : new Set(initialValue);
2120
+ const [set, setSet] = (0, react.useState)(initialSet);
2121
+ const actions = {
2122
+ add: (0, react.useCallback)((value) => {
2123
+ setSet((prev) => {
2124
+ const copy = new Set(prev);
2125
+ copy.add(value);
2126
+ return copy;
2127
+ });
2128
+ }, []),
2129
+ remove: (0, react.useCallback)((value) => {
2130
+ setSet((prev) => {
2131
+ const copy = new Set(prev);
2132
+ copy.delete(value);
2133
+ return copy;
2134
+ });
2135
+ }, []),
2136
+ toggle: (0, react.useCallback)((value) => {
2137
+ setSet((prev) => {
2138
+ const copy = new Set(prev);
2139
+ if (copy.has(value)) copy.delete(value);
2140
+ else copy.add(value);
2141
+ return copy;
2142
+ });
2143
+ }, []),
2144
+ has: (0, react.useCallback)((value) => set.has(value), [set]),
2145
+ clear: (0, react.useCallback)(() => {
2146
+ setSet(() => new Set());
2147
+ }, []),
2148
+ reset: (0, react.useCallback)(() => {
2149
+ setSet(() => new Set(initialSet));
2150
+ }, [])
2151
+ };
2152
+ return [set, actions];
2153
+ }
2154
+
2155
+ //#endregion
2156
+ //#region src/useStateList/useStateList.ts
2157
+ /**
2158
+ * Custom hook for navigating through a list of states.
2159
+ * Useful for step-by-step flows, carousels, or multi-step forms.
2160
+ * @template T - The type of the state values.
2161
+ * @param {T[]} stateSet - The array of possible states.
2162
+ * @returns {UseStateListReturn<T>} The current state and navigation functions.
2163
+ * @public
2164
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-state-list)
2165
+ * @example
2166
+ * ```tsx
2167
+ * const states = ['step1', 'step2', 'step3'];
2168
+ * const { state, next, prev, isFirst, isLast } = useStateList(states);
2169
+ *
2170
+ * return (
2171
+ * <div>
2172
+ * <p>Current: {state}</p>
2173
+ * <button onClick={prev} disabled={isFirst}>Back</button>
2174
+ * <button onClick={next} disabled={isLast}>Next</button>
2175
+ * </div>
2176
+ * );
2177
+ * ```
2178
+ */
2179
+ function useStateList(stateSet) {
2180
+ if (stateSet.length === 0) throw new Error("useStateList requires at least one state value");
2181
+ const stateSetRef = (0, react.useRef)(stateSet);
2182
+ const [currentIndex, setCurrentIndex] = (0, react.useState)(0);
2183
+ const state = stateSetRef.current[currentIndex];
2184
+ const isFirst = currentIndex === 0;
2185
+ const isLast = currentIndex === stateSetRef.current.length - 1;
2186
+ const prev = (0, react.useCallback)(() => {
2187
+ setCurrentIndex((index) => index > 0 ? index - 1 : index);
2188
+ }, []);
2189
+ const next = (0, react.useCallback)(() => {
2190
+ setCurrentIndex((index) => index < stateSetRef.current.length - 1 ? index + 1 : index);
2191
+ }, []);
2192
+ const setStateAt = (0, react.useCallback)((index) => {
2193
+ if (index >= 0 && index < stateSetRef.current.length) setCurrentIndex(index);
2194
+ }, []);
2195
+ const setState = (0, react.useCallback)((newState) => {
2196
+ const index = stateSetRef.current.indexOf(newState);
2197
+ if (index !== -1) setCurrentIndex(index);
2198
+ }, []);
2199
+ return {
2200
+ state,
2201
+ currentIndex,
2202
+ isFirst,
2203
+ isLast,
2204
+ prev,
2205
+ next,
2206
+ setStateAt,
2207
+ setState
2208
+ };
2209
+ }
2210
+
2211
+ //#endregion
2212
+ //#region src/useStep/useStep.ts
2213
+ /**
2214
+ * Custom hook that manages and navigates between steps in a multi-step process.
2215
+ * @param {number} maxStep - The maximum step in the process.
2216
+ * @returns {[number, UseStepActions]} An tuple containing the current step and helper functions for navigating steps.
2217
+ * @public
2218
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-step)
2219
+ * @example
2220
+ * ```tsx
2221
+ * const [currentStep, { goToNextStep, goToPrevStep, reset, canGoToNextStep, canGoToPrevStep, setStep }] = useStep(3);
2222
+ * // Access and use the current step and provided helper functions.
2223
+ * ```
2224
+ */
2225
+ function useStep(maxStep) {
2226
+ const [currentStep, setCurrentStep] = (0, react.useState)(1);
2227
+ const canGoToNextStep = currentStep + 1 <= maxStep;
2228
+ const canGoToPrevStep = currentStep - 1 > 0;
2229
+ const setStep = (0, react.useCallback)((step) => {
2230
+ const newStep = step instanceof Function ? step(currentStep) : step;
2231
+ if (newStep >= 1 && newStep <= maxStep) {
2232
+ setCurrentStep(newStep);
2233
+ return;
2234
+ }
2235
+ throw new Error("Step not valid");
2236
+ }, [maxStep, currentStep]);
2237
+ const goToNextStep = (0, react.useCallback)(() => {
2238
+ if (canGoToNextStep) setCurrentStep((step) => step + 1);
2239
+ }, [canGoToNextStep]);
2240
+ const goToPrevStep = (0, react.useCallback)(() => {
2241
+ if (canGoToPrevStep) setCurrentStep((step) => step - 1);
2242
+ }, [canGoToPrevStep]);
2243
+ const reset = (0, react.useCallback)(() => {
2244
+ setCurrentStep(1);
2245
+ }, []);
2246
+ return [currentStep, {
2247
+ goToNextStep,
2248
+ goToPrevStep,
2249
+ canGoToNextStep,
2250
+ canGoToPrevStep,
2251
+ setStep,
2252
+ reset
2253
+ }];
2254
+ }
2255
+
2256
+ //#endregion
2257
+ //#region src/useTernaryDarkMode/useTernaryDarkMode.ts
2258
+ const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
2259
+ const LOCAL_STORAGE_KEY = "usehooks-ts-ternary-dark-mode";
2260
+ /**
2261
+ * Custom hook that manages ternary (system, dark, light) dark mode with local storage support.
2262
+ * @param {?TernaryDarkModeOptions | string} [options] - Options or the local storage key for the hook.
2263
+ * @returns {TernaryDarkModeReturn} An object containing the dark mode state and helper functions.
2264
+ * @public
2265
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-ternary-dark-mode)
2266
+ * @example
2267
+ * ```tsx
2268
+ * const { isDarkMode, ternaryDarkMode, setTernaryDarkMode, toggleTernaryDarkMode } = useTernaryDarkMode({ defaultValue: 'dark' });
2269
+ * // Access and use the dark mode state and provided helper functions.
2270
+ * ```
2271
+ */
2272
+ function useTernaryDarkMode({ defaultValue = "system", localStorageKey = LOCAL_STORAGE_KEY, initializeWithValue = true } = {}) {
2273
+ const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY, { initializeWithValue });
2274
+ const [mode, setMode] = useLocalStorage(localStorageKey, defaultValue, { initializeWithValue });
2275
+ const isDarkMode = mode === "dark" || mode === "system" && isDarkOS;
2276
+ const toggleTernaryDarkMode = () => {
2277
+ const modes = [
2278
+ "light",
2279
+ "system",
2280
+ "dark"
2281
+ ];
2282
+ setMode((prevMode) => {
2283
+ const prevIndex = modes.indexOf(prevMode);
2284
+ const nextIndex = (prevIndex + 1) % modes.length;
2285
+ return modes[nextIndex];
2286
+ });
2287
+ };
2288
+ return {
2289
+ isDarkMode,
2290
+ ternaryDarkMode: mode,
2291
+ setTernaryDarkMode: setMode,
2292
+ toggleTernaryDarkMode
2293
+ };
2294
+ }
2295
+
2296
+ //#endregion
2297
+ //#region src/useThrottle/useThrottle.ts
2298
+ /**
2299
+ * Custom hook that throttles a function, ensuring it is only called at most once per wait period.
2300
+ * @template T - The type of the function being throttled.
2301
+ * @param {T} fn - The function to throttle.
2302
+ * @param {number} wait - The number of milliseconds to throttle invocations to.
2303
+ * @returns {T} The throttled function.
2304
+ * @public
2305
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-throttle-fn)
2306
+ * @example
2307
+ * ```tsx
2308
+ * const throttledSave = useThrottleFn(saveToDatabase, 1000);
2309
+ * // Calling throttledSave() multiple times rapidly will only execute saveToDatabase once per second
2310
+ * ```
2311
+ */
2312
+ function useThrottleFn(fn, wait) {
2313
+ const timeoutRef = (0, react.useRef)(null);
2314
+ const lastCalledRef = (0, react.useRef)(0);
2315
+ const throttledFn = (0, react.useCallback)((...args) => {
2316
+ const now = Date.now();
2317
+ const remaining = wait - (now - lastCalledRef.current);
2318
+ if (remaining <= 0 || remaining > wait) {
2319
+ if (timeoutRef.current) {
2320
+ clearTimeout(timeoutRef.current);
2321
+ timeoutRef.current = null;
2322
+ }
2323
+ lastCalledRef.current = now;
2324
+ return fn(...args);
2325
+ }
2326
+ }, [fn, wait]);
2327
+ return throttledFn;
2328
+ }
2329
+ /**
2330
+ * Custom hook that throttles a value, ensuring updates occur at most once per wait period.
2331
+ * @template T - The type of the value being throttled.
2332
+ * @param {T} value - The value to throttle.
2333
+ * @param {number} wait - The number of milliseconds to throttle updates to.
2334
+ * @returns {T} The throttled value.
2335
+ * @public
2336
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-throttle)
2337
+ * @example
2338
+ * ```tsx
2339
+ * const throttledSearchTerm = useThrottle(searchTerm, 300);
2340
+ * // throttledSearchTerm will only update 300ms after the last change to searchTerm
2341
+ * ```
2342
+ */
2343
+ function useThrottle(value, wait) {
2344
+ const [throttledValue, setThrottledValue] = (0, react.useState)(value);
2345
+ const lastUpdatedRef = (0, react.useRef)(0);
2346
+ const previousValueRef = (0, react.useRef)(value);
2347
+ const now = Date.now();
2348
+ const remaining = wait - (now - lastUpdatedRef.current);
2349
+ if (remaining <= 0 || remaining > wait || previousValueRef.current !== value) {
2350
+ if (previousValueRef.current !== value) {
2351
+ setThrottledValue(value);
2352
+ lastUpdatedRef.current = now;
2353
+ previousValueRef.current = value;
2354
+ }
2355
+ }
2356
+ return throttledValue;
2357
+ }
2358
+
2359
+ //#endregion
2360
+ //#region src/useTimeout/useTimeout.ts
2361
+ /**
2362
+ * Custom hook that handles timeouts in React components using the [`setTimeout API`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout).
2363
+ * @param {() => void} callback - The function to be executed when the timeout elapses.
2364
+ * @param {number | null} delay - The duration (in milliseconds) for the timeout. Set to `null` to clear the timeout.
2365
+ * @returns {void} This hook does not return anything.
2366
+ * @public
2367
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-timeout)
2368
+ * @example
2369
+ * ```tsx
2370
+ * // Usage of useTimeout hook
2371
+ * useTimeout(() => {
2372
+ * // Code to be executed after the specified delay
2373
+ * }, 1000); // Set a timeout of 1000 milliseconds (1 second)
2374
+ * ```
2375
+ */
2376
+ function useTimeout(callback, delay) {
2377
+ const savedCallback = (0, react.useRef)(callback);
2378
+ useIsomorphicLayoutEffect(() => {
2379
+ savedCallback.current = callback;
2380
+ }, [callback]);
2381
+ (0, react.useEffect)(() => {
2382
+ if (!delay && delay !== 0) return;
2383
+ const id = setTimeout(() => {
2384
+ savedCallback.current();
2385
+ }, delay);
2386
+ return () => {
2387
+ clearTimeout(id);
2388
+ };
2389
+ }, [delay]);
2390
+ }
2391
+
2392
+ //#endregion
2393
+ //#region src/useToggle/useToggle.ts
2394
+ /**
2395
+ * Custom hook that manages a boolean toggle state in React components.
2396
+ * @param {boolean} [defaultValue] - The initial value for the toggle state.
2397
+ * @returns {[boolean, () => void, Dispatch<SetStateAction<boolean>>]} A tuple containing the current state,
2398
+ * a function to toggle the state, and a function to set the state explicitly.
2399
+ * @public
2400
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-toggle)
2401
+ * @example
2402
+ * ```tsx
2403
+ * const [isToggled, toggle, setToggle] = useToggle(); // Initial value is false
2404
+ * // OR
2405
+ * const [isToggled, toggle, setToggle] = useToggle(true); // Initial value is true
2406
+ * // Use isToggled in your component, toggle to switch the state, setToggle to set the state explicitly.
2407
+ * ```
2408
+ */
2409
+ function useToggle(defaultValue) {
2410
+ const [value, setValue] = (0, react.useState)(!!defaultValue);
2411
+ const toggle = (0, react.useCallback)(() => {
2412
+ setValue((x) => !x);
2413
+ }, []);
2414
+ return [
2415
+ value,
2416
+ toggle,
2417
+ setValue
2418
+ ];
2419
+ }
2420
+
2421
+ //#endregion
2422
+ //#region src/useUpdate/useUpdate.ts
2423
+ /**
2424
+ * Custom hook that returns a function to force a component re-render.
2425
+ * @returns {() => void} A function that, when called, will force the component to re-render.
2426
+ * @public
2427
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-update)
2428
+ * @example
2429
+ * ```tsx
2430
+ * const update = useUpdate();
2431
+ *
2432
+ * return (
2433
+ * <div>
2434
+ * <p>Current time: {Date.now()}</p>
2435
+ * <button onClick={update}>Update</button>
2436
+ * </div>
2437
+ * );
2438
+ * ```
2439
+ */
2440
+ function useUpdate() {
2441
+ const [, setTick] = (0, react.useState)(0);
2442
+ const update = (0, react.useCallback)(() => {
2443
+ setTick((tick) => tick + 1);
2444
+ }, []);
2445
+ return update;
2446
+ }
2447
+
2448
+ //#endregion
2449
+ //#region src/useUpdateEffect/useUpdateEffect.ts
2450
+ /**
2451
+ * A hook that runs an effect only when dependencies change, skipping the initial mount.
2452
+ * This is useful for responding to prop or state changes without running on first render.
2453
+ *
2454
+ * @param {() => void | (() => void)} effect - The effect function to run.
2455
+ * @param {unknown[]} deps - The dependency array.
2456
+ *
2457
+ * @example
2458
+ * ```tsx
2459
+ * function Component({ value }) {
2460
+ * useUpdateEffect(() => {
2461
+ * console.log('Value changed:', value);
2462
+ * }, [value]);
2463
+ *
2464
+ * return <div>{value}</div>;
2465
+ * }
2466
+ * ```
2467
+ */
2468
+ function useUpdateEffect(effect, deps) {
2469
+ const isFirstMount = (0, react.useRef)(true);
2470
+ (0, react.useEffect)(() => {
2471
+ if (isFirstMount.current) {
2472
+ isFirstMount.current = false;
2473
+ return;
2474
+ }
2475
+ return effect();
2476
+ }, deps);
2477
+ }
2478
+
2479
+ //#endregion
2480
+ //#region src/useWindowSize/useWindowSize.ts
2481
+ const IS_SERVER = typeof window === "undefined";
2482
+ /**
2483
+ * Custom hook that tracks the size of the window.
2484
+ * @param {?UseWindowSizeOptions} [options] - The options for customizing the behavior of the hook (optional).
2485
+ * @returns {object} An object containing the width and height of the window.
2486
+ * @public
2487
+ * @see [Documentation](https://usehooks-ts.com/react-hook/use-window-size)
2488
+ * @example
2489
+ * ```tsx
2490
+ * const { width = 0, height = 0 } = useWindowSize();
2491
+ * console.log(`Window size: ${width} x ${height}`);
2492
+ * ```
2493
+ */
2494
+ function useWindowSize(options = {}) {
2495
+ let { initializeWithValue = true } = options;
2496
+ if (IS_SERVER) initializeWithValue = false;
2497
+ const [windowSize, setWindowSize] = (0, react.useState)(() => {
2498
+ if (initializeWithValue) return {
2499
+ width: window.innerWidth,
2500
+ height: window.innerHeight
2501
+ };
2502
+ return {
2503
+ width: void 0,
2504
+ height: void 0
2505
+ };
2506
+ });
2507
+ const debouncedSetWindowSize = useDebounceCallback(setWindowSize, options.debounceDelay);
2508
+ function handleSize() {
2509
+ const setSize = options.debounceDelay ? debouncedSetWindowSize : setWindowSize;
2510
+ setSize({
2511
+ width: window.innerWidth,
2512
+ height: window.innerHeight
2513
+ });
2514
+ }
2515
+ useEventListener("resize", handleSize);
2516
+ useIsomorphicLayoutEffect(() => {
2517
+ handleSize();
2518
+ }, []);
2519
+ return windowSize;
2520
+ }
2521
+
2522
+ //#endregion
2523
+ exports.DOTS = DOTS
2524
+ exports.useAsync = useAsync
2525
+ exports.useBoolean = useBoolean
2526
+ exports.useClickAnyWhere = useClickAnyWhere
2527
+ exports.useCopyToClipboard = useCopyToClipboard
2528
+ exports.useCountdown = useCountdown
2529
+ exports.useCounter = useCounter
2530
+ exports.useDarkMode = useDarkMode
2531
+ exports.useDebounceCallback = useDebounceCallback
2532
+ exports.useDebounceValue = useDebounceValue
2533
+ exports.useDisclosure = useDisclosure
2534
+ exports.useDocumentTitle = useDocumentTitle
2535
+ exports.useEventCallback = useEventCallback
2536
+ exports.useEventListener = useEventListener
2537
+ exports.useGeolocation = useGeolocation
2538
+ exports.useHover = useHover
2539
+ exports.useIdle = useIdle
2540
+ exports.useIntersectionObserver = useIntersectionObserver
2541
+ exports.useInterval = useInterval
2542
+ exports.useIsClient = useIsClient
2543
+ exports.useIsMounted = useIsMounted
2544
+ exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect
2545
+ exports.useList = useList
2546
+ exports.useLocalStorage = useLocalStorage
2547
+ exports.useMap = useMap
2548
+ exports.useMediaQuery = useMediaQuery
2549
+ exports.useMemoizedFn = useMemoizedFn
2550
+ exports.useNetwork = useNetwork
2551
+ exports.useOnClickOutside = useOnClickOutside
2552
+ exports.usePageLeave = usePageLeave
2553
+ exports.usePagination = usePagination
2554
+ exports.usePermission = usePermission
2555
+ exports.usePrevious = usePrevious
2556
+ exports.useQueue = useQueue
2557
+ exports.useReadLocalStorage = useReadLocalStorage
2558
+ exports.useResizeObserver = useResizeObserver
2559
+ exports.useScreen = useScreen
2560
+ exports.useScript = useScript
2561
+ exports.useScrollLock = useScrollLock
2562
+ exports.useSessionStorage = useSessionStorage
2563
+ exports.useSet = useSet
2564
+ exports.useStateList = useStateList
2565
+ exports.useStep = useStep
2566
+ exports.useTernaryDarkMode = useTernaryDarkMode
2567
+ exports.useThrottle = useThrottle
2568
+ exports.useThrottleFn = useThrottleFn
2569
+ exports.useTimeout = useTimeout
2570
+ exports.useToggle = useToggle
2571
+ exports.useUnmount = useUnmount
2572
+ exports.useUpdate = useUpdate
2573
+ exports.useUpdateEffect = useUpdateEffect
2574
+ exports.useWindowSize = useWindowSize