react-simplikit 0.0.35 → 0.0.36

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 (54) hide show
  1. package/README.md +1 -1
  2. package/dist/components/ImpressionArea/index.cjs +17 -20
  3. package/dist/components/ImpressionArea/index.d.cts +2 -2
  4. package/dist/hooks/useAsyncEffect/index.d.cts +1 -1
  5. package/dist/hooks/useCallbackOncePerRender/index.d.cts +2 -3
  6. package/dist/hooks/useControlledState/index.d.cts +1 -1
  7. package/dist/hooks/useCounter/index.cjs +1 -1
  8. package/dist/hooks/useCounter/index.d.cts +3 -5
  9. package/dist/hooks/useDebouncedCallback/index.cjs +144 -0
  10. package/dist/hooks/useDebouncedCallback/index.d.cts +32 -0
  11. package/dist/hooks/useDoubleClick/index.d.cts +4 -4
  12. package/dist/hooks/useGeolocation/index.cjs +153 -0
  13. package/dist/hooks/useGeolocation/index.d.cts +106 -0
  14. package/dist/hooks/useImpressionRef/index.d.cts +2 -2
  15. package/dist/hooks/useIntersectionObserver/index.d.cts +2 -2
  16. package/dist/hooks/useIsomorphicLayoutEffect/index.d.cts +3 -3
  17. package/dist/hooks/useLongPress/index.cjs +123 -0
  18. package/dist/hooks/useLongPress/index.d.cts +70 -0
  19. package/dist/hooks/useMap/index.cjs +77 -0
  20. package/dist/hooks/useMap/index.d.cts +46 -0
  21. package/dist/hooks/usePrevious/index.d.cts +2 -2
  22. package/dist/hooks/useRefEffect/index.d.cts +1 -1
  23. package/dist/hooks/useStorageState/index.d.cts +1 -1
  24. package/dist/hooks/useThrottle/index.d.cts +1 -1
  25. package/dist/hooks/useVisibilityEvent/index.d.cts +1 -1
  26. package/dist/index.cjs +453 -98
  27. package/dist/index.d.cts +9 -1
  28. package/esm/components/ImpressionArea/index.d.ts +2 -2
  29. package/esm/components/ImpressionArea/index.js +17 -20
  30. package/esm/hooks/useAsyncEffect/index.d.ts +1 -1
  31. package/esm/hooks/useCallbackOncePerRender/index.d.ts +2 -3
  32. package/esm/hooks/useControlledState/index.d.ts +1 -1
  33. package/esm/hooks/useCounter/index.d.ts +3 -5
  34. package/esm/hooks/useCounter/index.js +1 -1
  35. package/esm/hooks/useDebouncedCallback/index.d.ts +32 -0
  36. package/esm/hooks/useDebouncedCallback/index.js +117 -0
  37. package/esm/hooks/useDoubleClick/index.d.ts +4 -4
  38. package/esm/hooks/useGeolocation/index.d.ts +106 -0
  39. package/esm/hooks/useGeolocation/index.js +126 -0
  40. package/esm/hooks/useImpressionRef/index.d.ts +2 -2
  41. package/esm/hooks/useIntersectionObserver/index.d.ts +2 -2
  42. package/esm/hooks/useIsomorphicLayoutEffect/index.d.ts +3 -3
  43. package/esm/hooks/useLongPress/index.d.ts +70 -0
  44. package/esm/hooks/useLongPress/index.js +96 -0
  45. package/esm/hooks/useMap/index.d.ts +46 -0
  46. package/esm/hooks/useMap/index.js +50 -0
  47. package/esm/hooks/usePrevious/index.d.ts +2 -2
  48. package/esm/hooks/useRefEffect/index.d.ts +1 -1
  49. package/esm/hooks/useStorageState/index.d.ts +1 -1
  50. package/esm/hooks/useThrottle/index.d.ts +1 -1
  51. package/esm/hooks/useVisibilityEvent/index.d.ts +1 -1
  52. package/esm/index.d.ts +9 -1
  53. package/esm/index.js +421 -74
  54. package/package.json +1 -1
package/esm/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/components/ImpressionArea/ImpressionArea.tsx
2
+ import { forwardRef } from "react";
3
+
1
4
  // src/hooks/useImpressionRef/useImpressionRef.ts
2
5
  import { useRef as useRef4 } from "react";
3
6
 
@@ -241,26 +244,20 @@ function mergeRefs(...refs) {
241
244
 
242
245
  // src/components/ImpressionArea/ImpressionArea.tsx
243
246
  import { jsx } from "react/jsx-runtime";
244
- function ImpressionArea({
245
- as,
246
- rootMargin,
247
- areaThreshold,
248
- timeThreshold,
249
- onImpressionStart,
250
- onImpressionEnd,
251
- ref,
252
- ...props
253
- }) {
254
- const Component = as ?? "div";
255
- const impressionRef = useImpressionRef({
256
- onImpressionStart,
257
- onImpressionEnd,
258
- areaThreshold,
259
- timeThreshold,
260
- rootMargin
261
- });
262
- return /* @__PURE__ */ jsx(Component, { ref: mergeRefs(ref, impressionRef), ...props });
263
- }
247
+ var ImpressionArea = forwardRef(
248
+ ({ as, rootMargin, areaThreshold, timeThreshold, onImpressionStart, onImpressionEnd, ...props }, ref) => {
249
+ const Component = as ?? "div";
250
+ const impressionRef = useImpressionRef({
251
+ onImpressionStart,
252
+ onImpressionEnd,
253
+ areaThreshold,
254
+ timeThreshold,
255
+ rootMargin
256
+ });
257
+ return /* @__PURE__ */ jsx(Component, { ref: mergeRefs(ref, impressionRef), ...props });
258
+ }
259
+ );
260
+ ImpressionArea.displayName = "ImpressionArea";
264
261
 
265
262
  // src/components/Separated/Separated.tsx
266
263
  import { Children, Fragment, isValidElement } from "react";
@@ -325,9 +322,36 @@ function useCallbackOncePerRender(callback, deps) {
325
322
  });
326
323
  }
327
324
 
328
- // src/hooks/useCounter/useCounter.ts
325
+ // src/hooks/useControlledState/useControlledState.ts
329
326
  import { useCallback as useCallback6, useState as useState2 } from "react";
330
- function useCounter({ initialValue = 0, min, max, step = 1 } = {}) {
327
+ function useControlledState({
328
+ value: valueProp,
329
+ defaultValue,
330
+ onChange,
331
+ equalityFn = Object.is
332
+ }) {
333
+ const [uncontrolledState, setUncontrolledState] = useState2(defaultValue);
334
+ const controlled = valueProp !== void 0;
335
+ const value = controlled ? valueProp : uncontrolledState;
336
+ const setValue = useCallback6(
337
+ (next) => {
338
+ const nextValue = isSetStateAction(next) ? next(value) : next;
339
+ if (equalityFn(value, nextValue) === true) return;
340
+ if (controlled === false) setUncontrolledState(nextValue);
341
+ if (controlled === true && nextValue === void 0) setUncontrolledState(nextValue);
342
+ onChange?.(nextValue);
343
+ },
344
+ [controlled, onChange, equalityFn, value]
345
+ );
346
+ return [value, setValue];
347
+ }
348
+ function isSetStateAction(next) {
349
+ return typeof next === "function";
350
+ }
351
+
352
+ // src/hooks/useCounter/useCounter.ts
353
+ import { useCallback as useCallback7, useState as useState3 } from "react";
354
+ function useCounter(initialValue = 0, { min, max, step = 1 } = {}) {
331
355
  const validateValue = (value) => {
332
356
  let validatedValue = value;
333
357
  if (min !== void 0 && validatedValue < min) {
@@ -338,9 +362,9 @@ function useCounter({ initialValue = 0, min, max, step = 1 } = {}) {
338
362
  }
339
363
  return validatedValue;
340
364
  };
341
- const [count, setCountState] = useState2(() => validateValue(initialValue));
342
- const validateValueMemoized = useCallback6(validateValue, [min, max]);
343
- const setCount = useCallback6(
365
+ const [count, setCountState] = useState3(() => validateValue(initialValue));
366
+ const validateValueMemoized = useCallback7(validateValue, [min, max]);
367
+ const setCount = useCallback7(
344
368
  (value) => {
345
369
  setCountState((prev) => {
346
370
  const nextValue = typeof value === "function" ? value(prev) : value;
@@ -349,13 +373,13 @@ function useCounter({ initialValue = 0, min, max, step = 1 } = {}) {
349
373
  },
350
374
  [validateValueMemoized]
351
375
  );
352
- const increment = useCallback6(() => {
376
+ const increment = useCallback7(() => {
353
377
  setCount((prev) => prev + step);
354
378
  }, [setCount, step]);
355
- const decrement = useCallback6(() => {
379
+ const decrement = useCallback7(() => {
356
380
  setCount((prev) => prev - step);
357
381
  }, [setCount, step]);
358
- const reset = useCallback6(() => {
382
+ const reset = useCallback7(() => {
359
383
  setCount(initialValue);
360
384
  }, [setCount, initialValue]);
361
385
  return {
@@ -394,11 +418,167 @@ function useDebounce(callback, wait, options = {}) {
394
418
  return debounced;
395
419
  }
396
420
 
421
+ // src/hooks/useDoubleClick/useDoubleClick.ts
422
+ import { useCallback as useCallback8, useEffect as useEffect7, useRef as useRef6 } from "react";
423
+ function useDoubleClick({
424
+ delay = 250,
425
+ click,
426
+ doubleClick
427
+ }) {
428
+ const clickTimeout = useRef6(null);
429
+ const clearClickTimeout = usePreservedCallback(() => {
430
+ if (clickTimeout.current != null) {
431
+ window.clearTimeout(clickTimeout.current);
432
+ clickTimeout.current = null;
433
+ }
434
+ });
435
+ useEffect7(() => () => clearClickTimeout(), [clearClickTimeout]);
436
+ const handleEvent = useCallback8(
437
+ (event) => {
438
+ clearClickTimeout();
439
+ if (click && event.detail === 1) {
440
+ clickTimeout.current = window.setTimeout(() => {
441
+ click(event);
442
+ }, delay);
443
+ }
444
+ if (event.detail === 2) {
445
+ doubleClick(event);
446
+ }
447
+ },
448
+ [click, doubleClick, delay, clearClickTimeout]
449
+ );
450
+ return handleEvent;
451
+ }
452
+
453
+ // src/hooks/useGeolocation/useGeolocation.ts
454
+ import { useCallback as useCallback9, useEffect as useEffect8, useRef as useRef7, useState as useState4 } from "react";
455
+ var CustomGeoLocationError = class extends Error {
456
+ code;
457
+ constructor({ code, message }) {
458
+ super(message);
459
+ this.name = "CustomGeoLocationError";
460
+ this.code = code;
461
+ }
462
+ };
463
+ var GeolocationMountBehavior = {
464
+ GET: "get",
465
+ WATCH: "watch"
466
+ };
467
+ function useGeolocation(options) {
468
+ const [state, setState] = useState4({
469
+ loading: !!options?.mountBehavior,
470
+ error: null,
471
+ data: null
472
+ });
473
+ const [isTracking, setIsTracking] = useState4(false);
474
+ const watchIdRef = useRef7(null);
475
+ const checkGeolocationSupport = useCallback9(() => {
476
+ if (typeof window === "undefined" || navigator.geolocation === void 0) {
477
+ setState((prev) => ({
478
+ ...prev,
479
+ loading: false,
480
+ error: new CustomGeoLocationError({
481
+ code: 0,
482
+ message: "Geolocation is not supported by this environment."
483
+ })
484
+ }));
485
+ return false;
486
+ }
487
+ return true;
488
+ }, []);
489
+ const handleSuccess = useCallback9((position) => {
490
+ const { coords } = position;
491
+ setState((prev) => ({
492
+ ...prev,
493
+ loading: false,
494
+ error: null,
495
+ data: {
496
+ latitude: coords.latitude,
497
+ longitude: coords.longitude,
498
+ accuracy: coords.accuracy,
499
+ altitude: coords.altitude,
500
+ altitudeAccuracy: coords.altitudeAccuracy,
501
+ heading: coords.heading,
502
+ speed: coords.speed,
503
+ timestamp: position.timestamp
504
+ }
505
+ }));
506
+ }, []);
507
+ const handleError = useCallback9((error) => {
508
+ const { code, message } = error;
509
+ setState((prev) => ({
510
+ ...prev,
511
+ loading: false,
512
+ error: new CustomGeoLocationError({ code, message })
513
+ }));
514
+ }, []);
515
+ const getGeolocationOptions = useCallback9(
516
+ () => ({
517
+ enableHighAccuracy: options?.enableHighAccuracy,
518
+ maximumAge: options?.maximumAge,
519
+ timeout: options?.timeout
520
+ }),
521
+ [options?.enableHighAccuracy, options?.maximumAge, options?.timeout]
522
+ );
523
+ const getCurrentPosition = useCallback9(() => {
524
+ if (!checkGeolocationSupport()) {
525
+ return;
526
+ }
527
+ setState((prev) => ({ ...prev, loading: true }));
528
+ navigator.geolocation.getCurrentPosition(handleSuccess, handleError, getGeolocationOptions());
529
+ }, [handleSuccess, handleError, getGeolocationOptions, checkGeolocationSupport]);
530
+ const startTracking = useCallback9(() => {
531
+ if (!checkGeolocationSupport()) {
532
+ return;
533
+ }
534
+ if (watchIdRef.current !== null) {
535
+ navigator.geolocation.clearWatch(watchIdRef.current);
536
+ }
537
+ setState((prev) => ({ ...prev, loading: true }));
538
+ watchIdRef.current = navigator.geolocation.watchPosition(
539
+ (position) => {
540
+ setIsTracking(true);
541
+ handleSuccess(position);
542
+ },
543
+ handleError,
544
+ getGeolocationOptions()
545
+ );
546
+ }, [handleSuccess, handleError, getGeolocationOptions, checkGeolocationSupport]);
547
+ const stopTracking = useCallback9(() => {
548
+ if (watchIdRef.current === null) {
549
+ return;
550
+ }
551
+ navigator.geolocation.clearWatch(watchIdRef.current);
552
+ watchIdRef.current = null;
553
+ setIsTracking(false);
554
+ }, []);
555
+ useEffect8(() => {
556
+ if (options?.mountBehavior === GeolocationMountBehavior.WATCH) {
557
+ startTracking();
558
+ } else if (options?.mountBehavior === GeolocationMountBehavior.GET) {
559
+ getCurrentPosition();
560
+ }
561
+ return () => {
562
+ if (watchIdRef.current !== null) {
563
+ navigator.geolocation.clearWatch(watchIdRef.current);
564
+ watchIdRef.current = null;
565
+ }
566
+ };
567
+ }, [options?.mountBehavior, getCurrentPosition, startTracking]);
568
+ return {
569
+ ...state,
570
+ getCurrentPosition,
571
+ startTracking,
572
+ stopTracking,
573
+ isTracking
574
+ };
575
+ }
576
+
397
577
  // src/hooks/useInputState/useInputState.ts
398
- import { useCallback as useCallback7, useState as useState3 } from "react";
578
+ import { useCallback as useCallback10, useState as useState5 } from "react";
399
579
  function useInputState(initialValue = "", transformValue = echo) {
400
- const [value, setValue] = useState3(initialValue);
401
- const handleValueChange = useCallback7(
580
+ const [value, setValue] = useState5(initialValue);
581
+ const handleValueChange = useCallback10(
402
582
  ({ target: { value: value2 } }) => {
403
583
  setValue(transformValue(value2));
404
584
  },
@@ -411,18 +591,18 @@ function echo(v) {
411
591
  }
412
592
 
413
593
  // src/hooks/useInterval/useInterval.ts
414
- import { useEffect as useEffect7 } from "react";
594
+ import { useEffect as useEffect9 } from "react";
415
595
  function useInterval(callback, options) {
416
596
  const delay = typeof options === "number" ? options : options.delay;
417
597
  const immediate = typeof options === "number" ? false : options.immediate;
418
598
  const enabled = typeof options === "number" ? true : options.enabled ?? true;
419
599
  const preservedCallback = usePreservedCallback(callback);
420
- useEffect7(() => {
600
+ useEffect9(() => {
421
601
  if (immediate === true && enabled) {
422
602
  preservedCallback();
423
603
  }
424
604
  }, [immediate, preservedCallback, enabled]);
425
- useEffect7(() => {
605
+ useEffect9(() => {
426
606
  if (!enabled) {
427
607
  return;
428
608
  }
@@ -431,12 +611,17 @@ function useInterval(callback, options) {
431
611
  }, [delay, preservedCallback, enabled]);
432
612
  }
433
613
 
614
+ // src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.ts
615
+ import { useEffect as useEffect10, useLayoutEffect } from "react";
616
+ var isServer = typeof window === "undefined";
617
+ var useIsomorphicLayoutEffect = isServer ? useEffect10 : useLayoutEffect;
618
+
434
619
  // src/hooks/useLoading/useLoading.ts
435
- import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef6, useState as useState4 } from "react";
620
+ import { useCallback as useCallback11, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef8, useState as useState6 } from "react";
436
621
  function useLoading() {
437
- const [loading, setLoading] = useState4(false);
622
+ const [loading, setLoading] = useState6(false);
438
623
  const ref = useIsMountedRef();
439
- const startTransition = useCallback8(
624
+ const startTransition = useCallback11(
440
625
  async (promise) => {
441
626
  try {
442
627
  setLoading(true);
@@ -453,8 +638,8 @@ function useLoading() {
453
638
  return useMemo4(() => [loading, startTransition], [loading, startTransition]);
454
639
  }
455
640
  function useIsMountedRef() {
456
- const ref = useRef6({ isMounted: true }).current;
457
- useEffect8(() => {
641
+ const ref = useRef8({ isMounted: true }).current;
642
+ useEffect11(() => {
458
643
  ref.isMounted = true;
459
644
  return () => {
460
645
  ref.isMounted = false;
@@ -463,10 +648,138 @@ function useIsMountedRef() {
463
648
  return ref;
464
649
  }
465
650
 
651
+ // src/hooks/useLongPress/useLongPress.ts
652
+ import { useCallback as useCallback12, useRef as useRef9 } from "react";
653
+ function useLongPress(onLongPress, { delay = 500, moveThreshold, onClick, onLongPressEnd } = {}) {
654
+ const timeoutRef = useRef9(null);
655
+ const isLongPressActiveRef = useRef9(false);
656
+ const initialPositionRef = useRef9({ x: 0, y: 0 });
657
+ const preservedOnLongPress = usePreservedCallback(onLongPress);
658
+ const preservedOnClick = usePreservedCallback(onClick || (() => {
659
+ }));
660
+ const preservedOnLongPressEnd = usePreservedCallback(onLongPressEnd || (() => {
661
+ }));
662
+ const hasThreshold = moveThreshold?.x !== void 0 || moveThreshold?.y !== void 0;
663
+ const getClientPosition = useCallback12((event) => {
664
+ if ("touches" in event.nativeEvent) {
665
+ const touch = event.nativeEvent.touches[0];
666
+ return { x: touch.clientX, y: touch.clientY };
667
+ }
668
+ return {
669
+ x: event.nativeEvent.clientX,
670
+ y: event.nativeEvent.clientY
671
+ };
672
+ }, []);
673
+ const isMovedBeyondThreshold = useCallback12(
674
+ (event) => {
675
+ const { x, y } = getClientPosition(event);
676
+ const deltaX = Math.abs(x - initialPositionRef.current.x);
677
+ const deltaY = Math.abs(y - initialPositionRef.current.y);
678
+ return moveThreshold?.x !== void 0 && deltaX > moveThreshold.x || moveThreshold?.y !== void 0 && deltaY > moveThreshold.y;
679
+ },
680
+ [getClientPosition, moveThreshold]
681
+ );
682
+ const cancelLongPress = useCallback12(() => {
683
+ if (timeoutRef.current !== null) {
684
+ window.clearTimeout(timeoutRef.current);
685
+ timeoutRef.current = null;
686
+ }
687
+ }, []);
688
+ const handlePressStart = useCallback12(
689
+ (event) => {
690
+ cancelLongPress();
691
+ const position = getClientPosition(event);
692
+ initialPositionRef.current = position;
693
+ isLongPressActiveRef.current = false;
694
+ timeoutRef.current = window.setTimeout(() => {
695
+ isLongPressActiveRef.current = true;
696
+ preservedOnLongPress(event);
697
+ }, delay);
698
+ },
699
+ [cancelLongPress, delay, getClientPosition, preservedOnLongPress]
700
+ );
701
+ const handlePressEnd = useCallback12(
702
+ (event) => {
703
+ if (isLongPressActiveRef.current) {
704
+ preservedOnLongPressEnd(event);
705
+ } else if (timeoutRef.current !== null) {
706
+ preservedOnClick(event);
707
+ }
708
+ cancelLongPress();
709
+ isLongPressActiveRef.current = false;
710
+ },
711
+ [cancelLongPress, preservedOnClick, preservedOnLongPressEnd]
712
+ );
713
+ const handlePressMove = useCallback12(
714
+ (event) => {
715
+ if (timeoutRef.current !== null && isMovedBeyondThreshold(event)) {
716
+ cancelLongPress();
717
+ }
718
+ },
719
+ [cancelLongPress, isMovedBeyondThreshold]
720
+ );
721
+ return {
722
+ onMouseDown: handlePressStart,
723
+ onMouseUp: handlePressEnd,
724
+ onMouseLeave: cancelLongPress,
725
+ onTouchStart: handlePressStart,
726
+ onTouchEnd: handlePressEnd,
727
+ ...hasThreshold ? { onTouchMove: handlePressMove, onMouseMove: handlePressMove } : {}
728
+ };
729
+ }
730
+
731
+ // src/hooks/useMap/useMap.ts
732
+ import { useCallback as useCallback13, useMemo as useMemo6, useState as useState7 } from "react";
733
+
734
+ // src/hooks/usePreservedReference/usePreservedReference.ts
735
+ import { useMemo as useMemo5, useRef as useRef10 } from "react";
736
+ function usePreservedReference(value, areValuesEqual = areDeeplyEqual) {
737
+ const ref = useRef10(value);
738
+ return useMemo5(() => {
739
+ if (!areValuesEqual(ref.current, value)) {
740
+ ref.current = value;
741
+ }
742
+ return ref.current;
743
+ }, [areValuesEqual, value]);
744
+ }
745
+ function areDeeplyEqual(x, y) {
746
+ return JSON.stringify(x) === JSON.stringify(y);
747
+ }
748
+
749
+ // src/hooks/useMap/useMap.ts
750
+ function useMap(initialState = /* @__PURE__ */ new Map()) {
751
+ const [map, setMap] = useState7(() => new Map(initialState));
752
+ const preservedInitialState = usePreservedReference(initialState);
753
+ const set = useCallback13((key, value) => {
754
+ setMap((prev) => {
755
+ const nextMap = new Map(prev);
756
+ nextMap.set(key, value);
757
+ return nextMap;
758
+ });
759
+ }, []);
760
+ const setAll = useCallback13((entries) => {
761
+ setMap(() => new Map(entries));
762
+ }, []);
763
+ const remove = useCallback13((key) => {
764
+ setMap((prev) => {
765
+ const nextMap = new Map(prev);
766
+ nextMap.delete(key);
767
+ return nextMap;
768
+ });
769
+ }, []);
770
+ const reset = useCallback13(() => {
771
+ setMap(() => new Map(preservedInitialState));
772
+ }, [preservedInitialState]);
773
+ const actions = useMemo6(() => {
774
+ return { set, setAll, remove, reset };
775
+ }, [set, setAll, remove, reset]);
776
+ return [map, actions];
777
+ }
778
+
466
779
  // src/hooks/useOutsideClickEffect/useOutsideClickEffect.ts
467
- import { useEffect as useEffect9, useRef as useRef7 } from "react";
780
+ import { useEffect as useEffect12, useRef as useRef11 } from "react";
468
781
  function useOutsideClickEffect(container, callback) {
469
- const containers = useRef7([]);
782
+ const containers = useRef11([]);
470
783
  const handleDocumentClick = usePreservedCallback(({ target }) => {
471
784
  if (target === null) {
472
785
  return;
@@ -479,10 +792,10 @@ function useOutsideClickEffect(container, callback) {
479
792
  }
480
793
  callback();
481
794
  });
482
- useEffect9(() => {
795
+ useEffect12(() => {
483
796
  containers.current = [container].flat(1).filter((item) => item != null);
484
797
  }, [container]);
485
- useEffect9(() => {
798
+ useEffect12(() => {
486
799
  document.addEventListener("click", handleDocumentClick);
487
800
  return () => {
488
801
  document.removeEventListener("click", handleDocumentClick);
@@ -490,28 +803,13 @@ function useOutsideClickEffect(container, callback) {
490
803
  }, [handleDocumentClick]);
491
804
  }
492
805
 
493
- // src/hooks/usePreservedReference/usePreservedReference.ts
494
- import { useMemo as useMemo5, useRef as useRef8 } from "react";
495
- function usePreservedReference(value, areValuesEqual = areDeeplyEqual) {
496
- const ref = useRef8(value);
497
- return useMemo5(() => {
498
- if (!areValuesEqual(ref.current, value)) {
499
- ref.current = value;
500
- }
501
- return ref.current;
502
- }, [areValuesEqual, value]);
503
- }
504
- function areDeeplyEqual(x, y) {
505
- return JSON.stringify(x) === JSON.stringify(y);
506
- }
507
-
508
806
  // src/hooks/usePrevious/usePrevious.ts
509
- import { useRef as useRef9 } from "react";
807
+ import { useRef as useRef12 } from "react";
510
808
  var strictEquals = (prev, next) => prev === next;
511
809
  function usePrevious(state, compare = strictEquals) {
512
- const prevRef = useRef9(state);
513
- const currentRef = useRef9(state);
514
- const isFirstRender = useRef9(true);
810
+ const prevRef = useRef12(state);
811
+ const currentRef = useRef12(state);
812
+ const isFirstRender = useRef12(true);
515
813
  if (isFirstRender.current) {
516
814
  isFirstRender.current = false;
517
815
  return prevRef.current;
@@ -524,7 +822,7 @@ function usePrevious(state, compare = strictEquals) {
524
822
  }
525
823
 
526
824
  // src/hooks/useStorageState/useStorageState.ts
527
- import { useCallback as useCallback9, useRef as useRef10, useSyncExternalStore } from "react";
825
+ import { useCallback as useCallback14, useRef as useRef13, useSyncExternalStore } from "react";
528
826
 
529
827
  // src/hooks/useStorageState/storage.ts
530
828
  var MemoStorage = class {
@@ -636,11 +934,11 @@ function useStorageState(key, {
636
934
  ...options
637
935
  } = {}) {
638
936
  const serializedDefaultValue = defaultValue;
639
- const cache = useRef10({
937
+ const cache = useRef13({
640
938
  data: null,
641
939
  parsed: serializedDefaultValue
642
940
  });
643
- const getSnapshot = useCallback9(() => {
941
+ const getSnapshot = useCallback14(() => {
644
942
  const deserializer = "deserializer" in options ? options.deserializer : JSON.parse;
645
943
  const data = storage.get(key);
646
944
  if (data !== cache.current.data) {
@@ -670,7 +968,7 @@ function useStorageState(key, {
670
968
  () => getSnapshot(),
671
969
  () => serializedDefaultValue
672
970
  );
673
- const setStorageState = useCallback9(
971
+ const setStorageState = useCallback14(
674
972
  (value) => {
675
973
  const serializer = "serializer" in options ? options.serializer : JSON.stringify;
676
974
  const nextValue = typeof value === "function" ? value(getSnapshot()) : value;
@@ -683,14 +981,14 @@ function useStorageState(key, {
683
981
  },
684
982
  [getSnapshot, key, storage]
685
983
  );
686
- const refreshStorageState = useCallback9(() => {
984
+ const refreshStorageState = useCallback14(() => {
687
985
  setStorageState(getSnapshot());
688
986
  }, [storage, getSnapshot, setStorageState]);
689
987
  return ensureSerializable([storageState, setStorageState, refreshStorageState]);
690
988
  }
691
989
 
692
990
  // src/hooks/useThrottle/useThrottle.ts
693
- import { useEffect as useEffect10, useMemo as useMemo6 } from "react";
991
+ import { useEffect as useEffect13, useMemo as useMemo7 } from "react";
694
992
 
695
993
  // src/hooks/useThrottle/throttle.ts
696
994
  function throttle(func, throttleMs, { edges = ["leading", "trailing"] } = {}) {
@@ -715,11 +1013,11 @@ function throttle(func, throttleMs, { edges = ["leading", "trailing"] } = {}) {
715
1013
  function useThrottle(callback, wait, options) {
716
1014
  const preservedCallback = usePreservedCallback(callback);
717
1015
  const preservedOptions = usePreservedReference(options ?? {});
718
- const throttledCallback = useMemo6(
1016
+ const throttledCallback = useMemo7(
719
1017
  () => throttle(preservedCallback, wait, preservedOptions),
720
1018
  [preservedOptions, preservedCallback, wait]
721
1019
  );
722
- useEffect10(() => {
1020
+ useEffect13(() => {
723
1021
  return () => {
724
1022
  throttledCallback.cancel();
725
1023
  };
@@ -728,10 +1026,10 @@ function useThrottle(callback, wait, options) {
728
1026
  }
729
1027
 
730
1028
  // src/hooks/useTimeout/useTimeout.ts
731
- import { useEffect as useEffect11 } from "react";
1029
+ import { useEffect as useEffect14 } from "react";
732
1030
  function useTimeout(callback, delay = 0) {
733
1031
  const preservedCallback = usePreservedCallback(callback);
734
- useEffect11(() => {
1032
+ useEffect14(() => {
735
1033
  const timeoutId = window.setTimeout(preservedCallback, delay);
736
1034
  return () => window.clearTimeout(timeoutId);
737
1035
  }, [delay, preservedCallback]);
@@ -745,12 +1043,12 @@ function useToggle(initialValue = false) {
745
1043
  var toggle = (state) => !state;
746
1044
 
747
1045
  // src/utils/buildContext/buildContext.tsx
748
- import { createContext, useContext, useMemo as useMemo7 } from "react";
1046
+ import { createContext, useContext, useMemo as useMemo8 } from "react";
749
1047
  import { jsx as jsx3 } from "react/jsx-runtime";
750
1048
  function buildContext(contextName, defaultContextValues) {
751
1049
  const Context = createContext(defaultContextValues ?? void 0);
752
1050
  function Provider({ children, ...contextValues }) {
753
- const value = useMemo7(
1051
+ const value = useMemo8(
754
1052
  () => Object.keys(contextValues).length > 0 ? contextValues : null,
755
1053
  // eslint-disable-next-line react-hooks/exhaustive-deps
756
1054
  [...Object.values(contextValues)]
@@ -769,22 +1067,71 @@ function buildContext(contextName, defaultContextValues) {
769
1067
  }
770
1068
  return [Provider, useInnerContext];
771
1069
  }
1070
+
1071
+ // src/utils/mergeProps/mergeProps.ts
1072
+ function mergeProps(...props) {
1073
+ return props.reduce(pushProp, {});
1074
+ }
1075
+ function pushProp(prev, curr) {
1076
+ for (const key in curr) {
1077
+ if (curr[key] === void 0) continue;
1078
+ switch (key) {
1079
+ case "className": {
1080
+ prev[key] = [prev[key], curr[key]].join(" ").trim();
1081
+ break;
1082
+ }
1083
+ case "style": {
1084
+ prev[key] = mergeStyle(prev[key], curr[key]);
1085
+ break;
1086
+ }
1087
+ default: {
1088
+ const mergedFunction = mergeFunction(prev[key], curr[key]);
1089
+ if (mergedFunction) {
1090
+ prev[key] = mergedFunction;
1091
+ } else if (curr[key] !== void 0) {
1092
+ prev[key] = curr[key];
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+ return prev;
1098
+ }
1099
+ function mergeStyle(a, b) {
1100
+ if (a == null) return b;
1101
+ return { ...a, ...b };
1102
+ }
1103
+ function mergeFunction(a, b) {
1104
+ if (typeof a === "function" && typeof b === "function") {
1105
+ return (...args) => {
1106
+ a(...args);
1107
+ b(...args);
1108
+ };
1109
+ }
1110
+ }
772
1111
  export {
773
1112
  ImpressionArea,
774
1113
  Separated,
775
1114
  SwitchCase,
776
1115
  buildContext,
1116
+ mergeProps,
777
1117
  mergeRefs,
778
1118
  useAsyncEffect,
779
1119
  useBooleanState,
780
1120
  useCallbackOncePerRender,
1121
+ useControlledState,
781
1122
  useCounter,
782
1123
  useDebounce,
1124
+ useDebouncedCallback,
1125
+ useDoubleClick,
1126
+ useGeolocation,
783
1127
  useImpressionRef,
784
1128
  useInputState,
785
1129
  useIntersectionObserver,
786
1130
  useInterval,
1131
+ useIsomorphicLayoutEffect,
787
1132
  useLoading,
1133
+ useLongPress,
1134
+ useMap,
788
1135
  useOutsideClickEffect,
789
1136
  usePreservedCallback,
790
1137
  usePreservedReference,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-simplikit",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "main": "./dist/index.cjs",
5
5
  "type": "module",
6
6
  "sideEffects": false,