react-simplikit 0.0.35 → 0.0.37

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