react-simplikit 0.0.53 → 0.2.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.
Files changed (153) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +2 -42
  3. package/dist/hooks/useAsyncEffect/useAsyncEffect.cjs +1 -0
  4. package/dist/hooks/useAsyncEffect/useAsyncEffect.mjs +1 -0
  5. package/dist/hooks/useCallbackOncePerRender/useCallbackOncePerRender.cjs +1 -0
  6. package/dist/hooks/useCallbackOncePerRender/useCallbackOncePerRender.mjs +1 -0
  7. package/dist/hooks/useConditionalEffect/useConditionalEffect.cjs +1 -0
  8. package/dist/hooks/useConditionalEffect/useConditionalEffect.mjs +1 -0
  9. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.cjs +24 -6
  10. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.d.cts +17 -7
  11. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.d.mts +17 -7
  12. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.mjs +24 -6
  13. package/dist/hooks/useDoubleClick/useDoubleClick.cjs +0 -4
  14. package/dist/hooks/useDoubleClick/useDoubleClick.d.cts +0 -4
  15. package/dist/hooks/useDoubleClick/useDoubleClick.d.mts +0 -4
  16. package/dist/hooks/useDoubleClick/useDoubleClick.mjs +0 -4
  17. package/dist/hooks/useGeolocation/useGeolocation.cjs +0 -4
  18. package/dist/hooks/useGeolocation/useGeolocation.d.cts +0 -4
  19. package/dist/hooks/useGeolocation/useGeolocation.d.mts +0 -4
  20. package/dist/hooks/useGeolocation/useGeolocation.mjs +0 -4
  21. package/dist/hooks/useImpressionRef/useImpressionRef.cjs +7 -5
  22. package/dist/hooks/useImpressionRef/useImpressionRef.d.cts +0 -4
  23. package/dist/hooks/useImpressionRef/useImpressionRef.d.mts +0 -4
  24. package/dist/hooks/useImpressionRef/useImpressionRef.mjs +7 -5
  25. package/dist/hooks/useInputState/useInputState.cjs +9 -3
  26. package/dist/hooks/useInputState/useInputState.d.cts +11 -4
  27. package/dist/hooks/useInputState/useInputState.d.mts +11 -4
  28. package/dist/hooks/useInputState/useInputState.mjs +9 -3
  29. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.cjs +1 -5
  30. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.d.cts +1 -5
  31. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.d.mts +1 -5
  32. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.mjs +1 -5
  33. package/dist/hooks/useList/useList.cjs +11 -8
  34. package/dist/hooks/useList/useList.d.cts +12 -9
  35. package/dist/hooks/useList/useList.d.mts +12 -9
  36. package/dist/hooks/useList/useList.mjs +11 -8
  37. package/dist/hooks/useLoading/useLoading.cjs +3 -5
  38. package/dist/hooks/useLoading/useLoading.d.cts +2 -5
  39. package/dist/hooks/useLoading/useLoading.d.mts +2 -5
  40. package/dist/hooks/useLoading/useLoading.mjs +3 -5
  41. package/dist/hooks/useLongPress/useLongPress.cjs +0 -4
  42. package/dist/hooks/useLongPress/useLongPress.d.cts +0 -4
  43. package/dist/hooks/useLongPress/useLongPress.d.mts +0 -4
  44. package/dist/hooks/useLongPress/useLongPress.mjs +0 -4
  45. package/dist/hooks/useOutsideClickEffect/useOutsideClickEffect.cjs +0 -4
  46. package/dist/hooks/useOutsideClickEffect/useOutsideClickEffect.d.cts +0 -4
  47. package/dist/hooks/useOutsideClickEffect/useOutsideClickEffect.d.mts +0 -4
  48. package/dist/hooks/useOutsideClickEffect/useOutsideClickEffect.mjs +0 -4
  49. package/dist/hooks/usePreservedReference/usePreservedReference.cjs +1 -0
  50. package/dist/hooks/usePreservedReference/usePreservedReference.mjs +1 -0
  51. package/dist/hooks/useRefEffect/useRefEffect.cjs +1 -0
  52. package/dist/hooks/useRefEffect/useRefEffect.mjs +1 -0
  53. package/dist/hooks/useSet/useSet.cjs +11 -2
  54. package/dist/hooks/useSet/useSet.d.cts +11 -2
  55. package/dist/hooks/useSet/useSet.d.mts +11 -2
  56. package/dist/hooks/useSet/useSet.mjs +11 -2
  57. package/dist/hooks/useStorageState/useStorageState.cjs +1 -0
  58. package/dist/hooks/useStorageState/useStorageState.d.cts +0 -4
  59. package/dist/hooks/useStorageState/useStorageState.d.mts +0 -4
  60. package/dist/hooks/useStorageState/useStorageState.mjs +1 -0
  61. package/dist/hooks/useThrottledCallback/useThrottledCallback.cjs +16 -9
  62. package/dist/hooks/useThrottledCallback/useThrottledCallback.d.cts +18 -11
  63. package/dist/hooks/useThrottledCallback/useThrottledCallback.d.mts +18 -11
  64. package/dist/hooks/useThrottledCallback/useThrottledCallback.mjs +16 -9
  65. package/dist/hooks/useVisibilityEvent/useVisibilityEvent.cjs +2 -4
  66. package/dist/hooks/useVisibilityEvent/useVisibilityEvent.d.cts +2 -4
  67. package/dist/hooks/useVisibilityEvent/useVisibilityEvent.d.mts +2 -4
  68. package/dist/hooks/useVisibilityEvent/useVisibilityEvent.mjs +2 -4
  69. package/dist/index.cjs +34 -0
  70. package/dist/index.d.cts +19 -1
  71. package/dist/index.d.mts +19 -1
  72. package/dist/index.mjs +18 -1
  73. package/dist/mobile/hooks/useAvoidKeyboard/index.d.cts +3 -0
  74. package/dist/mobile/hooks/useAvoidKeyboard/index.d.mts +3 -0
  75. package/dist/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.cjs +75 -0
  76. package/dist/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.d.cts +89 -0
  77. package/dist/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.d.mts +89 -0
  78. package/dist/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.mjs +75 -0
  79. package/dist/mobile/hooks/useBodyScrollLock/useBodyScrollLock.cjs +47 -0
  80. package/dist/mobile/hooks/useBodyScrollLock/useBodyScrollLock.d.cts +37 -0
  81. package/dist/mobile/hooks/useBodyScrollLock/useBodyScrollLock.d.mts +37 -0
  82. package/dist/mobile/hooks/useBodyScrollLock/useBodyScrollLock.mjs +47 -0
  83. package/dist/mobile/hooks/useKeyboardHeight/useKeyboardHeight.cjs +41 -0
  84. package/dist/mobile/hooks/useKeyboardHeight/useKeyboardHeight.d.cts +41 -0
  85. package/dist/mobile/hooks/useKeyboardHeight/useKeyboardHeight.d.mts +41 -0
  86. package/dist/mobile/hooks/useKeyboardHeight/useKeyboardHeight.mjs +41 -0
  87. package/dist/mobile/hooks/useNetworkStatus/useNetworkStatus.cjs +88 -0
  88. package/dist/mobile/hooks/useNetworkStatus/useNetworkStatus.d.cts +77 -0
  89. package/dist/mobile/hooks/useNetworkStatus/useNetworkStatus.d.mts +77 -0
  90. package/dist/mobile/hooks/useNetworkStatus/useNetworkStatus.mjs +88 -0
  91. package/dist/mobile/hooks/usePageVisibility/usePageVisibility.cjs +75 -0
  92. package/dist/mobile/hooks/usePageVisibility/usePageVisibility.d.cts +64 -0
  93. package/dist/mobile/hooks/usePageVisibility/usePageVisibility.d.mts +64 -0
  94. package/dist/mobile/hooks/usePageVisibility/usePageVisibility.mjs +75 -0
  95. package/dist/mobile/hooks/useSafeAreaInset/useSafeAreaInset.cjs +74 -0
  96. package/dist/mobile/hooks/useSafeAreaInset/useSafeAreaInset.d.cts +55 -0
  97. package/dist/mobile/hooks/useSafeAreaInset/useSafeAreaInset.d.mts +55 -0
  98. package/dist/mobile/hooks/useSafeAreaInset/useSafeAreaInset.mjs +74 -0
  99. package/dist/mobile/hooks/useScrollDirection/useScrollDirection.cjs +79 -0
  100. package/dist/mobile/hooks/useScrollDirection/useScrollDirection.d.cts +40 -0
  101. package/dist/mobile/hooks/useScrollDirection/useScrollDirection.d.mts +40 -0
  102. package/dist/mobile/hooks/useScrollDirection/useScrollDirection.mjs +79 -0
  103. package/dist/mobile/hooks/useVisualViewport/useVisualViewport.cjs +77 -0
  104. package/dist/mobile/hooks/useVisualViewport/useVisualViewport.d.cts +89 -0
  105. package/dist/mobile/hooks/useVisualViewport/useVisualViewport.d.mts +89 -0
  106. package/dist/mobile/hooks/useVisualViewport/useVisualViewport.mjs +77 -0
  107. package/dist/mobile/utils/disableBodyScrollLock/disableBodyScrollLock.cjs +55 -0
  108. package/dist/mobile/utils/disableBodyScrollLock/disableBodyScrollLock.d.cts +22 -0
  109. package/dist/mobile/utils/disableBodyScrollLock/disableBodyScrollLock.d.mts +22 -0
  110. package/dist/mobile/utils/disableBodyScrollLock/disableBodyScrollLock.mjs +55 -0
  111. package/dist/mobile/utils/enableBodyScrollLock/enableBodyScrollLock.cjs +49 -0
  112. package/dist/mobile/utils/enableBodyScrollLock/enableBodyScrollLock.d.cts +23 -0
  113. package/dist/mobile/utils/enableBodyScrollLock/enableBodyScrollLock.d.mts +23 -0
  114. package/dist/mobile/utils/enableBodyScrollLock/enableBodyScrollLock.mjs +49 -0
  115. package/dist/mobile/utils/getKeyboardHeight/getKeyboardHeight.cjs +35 -0
  116. package/dist/mobile/utils/getKeyboardHeight/getKeyboardHeight.d.cts +28 -0
  117. package/dist/mobile/utils/getKeyboardHeight/getKeyboardHeight.d.mts +28 -0
  118. package/dist/mobile/utils/getKeyboardHeight/getKeyboardHeight.mjs +35 -0
  119. package/dist/mobile/utils/getSafeAreaInset/getSafeAreaInset.cjs +58 -0
  120. package/dist/mobile/utils/getSafeAreaInset/getSafeAreaInset.d.cts +44 -0
  121. package/dist/mobile/utils/getSafeAreaInset/getSafeAreaInset.d.mts +44 -0
  122. package/dist/mobile/utils/getSafeAreaInset/getSafeAreaInset.mjs +58 -0
  123. package/dist/mobile/utils/isAndroid/isAndroid.cjs +32 -0
  124. package/dist/mobile/utils/isAndroid/isAndroid.d.cts +27 -0
  125. package/dist/mobile/utils/isAndroid/isAndroid.d.mts +27 -0
  126. package/dist/mobile/utils/isAndroid/isAndroid.mjs +32 -0
  127. package/dist/mobile/utils/isIOS/isIOS.cjs +37 -0
  128. package/dist/mobile/utils/isIOS/isIOS.d.cts +30 -0
  129. package/dist/mobile/utils/isIOS/isIOS.d.mts +30 -0
  130. package/dist/mobile/utils/isIOS/isIOS.mjs +37 -0
  131. package/dist/mobile/utils/isKeyboardVisible/isKeyboardVisible.cjs +28 -0
  132. package/dist/mobile/utils/isKeyboardVisible/isKeyboardVisible.d.cts +25 -0
  133. package/dist/mobile/utils/isKeyboardVisible/isKeyboardVisible.d.mts +25 -0
  134. package/dist/mobile/utils/isKeyboardVisible/isKeyboardVisible.mjs +28 -0
  135. package/dist/mobile/utils/isServer/isServer.cjs +24 -0
  136. package/dist/mobile/utils/isServer/isServer.d.cts +22 -0
  137. package/dist/mobile/utils/isServer/isServer.d.mts +22 -0
  138. package/dist/mobile/utils/isServer/isServer.mjs +24 -0
  139. package/dist/mobile/utils/subscribeKeyboardHeight/subscribeKeyboardHeight.cjs +71 -0
  140. package/dist/mobile/utils/subscribeKeyboardHeight/subscribeKeyboardHeight.d.cts +64 -0
  141. package/dist/mobile/utils/subscribeKeyboardHeight/subscribeKeyboardHeight.d.mts +64 -0
  142. package/dist/mobile/utils/subscribeKeyboardHeight/subscribeKeyboardHeight.mjs +71 -0
  143. package/dist/utils/buildContext/buildContext.cjs +1 -0
  144. package/dist/utils/buildContext/buildContext.mjs +1 -0
  145. package/dist/utils/mergeProps/mergeProps.cjs +1 -1
  146. package/dist/utils/mergeProps/mergeProps.d.cts +1 -1
  147. package/dist/utils/mergeProps/mergeProps.d.mts +1 -1
  148. package/dist/utils/mergeProps/mergeProps.mjs +1 -1
  149. package/dist/utils/mergeRefs/mergeRefs.cjs +1 -1
  150. package/dist/utils/mergeRefs/mergeRefs.d.cts +1 -1
  151. package/dist/utils/mergeRefs/mergeRefs.d.mts +1 -1
  152. package/dist/utils/mergeRefs/mergeRefs.mjs +1 -1
  153. package/package.json +22 -10
@@ -0,0 +1,55 @@
1
+
2
+ import { SafeAreaInset } from "../../utils/getSafeAreaInset/getSafeAreaInset.mjs";
3
+ //#region src/mobile/hooks/useSafeAreaInset/useSafeAreaInset.d.ts
4
+ /**
5
+ * @description
6
+ * `useSafeAreaInset` is a React hook that tracks safe area inset changes.
7
+ * It returns the safe area insets that automatically update when the screen
8
+ * orientation changes (e.g., portrait to landscape).
9
+ *
10
+ * Safe area insets account for device-specific UI elements:
11
+ * - **top**: Notch, Dynamic Island, or status bar
12
+ * - **bottom**: Home indicator on Face ID devices
13
+ * - **left/right**: Rounded corners in landscape mode
14
+ *
15
+ * @returns {SafeAreaInset} An object containing safe area insets for all four sides.
16
+ * - top `number` - Top safe area inset in pixels. Accounts for the notch, Dynamic Island, or status bar;
17
+ * - bottom `number` - Bottom safe area inset in pixels. Accounts for the home indicator on Face ID devices;
18
+ * - left `number` - Left safe area inset in pixels. Accounts for rounded corners in landscape mode;
19
+ * - right `number` - Right safe area inset in pixels. Accounts for rounded corners in landscape mode;
20
+ *
21
+ * @example
22
+ * function MyComponent() {
23
+ * const safeArea = useSafeAreaInset();
24
+ *
25
+ * return (
26
+ * <div style={{
27
+ * paddingTop: safeArea.top,
28
+ * paddingBottom: safeArea.bottom,
29
+ * paddingLeft: safeArea.left,
30
+ * paddingRight: safeArea.right,
31
+ * }}>
32
+ * Content that respects safe areas
33
+ * </div>
34
+ * );
35
+ * }
36
+ *
37
+ * @example
38
+ * // Automatically updates when screen rotates
39
+ * function RotationAwareHeader() {
40
+ * const { top, left, right } = useSafeAreaInset();
41
+ *
42
+ * return (
43
+ * <header style={{
44
+ * paddingTop: top,
45
+ * paddingLeft: left,
46
+ * paddingRight: right,
47
+ * }}>
48
+ * Header content
49
+ * </header>
50
+ * );
51
+ * }
52
+ */
53
+ declare function useSafeAreaInset(): SafeAreaInset;
54
+ //#endregion
55
+ export { useSafeAreaInset };
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { isServer } from "../../utils/isServer/isServer.mjs";
3
+ import { getSafeAreaInset } from "../../utils/getSafeAreaInset/getSafeAreaInset.mjs";
4
+ import { startTransition, useCallback, useEffect, useState } from "react";
5
+ //#region src/mobile/hooks/useSafeAreaInset/useSafeAreaInset.ts
6
+ /**
7
+ * @description
8
+ * `useSafeAreaInset` is a React hook that tracks safe area inset changes.
9
+ * It returns the safe area insets that automatically update when the screen
10
+ * orientation changes (e.g., portrait to landscape).
11
+ *
12
+ * Safe area insets account for device-specific UI elements:
13
+ * - **top**: Notch, Dynamic Island, or status bar
14
+ * - **bottom**: Home indicator on Face ID devices
15
+ * - **left/right**: Rounded corners in landscape mode
16
+ *
17
+ * @returns {SafeAreaInset} An object containing safe area insets for all four sides.
18
+ * - top `number` - Top safe area inset in pixels. Accounts for the notch, Dynamic Island, or status bar;
19
+ * - bottom `number` - Bottom safe area inset in pixels. Accounts for the home indicator on Face ID devices;
20
+ * - left `number` - Left safe area inset in pixels. Accounts for rounded corners in landscape mode;
21
+ * - right `number` - Right safe area inset in pixels. Accounts for rounded corners in landscape mode;
22
+ *
23
+ * @example
24
+ * function MyComponent() {
25
+ * const safeArea = useSafeAreaInset();
26
+ *
27
+ * return (
28
+ * <div style={{
29
+ * paddingTop: safeArea.top,
30
+ * paddingBottom: safeArea.bottom,
31
+ * paddingLeft: safeArea.left,
32
+ * paddingRight: safeArea.right,
33
+ * }}>
34
+ * Content that respects safe areas
35
+ * </div>
36
+ * );
37
+ * }
38
+ *
39
+ * @example
40
+ * // Automatically updates when screen rotates
41
+ * function RotationAwareHeader() {
42
+ * const { top, left, right } = useSafeAreaInset();
43
+ *
44
+ * return (
45
+ * <header style={{
46
+ * paddingTop: top,
47
+ * paddingLeft: left,
48
+ * paddingRight: right,
49
+ * }}>
50
+ * Header content
51
+ * </header>
52
+ * );
53
+ * }
54
+ */
55
+ function useSafeAreaInset() {
56
+ const [inset, setInset] = useState(() => getSafeAreaInset());
57
+ const updateInset = useCallback(() => {
58
+ startTransition(() => {
59
+ setInset(getSafeAreaInset());
60
+ });
61
+ }, []);
62
+ useEffect(function handleOrientationChange() {
63
+ if (isServer()) return;
64
+ window.addEventListener("resize", updateInset);
65
+ window.addEventListener("orientationchange", updateInset);
66
+ return function cleanup() {
67
+ window.removeEventListener("resize", updateInset);
68
+ window.removeEventListener("orientationchange", updateInset);
69
+ };
70
+ }, [updateInset]);
71
+ return inset;
72
+ }
73
+ //#endregion
74
+ export { useSafeAreaInset };
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ const require_isServer = require("../../utils/isServer/isServer.cjs");
3
+ let react = require("react");
4
+ //#region src/mobile/hooks/useScrollDirection/useScrollDirection.ts
5
+ /**
6
+ * @description
7
+ * `useScrollDirection` is a React hook that detects scroll direction.
8
+ * It returns scroll direction (up/down) and current scroll position.
9
+ * Throttled by default (50ms) for performance.
10
+ *
11
+ * @param {UseScrollDirectionOptions} [options] - Configuration options.
12
+ * @param {number} [options.throttleMs=50] - Throttle interval in milliseconds.
13
+ * @returns {ScrollDirectionState} Scroll direction state: `direction` (`'up' | 'down' | null`) and `position` (px).
14
+ *
15
+ * @example
16
+ * function Header() {
17
+ * const { direction, position } = useScrollDirection();
18
+ *
19
+ * // Hide header on scroll down
20
+ * const isHidden = direction === 'down' && position > 100;
21
+ *
22
+ * return (
23
+ * <header className={isHidden ? 'hidden' : 'visible'}>
24
+ * My Header
25
+ * </header>
26
+ * );
27
+ * }
28
+ */
29
+ function useScrollDirection(options = {}) {
30
+ const { throttleMs = 50 } = options;
31
+ const [scrollInfo, setScrollInfo] = (0, react.useState)({
32
+ direction: null,
33
+ position: require_isServer.isServer() ? 0 : window.scrollY
34
+ });
35
+ const lastScrollYRef = (0, react.useRef)(require_isServer.isServer() ? 0 : window.scrollY);
36
+ const throttleTimerRef = (0, react.useRef)(null);
37
+ const updateScrollDirection = (0, react.useCallback)(({ currentScrollY, lastScrollY }) => {
38
+ if (currentScrollY > lastScrollY) {
39
+ setScrollInfo({
40
+ direction: "down",
41
+ position: currentScrollY
42
+ });
43
+ return;
44
+ }
45
+ if (currentScrollY < lastScrollY) {
46
+ setScrollInfo({
47
+ direction: "up",
48
+ position: currentScrollY
49
+ });
50
+ return;
51
+ }
52
+ }, []);
53
+ const startThrottle = (0, react.useCallback)(() => {
54
+ throttleTimerRef.current = setTimeout(function clearThrottle() {
55
+ throttleTimerRef.current = null;
56
+ }, throttleMs);
57
+ }, [throttleMs]);
58
+ (0, react.useEffect)(function handleScrollDirectionChange() {
59
+ function handleScroll() {
60
+ if (throttleTimerRef.current != null) return;
61
+ const currentScrollY = window.scrollY;
62
+ const lastScrollY = lastScrollYRef.current;
63
+ lastScrollYRef.current = currentScrollY;
64
+ startThrottle();
65
+ updateScrollDirection({
66
+ currentScrollY,
67
+ lastScrollY
68
+ });
69
+ }
70
+ window.addEventListener("scroll", handleScroll, { passive: true });
71
+ return function cleanup() {
72
+ window.removeEventListener("scroll", handleScroll);
73
+ if (throttleTimerRef.current != null) clearTimeout(throttleTimerRef.current);
74
+ };
75
+ }, [startThrottle, updateScrollDirection]);
76
+ return scrollInfo;
77
+ }
78
+ //#endregion
79
+ exports.useScrollDirection = useScrollDirection;
@@ -0,0 +1,40 @@
1
+
2
+ //#region src/mobile/hooks/useScrollDirection/useScrollDirection.d.ts
3
+ type ScrollDirection = 'up' | 'down' | null;
4
+ type ScrollDirectionState = {
5
+ /** Current scroll direction */
6
+ direction: ScrollDirection;
7
+ /** Current scroll Y position (px) */
8
+ position: number;
9
+ };
10
+ type UseScrollDirectionOptions = {
11
+ /** Throttle interval (ms) - default: 50ms */
12
+ throttleMs?: number;
13
+ };
14
+ /**
15
+ * @description
16
+ * `useScrollDirection` is a React hook that detects scroll direction.
17
+ * It returns scroll direction (up/down) and current scroll position.
18
+ * Throttled by default (50ms) for performance.
19
+ *
20
+ * @param {UseScrollDirectionOptions} [options] - Configuration options.
21
+ * @param {number} [options.throttleMs=50] - Throttle interval in milliseconds.
22
+ * @returns {ScrollDirectionState} Scroll direction state: `direction` (`'up' | 'down' | null`) and `position` (px).
23
+ *
24
+ * @example
25
+ * function Header() {
26
+ * const { direction, position } = useScrollDirection();
27
+ *
28
+ * // Hide header on scroll down
29
+ * const isHidden = direction === 'down' && position > 100;
30
+ *
31
+ * return (
32
+ * <header className={isHidden ? 'hidden' : 'visible'}>
33
+ * My Header
34
+ * </header>
35
+ * );
36
+ * }
37
+ */
38
+ declare function useScrollDirection(options?: UseScrollDirectionOptions): ScrollDirectionState;
39
+ //#endregion
40
+ export { useScrollDirection };
@@ -0,0 +1,40 @@
1
+
2
+ //#region src/mobile/hooks/useScrollDirection/useScrollDirection.d.ts
3
+ type ScrollDirection = 'up' | 'down' | null;
4
+ type ScrollDirectionState = {
5
+ /** Current scroll direction */
6
+ direction: ScrollDirection;
7
+ /** Current scroll Y position (px) */
8
+ position: number;
9
+ };
10
+ type UseScrollDirectionOptions = {
11
+ /** Throttle interval (ms) - default: 50ms */
12
+ throttleMs?: number;
13
+ };
14
+ /**
15
+ * @description
16
+ * `useScrollDirection` is a React hook that detects scroll direction.
17
+ * It returns scroll direction (up/down) and current scroll position.
18
+ * Throttled by default (50ms) for performance.
19
+ *
20
+ * @param {UseScrollDirectionOptions} [options] - Configuration options.
21
+ * @param {number} [options.throttleMs=50] - Throttle interval in milliseconds.
22
+ * @returns {ScrollDirectionState} Scroll direction state: `direction` (`'up' | 'down' | null`) and `position` (px).
23
+ *
24
+ * @example
25
+ * function Header() {
26
+ * const { direction, position } = useScrollDirection();
27
+ *
28
+ * // Hide header on scroll down
29
+ * const isHidden = direction === 'down' && position > 100;
30
+ *
31
+ * return (
32
+ * <header className={isHidden ? 'hidden' : 'visible'}>
33
+ * My Header
34
+ * </header>
35
+ * );
36
+ * }
37
+ */
38
+ declare function useScrollDirection(options?: UseScrollDirectionOptions): ScrollDirectionState;
39
+ //#endregion
40
+ export { useScrollDirection };
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { isServer } from "../../utils/isServer/isServer.mjs";
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ //#region src/mobile/hooks/useScrollDirection/useScrollDirection.ts
5
+ /**
6
+ * @description
7
+ * `useScrollDirection` is a React hook that detects scroll direction.
8
+ * It returns scroll direction (up/down) and current scroll position.
9
+ * Throttled by default (50ms) for performance.
10
+ *
11
+ * @param {UseScrollDirectionOptions} [options] - Configuration options.
12
+ * @param {number} [options.throttleMs=50] - Throttle interval in milliseconds.
13
+ * @returns {ScrollDirectionState} Scroll direction state: `direction` (`'up' | 'down' | null`) and `position` (px).
14
+ *
15
+ * @example
16
+ * function Header() {
17
+ * const { direction, position } = useScrollDirection();
18
+ *
19
+ * // Hide header on scroll down
20
+ * const isHidden = direction === 'down' && position > 100;
21
+ *
22
+ * return (
23
+ * <header className={isHidden ? 'hidden' : 'visible'}>
24
+ * My Header
25
+ * </header>
26
+ * );
27
+ * }
28
+ */
29
+ function useScrollDirection(options = {}) {
30
+ const { throttleMs = 50 } = options;
31
+ const [scrollInfo, setScrollInfo] = useState({
32
+ direction: null,
33
+ position: isServer() ? 0 : window.scrollY
34
+ });
35
+ const lastScrollYRef = useRef(isServer() ? 0 : window.scrollY);
36
+ const throttleTimerRef = useRef(null);
37
+ const updateScrollDirection = useCallback(({ currentScrollY, lastScrollY }) => {
38
+ if (currentScrollY > lastScrollY) {
39
+ setScrollInfo({
40
+ direction: "down",
41
+ position: currentScrollY
42
+ });
43
+ return;
44
+ }
45
+ if (currentScrollY < lastScrollY) {
46
+ setScrollInfo({
47
+ direction: "up",
48
+ position: currentScrollY
49
+ });
50
+ return;
51
+ }
52
+ }, []);
53
+ const startThrottle = useCallback(() => {
54
+ throttleTimerRef.current = setTimeout(function clearThrottle() {
55
+ throttleTimerRef.current = null;
56
+ }, throttleMs);
57
+ }, [throttleMs]);
58
+ useEffect(function handleScrollDirectionChange() {
59
+ function handleScroll() {
60
+ if (throttleTimerRef.current != null) return;
61
+ const currentScrollY = window.scrollY;
62
+ const lastScrollY = lastScrollYRef.current;
63
+ lastScrollYRef.current = currentScrollY;
64
+ startThrottle();
65
+ updateScrollDirection({
66
+ currentScrollY,
67
+ lastScrollY
68
+ });
69
+ }
70
+ window.addEventListener("scroll", handleScroll, { passive: true });
71
+ return function cleanup() {
72
+ window.removeEventListener("scroll", handleScroll);
73
+ if (throttleTimerRef.current != null) clearTimeout(throttleTimerRef.current);
74
+ };
75
+ }, [startThrottle, updateScrollDirection]);
76
+ return scrollInfo;
77
+ }
78
+ //#endregion
79
+ export { useScrollDirection };
@@ -0,0 +1,77 @@
1
+ "use client";
2
+ const require_isServer = require("../../utils/isServer/isServer.cjs");
3
+ let react = require("react");
4
+ //#region src/mobile/hooks/useVisualViewport/useVisualViewport.ts
5
+ /**
6
+ * @description
7
+ * `useVisualViewport` is a React hook that tracks Visual Viewport changes.
8
+ * It returns the actual visible area in mobile WebView, which changes when
9
+ * the keyboard appears or the user zooms/scrolls.
10
+ *
11
+ * **Important:** `viewport` is `null` on SSR or in browsers that don't support Visual Viewport API.
12
+ * Always check for null before accessing viewport properties.
13
+ *
14
+ * **Tip:** If you only need keyboard height, use `useKeyboardHeight()` instead
15
+ * for a simpler API.
16
+ *
17
+ * @returns {{ viewport: VisualViewportState | null }} An object containing the Visual Viewport state.
18
+ * - viewport `VisualViewportState | null` - Visual Viewport state object, or `null` if not supported (SSR or browsers without the Visual Viewport API);
19
+ * - viewport.width `number` - Viewport width in pixels;
20
+ * - viewport.height `number` - Viewport height in pixels;
21
+ * - viewport.offsetLeft `number` - Viewport left offset in pixels from the layout viewport. Typically 0 unless horizontal scrolling or panning occurs;
22
+ * - viewport.offsetTop `number` - Viewport top offset in pixels from the layout viewport. Becomes negative on iOS when the keyboard appears, so use `-offsetTop` for the keyboard height. Typically remains 0 on Android;
23
+ * - viewport.scale `number` - Pinch-zoom scaling factor. 1.0 means no zoom, greater than 1.0 means zoomed in;
24
+ *
25
+ * @see {@link useKeyboardHeight} - Simpler hook for keyboard height only
26
+ *
27
+ * @example
28
+ * function CustomLayout() {
29
+ * const { viewport } = useVisualViewport();
30
+ *
31
+ * // Always check for null first
32
+ * if (!viewport) {
33
+ * return <div>Visual Viewport not supported</div>;
34
+ * }
35
+ *
36
+ * const { width, height, offsetTop, scale } = viewport;
37
+ *
38
+ * // Hide floating UI when user zooms in
39
+ * const showFloatingUI = scale <= 1.3;
40
+ *
41
+ * return (
42
+ * <div style={{ height }}>
43
+ * {showFloatingUI && <FloatingButton />}
44
+ * Viewport-aware content
45
+ * </div>
46
+ * );
47
+ * }
48
+ */
49
+ function useVisualViewport() {
50
+ const visualViewport = require_isServer.isServer() ? null : window.visualViewport;
51
+ const [viewport, setViewport] = (0, react.useState)(() => visualViewport != null ? getVisualViewportState(visualViewport) : null);
52
+ const updateViewportState = (0, react.useCallback)(() => {
53
+ (0, react.startTransition)(() => {
54
+ setViewport(window.visualViewport != null ? getVisualViewportState(window.visualViewport) : null);
55
+ });
56
+ }, []);
57
+ (0, react.useEffect)(function handleVisualViewportChange() {
58
+ window.visualViewport?.addEventListener("resize", updateViewportState);
59
+ window.visualViewport?.addEventListener("scroll", updateViewportState);
60
+ return function cleanup() {
61
+ window.visualViewport?.removeEventListener("resize", updateViewportState);
62
+ window.visualViewport?.removeEventListener("scroll", updateViewportState);
63
+ };
64
+ }, [updateViewportState]);
65
+ return { viewport };
66
+ }
67
+ function getVisualViewportState(visualViewport) {
68
+ return {
69
+ width: visualViewport.width,
70
+ height: visualViewport.height,
71
+ offsetLeft: visualViewport.offsetLeft,
72
+ offsetTop: visualViewport.offsetTop,
73
+ scale: visualViewport.scale
74
+ };
75
+ }
76
+ //#endregion
77
+ exports.useVisualViewport = useVisualViewport;
@@ -0,0 +1,89 @@
1
+
2
+ //#region src/mobile/hooks/useVisualViewport/useVisualViewport.d.ts
3
+ type VisualViewportState = {
4
+ /** Viewport width (px) */
5
+ width: number;
6
+ /** Viewport height (px) */
7
+ height: number;
8
+ /**
9
+ * Viewport left offset (px) from the layout viewport
10
+ *
11
+ * Typically 0 unless horizontal scrolling or panning occurs
12
+ */
13
+ offsetLeft: number;
14
+ /**
15
+ * Viewport top offset (px) from the layout viewport
16
+ *
17
+ * On iOS: Becomes negative when keyboard appears (e.g., -300px means 300px keyboard height)
18
+ * On Android: Typically remains 0
19
+ *
20
+ * Use `-offsetTop` to get accurate keyboard height on iOS
21
+ */
22
+ offsetTop: number;
23
+ /**
24
+ * Pinch-zoom scaling factor
25
+ *
26
+ * - 1.0 = no zoom (default)
27
+ * - > 1.0 = zoomed in
28
+ * - < 1.0 = zoomed out (rare, depends on viewport settings)
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * const { viewport } = useVisualViewport();
33
+ * if (viewport && viewport.scale > 1.3) {
34
+ * // Hide floating UI when user zooms in
35
+ * setShowFloatingButton(false);
36
+ * }
37
+ * ```
38
+ */
39
+ scale: number;
40
+ };
41
+ /**
42
+ * @description
43
+ * `useVisualViewport` is a React hook that tracks Visual Viewport changes.
44
+ * It returns the actual visible area in mobile WebView, which changes when
45
+ * the keyboard appears or the user zooms/scrolls.
46
+ *
47
+ * **Important:** `viewport` is `null` on SSR or in browsers that don't support Visual Viewport API.
48
+ * Always check for null before accessing viewport properties.
49
+ *
50
+ * **Tip:** If you only need keyboard height, use `useKeyboardHeight()` instead
51
+ * for a simpler API.
52
+ *
53
+ * @returns {{ viewport: VisualViewportState | null }} An object containing the Visual Viewport state.
54
+ * - viewport `VisualViewportState | null` - Visual Viewport state object, or `null` if not supported (SSR or browsers without the Visual Viewport API);
55
+ * - viewport.width `number` - Viewport width in pixels;
56
+ * - viewport.height `number` - Viewport height in pixels;
57
+ * - viewport.offsetLeft `number` - Viewport left offset in pixels from the layout viewport. Typically 0 unless horizontal scrolling or panning occurs;
58
+ * - viewport.offsetTop `number` - Viewport top offset in pixels from the layout viewport. Becomes negative on iOS when the keyboard appears, so use `-offsetTop` for the keyboard height. Typically remains 0 on Android;
59
+ * - viewport.scale `number` - Pinch-zoom scaling factor. 1.0 means no zoom, greater than 1.0 means zoomed in;
60
+ *
61
+ * @see {@link useKeyboardHeight} - Simpler hook for keyboard height only
62
+ *
63
+ * @example
64
+ * function CustomLayout() {
65
+ * const { viewport } = useVisualViewport();
66
+ *
67
+ * // Always check for null first
68
+ * if (!viewport) {
69
+ * return <div>Visual Viewport not supported</div>;
70
+ * }
71
+ *
72
+ * const { width, height, offsetTop, scale } = viewport;
73
+ *
74
+ * // Hide floating UI when user zooms in
75
+ * const showFloatingUI = scale <= 1.3;
76
+ *
77
+ * return (
78
+ * <div style={{ height }}>
79
+ * {showFloatingUI && <FloatingButton />}
80
+ * Viewport-aware content
81
+ * </div>
82
+ * );
83
+ * }
84
+ */
85
+ declare function useVisualViewport(): {
86
+ viewport: VisualViewportState | null;
87
+ };
88
+ //#endregion
89
+ export { useVisualViewport };
@@ -0,0 +1,89 @@
1
+
2
+ //#region src/mobile/hooks/useVisualViewport/useVisualViewport.d.ts
3
+ type VisualViewportState = {
4
+ /** Viewport width (px) */
5
+ width: number;
6
+ /** Viewport height (px) */
7
+ height: number;
8
+ /**
9
+ * Viewport left offset (px) from the layout viewport
10
+ *
11
+ * Typically 0 unless horizontal scrolling or panning occurs
12
+ */
13
+ offsetLeft: number;
14
+ /**
15
+ * Viewport top offset (px) from the layout viewport
16
+ *
17
+ * On iOS: Becomes negative when keyboard appears (e.g., -300px means 300px keyboard height)
18
+ * On Android: Typically remains 0
19
+ *
20
+ * Use `-offsetTop` to get accurate keyboard height on iOS
21
+ */
22
+ offsetTop: number;
23
+ /**
24
+ * Pinch-zoom scaling factor
25
+ *
26
+ * - 1.0 = no zoom (default)
27
+ * - > 1.0 = zoomed in
28
+ * - < 1.0 = zoomed out (rare, depends on viewport settings)
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * const { viewport } = useVisualViewport();
33
+ * if (viewport && viewport.scale > 1.3) {
34
+ * // Hide floating UI when user zooms in
35
+ * setShowFloatingButton(false);
36
+ * }
37
+ * ```
38
+ */
39
+ scale: number;
40
+ };
41
+ /**
42
+ * @description
43
+ * `useVisualViewport` is a React hook that tracks Visual Viewport changes.
44
+ * It returns the actual visible area in mobile WebView, which changes when
45
+ * the keyboard appears or the user zooms/scrolls.
46
+ *
47
+ * **Important:** `viewport` is `null` on SSR or in browsers that don't support Visual Viewport API.
48
+ * Always check for null before accessing viewport properties.
49
+ *
50
+ * **Tip:** If you only need keyboard height, use `useKeyboardHeight()` instead
51
+ * for a simpler API.
52
+ *
53
+ * @returns {{ viewport: VisualViewportState | null }} An object containing the Visual Viewport state.
54
+ * - viewport `VisualViewportState | null` - Visual Viewport state object, or `null` if not supported (SSR or browsers without the Visual Viewport API);
55
+ * - viewport.width `number` - Viewport width in pixels;
56
+ * - viewport.height `number` - Viewport height in pixels;
57
+ * - viewport.offsetLeft `number` - Viewport left offset in pixels from the layout viewport. Typically 0 unless horizontal scrolling or panning occurs;
58
+ * - viewport.offsetTop `number` - Viewport top offset in pixels from the layout viewport. Becomes negative on iOS when the keyboard appears, so use `-offsetTop` for the keyboard height. Typically remains 0 on Android;
59
+ * - viewport.scale `number` - Pinch-zoom scaling factor. 1.0 means no zoom, greater than 1.0 means zoomed in;
60
+ *
61
+ * @see {@link useKeyboardHeight} - Simpler hook for keyboard height only
62
+ *
63
+ * @example
64
+ * function CustomLayout() {
65
+ * const { viewport } = useVisualViewport();
66
+ *
67
+ * // Always check for null first
68
+ * if (!viewport) {
69
+ * return <div>Visual Viewport not supported</div>;
70
+ * }
71
+ *
72
+ * const { width, height, offsetTop, scale } = viewport;
73
+ *
74
+ * // Hide floating UI when user zooms in
75
+ * const showFloatingUI = scale <= 1.3;
76
+ *
77
+ * return (
78
+ * <div style={{ height }}>
79
+ * {showFloatingUI && <FloatingButton />}
80
+ * Viewport-aware content
81
+ * </div>
82
+ * );
83
+ * }
84
+ */
85
+ declare function useVisualViewport(): {
86
+ viewport: VisualViewportState | null;
87
+ };
88
+ //#endregion
89
+ export { useVisualViewport };