react-simplikit 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -0
  3. package/dist/components/ImpressionArea/index.d.ts +46 -0
  4. package/dist/components/ImpressionArea/index.js +276 -0
  5. package/dist/components/Separated/index.d.ts +38 -0
  6. package/dist/components/Separated/index.js +40 -0
  7. package/dist/components/SwitchCase/index.d.ts +46 -0
  8. package/dist/components/SwitchCase/index.js +35 -0
  9. package/dist/hooks/useAsyncEffect/index.d.ts +25 -0
  10. package/dist/hooks/useAsyncEffect/index.js +43 -0
  11. package/dist/hooks/useBooleanState/index.d.ts +19 -0
  12. package/dist/hooks/useBooleanState/index.js +45 -0
  13. package/dist/hooks/useCallbackOncePerRender/index.d.ts +41 -0
  14. package/dist/hooks/useCallbackOncePerRender/index.js +59 -0
  15. package/dist/hooks/useDebounce/index.d.ts +48 -0
  16. package/dist/hooks/useDebounce/index.js +123 -0
  17. package/dist/hooks/useImpressionRef/index.d.ts +38 -0
  18. package/dist/hooks/useImpressionRef/index.js +237 -0
  19. package/dist/hooks/useInputState/index.d.ts +27 -0
  20. package/dist/hooks/useInputState/index.js +45 -0
  21. package/dist/hooks/useIntersectionObserver/index.d.ts +33 -0
  22. package/dist/hooks/useIntersectionObserver/index.js +91 -0
  23. package/dist/hooks/useInterval/index.d.ts +37 -0
  24. package/dist/hooks/useInterval/index.js +64 -0
  25. package/dist/hooks/useLoading/index.d.ts +37 -0
  26. package/dist/hooks/useLoading/index.js +61 -0
  27. package/dist/hooks/useOutsideClickEffect/index.d.ts +27 -0
  28. package/dist/hooks/useOutsideClickEffect/index.js +70 -0
  29. package/dist/hooks/usePreservedCallback/index.d.ts +30 -0
  30. package/dist/hooks/usePreservedCallback/index.js +41 -0
  31. package/dist/hooks/usePreservedReference/index.d.ts +42 -0
  32. package/dist/hooks/usePreservedReference/index.js +44 -0
  33. package/dist/hooks/usePrevious/index.d.ts +21 -0
  34. package/dist/hooks/usePrevious/index.js +47 -0
  35. package/dist/hooks/useRefEffect/index.d.ts +31 -0
  36. package/dist/hooks/useRefEffect/index.js +68 -0
  37. package/dist/hooks/useStorageState/index.d.ts +50 -0
  38. package/dist/hooks/useStorageState/index.js +168 -0
  39. package/dist/hooks/useThrottle/index.d.ts +47 -0
  40. package/dist/hooks/useThrottle/index.js +147 -0
  41. package/dist/hooks/useTimeout/index.d.ts +30 -0
  42. package/dist/hooks/useTimeout/index.js +53 -0
  43. package/dist/hooks/useToggle/index.d.ts +30 -0
  44. package/dist/hooks/useToggle/index.js +36 -0
  45. package/dist/hooks/useVisibilityEvent/index.d.ts +27 -0
  46. package/dist/hooks/useVisibilityEvent/index.js +46 -0
  47. package/dist/index.d.ts +26 -0
  48. package/dist/index.js +761 -0
  49. package/dist/utils/buildContext/index.d.ts +38 -0
  50. package/dist/utils/buildContext/index.js +55 -0
  51. package/dist/utils/mergeRefs/index.d.ts +37 -0
  52. package/dist/utils/mergeRefs/index.js +45 -0
  53. package/esm/components/ImpressionArea/index.d.mts +46 -0
  54. package/esm/components/ImpressionArea/index.mjs +249 -0
  55. package/esm/components/Separated/index.d.mts +38 -0
  56. package/esm/components/Separated/index.mjs +13 -0
  57. package/esm/components/SwitchCase/index.d.mts +46 -0
  58. package/esm/components/SwitchCase/index.mjs +8 -0
  59. package/esm/hooks/useAsyncEffect/index.d.mts +25 -0
  60. package/esm/hooks/useAsyncEffect/index.mjs +16 -0
  61. package/esm/hooks/useBooleanState/index.d.mts +19 -0
  62. package/esm/hooks/useBooleanState/index.mjs +18 -0
  63. package/esm/hooks/useCallbackOncePerRender/index.d.mts +41 -0
  64. package/esm/hooks/useCallbackOncePerRender/index.mjs +32 -0
  65. package/esm/hooks/useDebounce/index.d.mts +48 -0
  66. package/esm/hooks/useDebounce/index.mjs +96 -0
  67. package/esm/hooks/useImpressionRef/index.d.mts +38 -0
  68. package/esm/hooks/useImpressionRef/index.mjs +210 -0
  69. package/esm/hooks/useInputState/index.d.mts +27 -0
  70. package/esm/hooks/useInputState/index.mjs +18 -0
  71. package/esm/hooks/useIntersectionObserver/index.d.mts +33 -0
  72. package/esm/hooks/useIntersectionObserver/index.mjs +64 -0
  73. package/esm/hooks/useInterval/index.d.mts +37 -0
  74. package/esm/hooks/useInterval/index.mjs +37 -0
  75. package/esm/hooks/useLoading/index.d.mts +37 -0
  76. package/esm/hooks/useLoading/index.mjs +34 -0
  77. package/esm/hooks/useOutsideClickEffect/index.d.mts +27 -0
  78. package/esm/hooks/useOutsideClickEffect/index.mjs +43 -0
  79. package/esm/hooks/usePreservedCallback/index.d.mts +30 -0
  80. package/esm/hooks/usePreservedCallback/index.mjs +14 -0
  81. package/esm/hooks/usePreservedReference/index.d.mts +42 -0
  82. package/esm/hooks/usePreservedReference/index.mjs +17 -0
  83. package/esm/hooks/usePrevious/index.d.mts +21 -0
  84. package/esm/hooks/usePrevious/index.mjs +20 -0
  85. package/esm/hooks/useRefEffect/index.d.mts +31 -0
  86. package/esm/hooks/useRefEffect/index.mjs +41 -0
  87. package/esm/hooks/useStorageState/index.d.mts +50 -0
  88. package/esm/hooks/useStorageState/index.mjs +141 -0
  89. package/esm/hooks/useThrottle/index.d.mts +47 -0
  90. package/esm/hooks/useThrottle/index.mjs +120 -0
  91. package/esm/hooks/useTimeout/index.d.mts +30 -0
  92. package/esm/hooks/useTimeout/index.mjs +26 -0
  93. package/esm/hooks/useToggle/index.d.mts +30 -0
  94. package/esm/hooks/useToggle/index.mjs +9 -0
  95. package/esm/hooks/useVisibilityEvent/index.d.mts +27 -0
  96. package/esm/hooks/useVisibilityEvent/index.mjs +19 -0
  97. package/esm/index.d.mts +26 -0
  98. package/esm/index.mjs +711 -0
  99. package/esm/utils/buildContext/index.d.mts +38 -0
  100. package/esm/utils/buildContext/index.mjs +28 -0
  101. package/esm/utils/mergeRefs/index.d.mts +37 -0
  102. package/esm/utils/mergeRefs/index.mjs +18 -0
  103. package/package.json +87 -7
package/esm/index.mjs ADDED
@@ -0,0 +1,711 @@
1
+ // src/hooks/useImpressionRef/useImpressionRef.ts
2
+ import { useRef as useRef4 } from "react";
3
+
4
+ // src/hooks/useIntersectionObserver/useIntersectionObserver.ts
5
+ import { useMemo } from "react";
6
+
7
+ // src/hooks/usePreservedCallback/usePreservedCallback.ts
8
+ import { useCallback, useEffect, useRef } from "react";
9
+ function usePreservedCallback(callback) {
10
+ const callbackRef = useRef(callback);
11
+ useEffect(() => {
12
+ callbackRef.current = callback;
13
+ }, [callback]);
14
+ return useCallback((...args) => {
15
+ return callbackRef.current(...args);
16
+ }, []);
17
+ }
18
+
19
+ // src/hooks/useRefEffect/useRefEffect.ts
20
+ import { useCallback as useCallback2, useRef as useRef2 } from "react";
21
+ function useRefEffect(callback, deps) {
22
+ const preservedCallback = usePreservedCallback(callback);
23
+ const cleanupCallbackRef = useRef2(() => {
24
+ });
25
+ const effect = useCallback2(
26
+ (element) => {
27
+ cleanupCallbackRef.current();
28
+ cleanupCallbackRef.current = () => {
29
+ };
30
+ if (element == null) {
31
+ return;
32
+ }
33
+ const cleanup = preservedCallback(element);
34
+ if (typeof cleanup === "function") {
35
+ cleanupCallbackRef.current = cleanup;
36
+ }
37
+ },
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ [preservedCallback, ...deps]
40
+ );
41
+ return effect;
42
+ }
43
+
44
+ // src/hooks/useIntersectionObserver/useIntersectionObserver.ts
45
+ function useIntersectionObserver(callback, options) {
46
+ const preservedCallback = usePreservedCallback(callback);
47
+ const observer = useMemo(() => {
48
+ if (typeof IntersectionObserver === "undefined") {
49
+ return;
50
+ }
51
+ return new IntersectionObserver(([entry]) => {
52
+ preservedCallback(entry);
53
+ }, options);
54
+ }, [preservedCallback, options]);
55
+ return useRefEffect(
56
+ (element) => {
57
+ observer?.observe(element);
58
+ return () => {
59
+ observer?.unobserve(element);
60
+ };
61
+ },
62
+ [preservedCallback, options]
63
+ );
64
+ }
65
+
66
+ // src/hooks/useVisibilityEvent/useVisibilityEvent.ts
67
+ import { useCallback as useCallback3, useEffect as useEffect2 } from "react";
68
+ function useVisibilityEvent(callback, options = {}) {
69
+ const handleVisibilityChange = useCallback3(() => {
70
+ callback(document.visibilityState);
71
+ }, [callback]);
72
+ useEffect2(() => {
73
+ if (options?.immediate ?? false) {
74
+ handleVisibilityChange();
75
+ }
76
+ document.addEventListener("visibilitychange", handleVisibilityChange);
77
+ return () => {
78
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
79
+ };
80
+ }, [handleVisibilityChange, options?.immediate]);
81
+ }
82
+
83
+ // src/hooks/useImpressionRef/useDebouncedCallback.ts
84
+ import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3 } from "react";
85
+
86
+ // src/hooks/useDebounce/debounce.ts
87
+ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
88
+ let pendingThis = void 0;
89
+ let pendingArgs = null;
90
+ const leading = edges != null && edges.includes("leading");
91
+ const trailing = edges == null || edges.includes("trailing");
92
+ const invoke = () => {
93
+ if (pendingArgs !== null) {
94
+ func.apply(pendingThis, pendingArgs);
95
+ pendingThis = void 0;
96
+ pendingArgs = null;
97
+ }
98
+ };
99
+ const onTimerEnd = () => {
100
+ if (trailing) {
101
+ invoke();
102
+ }
103
+ cancel();
104
+ };
105
+ let timeoutId = null;
106
+ const schedule = () => {
107
+ if (timeoutId != null) {
108
+ clearTimeout(timeoutId);
109
+ }
110
+ timeoutId = setTimeout(() => {
111
+ timeoutId = null;
112
+ onTimerEnd();
113
+ }, debounceMs);
114
+ };
115
+ const cancelTimer = () => {
116
+ if (timeoutId !== null) {
117
+ clearTimeout(timeoutId);
118
+ timeoutId = null;
119
+ }
120
+ };
121
+ const cancel = () => {
122
+ cancelTimer();
123
+ pendingThis = void 0;
124
+ pendingArgs = null;
125
+ };
126
+ const debounced = function(...args) {
127
+ pendingThis = this;
128
+ pendingArgs = args;
129
+ const isFirstCall = timeoutId == null;
130
+ schedule();
131
+ if (leading && isFirstCall) {
132
+ invoke();
133
+ }
134
+ };
135
+ debounced.cancel = cancel;
136
+ return debounced;
137
+ }
138
+
139
+ // src/hooks/useImpressionRef/useDebouncedCallback.ts
140
+ function useDebouncedCallback({
141
+ onChange,
142
+ timeThreshold
143
+ }) {
144
+ const handleChange = usePreservedCallback(onChange);
145
+ const ref = useRef3({ value: false, clearPreviousDebounce: () => {
146
+ } });
147
+ useEffect3(() => {
148
+ const current = ref.current;
149
+ return () => {
150
+ current.clearPreviousDebounce();
151
+ };
152
+ }, []);
153
+ return useCallback4(
154
+ (nextValue) => {
155
+ if (nextValue === ref.current.value) {
156
+ return;
157
+ }
158
+ const debounced = debounce(() => {
159
+ handleChange(nextValue);
160
+ ref.current.value = nextValue;
161
+ }, timeThreshold);
162
+ ref.current.clearPreviousDebounce();
163
+ debounced();
164
+ ref.current.clearPreviousDebounce = debounced.cancel;
165
+ },
166
+ [handleChange, timeThreshold]
167
+ );
168
+ }
169
+
170
+ // src/hooks/useImpressionRef/useImpressionRef.ts
171
+ function useImpressionRef({
172
+ onImpressionStart = () => {
173
+ },
174
+ onImpressionEnd = () => {
175
+ },
176
+ rootMargin,
177
+ areaThreshold = 0,
178
+ timeThreshold = 0
179
+ }) {
180
+ const impressionStartHandler = usePreservedCallback(onImpressionStart);
181
+ const impressionEndHandler = usePreservedCallback(onImpressionEnd);
182
+ const isIntersectingRef = useRef4(false);
183
+ const impressionEventHandler = useDebouncedCallback({
184
+ timeThreshold,
185
+ onChange: (impressed) => {
186
+ (impressed ? impressionStartHandler : impressionEndHandler)();
187
+ }
188
+ });
189
+ useVisibilityEvent((documentVisible) => {
190
+ if (!isIntersectingRef.current) {
191
+ return;
192
+ }
193
+ impressionEventHandler(documentVisible === "visible");
194
+ });
195
+ return useIntersectionObserver(
196
+ (entry) => {
197
+ if (document.visibilityState === "hidden") {
198
+ return;
199
+ }
200
+ const currentRatio = entry.intersectionRatio;
201
+ const isIntersecting = areaThreshold === 0 ? entry.isIntersecting : currentRatio >= areaThreshold;
202
+ isIntersectingRef.current = isIntersecting;
203
+ impressionEventHandler(isIntersecting);
204
+ },
205
+ { rootMargin, threshold: areaThreshold }
206
+ );
207
+ }
208
+
209
+ // src/utils/mergeRefs/mergeRefs.ts
210
+ function mergeRefs(...refs) {
211
+ return (value) => {
212
+ for (const ref of refs) {
213
+ if (ref == null) {
214
+ continue;
215
+ }
216
+ if (typeof ref === "function") {
217
+ ref(value);
218
+ continue;
219
+ }
220
+ ref.current = value;
221
+ }
222
+ };
223
+ }
224
+
225
+ // src/components/ImpressionArea/ImpressionArea.tsx
226
+ import { jsx } from "react/jsx-runtime";
227
+ function ImpressionArea({
228
+ as,
229
+ rootMargin,
230
+ areaThreshold,
231
+ timeThreshold,
232
+ onImpressionStart,
233
+ onImpressionEnd,
234
+ ref,
235
+ ...props
236
+ }) {
237
+ const Component = as ?? "div";
238
+ const impressionRef = useImpressionRef({
239
+ onImpressionStart,
240
+ onImpressionEnd,
241
+ areaThreshold,
242
+ timeThreshold,
243
+ rootMargin
244
+ });
245
+ return /* @__PURE__ */ jsx(Component, { ref: mergeRefs(ref, impressionRef), ...props });
246
+ }
247
+
248
+ // src/components/Separated/Separated.tsx
249
+ import { Children, Fragment, isValidElement } from "react";
250
+ import { Fragment as Fragment2, jsx as jsx2, jsxs } from "react/jsx-runtime";
251
+ function Separated({ children, with: separator }) {
252
+ const childrenArray = Children.toArray(children).filter(isValidElement);
253
+ return /* @__PURE__ */ jsx2(Fragment2, { children: childrenArray.map((child, i, { length }) => /* @__PURE__ */ jsxs(Fragment, { children: [
254
+ child,
255
+ i + 1 !== length ? separator : null
256
+ ] }, i)) });
257
+ }
258
+
259
+ // src/components/SwitchCase/SwitchCase.tsx
260
+ function SwitchCase({ value, caseBy, defaultComponent = () => null }) {
261
+ const stringifiedValue = String(value);
262
+ return (caseBy[stringifiedValue] ?? defaultComponent)();
263
+ }
264
+
265
+ // src/hooks/useAsyncEffect/useAsyncEffect.ts
266
+ import { useEffect as useEffect4 } from "react";
267
+ function useAsyncEffect(effect, deps) {
268
+ useEffect4(() => {
269
+ let cleanup;
270
+ effect().then((result) => {
271
+ cleanup = result;
272
+ });
273
+ return () => {
274
+ cleanup?.();
275
+ };
276
+ }, deps);
277
+ }
278
+
279
+ // src/hooks/useBooleanState/useBooleanState.ts
280
+ import { useCallback as useCallback5, useState } from "react";
281
+ var useBooleanState = (defaultValue = false) => {
282
+ const [bool, setBool] = useState(defaultValue);
283
+ const setTrue = useCallback5(() => {
284
+ setBool(true);
285
+ }, []);
286
+ const setFalse = useCallback5(() => {
287
+ setBool(false);
288
+ }, []);
289
+ const toggle2 = useCallback5(() => {
290
+ setBool((b) => !b);
291
+ }, []);
292
+ return [bool, setTrue, setFalse, toggle2];
293
+ };
294
+
295
+ // src/hooks/useCallbackOncePerRender/useCallbackOncePerRender.ts
296
+ import { useEffect as useEffect5, useRef as useRef5 } from "react";
297
+ function useCallbackOncePerRender(callback, deps) {
298
+ const hasFired = useRef5(false);
299
+ useEffect5(() => {
300
+ hasFired.current = false;
301
+ }, deps);
302
+ return usePreservedCallback((...args) => {
303
+ if (hasFired.current) {
304
+ return;
305
+ }
306
+ callback(...args);
307
+ hasFired.current = true;
308
+ });
309
+ }
310
+
311
+ // src/hooks/useDebounce/useDebounce.ts
312
+ import { useEffect as useEffect6 } from "react";
313
+ import { useMemo as useMemo2 } from "react";
314
+ function useDebounce(callback, wait, options = {}) {
315
+ const preservedCallback = usePreservedCallback(callback);
316
+ const { leading = false, trailing = true } = options;
317
+ const edges = useMemo2(() => {
318
+ const _edges = [];
319
+ if (leading) {
320
+ _edges.push("leading");
321
+ }
322
+ if (trailing) {
323
+ _edges.push("trailing");
324
+ }
325
+ return _edges;
326
+ }, [leading, trailing]);
327
+ const debounced = useMemo2(() => {
328
+ return debounce(preservedCallback, wait, { edges });
329
+ }, [preservedCallback, wait, edges]);
330
+ useEffect6(() => {
331
+ return () => {
332
+ debounced.cancel();
333
+ };
334
+ }, [debounced]);
335
+ return debounced;
336
+ }
337
+
338
+ // src/hooks/useInputState/useInputState.ts
339
+ import { useCallback as useCallback6, useState as useState2 } from "react";
340
+ function useInputState(initialValue = "", transformValue = echo) {
341
+ const [value, setValue] = useState2(initialValue);
342
+ const handleValueChange = useCallback6(
343
+ ({ target: { value: value2 } }) => {
344
+ setValue(transformValue(value2));
345
+ },
346
+ [transformValue]
347
+ );
348
+ return [value, handleValueChange];
349
+ }
350
+ function echo(v) {
351
+ return v;
352
+ }
353
+
354
+ // src/hooks/useInterval/useInterval.ts
355
+ import { useEffect as useEffect7 } from "react";
356
+ function useInterval(callback, options) {
357
+ const delay = typeof options === "number" ? options : options.delay;
358
+ const immediate = typeof options === "number" ? false : options.immediate;
359
+ const enabled = typeof options === "number" ? true : options.enabled ?? true;
360
+ const preservedCallback = usePreservedCallback(callback);
361
+ useEffect7(() => {
362
+ if (immediate === true && enabled) {
363
+ preservedCallback();
364
+ }
365
+ }, [immediate, preservedCallback, enabled]);
366
+ useEffect7(() => {
367
+ if (!enabled) {
368
+ return;
369
+ }
370
+ const id = window.setInterval(preservedCallback, delay);
371
+ return () => window.clearInterval(id);
372
+ }, [delay, preservedCallback, enabled]);
373
+ }
374
+
375
+ // src/hooks/useLoading/useLoading.ts
376
+ import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo3, useRef as useRef6, useState as useState3 } from "react";
377
+ function useLoading() {
378
+ const [loading, setLoading] = useState3(false);
379
+ const ref = useIsMountedRef();
380
+ const startTransition = useCallback7(
381
+ async (promise) => {
382
+ try {
383
+ setLoading(true);
384
+ const data = await promise;
385
+ return data;
386
+ } finally {
387
+ if (ref.isMounted) {
388
+ setLoading(false);
389
+ }
390
+ }
391
+ },
392
+ [ref.isMounted]
393
+ );
394
+ return useMemo3(() => [loading, startTransition], [loading, startTransition]);
395
+ }
396
+ function useIsMountedRef() {
397
+ const ref = useRef6({ isMounted: true }).current;
398
+ useEffect8(() => {
399
+ ref.isMounted = true;
400
+ return () => {
401
+ ref.isMounted = false;
402
+ };
403
+ }, [ref]);
404
+ return ref;
405
+ }
406
+
407
+ // src/hooks/useOutsideClickEffect/useOutsideClickEffect.ts
408
+ import { useEffect as useEffect9, useRef as useRef7 } from "react";
409
+ function useOutsideClickEffect(container, callback) {
410
+ const containers = useRef7([]);
411
+ const handleDocumentClick = usePreservedCallback(({ target }) => {
412
+ if (target === null) {
413
+ return;
414
+ }
415
+ if (containers.current.length === 0) {
416
+ return;
417
+ }
418
+ if (containers.current.some((x) => x.contains(target))) {
419
+ return;
420
+ }
421
+ callback();
422
+ });
423
+ useEffect9(() => {
424
+ containers.current = [container].flat(1).filter((item) => item != null);
425
+ }, [container]);
426
+ useEffect9(() => {
427
+ document.addEventListener("click", handleDocumentClick);
428
+ return () => {
429
+ document.removeEventListener("click", handleDocumentClick);
430
+ };
431
+ }, [handleDocumentClick]);
432
+ }
433
+
434
+ // src/hooks/usePreservedReference/usePreservedReference.ts
435
+ import { useMemo as useMemo4, useRef as useRef8 } from "react";
436
+ function usePreservedReference(value, areValuesEqual = areDeeplyEqual) {
437
+ const ref = useRef8(value);
438
+ return useMemo4(() => {
439
+ if (!areValuesEqual(ref.current, value)) {
440
+ ref.current = value;
441
+ }
442
+ return ref.current;
443
+ }, [areValuesEqual, value]);
444
+ }
445
+ function areDeeplyEqual(x, y) {
446
+ return JSON.stringify(x) === JSON.stringify(y);
447
+ }
448
+
449
+ // src/hooks/usePrevious/usePrevious.ts
450
+ import { useEffect as useEffect10, useRef as useRef9 } from "react";
451
+ var strictEquals = (prev, next) => prev === next;
452
+ function usePrevious(state, compare = strictEquals) {
453
+ const prevRef = useRef9(state);
454
+ const currentRef = useRef9(state);
455
+ const isFirstRender = useRef9(true);
456
+ useEffect10(() => {
457
+ isFirstRender.current = false;
458
+ }, []);
459
+ if (isFirstRender.current || compare(currentRef.current, state)) {
460
+ return prevRef.current;
461
+ }
462
+ prevRef.current = currentRef.current;
463
+ currentRef.current = state;
464
+ return prevRef.current;
465
+ }
466
+
467
+ // src/hooks/useStorageState/useStorageState.ts
468
+ import { useCallback as useCallback8, useRef as useRef10, useSyncExternalStore } from "react";
469
+
470
+ // src/hooks/useStorageState/storage.ts
471
+ var MemoStorage = class {
472
+ storage = /* @__PURE__ */ new Map();
473
+ get(key) {
474
+ return this.storage.get(key) ?? null;
475
+ }
476
+ set(key, value) {
477
+ this.storage.set(key, value);
478
+ }
479
+ remove(key) {
480
+ this.storage.delete(key);
481
+ }
482
+ clear() {
483
+ this.storage.clear();
484
+ }
485
+ };
486
+ var LocalStorage = class {
487
+ static canUse() {
488
+ const TEST_KEY = generateTestKey();
489
+ try {
490
+ localStorage.setItem(TEST_KEY, "test");
491
+ localStorage.removeItem(TEST_KEY);
492
+ return true;
493
+ } catch {
494
+ return false;
495
+ }
496
+ }
497
+ get(key) {
498
+ return localStorage.getItem(key);
499
+ }
500
+ set(key, value) {
501
+ localStorage.setItem(key, value);
502
+ }
503
+ remove(key) {
504
+ localStorage.removeItem(key);
505
+ }
506
+ clear() {
507
+ localStorage.clear();
508
+ }
509
+ };
510
+ var SessionStorage = class {
511
+ static canUse() {
512
+ const TEST_KEY = generateTestKey();
513
+ try {
514
+ sessionStorage.setItem(TEST_KEY, "test");
515
+ sessionStorage.removeItem(TEST_KEY);
516
+ return true;
517
+ } catch {
518
+ return false;
519
+ }
520
+ }
521
+ get(key) {
522
+ return sessionStorage.getItem(key);
523
+ }
524
+ set(key, value) {
525
+ sessionStorage.setItem(key, value);
526
+ }
527
+ remove(key) {
528
+ sessionStorage.removeItem(key);
529
+ }
530
+ clear() {
531
+ sessionStorage.clear();
532
+ }
533
+ };
534
+ function generateTestKey() {
535
+ return new Array(4).fill(null).map(() => Math.random().toString(36).slice(2)).join("");
536
+ }
537
+ function generateStorage() {
538
+ if (LocalStorage.canUse()) {
539
+ return new LocalStorage();
540
+ }
541
+ return new MemoStorage();
542
+ }
543
+ function generateSessionStorage() {
544
+ if (SessionStorage.canUse()) {
545
+ return new SessionStorage();
546
+ }
547
+ return new MemoStorage();
548
+ }
549
+ var safeLocalStorage = generateStorage();
550
+ var safeSessionStorage = generateSessionStorage();
551
+
552
+ // src/hooks/useStorageState/useStorageState.ts
553
+ var listeners = /* @__PURE__ */ new Set();
554
+ var emitListeners = () => {
555
+ listeners.forEach((listener) => listener());
556
+ };
557
+ function useStorageState(key, { storage = safeLocalStorage, defaultValue } = {}) {
558
+ const cache = useRef10({
559
+ data: null,
560
+ parsed: defaultValue
561
+ });
562
+ const getSnapshot = useCallback8(() => {
563
+ const data = storage.get(key);
564
+ if (data !== cache.current.data) {
565
+ try {
566
+ cache.current.parsed = data != null ? JSON.parse(data) : defaultValue;
567
+ } catch {
568
+ cache.current.parsed = defaultValue;
569
+ }
570
+ cache.current.data = data;
571
+ }
572
+ return cache.current.parsed;
573
+ }, [defaultValue, key, storage]);
574
+ const storageState = useSyncExternalStore(
575
+ (onStoreChange) => {
576
+ listeners.add(onStoreChange);
577
+ const handler = (event) => {
578
+ if (event.key === key) {
579
+ onStoreChange();
580
+ }
581
+ };
582
+ window.addEventListener("storage", handler);
583
+ return () => {
584
+ listeners.delete(onStoreChange);
585
+ window.removeEventListener("storage", handler);
586
+ };
587
+ },
588
+ () => getSnapshot(),
589
+ () => defaultValue
590
+ );
591
+ const setStorageState = useCallback8(
592
+ (value) => {
593
+ const nextValue = typeof value === "function" ? value(getSnapshot()) : value;
594
+ if (nextValue == null) {
595
+ storage.remove(key);
596
+ } else {
597
+ storage.set(key, JSON.stringify(nextValue));
598
+ }
599
+ emitListeners();
600
+ },
601
+ [getSnapshot, key, storage]
602
+ );
603
+ return [storageState, setStorageState];
604
+ }
605
+
606
+ // src/hooks/useThrottle/useThrottle.ts
607
+ import { useEffect as useEffect11, useMemo as useMemo5 } from "react";
608
+
609
+ // src/hooks/useThrottle/throttle.ts
610
+ function throttle(func, throttleMs, { edges = ["leading", "trailing"] } = {}) {
611
+ let pendingAt = null;
612
+ const debounced = debounce(func, throttleMs, { edges });
613
+ const throttled = function(...args) {
614
+ if (pendingAt == null) {
615
+ pendingAt = Date.now();
616
+ } else {
617
+ if (Date.now() - pendingAt >= throttleMs) {
618
+ pendingAt = Date.now();
619
+ debounced.cancel();
620
+ debounced(...args);
621
+ }
622
+ }
623
+ debounced(...args);
624
+ };
625
+ throttled.cancel = debounced.cancel;
626
+ return throttled;
627
+ }
628
+
629
+ // src/hooks/useThrottle/useThrottle.ts
630
+ function useThrottle(callback, wait, options) {
631
+ const preservedCallback = usePreservedCallback(callback);
632
+ const preservedOptions = usePreservedReference(options ?? {});
633
+ const throttledCallback = useMemo5(() => {
634
+ return throttle(preservedCallback, wait, preservedOptions);
635
+ }, [preservedOptions, preservedCallback, wait]);
636
+ useEffect11(() => {
637
+ return () => {
638
+ throttledCallback.cancel();
639
+ };
640
+ }, [throttledCallback]);
641
+ return throttledCallback;
642
+ }
643
+
644
+ // src/hooks/useTimeout/useTimeout.ts
645
+ import { useEffect as useEffect12 } from "react";
646
+ function useTimeout(callback, delay = 0) {
647
+ const preservedCallback = usePreservedCallback(callback);
648
+ useEffect12(() => {
649
+ const timeoutId = window.setTimeout(preservedCallback, delay);
650
+ return () => window.clearTimeout(timeoutId);
651
+ }, [delay, preservedCallback]);
652
+ }
653
+
654
+ // src/hooks/useToggle/useToggle.ts
655
+ import { useReducer } from "react";
656
+ function useToggle(initialValue = false) {
657
+ return useReducer(toggle, initialValue);
658
+ }
659
+ var toggle = (state) => !state;
660
+
661
+ // src/utils/buildContext/buildContext.tsx
662
+ import { createContext, useContext, useMemo as useMemo6 } from "react";
663
+ import { jsx as jsx3 } from "react/jsx-runtime";
664
+ function buildContext(contextName, defaultContextValues) {
665
+ const Context = createContext(defaultContextValues ?? void 0);
666
+ function Provider({ children, ...contextValues }) {
667
+ const value = useMemo6(
668
+ () => Object.keys(contextValues).length > 0 ? contextValues : null,
669
+ // eslint-disable-next-line react-hooks/exhaustive-deps
670
+ [...Object.values(contextValues)]
671
+ );
672
+ return /* @__PURE__ */ jsx3(Context.Provider, { value, children });
673
+ }
674
+ function useInnerContext() {
675
+ const context = useContext(Context);
676
+ if (context != null) {
677
+ return context;
678
+ }
679
+ if (defaultContextValues != null) {
680
+ return defaultContextValues;
681
+ }
682
+ throw new Error(`\`${contextName}Context\` must be used within \`${contextName}Provider\``);
683
+ }
684
+ return [Provider, useInnerContext];
685
+ }
686
+ export {
687
+ ImpressionArea,
688
+ Separated,
689
+ SwitchCase,
690
+ buildContext,
691
+ mergeRefs,
692
+ useAsyncEffect,
693
+ useBooleanState,
694
+ useCallbackOncePerRender,
695
+ useDebounce,
696
+ useImpressionRef,
697
+ useInputState,
698
+ useIntersectionObserver,
699
+ useInterval,
700
+ useLoading,
701
+ useOutsideClickEffect,
702
+ usePreservedCallback,
703
+ usePreservedReference,
704
+ usePrevious,
705
+ useRefEffect,
706
+ useStorageState,
707
+ useThrottle,
708
+ useTimeout,
709
+ useToggle,
710
+ useVisibilityEvent
711
+ };