@reactuses/core 1.1.5 → 2.0.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 CHANGED
@@ -131,7 +131,7 @@ function useStorage(key, defaults, getStorage, options = {}) {
131
131
  }
132
132
  const type = guessSerializerType(defaults);
133
133
  const serializer = (_a = options.serializer) != null ? _a : StorageSerializers[type];
134
- const getStoredValue = () => {
134
+ const getStoredValue = useEvent(() => {
135
135
  try {
136
136
  const raw = storage == null ? void 0 : storage.getItem(key);
137
137
  if (raw !== void 0 && raw !== null) {
@@ -143,11 +143,11 @@ function useStorage(key, defaults, getStorage, options = {}) {
143
143
  } catch (e) {
144
144
  onError(e);
145
145
  }
146
- };
147
- const [state, setState] = React.useState(() => getStoredValue());
148
- useUpdateEffect(() => {
146
+ });
147
+ const [state, setState] = React.useState(defaults);
148
+ React.useEffect(() => {
149
149
  setState(getStoredValue());
150
- }, [key]);
150
+ }, [getStoredValue, key]);
151
151
  const updateState = useEvent(
152
152
  (valOrFunc) => {
153
153
  const currentState = isFunction(valOrFunc) ? valOrFunc(state) : valOrFunc;
@@ -205,12 +205,12 @@ function useInterval(callback, delay, options) {
205
205
  }
206
206
 
207
207
  const getInitialState = (query, defaultState) => {
208
- if (isBrowser) {
209
- return window.matchMedia(query).matches;
210
- }
211
208
  if (defaultState !== void 0) {
212
209
  return defaultState;
213
210
  }
211
+ if (isBrowser) {
212
+ return window.matchMedia(query).matches;
213
+ }
214
214
  if (process.env.NODE_ENV !== "production") {
215
215
  console.warn(
216
216
  "`useMediaQuery` When server side rendering, defaultState should be defined to prevent a hydration mismatches."
@@ -262,21 +262,24 @@ function useDarkMode(options = {}) {
262
262
  const prefersDarkMode = usePreferredDark(false);
263
263
  const value = initialValue ? initialValue : prefersDarkMode ? "dark" : "light";
264
264
  const [dark, setDark] = useStorage(storageKey, value, storage);
265
- React.useEffect(() => {
266
- const element = window == null ? void 0 : window.document.querySelector(selector);
267
- if (!element) {
268
- return;
269
- }
270
- if (attribute === "class") {
271
- dark && element.classList.add(dark);
272
- } else {
273
- dark && element.setAttribute(attribute, dark);
274
- }
275
- return () => {
276
- dark && (element == null ? void 0 : element.classList.remove(dark));
277
- };
278
- }, [attribute, dark, selector]);
279
- return [dark, setDark];
265
+ const wrappedSetDark = React.useCallback(
266
+ (latestDark) => {
267
+ const element = window == null ? void 0 : window.document.querySelector(selector);
268
+ if (!element) {
269
+ return;
270
+ }
271
+ if (attribute === "class") {
272
+ latestDark && element.classList.add(latestDark);
273
+ dark && element.classList.remove(dark);
274
+ } else {
275
+ latestDark && element.setAttribute(attribute, latestDark);
276
+ dark && element.removeAttribute(attribute);
277
+ }
278
+ setDark(latestDark);
279
+ },
280
+ [attribute, dark, selector, setDark]
281
+ );
282
+ return [dark, wrappedSetDark];
280
283
  }
281
284
 
282
285
  function useMount(fn) {
@@ -711,7 +714,7 @@ function useMutationObserver(callback, target, options = {}) {
711
714
  observerRef.current = new MutationObserver(callbackRef.current);
712
715
  observerRef.current.observe(element, options);
713
716
  return stop;
714
- }, [options]);
717
+ }, [options, target]);
715
718
  return stop;
716
719
  }
717
720
 
@@ -1512,7 +1515,7 @@ function useIntersectionObserver(target, callback, options = {}) {
1512
1515
  );
1513
1516
  observerRef.current.observe(element);
1514
1517
  return stop;
1515
- }, [options]);
1518
+ }, [options, target]);
1516
1519
  return stop;
1517
1520
  }
1518
1521
 
@@ -1565,7 +1568,7 @@ function useResizeObserver(target, callback, options = {}) {
1565
1568
  observerRef.current = new ResizeObserver(savedCallback.current);
1566
1569
  observerRef.current.observe(element, options);
1567
1570
  return stop;
1568
- }, [options]);
1571
+ }, [options, target]);
1569
1572
  return stop;
1570
1573
  }
1571
1574
 
@@ -1808,7 +1811,7 @@ function useInfiniteScroll(target, onLoadMore, options = {}) {
1808
1811
  }
1809
1812
  });
1810
1813
  fn();
1811
- }, [di, options.preserveScrollPosition]);
1814
+ }, [di, options.preserveScrollPosition, target]);
1812
1815
  }
1813
1816
 
1814
1817
  const defaultEvents = [
@@ -1859,7 +1862,7 @@ function useMousePressed(target, options = {}) {
1859
1862
  useEventListener("mousedown", onPressed("mouse"), target, { passive: true });
1860
1863
  useEventListener("mouseleave", onReleased, () => window, { passive: true });
1861
1864
  useEventListener("mouseup", onReleased, () => window, { passive: true });
1862
- useMount(() => {
1865
+ React.useEffect(() => {
1863
1866
  const element = getTargetElement(target);
1864
1867
  if (drag) {
1865
1868
  element == null ? void 0 : element.addEventListener("dragstart", onPressed("mouse"), {
@@ -1895,7 +1898,7 @@ function useMousePressed(target, options = {}) {
1895
1898
  element == null ? void 0 : element.removeEventListener("touchcancel", onReleased);
1896
1899
  }
1897
1900
  };
1898
- });
1901
+ }, [drag, onPressed, onReleased, target, touch]);
1899
1902
  return [pressed, sourceType];
1900
1903
  }
1901
1904
 
@@ -1912,7 +1915,7 @@ function preventDefault(rawEvent) {
1912
1915
  function useScrollLock(target, initialState = false) {
1913
1916
  const [locked, setLocked] = React.useState(initialState);
1914
1917
  const initialOverflowRef = React.useRef("scroll");
1915
- useMount(() => {
1918
+ React.useEffect(() => {
1916
1919
  const element = getTargetElement(target);
1917
1920
  if (element) {
1918
1921
  initialOverflowRef.current = element.style.overflow;
@@ -1920,7 +1923,7 @@ function useScrollLock(target, initialState = false) {
1920
1923
  element.style.overflow = "hidden";
1921
1924
  }
1922
1925
  }
1923
- });
1926
+ }, [locked, target]);
1924
1927
  const lock = useEvent(() => {
1925
1928
  const element = getTargetElement(target);
1926
1929
  if (!element || locked) {
@@ -1929,7 +1932,6 @@ function useScrollLock(target, initialState = false) {
1929
1932
  if (isIOS) {
1930
1933
  element.addEventListener("touchmove", preventDefault, { passive: false });
1931
1934
  }
1932
- element.style.overflow = "hidden";
1933
1935
  setLocked(true);
1934
1936
  });
1935
1937
  const unlock = useEvent(() => {
@@ -2480,6 +2482,243 @@ var useOnceEffect = createOnceEffect(React.useEffect);
2480
2482
 
2481
2483
  var useOnceLayoutEffect = createOnceEffect(React.useLayoutEffect);
2482
2484
 
2485
+ function useReducedMotion(defaultState) {
2486
+ return useMediaQuery("(prefers-reduced-motion: reduce)", defaultState);
2487
+ }
2488
+
2489
+ const setScrollParam = ({
2490
+ axis,
2491
+ parent,
2492
+ distance
2493
+ }) => {
2494
+ if (!parent && typeof document === "undefined") {
2495
+ return;
2496
+ }
2497
+ const method = axis === "y" ? "scrollTop" : "scrollLeft";
2498
+ if (parent) {
2499
+ parent[method] = distance;
2500
+ } else {
2501
+ const { body, documentElement } = document;
2502
+ body[method] = distance;
2503
+ documentElement[method] = distance;
2504
+ }
2505
+ };
2506
+ const isScrollElement = (axis, node) => {
2507
+ if (!node) {
2508
+ return false;
2509
+ }
2510
+ const AXIS = axis === "x" ? "X" : "Y";
2511
+ return getComputedStyle(node)[`overflow${AXIS}`] === "auto" || getComputedStyle(node)[`overflow${AXIS}`] === "scroll";
2512
+ };
2513
+ const cache = /* @__PURE__ */ new Map();
2514
+ const getScrollParent = (axis, node) => {
2515
+ if (!node || !node.parentElement) {
2516
+ return null;
2517
+ }
2518
+ if (cache.has(node)) {
2519
+ return cache.get(node) || null;
2520
+ }
2521
+ let parent = node.parentElement;
2522
+ while (parent && !isScrollElement(axis, parent)) {
2523
+ parent = parent.parentElement;
2524
+ }
2525
+ if (parent) {
2526
+ cache.set(node, parent);
2527
+ }
2528
+ return parent;
2529
+ };
2530
+ const getScrollStart = ({
2531
+ axis,
2532
+ parent
2533
+ }) => {
2534
+ if (!parent && typeof document === "undefined") {
2535
+ return 0;
2536
+ }
2537
+ const method = axis === "y" ? "scrollTop" : "scrollLeft";
2538
+ if (parent) {
2539
+ return parent[method];
2540
+ }
2541
+ const { body, documentElement } = document;
2542
+ return body[method] + documentElement[method];
2543
+ };
2544
+
2545
+ const easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
2546
+
2547
+ const getRelativePosition = ({
2548
+ axis,
2549
+ target,
2550
+ parent,
2551
+ alignment,
2552
+ offset,
2553
+ isList
2554
+ }) => {
2555
+ if (!target || !parent && typeof document === "undefined") {
2556
+ return 0;
2557
+ }
2558
+ const isCustomParent = !!parent;
2559
+ const parentElement = parent || document.body;
2560
+ const parentPosition = parentElement.getBoundingClientRect();
2561
+ const targetPosition = target.getBoundingClientRect();
2562
+ const getDiff = (property) => targetPosition[property] - parentPosition[property];
2563
+ if (axis === "y") {
2564
+ const diff = getDiff("top");
2565
+ if (diff === 0) {
2566
+ return 0;
2567
+ }
2568
+ if (alignment === "start") {
2569
+ const distance = diff - offset;
2570
+ const shouldScroll = distance <= targetPosition.height * (isList ? 0 : 1) || !isList;
2571
+ return shouldScroll ? distance : 0;
2572
+ }
2573
+ const parentHeight = isCustomParent ? parentPosition.height : window.innerHeight;
2574
+ if (alignment === "end") {
2575
+ const distance = diff + offset - parentHeight + targetPosition.height;
2576
+ const shouldScroll = distance >= -targetPosition.height * (isList ? 0 : 1) || !isList;
2577
+ return shouldScroll ? distance : 0;
2578
+ }
2579
+ if (alignment === "center") {
2580
+ return diff - parentHeight / 2 + targetPosition.height / 2;
2581
+ }
2582
+ return 0;
2583
+ }
2584
+ if (axis === "x") {
2585
+ const diff = getDiff("left");
2586
+ if (diff === 0) {
2587
+ return 0;
2588
+ }
2589
+ if (alignment === "start") {
2590
+ const distance = diff - offset;
2591
+ const shouldScroll = distance <= targetPosition.width || !isList;
2592
+ return shouldScroll ? distance : 0;
2593
+ }
2594
+ const parentWidth = isCustomParent ? parentPosition.width : window.innerWidth;
2595
+ if (alignment === "end") {
2596
+ const distance = diff + offset - parentWidth + targetPosition.width;
2597
+ const shouldScroll = distance >= -targetPosition.width || !isList;
2598
+ return shouldScroll ? distance : 0;
2599
+ }
2600
+ if (alignment === "center") {
2601
+ return diff - parentWidth / 2 + targetPosition.width / 2;
2602
+ }
2603
+ return 0;
2604
+ }
2605
+ return 0;
2606
+ };
2607
+
2608
+ function useScrollIntoView({
2609
+ duration = 1250,
2610
+ axis = "y",
2611
+ onScrollFinish,
2612
+ easing = easeInOutQuad,
2613
+ offset = 0,
2614
+ cancelable = true,
2615
+ isList = false,
2616
+ targetElement,
2617
+ scrollElement
2618
+ }) {
2619
+ const frameID = React.useRef(0);
2620
+ const startTime = React.useRef(0);
2621
+ const shouldStop = React.useRef(false);
2622
+ const reducedMotion = useReducedMotion(false);
2623
+ const cancel = () => {
2624
+ if (frameID.current) {
2625
+ cancelAnimationFrame(frameID.current);
2626
+ }
2627
+ };
2628
+ const scrollIntoView = useEvent(
2629
+ ({ alignment = "start" } = {}) => {
2630
+ var _a;
2631
+ const element = getTargetElement(targetElement);
2632
+ const parent = getTargetElement(scrollElement) || getScrollParent(axis, element);
2633
+ shouldStop.current = false;
2634
+ if (frameID.current) {
2635
+ cancel();
2636
+ }
2637
+ const start = (_a = getScrollStart({ parent, axis })) != null ? _a : 0;
2638
+ const change = getRelativePosition({
2639
+ parent,
2640
+ target: element,
2641
+ axis,
2642
+ alignment,
2643
+ offset,
2644
+ isList
2645
+ }) - (parent ? 0 : start);
2646
+ const animateScroll = () => {
2647
+ if (startTime.current === 0) {
2648
+ startTime.current = performance.now();
2649
+ }
2650
+ const now = performance.now();
2651
+ const elapsed = now - startTime.current;
2652
+ const t = reducedMotion || duration === 0 ? 1 : elapsed / duration;
2653
+ const distance = start + change * easing(t);
2654
+ setScrollParam({
2655
+ parent,
2656
+ axis,
2657
+ distance
2658
+ });
2659
+ if (!shouldStop.current && t < 1) {
2660
+ frameID.current = requestAnimationFrame(animateScroll);
2661
+ } else {
2662
+ typeof onScrollFinish === "function" && onScrollFinish();
2663
+ startTime.current = 0;
2664
+ frameID.current = 0;
2665
+ cancel();
2666
+ }
2667
+ };
2668
+ animateScroll();
2669
+ }
2670
+ );
2671
+ const handleStop = () => {
2672
+ if (cancelable) {
2673
+ shouldStop.current = true;
2674
+ }
2675
+ };
2676
+ useEventListener("wheel", handleStop, null, { passive: true });
2677
+ useEventListener("touchmove", handleStop, null, { passive: true });
2678
+ React.useEffect(() => cancel, []);
2679
+ return {
2680
+ scrollIntoView,
2681
+ cancel
2682
+ };
2683
+ }
2684
+
2685
+ const useSticky = ({
2686
+ targetElement,
2687
+ scrollElement,
2688
+ axis = "y",
2689
+ nav = 0
2690
+ }) => {
2691
+ const [isSticky, setSticky] = React.useState(false);
2692
+ const { run: scrollHandler } = useThrottleFn(() => {
2693
+ const element = getTargetElement(targetElement);
2694
+ if (!element) {
2695
+ return;
2696
+ }
2697
+ const rect = element.getBoundingClientRect();
2698
+ if (axis === "y") {
2699
+ setSticky((rect == null ? void 0 : rect.top) <= nav);
2700
+ } else {
2701
+ setSticky((rect == null ? void 0 : rect.left) <= nav);
2702
+ }
2703
+ }, 50);
2704
+ React.useEffect(() => {
2705
+ const element = getTargetElement(targetElement);
2706
+ if (!element) {
2707
+ return;
2708
+ }
2709
+ const scrollParent = getTargetElement(scrollElement) || getScrollParent(axis, element);
2710
+ if (!scrollParent) {
2711
+ return;
2712
+ }
2713
+ scrollParent.addEventListener("scroll", scrollHandler);
2714
+ scrollHandler();
2715
+ return () => {
2716
+ scrollParent.removeEventListener("scroll", scrollHandler);
2717
+ };
2718
+ }, [axis, scrollElement, scrollHandler, targetElement]);
2719
+ return [isSticky, setSticky];
2720
+ };
2721
+
2483
2722
  exports.useActiveElement = useActiveElement;
2484
2723
  exports.useClickOutside = useClickOutSide;
2485
2724
  exports.useClipboard = useClipBorad;
@@ -2537,11 +2776,14 @@ exports.usePreferredDark = usePreferredDark;
2537
2776
  exports.usePrevious = usePrevious;
2538
2777
  exports.useRafFn = useRafFn;
2539
2778
  exports.useRafState = useRafState;
2779
+ exports.useReducedMotion = useReducedMotion;
2540
2780
  exports.useResizeObserver = useResizeObserver;
2541
2781
  exports.useScriptTag = useScriptTag;
2542
2782
  exports.useScroll = useScroll;
2783
+ exports.useScrollIntoView = useScrollIntoView;
2543
2784
  exports.useScrollLock = useScrollLock;
2544
2785
  exports.useSessionStorage = useSessionStorage;
2786
+ exports.useSticky = useSticky;
2545
2787
  exports.useTextDirection = useTextDirection;
2546
2788
  exports.useThrottle = useThrottle;
2547
2789
  exports.useThrottleFn = useThrottleFn;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { MutableRefObject, useEffect, useLayoutEffect, Dispatch, SetStateAction, DependencyList, EffectCallback, RefObject, CSSProperties } from 'react';
2
+ import react__default, { MutableRefObject, useEffect, useLayoutEffect, Dispatch, SetStateAction, DependencyList, EffectCallback, RefObject, CSSProperties } from 'react';
3
3
  import * as lodash from 'lodash';
4
4
 
5
5
  declare function usePrevious<T>(state: T): T | undefined;
@@ -74,7 +74,8 @@ interface UseDarkOptions<T> {
74
74
  */
75
75
  attribute?: string;
76
76
  /**
77
- * The initial value write the target element
77
+ * The initial value write the target element, defaultValue follow system prefer color
78
+ * must be set in SSR
78
79
  * @default 'light | dark'
79
80
  */
80
81
  initialValue?: T;
@@ -91,7 +92,7 @@ interface UseDarkOptions<T> {
91
92
  */
92
93
  storage?: () => Storage;
93
94
  }
94
- declare function useDarkMode<T extends string | "light" | "dark">(options?: UseDarkOptions<T>): readonly [T | null, react.Dispatch<react.SetStateAction<T | null>>];
95
+ declare function useDarkMode<T extends string | "light" | "dark">(options?: UseDarkOptions<T>): readonly [T | null, (latestDark: T) => void];
95
96
 
96
97
  declare function useMediaQuery(query: string, defaultState?: boolean): boolean;
97
98
 
@@ -749,4 +750,46 @@ declare const _default$1: typeof useEffect | typeof react.useLayoutEffect;
749
750
 
750
751
  declare const _default: typeof react.useEffect | typeof useLayoutEffect;
751
752
 
752
- export { ColorScheme, Contrast, CursorState, GeneralPermissionDescriptor, IDisposable, IEvent, IEventOnce, IListener, INetworkInformation, IState, IUseNetworkState, KeyModifier, MousePressedOptions, MouseSourceType, OrientationState, RafLoopReturns, State, Status, Target, UseDarkOptions, UseDraggableOptions, UseElementBoundingOptions, UseEventEmitterReturn, UseFileDialogOptions, UseFpsOptions, UseFullScreenOptions, UseInfiniteScrollOptions, UseLongPressOptions, UseModifierOptions, UseScriptTagOptions, UseScrollOptions, UseTextDirectionOptions, UseTextDirectionValue, UseTimeoutFnOptions, UseVirtualListItem, UseVirtualListOptions, UseVirtualListReturn, WindowSize, useActiveElement, useClickOutSide as useClickOutside, useClipBorad as useClipboard, useControlled, useCounter, useCustomCompareEffect, useCycleList, useDarkMode, useDebounce, useDebounceFn, useDeepCompareEffect, useDocumentVisibility, useDraggable, useDropZone, useElementBounding, useElementSize, useElementVisibility, useEvent, useEventEmitter, useEventListener, useFavicon, useFileDialog, useFirstMountState, useFocus, _default$2 as useFps, useFullscreen, useGeolocation, useIdle, useInfiniteScroll, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyModifier, useLatest, useLocalStorage, useLongPress, _default$3 as useMediaDevices, useMediaQuery, useMount, useMountedState, useMouse, useMousePressed, useMutationObserver, useNetwork, useObjectUrl, _default$1 as useOnceEffect, _default as useOnceLayoutEffect, useOnline, useOrientation, usePageLeave, usePermission, usePreferredColorScheme, usePreferredContrast, usePreferredDark, usePrevious, useRafFn, useRafState, useResizeObserver, useScriptTag, useScroll, useScrollLock, useSessionStorage, useTextDirection, useThrottle, useThrottleFn, useTimeout, useTimeoutFn, useTitle, useToggle, useUnmount, useUpdate, _default$5 as useUpdateEffect, _default$4 as useUpdateLayoutEffect, useVirtualList, useWindowScroll, useWindowSize, useWindowsFocus };
753
+ declare function useReducedMotion(defaultState?: boolean): boolean;
754
+
755
+ interface ScrollIntoViewAnimation {
756
+ /** target element alignment relatively to parent based on current axis */
757
+ alignment?: "start" | "end" | "center";
758
+ }
759
+ interface ScrollIntoViewParams {
760
+ /** callback fired after scroll */
761
+ onScrollFinish?: () => void;
762
+ /** duration of scroll in milliseconds */
763
+ duration?: number;
764
+ /** axis of scroll */
765
+ axis?: "x" | "y";
766
+ /** custom mathematical easing function */
767
+ easing?: (t: number) => number;
768
+ /** additional distance between nearest edge and element */
769
+ offset?: number;
770
+ /** indicator if animation may be interrupted by user scrolling */
771
+ cancelable?: boolean;
772
+ /** prevents content jumping in scrolling lists with multiple targets */
773
+ isList?: boolean;
774
+ targetElement: BasicTarget<HTMLElement>;
775
+ scrollElement?: BasicTarget<HTMLElement>;
776
+ }
777
+ declare function useScrollIntoView({ duration, axis, onScrollFinish, easing, offset, cancelable, isList, targetElement, scrollElement, }: ScrollIntoViewParams): {
778
+ scrollIntoView: ({ alignment }?: ScrollIntoViewAnimation) => void;
779
+ cancel: () => void;
780
+ };
781
+
782
+ interface UseStickyParams {
783
+ targetElement: BasicTarget<HTMLElement>;
784
+ scrollElement?: BasicTarget<HTMLElement>;
785
+ /** axis of scroll */
786
+ axis?: "x" | "y";
787
+ /** cover height or width */
788
+ nav: number;
789
+ }
790
+ declare const useSticky: ({ targetElement, scrollElement, axis, nav, }: UseStickyParams) => [
791
+ boolean,
792
+ react__default.Dispatch<react__default.SetStateAction<boolean>>
793
+ ];
794
+
795
+ export { ColorScheme, Contrast, CursorState, GeneralPermissionDescriptor, IDisposable, IEvent, IEventOnce, IListener, INetworkInformation, IState, IUseNetworkState, KeyModifier, MousePressedOptions, MouseSourceType, OrientationState, RafLoopReturns, ScrollIntoViewAnimation, ScrollIntoViewParams, State, Status, Target, UseDarkOptions, UseDraggableOptions, UseElementBoundingOptions, UseEventEmitterReturn, UseFileDialogOptions, UseFpsOptions, UseFullScreenOptions, UseInfiniteScrollOptions, UseLongPressOptions, UseModifierOptions, UseScriptTagOptions, UseScrollOptions, UseStickyParams, UseTextDirectionOptions, UseTextDirectionValue, UseTimeoutFnOptions, UseVirtualListItem, UseVirtualListOptions, UseVirtualListReturn, WindowSize, useActiveElement, useClickOutSide as useClickOutside, useClipBorad as useClipboard, useControlled, useCounter, useCustomCompareEffect, useCycleList, useDarkMode, useDebounce, useDebounceFn, useDeepCompareEffect, useDocumentVisibility, useDraggable, useDropZone, useElementBounding, useElementSize, useElementVisibility, useEvent, useEventEmitter, useEventListener, useFavicon, useFileDialog, useFirstMountState, useFocus, _default$2 as useFps, useFullscreen, useGeolocation, useIdle, useInfiniteScroll, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyModifier, useLatest, useLocalStorage, useLongPress, _default$3 as useMediaDevices, useMediaQuery, useMount, useMountedState, useMouse, useMousePressed, useMutationObserver, useNetwork, useObjectUrl, _default$1 as useOnceEffect, _default as useOnceLayoutEffect, useOnline, useOrientation, usePageLeave, usePermission, usePreferredColorScheme, usePreferredContrast, usePreferredDark, usePrevious, useRafFn, useRafState, useReducedMotion, useResizeObserver, useScriptTag, useScroll, useScrollIntoView, useScrollLock, useSessionStorage, useSticky, useTextDirection, useThrottle, useThrottleFn, useTimeout, useTimeoutFn, useTitle, useToggle, useUnmount, useUpdate, _default$5 as useUpdateEffect, _default$4 as useUpdateLayoutEffect, useVirtualList, useWindowScroll, useWindowSize, useWindowsFocus };
package/dist/index.mjs CHANGED
@@ -123,7 +123,7 @@ function useStorage(key, defaults, getStorage, options = {}) {
123
123
  }
124
124
  const type = guessSerializerType(defaults);
125
125
  const serializer = (_a = options.serializer) != null ? _a : StorageSerializers[type];
126
- const getStoredValue = () => {
126
+ const getStoredValue = useEvent(() => {
127
127
  try {
128
128
  const raw = storage == null ? void 0 : storage.getItem(key);
129
129
  if (raw !== void 0 && raw !== null) {
@@ -135,11 +135,11 @@ function useStorage(key, defaults, getStorage, options = {}) {
135
135
  } catch (e) {
136
136
  onError(e);
137
137
  }
138
- };
139
- const [state, setState] = useState(() => getStoredValue());
140
- useUpdateEffect(() => {
138
+ });
139
+ const [state, setState] = useState(defaults);
140
+ useEffect(() => {
141
141
  setState(getStoredValue());
142
- }, [key]);
142
+ }, [getStoredValue, key]);
143
143
  const updateState = useEvent(
144
144
  (valOrFunc) => {
145
145
  const currentState = isFunction(valOrFunc) ? valOrFunc(state) : valOrFunc;
@@ -197,12 +197,12 @@ function useInterval(callback, delay, options) {
197
197
  }
198
198
 
199
199
  const getInitialState = (query, defaultState) => {
200
- if (isBrowser) {
201
- return window.matchMedia(query).matches;
202
- }
203
200
  if (defaultState !== void 0) {
204
201
  return defaultState;
205
202
  }
203
+ if (isBrowser) {
204
+ return window.matchMedia(query).matches;
205
+ }
206
206
  if (process.env.NODE_ENV !== "production") {
207
207
  console.warn(
208
208
  "`useMediaQuery` When server side rendering, defaultState should be defined to prevent a hydration mismatches."
@@ -254,21 +254,24 @@ function useDarkMode(options = {}) {
254
254
  const prefersDarkMode = usePreferredDark(false);
255
255
  const value = initialValue ? initialValue : prefersDarkMode ? "dark" : "light";
256
256
  const [dark, setDark] = useStorage(storageKey, value, storage);
257
- useEffect(() => {
258
- const element = window == null ? void 0 : window.document.querySelector(selector);
259
- if (!element) {
260
- return;
261
- }
262
- if (attribute === "class") {
263
- dark && element.classList.add(dark);
264
- } else {
265
- dark && element.setAttribute(attribute, dark);
266
- }
267
- return () => {
268
- dark && (element == null ? void 0 : element.classList.remove(dark));
269
- };
270
- }, [attribute, dark, selector]);
271
- return [dark, setDark];
257
+ const wrappedSetDark = useCallback(
258
+ (latestDark) => {
259
+ const element = window == null ? void 0 : window.document.querySelector(selector);
260
+ if (!element) {
261
+ return;
262
+ }
263
+ if (attribute === "class") {
264
+ latestDark && element.classList.add(latestDark);
265
+ dark && element.classList.remove(dark);
266
+ } else {
267
+ latestDark && element.setAttribute(attribute, latestDark);
268
+ dark && element.removeAttribute(attribute);
269
+ }
270
+ setDark(latestDark);
271
+ },
272
+ [attribute, dark, selector, setDark]
273
+ );
274
+ return [dark, wrappedSetDark];
272
275
  }
273
276
 
274
277
  function useMount(fn) {
@@ -703,7 +706,7 @@ function useMutationObserver(callback, target, options = {}) {
703
706
  observerRef.current = new MutationObserver(callbackRef.current);
704
707
  observerRef.current.observe(element, options);
705
708
  return stop;
706
- }, [options]);
709
+ }, [options, target]);
707
710
  return stop;
708
711
  }
709
712
 
@@ -1504,7 +1507,7 @@ function useIntersectionObserver(target, callback, options = {}) {
1504
1507
  );
1505
1508
  observerRef.current.observe(element);
1506
1509
  return stop;
1507
- }, [options]);
1510
+ }, [options, target]);
1508
1511
  return stop;
1509
1512
  }
1510
1513
 
@@ -1557,7 +1560,7 @@ function useResizeObserver(target, callback, options = {}) {
1557
1560
  observerRef.current = new ResizeObserver(savedCallback.current);
1558
1561
  observerRef.current.observe(element, options);
1559
1562
  return stop;
1560
- }, [options]);
1563
+ }, [options, target]);
1561
1564
  return stop;
1562
1565
  }
1563
1566
 
@@ -1800,7 +1803,7 @@ function useInfiniteScroll(target, onLoadMore, options = {}) {
1800
1803
  }
1801
1804
  });
1802
1805
  fn();
1803
- }, [di, options.preserveScrollPosition]);
1806
+ }, [di, options.preserveScrollPosition, target]);
1804
1807
  }
1805
1808
 
1806
1809
  const defaultEvents = [
@@ -1851,7 +1854,7 @@ function useMousePressed(target, options = {}) {
1851
1854
  useEventListener("mousedown", onPressed("mouse"), target, { passive: true });
1852
1855
  useEventListener("mouseleave", onReleased, () => window, { passive: true });
1853
1856
  useEventListener("mouseup", onReleased, () => window, { passive: true });
1854
- useMount(() => {
1857
+ useEffect(() => {
1855
1858
  const element = getTargetElement(target);
1856
1859
  if (drag) {
1857
1860
  element == null ? void 0 : element.addEventListener("dragstart", onPressed("mouse"), {
@@ -1887,7 +1890,7 @@ function useMousePressed(target, options = {}) {
1887
1890
  element == null ? void 0 : element.removeEventListener("touchcancel", onReleased);
1888
1891
  }
1889
1892
  };
1890
- });
1893
+ }, [drag, onPressed, onReleased, target, touch]);
1891
1894
  return [pressed, sourceType];
1892
1895
  }
1893
1896
 
@@ -1904,7 +1907,7 @@ function preventDefault(rawEvent) {
1904
1907
  function useScrollLock(target, initialState = false) {
1905
1908
  const [locked, setLocked] = useState(initialState);
1906
1909
  const initialOverflowRef = useRef("scroll");
1907
- useMount(() => {
1910
+ useEffect(() => {
1908
1911
  const element = getTargetElement(target);
1909
1912
  if (element) {
1910
1913
  initialOverflowRef.current = element.style.overflow;
@@ -1912,7 +1915,7 @@ function useScrollLock(target, initialState = false) {
1912
1915
  element.style.overflow = "hidden";
1913
1916
  }
1914
1917
  }
1915
- });
1918
+ }, [locked, target]);
1916
1919
  const lock = useEvent(() => {
1917
1920
  const element = getTargetElement(target);
1918
1921
  if (!element || locked) {
@@ -1921,7 +1924,6 @@ function useScrollLock(target, initialState = false) {
1921
1924
  if (isIOS) {
1922
1925
  element.addEventListener("touchmove", preventDefault, { passive: false });
1923
1926
  }
1924
- element.style.overflow = "hidden";
1925
1927
  setLocked(true);
1926
1928
  });
1927
1929
  const unlock = useEvent(() => {
@@ -2472,4 +2474,241 @@ var useOnceEffect = createOnceEffect(useEffect);
2472
2474
 
2473
2475
  var useOnceLayoutEffect = createOnceEffect(useLayoutEffect);
2474
2476
 
2475
- export { useActiveElement, useClickOutSide as useClickOutside, useClipBorad as useClipboard, useControlled, useCounter, useCustomCompareEffect, useCycleList, useDarkMode, useDebounce, useDebounceFn, useDeepCompareEffect, useDocumentVisibility, useDraggable, useDropZone, useElementBounding, useElementSize, useElementVisibility, useEvent, useEventEmitter, useEventListener, useFavicon, useFileDialog, useFirstMountState, useFocus, useFps$1 as useFps, useFullscreen, useGeolocation, useIdle, useInfiniteScroll, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyModifier, useLatest, useLocalStorage, useLongPress, useMediaDevices$1 as useMediaDevices, useMediaQuery, useMount, useMountedState, useMouse, useMousePressed, useMutationObserver, useNetwork, useObjectUrl, useOnceEffect, useOnceLayoutEffect, useOnline, useOrientation, usePageLeave, usePermission, usePreferredColorScheme, usePreferredContrast, usePreferredDark, usePrevious, useRafFn, useRafState, useResizeObserver, useScriptTag, useScroll, useScrollLock, useSessionStorage, useTextDirection, useThrottle, useThrottleFn, useTimeout, useTimeoutFn, useTitle, useToggle, useUnmount, useUpdate, useUpdateEffect, useUpdateLayoutEffect, useVirtualList, useWindowScroll, useWindowSize, useWindowsFocus };
2477
+ function useReducedMotion(defaultState) {
2478
+ return useMediaQuery("(prefers-reduced-motion: reduce)", defaultState);
2479
+ }
2480
+
2481
+ const setScrollParam = ({
2482
+ axis,
2483
+ parent,
2484
+ distance
2485
+ }) => {
2486
+ if (!parent && typeof document === "undefined") {
2487
+ return;
2488
+ }
2489
+ const method = axis === "y" ? "scrollTop" : "scrollLeft";
2490
+ if (parent) {
2491
+ parent[method] = distance;
2492
+ } else {
2493
+ const { body, documentElement } = document;
2494
+ body[method] = distance;
2495
+ documentElement[method] = distance;
2496
+ }
2497
+ };
2498
+ const isScrollElement = (axis, node) => {
2499
+ if (!node) {
2500
+ return false;
2501
+ }
2502
+ const AXIS = axis === "x" ? "X" : "Y";
2503
+ return getComputedStyle(node)[`overflow${AXIS}`] === "auto" || getComputedStyle(node)[`overflow${AXIS}`] === "scroll";
2504
+ };
2505
+ const cache = /* @__PURE__ */ new Map();
2506
+ const getScrollParent = (axis, node) => {
2507
+ if (!node || !node.parentElement) {
2508
+ return null;
2509
+ }
2510
+ if (cache.has(node)) {
2511
+ return cache.get(node) || null;
2512
+ }
2513
+ let parent = node.parentElement;
2514
+ while (parent && !isScrollElement(axis, parent)) {
2515
+ parent = parent.parentElement;
2516
+ }
2517
+ if (parent) {
2518
+ cache.set(node, parent);
2519
+ }
2520
+ return parent;
2521
+ };
2522
+ const getScrollStart = ({
2523
+ axis,
2524
+ parent
2525
+ }) => {
2526
+ if (!parent && typeof document === "undefined") {
2527
+ return 0;
2528
+ }
2529
+ const method = axis === "y" ? "scrollTop" : "scrollLeft";
2530
+ if (parent) {
2531
+ return parent[method];
2532
+ }
2533
+ const { body, documentElement } = document;
2534
+ return body[method] + documentElement[method];
2535
+ };
2536
+
2537
+ const easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
2538
+
2539
+ const getRelativePosition = ({
2540
+ axis,
2541
+ target,
2542
+ parent,
2543
+ alignment,
2544
+ offset,
2545
+ isList
2546
+ }) => {
2547
+ if (!target || !parent && typeof document === "undefined") {
2548
+ return 0;
2549
+ }
2550
+ const isCustomParent = !!parent;
2551
+ const parentElement = parent || document.body;
2552
+ const parentPosition = parentElement.getBoundingClientRect();
2553
+ const targetPosition = target.getBoundingClientRect();
2554
+ const getDiff = (property) => targetPosition[property] - parentPosition[property];
2555
+ if (axis === "y") {
2556
+ const diff = getDiff("top");
2557
+ if (diff === 0) {
2558
+ return 0;
2559
+ }
2560
+ if (alignment === "start") {
2561
+ const distance = diff - offset;
2562
+ const shouldScroll = distance <= targetPosition.height * (isList ? 0 : 1) || !isList;
2563
+ return shouldScroll ? distance : 0;
2564
+ }
2565
+ const parentHeight = isCustomParent ? parentPosition.height : window.innerHeight;
2566
+ if (alignment === "end") {
2567
+ const distance = diff + offset - parentHeight + targetPosition.height;
2568
+ const shouldScroll = distance >= -targetPosition.height * (isList ? 0 : 1) || !isList;
2569
+ return shouldScroll ? distance : 0;
2570
+ }
2571
+ if (alignment === "center") {
2572
+ return diff - parentHeight / 2 + targetPosition.height / 2;
2573
+ }
2574
+ return 0;
2575
+ }
2576
+ if (axis === "x") {
2577
+ const diff = getDiff("left");
2578
+ if (diff === 0) {
2579
+ return 0;
2580
+ }
2581
+ if (alignment === "start") {
2582
+ const distance = diff - offset;
2583
+ const shouldScroll = distance <= targetPosition.width || !isList;
2584
+ return shouldScroll ? distance : 0;
2585
+ }
2586
+ const parentWidth = isCustomParent ? parentPosition.width : window.innerWidth;
2587
+ if (alignment === "end") {
2588
+ const distance = diff + offset - parentWidth + targetPosition.width;
2589
+ const shouldScroll = distance >= -targetPosition.width || !isList;
2590
+ return shouldScroll ? distance : 0;
2591
+ }
2592
+ if (alignment === "center") {
2593
+ return diff - parentWidth / 2 + targetPosition.width / 2;
2594
+ }
2595
+ return 0;
2596
+ }
2597
+ return 0;
2598
+ };
2599
+
2600
+ function useScrollIntoView({
2601
+ duration = 1250,
2602
+ axis = "y",
2603
+ onScrollFinish,
2604
+ easing = easeInOutQuad,
2605
+ offset = 0,
2606
+ cancelable = true,
2607
+ isList = false,
2608
+ targetElement,
2609
+ scrollElement
2610
+ }) {
2611
+ const frameID = useRef(0);
2612
+ const startTime = useRef(0);
2613
+ const shouldStop = useRef(false);
2614
+ const reducedMotion = useReducedMotion(false);
2615
+ const cancel = () => {
2616
+ if (frameID.current) {
2617
+ cancelAnimationFrame(frameID.current);
2618
+ }
2619
+ };
2620
+ const scrollIntoView = useEvent(
2621
+ ({ alignment = "start" } = {}) => {
2622
+ var _a;
2623
+ const element = getTargetElement(targetElement);
2624
+ const parent = getTargetElement(scrollElement) || getScrollParent(axis, element);
2625
+ shouldStop.current = false;
2626
+ if (frameID.current) {
2627
+ cancel();
2628
+ }
2629
+ const start = (_a = getScrollStart({ parent, axis })) != null ? _a : 0;
2630
+ const change = getRelativePosition({
2631
+ parent,
2632
+ target: element,
2633
+ axis,
2634
+ alignment,
2635
+ offset,
2636
+ isList
2637
+ }) - (parent ? 0 : start);
2638
+ const animateScroll = () => {
2639
+ if (startTime.current === 0) {
2640
+ startTime.current = performance.now();
2641
+ }
2642
+ const now = performance.now();
2643
+ const elapsed = now - startTime.current;
2644
+ const t = reducedMotion || duration === 0 ? 1 : elapsed / duration;
2645
+ const distance = start + change * easing(t);
2646
+ setScrollParam({
2647
+ parent,
2648
+ axis,
2649
+ distance
2650
+ });
2651
+ if (!shouldStop.current && t < 1) {
2652
+ frameID.current = requestAnimationFrame(animateScroll);
2653
+ } else {
2654
+ typeof onScrollFinish === "function" && onScrollFinish();
2655
+ startTime.current = 0;
2656
+ frameID.current = 0;
2657
+ cancel();
2658
+ }
2659
+ };
2660
+ animateScroll();
2661
+ }
2662
+ );
2663
+ const handleStop = () => {
2664
+ if (cancelable) {
2665
+ shouldStop.current = true;
2666
+ }
2667
+ };
2668
+ useEventListener("wheel", handleStop, null, { passive: true });
2669
+ useEventListener("touchmove", handleStop, null, { passive: true });
2670
+ useEffect(() => cancel, []);
2671
+ return {
2672
+ scrollIntoView,
2673
+ cancel
2674
+ };
2675
+ }
2676
+
2677
+ const useSticky = ({
2678
+ targetElement,
2679
+ scrollElement,
2680
+ axis = "y",
2681
+ nav = 0
2682
+ }) => {
2683
+ const [isSticky, setSticky] = useState(false);
2684
+ const { run: scrollHandler } = useThrottleFn(() => {
2685
+ const element = getTargetElement(targetElement);
2686
+ if (!element) {
2687
+ return;
2688
+ }
2689
+ const rect = element.getBoundingClientRect();
2690
+ if (axis === "y") {
2691
+ setSticky((rect == null ? void 0 : rect.top) <= nav);
2692
+ } else {
2693
+ setSticky((rect == null ? void 0 : rect.left) <= nav);
2694
+ }
2695
+ }, 50);
2696
+ useEffect(() => {
2697
+ const element = getTargetElement(targetElement);
2698
+ if (!element) {
2699
+ return;
2700
+ }
2701
+ const scrollParent = getTargetElement(scrollElement) || getScrollParent(axis, element);
2702
+ if (!scrollParent) {
2703
+ return;
2704
+ }
2705
+ scrollParent.addEventListener("scroll", scrollHandler);
2706
+ scrollHandler();
2707
+ return () => {
2708
+ scrollParent.removeEventListener("scroll", scrollHandler);
2709
+ };
2710
+ }, [axis, scrollElement, scrollHandler, targetElement]);
2711
+ return [isSticky, setSticky];
2712
+ };
2713
+
2714
+ export { useActiveElement, useClickOutSide as useClickOutside, useClipBorad as useClipboard, useControlled, useCounter, useCustomCompareEffect, useCycleList, useDarkMode, useDebounce, useDebounceFn, useDeepCompareEffect, useDocumentVisibility, useDraggable, useDropZone, useElementBounding, useElementSize, useElementVisibility, useEvent, useEventEmitter, useEventListener, useFavicon, useFileDialog, useFirstMountState, useFocus, useFps$1 as useFps, useFullscreen, useGeolocation, useIdle, useInfiniteScroll, useIntersectionObserver, useInterval, useIsomorphicLayoutEffect, useKeyModifier, useLatest, useLocalStorage, useLongPress, useMediaDevices$1 as useMediaDevices, useMediaQuery, useMount, useMountedState, useMouse, useMousePressed, useMutationObserver, useNetwork, useObjectUrl, useOnceEffect, useOnceLayoutEffect, useOnline, useOrientation, usePageLeave, usePermission, usePreferredColorScheme, usePreferredContrast, usePreferredDark, usePrevious, useRafFn, useRafState, useReducedMotion, useResizeObserver, useScriptTag, useScroll, useScrollIntoView, useScrollLock, useSessionStorage, useSticky, useTextDirection, useThrottle, useThrottleFn, useTimeout, useTimeoutFn, useTitle, useToggle, useUnmount, useUpdate, useUpdateEffect, useUpdateLayoutEffect, useVirtualList, useWindowScroll, useWindowSize, useWindowsFocus };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactuses/core",
3
- "version": "1.1.5",
3
+ "version": "2.0.0",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",