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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ![react-simplikit](./src/public/images/og.png)
2
2
 
3
- # react-simplikit · [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/toss/slash/blob/main/LICENSE) [![codecov](https://codecov.io/gh/toss/react-simplikit/graph/badge.svg?token=RHVOZ3J3TU)](https://codecov.io/gh/toss/react-simplikit)
3
+ # react-simplikit · [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/toss/slash/blob/main/LICENSE) [![codecov](https://codecov.io/gh/toss/react-simplikit/graph/badge.svg?token=RHVOZ3J3TU)](https://codecov.io/gh/toss/react-simplikit) [![Discord Badge](https://discord.com/api/guilds/1281071127052943361/widget.png?style=shield)](https://discord.gg/vGXbVjP2nY)
4
4
 
5
5
  English | [Korean](./README-ko_kr.md)
6
6
 
@@ -24,6 +24,9 @@ __export(ImpressionArea_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(ImpressionArea_exports);
26
26
 
27
+ // src/components/ImpressionArea/ImpressionArea.tsx
28
+ var import_react7 = require("react");
29
+
27
30
  // src/hooks/useImpressionRef/useImpressionRef.ts
28
31
  var import_react6 = require("react");
29
32
 
@@ -267,16 +270,8 @@ function mergeRefs(...refs) {
267
270
 
268
271
  // src/components/ImpressionArea/ImpressionArea.tsx
269
272
  var import_jsx_runtime = require("react/jsx-runtime");
270
- function ImpressionArea({
271
- as,
272
- rootMargin,
273
- areaThreshold,
274
- timeThreshold,
275
- onImpressionStart,
276
- onImpressionEnd,
277
- ref,
278
- ...props
279
- }) {
273
+ var ImpressionArea = (0, import_react7.forwardRef)(ImpressionAreaImpl);
274
+ function ImpressionAreaImpl({ as, rootMargin, areaThreshold, timeThreshold, onImpressionStart, onImpressionEnd, ...props }, ref) {
280
275
  const Component = as ?? "div";
281
276
  const impressionRef = useImpressionRef({
282
277
  onImpressionStart,
@@ -287,6 +282,9 @@ function ImpressionArea({
287
282
  });
288
283
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ref: mergeRefs(ref, impressionRef), ...props });
289
284
  }
285
+ Object.assign(ImpressionArea, {
286
+ displayName: "ImpressionArea"
287
+ });
290
288
  // Annotate the CommonJS export names for ESM import in node:
291
289
  0 && (module.exports = {
292
290
  ImpressionArea
@@ -1,10 +1,9 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ElementType, Ref, ReactNode } from 'react';
1
+ import { ElementType, ReactNode, Ref } from 'react';
3
2
  import { UseImpressionRefOptions } from '../../hooks/useImpressionRef/index.cjs';
4
3
 
4
+ type Element<T extends ElementType, InstrinsicElements = T extends keyof React.JSX.IntrinsicElements ? React.JSX.IntrinsicElements[T] : HTMLElement> = InstrinsicElements extends React.ClassAttributes<infer E extends HTMLElement> ? E : HTMLElement;
5
5
  type Props<Tag extends ElementType> = React.ComponentPropsWithoutRef<Tag> & UseImpressionRefOptions & {
6
6
  as?: Tag;
7
- ref?: Ref<HTMLElement>;
8
7
  children?: ReactNode;
9
8
  className?: string;
10
9
  };
@@ -14,13 +13,14 @@ type Props<Tag extends ElementType> = React.ComponentPropsWithoutRef<Tag> & UseI
14
13
  * and executes callbacks when the element enters or exits the viewport. This component uses the `useImpressionRef`
15
14
  * hook to track the element's visibility.
16
15
  *
17
- * @param {ElementType} [as='div'] - The HTML tag to render. Defaults to `div`.
16
+ * @template {ElementType} T - The HTML tag to render. Defaults to `div`.
17
+ * @param {T} [as='div'] - The HTML tag to render. Defaults to `div`.
18
18
  * @param {string} [rootMargin] - Margin to adjust the detection area.
19
19
  * @param {number} [areaThreshold] - Minimum ratio of the element that must be visible (0 to 1).
20
20
  * @param {number} [timeThreshold] - Minimum time the element must be visible (in milliseconds).
21
21
  * @param {() => void} [onImpressionStart] - Callback function executed when the element enters the view.
22
22
  * @param {() => void} [onImpressionEnd] - Callback function executed when the element exits the view.
23
- * @param {Ref<HTMLElement>} [ref] - Reference to the element.
23
+ * @param {Ref<Element<T>>} [ref] - Reference to the element.
24
24
  * @param {React.ReactNode} [children] - Child elements to be rendered inside the component.
25
25
  * @param {string} [className] - Additional class names for styling.
26
26
  *
@@ -40,6 +40,8 @@ type Props<Tag extends ElementType> = React.ComponentPropsWithoutRef<Tag> & UseI
40
40
  * );
41
41
  * }
42
42
  */
43
- declare function ImpressionArea<T extends ElementType = 'div'>({ as, rootMargin, areaThreshold, timeThreshold, onImpressionStart, onImpressionEnd, ref, ...props }: Props<T>): react_jsx_runtime.JSX.Element;
43
+ declare const ImpressionArea: <T extends ElementType = "div">(props: Props<T> & {
44
+ ref?: Ref<Element<T>>;
45
+ }) => React.ReactNode;
44
46
 
45
47
  export { ImpressionArea };
@@ -2,7 +2,7 @@ import { DependencyList } from 'react';
2
2
 
3
3
  /**
4
4
  * @description
5
- * `useAsyncEffect` is a custom hook for handling asynchronous side effects in React components.
5
+ * `useAsyncEffect` is a React hook for handling asynchronous side effects in React components.
6
6
  * It follows the same cleanup pattern as `useEffect` while ensuring async operations are handled safely.
7
7
  *
8
8
  * @param {() => Promise<void | (() => void)>} [effect] - An asynchronous function executed in the `useEffect` pattern.
@@ -2,9 +2,8 @@ import { DependencyList } from 'react';
2
2
 
3
3
  /**
4
4
  * @description
5
- * A React hook that ensures a callback function is executed only once, regardless of
6
- * how many times it's called. This is useful for one-time operations that should not
7
- * be repeated, even if the component re-renders.
5
+ * `useCallbackOncePerRender` is a React hook that ensures a callback function is executed only once, regardless of how many times it's called.
6
+ * This is useful for one-time operations that should not be repeated, even if the component re-renders.
8
7
  *
9
8
  * @param {() => void} callback - The callback function to be executed once.
10
9
  * @param {DependencyList} deps - Dependencies array that will trigger a new one-time execution when changed.
@@ -13,7 +13,7 @@ type UseControlledStateProps<T> = ControlledState<T> & {
13
13
  };
14
14
  /**
15
15
  * @description
16
- * `useControlledState` is a hook that allows you to control both controlled and uncontrolled states.
16
+ * `useControlledState` is a React hook that allows you to control both controlled and uncontrolled states.
17
17
  * If you pass the state to `value`, it will be a controlled state, and if you pass the state to `defaultValue`, it will be an uncontrolled state.
18
18
  * If both `value` and `defaultValue` are passed, `value` will take precedence.
19
19
  *
@@ -26,7 +26,7 @@ module.exports = __toCommonJS(useCounter_exports);
26
26
 
27
27
  // src/hooks/useCounter/useCounter.ts
28
28
  var import_react = require("react");
29
- function useCounter({ initialValue = 0, min, max, step = 1 } = {}) {
29
+ function useCounter(initialValue = 0, { min, max, step = 1 } = {}) {
30
30
  const validateValue = (value) => {
31
31
  let validatedValue = value;
32
32
  if (min !== void 0 && validatedValue < min) {
@@ -1,5 +1,4 @@
1
1
  type UseCounterOptions = {
2
- initialValue?: number;
3
2
  min?: number;
4
3
  max?: number;
5
4
  step?: number;
@@ -16,8 +15,8 @@ type UseCounterReturn = {
16
15
  * `useCounter` is a React hook that manages a numeric counter state with increment, decrement, and reset capabilities.
17
16
  * Optionally, you can provide minimum and maximum values to constrain the counter's range.
18
17
  *
18
+ * @param {number} [initialValue=0] - Initial value for the counter. Defaults to 0.
19
19
  * @param {UseCounterOptions} options - The options for the counter.
20
- * @param {number} [options.initialValue=0] - Initial value for the counter. Defaults to 0.
21
20
  * @param {number} [options.min] - Minimum value the counter can reach. If not provided, there is no lower limit.
22
21
  * @param {number} [options.max] - Maximum value the counter can reach. If not provided, there is no upper limit.
23
22
  * @param {number} [options.step=1] - Value to increment or decrement by. Defaults to 1.
@@ -33,8 +32,7 @@ type UseCounterReturn = {
33
32
  * import { useCounter } from 'react-simplikit';
34
33
  *
35
34
  * function ShoppingCart() {
36
- * const { count, increment, decrement, reset } = useCounter({
37
- * initialValue: 1,
35
+ * const { count, increment, decrement, reset } = useCounter(1, {
38
36
  * min: 1,
39
37
  * max: 10,
40
38
  * });
@@ -49,6 +47,6 @@ type UseCounterReturn = {
49
47
  * );
50
48
  * }
51
49
  */
52
- declare function useCounter({ initialValue, min, max, step }?: UseCounterOptions): UseCounterReturn;
50
+ declare function useCounter(initialValue?: number, { min, max, step }?: UseCounterOptions): UseCounterReturn;
53
51
 
54
52
  export { useCounter };
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/hooks/useDebouncedCallback/index.ts
21
+ var useDebouncedCallback_exports = {};
22
+ __export(useDebouncedCallback_exports, {
23
+ useDebouncedCallback: () => useDebouncedCallback
24
+ });
25
+ module.exports = __toCommonJS(useDebouncedCallback_exports);
26
+
27
+ // src/hooks/useDebouncedCallback/useDebouncedCallback.ts
28
+ var import_react2 = require("react");
29
+
30
+ // src/hooks/useDebounce/debounce.ts
31
+ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
32
+ let pendingThis = void 0;
33
+ let pendingArgs = null;
34
+ const leading = edges != null && edges.includes("leading");
35
+ const trailing = edges == null || edges.includes("trailing");
36
+ const invoke = () => {
37
+ if (pendingArgs !== null) {
38
+ func.apply(pendingThis, pendingArgs);
39
+ pendingThis = void 0;
40
+ pendingArgs = null;
41
+ }
42
+ };
43
+ const onTimerEnd = () => {
44
+ if (trailing) {
45
+ invoke();
46
+ }
47
+ cancel();
48
+ };
49
+ let timeoutId = null;
50
+ const schedule = () => {
51
+ if (timeoutId != null) {
52
+ clearTimeout(timeoutId);
53
+ }
54
+ timeoutId = setTimeout(() => {
55
+ timeoutId = null;
56
+ onTimerEnd();
57
+ }, debounceMs);
58
+ };
59
+ const cancelTimer = () => {
60
+ if (timeoutId !== null) {
61
+ clearTimeout(timeoutId);
62
+ timeoutId = null;
63
+ }
64
+ };
65
+ const cancel = () => {
66
+ cancelTimer();
67
+ pendingThis = void 0;
68
+ pendingArgs = null;
69
+ };
70
+ const debounced = function(...args) {
71
+ pendingThis = this;
72
+ pendingArgs = args;
73
+ const isFirstCall = timeoutId == null;
74
+ schedule();
75
+ if (leading && isFirstCall) {
76
+ invoke();
77
+ }
78
+ };
79
+ debounced.cancel = cancel;
80
+ return debounced;
81
+ }
82
+
83
+ // src/hooks/usePreservedCallback/usePreservedCallback.ts
84
+ var import_react = require("react");
85
+ function usePreservedCallback(callback) {
86
+ const callbackRef = (0, import_react.useRef)(callback);
87
+ (0, import_react.useEffect)(() => {
88
+ callbackRef.current = callback;
89
+ }, [callback]);
90
+ return (0, import_react.useCallback)((...args) => {
91
+ return callbackRef.current(...args);
92
+ }, []);
93
+ }
94
+
95
+ // src/hooks/useDebouncedCallback/useDebouncedCallback.ts
96
+ function useDebouncedCallback({
97
+ onChange,
98
+ timeThreshold,
99
+ leading = false,
100
+ trailing = true
101
+ }) {
102
+ const handleChange = usePreservedCallback(onChange);
103
+ const ref = (0, import_react2.useRef)({ value: false, clearPreviousDebounce: () => {
104
+ } });
105
+ (0, import_react2.useEffect)(() => {
106
+ const current = ref.current;
107
+ return () => {
108
+ current.clearPreviousDebounce();
109
+ };
110
+ }, []);
111
+ const edges = (0, import_react2.useMemo)(() => {
112
+ const _edges = [];
113
+ if (leading) {
114
+ _edges.push("leading");
115
+ }
116
+ if (trailing) {
117
+ _edges.push("trailing");
118
+ }
119
+ return _edges;
120
+ }, [leading, trailing]);
121
+ return (0, import_react2.useCallback)(
122
+ (nextValue) => {
123
+ if (nextValue === ref.current.value) {
124
+ return;
125
+ }
126
+ const debounced = debounce(
127
+ () => {
128
+ handleChange(nextValue);
129
+ ref.current.value = nextValue;
130
+ },
131
+ timeThreshold,
132
+ { edges }
133
+ );
134
+ ref.current.clearPreviousDebounce();
135
+ debounced();
136
+ ref.current.clearPreviousDebounce = debounced.cancel;
137
+ },
138
+ [handleChange, timeThreshold, edges]
139
+ );
140
+ }
141
+ // Annotate the CommonJS export names for ESM import in node:
142
+ 0 && (module.exports = {
143
+ useDebouncedCallback
144
+ });
@@ -0,0 +1,32 @@
1
+ type DebounceOptions = {
2
+ leading?: boolean;
3
+ trailing?: boolean;
4
+ };
5
+ /**
6
+ * @description
7
+ * `useDebouncedCallback` is a React hook that returns a debounced version of the provided callback function.
8
+ * It helps optimize event handling by delaying function execution and grouping multiple calls into one.
9
+ *
10
+ * Note that if both 'leading' and 'trailing' are set, the function will be called at both the start and end of the delay period. However, it must be called at least twice within debounceMs interval for this to happen, since one debounced function call cannot trigger the function twice.
11
+ *
12
+ * @param {Object} options - The options object.
13
+ * @param {Function} options.onChange - The callback function to debounce.
14
+ * @param {number} options.timeThreshold - The number of milliseconds to delay the function execution.
15
+ * @param {boolean} [options.leading=false] - If `true`, the function is called at the start of the sequence.
16
+ * @param {boolean} [options.trailing=true] - If `true`, the function is called at the end of the sequence.
17
+ *
18
+ * @returns {Function} A debounced function that delays invoking the callback.
19
+ *
20
+ * @example
21
+ * function SearchInput() {
22
+ * const [query, setQuery] = useState('');
23
+ * const debouncedSetQuery = useDebouncedCallback({ onChange: setQuery, timeThreshold: 100 });
24
+ * return <input type="text" onChange={(e) => debouncedSetQuery(e.target.value)} />;
25
+ * }
26
+ */
27
+ declare function useDebouncedCallback({ onChange, timeThreshold, leading, trailing, }: DebounceOptions & {
28
+ onChange: (newValue: boolean) => void;
29
+ timeThreshold: number;
30
+ }): (nextValue: boolean) => void;
31
+
32
+ export { useDebouncedCallback };
@@ -11,10 +11,10 @@ type UseDoubleClickProps<E extends HTMLElement> = {
11
11
  * It delays the single click callback execution for a specified time, and cancels it if a second click (i.e. a double click) occurs within that time.
12
12
  *
13
13
  * @template {HTMLElement} E - The specific type of HTMLElement to be used with this hook (e.g., HTMLButtonElement, HTMLDivElement).
14
- * @param {Object} params - Configuration options for click handling.
15
- * @param {number} [params.delay=250] - The number of milliseconds to wait before triggering the single click callback. Defaults to 250ms.
16
- * @param {(event: MouseEvent<E>) => void} [params.click] - The callback function to be executed on a single click.
17
- * @param {(event: MouseEvent<E>) => void} params.doubleClick - The callback function to be executed on a double click. Required.
14
+ * @param {Object} props - Configuration options for click handling.
15
+ * @param {number} [props.delay=250] - The number of milliseconds to wait before triggering the single click callback. Defaults to 250ms.
16
+ * @param {(event: MouseEvent<E>) => void} [props.click] - The callback function to be executed on a single click.
17
+ * @param {(event: MouseEvent<E>) => void} props.doubleClick - The callback function to be executed on a double click. Required.
18
18
  *
19
19
  * @returns {(event: MouseEvent<E>) => void} A click handler function to attach to an element's `onClick` event.
20
20
  *
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/hooks/useGeolocation/index.ts
21
+ var useGeolocation_exports = {};
22
+ __export(useGeolocation_exports, {
23
+ useGeolocation: () => useGeolocation
24
+ });
25
+ module.exports = __toCommonJS(useGeolocation_exports);
26
+
27
+ // src/hooks/useGeolocation/useGeolocation.ts
28
+ var import_react = require("react");
29
+ var CustomGeoLocationError = class extends Error {
30
+ code;
31
+ constructor({ code, message }) {
32
+ super(message);
33
+ this.name = "CustomGeoLocationError";
34
+ this.code = code;
35
+ }
36
+ };
37
+ var GeolocationMountBehavior = {
38
+ GET: "get",
39
+ WATCH: "watch"
40
+ };
41
+ function useGeolocation(options) {
42
+ const [state, setState] = (0, import_react.useState)({
43
+ loading: !!options?.mountBehavior,
44
+ error: null,
45
+ data: null
46
+ });
47
+ const [isTracking, setIsTracking] = (0, import_react.useState)(false);
48
+ const watchIdRef = (0, import_react.useRef)(null);
49
+ const checkGeolocationSupport = (0, import_react.useCallback)(() => {
50
+ if (typeof window === "undefined" || navigator.geolocation === void 0) {
51
+ setState((prev) => ({
52
+ ...prev,
53
+ loading: false,
54
+ error: new CustomGeoLocationError({
55
+ code: 0,
56
+ message: "Geolocation is not supported by this environment."
57
+ })
58
+ }));
59
+ return false;
60
+ }
61
+ return true;
62
+ }, []);
63
+ const handleSuccess = (0, import_react.useCallback)((position) => {
64
+ const { coords } = position;
65
+ setState((prev) => ({
66
+ ...prev,
67
+ loading: false,
68
+ error: null,
69
+ data: {
70
+ latitude: coords.latitude,
71
+ longitude: coords.longitude,
72
+ accuracy: coords.accuracy,
73
+ altitude: coords.altitude,
74
+ altitudeAccuracy: coords.altitudeAccuracy,
75
+ heading: coords.heading,
76
+ speed: coords.speed,
77
+ timestamp: position.timestamp
78
+ }
79
+ }));
80
+ }, []);
81
+ const handleError = (0, import_react.useCallback)((error) => {
82
+ const { code, message } = error;
83
+ setState((prev) => ({
84
+ ...prev,
85
+ loading: false,
86
+ error: new CustomGeoLocationError({ code, message })
87
+ }));
88
+ }, []);
89
+ const getGeolocationOptions = (0, import_react.useCallback)(
90
+ () => ({
91
+ enableHighAccuracy: options?.enableHighAccuracy,
92
+ maximumAge: options?.maximumAge,
93
+ timeout: options?.timeout
94
+ }),
95
+ [options?.enableHighAccuracy, options?.maximumAge, options?.timeout]
96
+ );
97
+ const getCurrentPosition = (0, import_react.useCallback)(() => {
98
+ if (!checkGeolocationSupport()) {
99
+ return;
100
+ }
101
+ setState((prev) => ({ ...prev, loading: true }));
102
+ navigator.geolocation.getCurrentPosition(handleSuccess, handleError, getGeolocationOptions());
103
+ }, [handleSuccess, handleError, getGeolocationOptions, checkGeolocationSupport]);
104
+ const startTracking = (0, import_react.useCallback)(() => {
105
+ if (!checkGeolocationSupport()) {
106
+ return;
107
+ }
108
+ if (watchIdRef.current !== null) {
109
+ navigator.geolocation.clearWatch(watchIdRef.current);
110
+ }
111
+ setState((prev) => ({ ...prev, loading: true }));
112
+ watchIdRef.current = navigator.geolocation.watchPosition(
113
+ (position) => {
114
+ setIsTracking(true);
115
+ handleSuccess(position);
116
+ },
117
+ handleError,
118
+ getGeolocationOptions()
119
+ );
120
+ }, [handleSuccess, handleError, getGeolocationOptions, checkGeolocationSupport]);
121
+ const stopTracking = (0, import_react.useCallback)(() => {
122
+ if (watchIdRef.current === null) {
123
+ return;
124
+ }
125
+ navigator.geolocation.clearWatch(watchIdRef.current);
126
+ watchIdRef.current = null;
127
+ setIsTracking(false);
128
+ }, []);
129
+ (0, import_react.useEffect)(() => {
130
+ if (options?.mountBehavior === GeolocationMountBehavior.WATCH) {
131
+ startTracking();
132
+ } else if (options?.mountBehavior === GeolocationMountBehavior.GET) {
133
+ getCurrentPosition();
134
+ }
135
+ return () => {
136
+ if (watchIdRef.current !== null) {
137
+ navigator.geolocation.clearWatch(watchIdRef.current);
138
+ watchIdRef.current = null;
139
+ }
140
+ };
141
+ }, [options?.mountBehavior, getCurrentPosition, startTracking]);
142
+ return {
143
+ ...state,
144
+ getCurrentPosition,
145
+ startTracking,
146
+ stopTracking,
147
+ isTracking
148
+ };
149
+ }
150
+ // Annotate the CommonJS export names for ESM import in node:
151
+ 0 && (module.exports = {
152
+ useGeolocation
153
+ });
@@ -0,0 +1,106 @@
1
+ declare class CustomGeoLocationError extends Error {
2
+ code: number;
3
+ constructor({ code, message }: {
4
+ message: string;
5
+ code: number;
6
+ });
7
+ }
8
+ type GeolocationData = {
9
+ latitude: number;
10
+ longitude: number;
11
+ accuracy: number;
12
+ altitude: number | null;
13
+ altitudeAccuracy: number | null;
14
+ heading: number | null;
15
+ speed: number | null;
16
+ timestamp: number;
17
+ };
18
+ declare const GeolocationMountBehavior: {
19
+ readonly GET: "get";
20
+ readonly WATCH: "watch";
21
+ };
22
+ type GeolocationMountBehaviorType = (typeof GeolocationMountBehavior)[keyof typeof GeolocationMountBehavior];
23
+ type GeolocationOptions = {
24
+ mountBehavior?: GeolocationMountBehaviorType;
25
+ } & PositionOptions;
26
+ /**
27
+ * @description
28
+ * `useGeolocation` is a React hook that retrieves and tracks the user's geographical location.
29
+ * It uses the browser's `Geolocation API` to support both one-time position retrieval and continuous location tracking.
30
+ *
31
+ * @param {GeolocationOptions} [options] - Geolocation options configuration
32
+ * @param {GeolocationMountBehaviorType} [options.mountBehavior] - How the hook behaves on mount:
33
+ * -- If not provided, no automatic location fetching occurs
34
+ * -- `get`: automatically fetches location once when component mounts
35
+ * -- `watch`: automatically starts tracking location changes when component mounts
36
+ * @param {boolean} [options.enableHighAccuracy=false] - If true, provides more accurate position information (increases battery consumption)
37
+ * @param {number} [options.maximumAge=0] - Maximum age in milliseconds of a cached position that is acceptable to return
38
+ * @param {number} [options.timeout=Infinity] - Maximum time (in milliseconds) allowed for the location request
39
+ *
40
+ * @returns {Object} Object containing location data and related functions
41
+ * - loading `boolean` - Whether location data is currently being fetched;
42
+ * - error `CustomGeoLocationError|null` - Error object if an error occurred, or null
43
+ * The hook uses standard Geolocation API error codes (`1-3`) and adds a custom code (`0`)
44
+ * : `0` - Geolocation is not supported by the environment
45
+ * : `1` - User denied permission to access geolocation
46
+ * : `2` - Position unavailable
47
+ * : `3` - Timeout - geolocation request took too long;
48
+ * - data `GeolocationData|null` - Location data object or null
49
+ * : latitude `number` - The latitude in decimal degrees
50
+ * : longitude `number` - The longitude in decimal degrees
51
+ * : accuracy `number` - The accuracy of position in meters
52
+ * : altitude `number|null` - The altitude in meters above the WGS84 ellipsoid
53
+ * : altitudeAccuracy `number|null` - The altitude accuracy in meters
54
+ * : heading `number|null` - The heading in degrees clockwise from true north
55
+ * : speed `number|null` - The speed in meters per second
56
+ * : timestamp `number` - The time when the position was retrieved;
57
+ * - getCurrentPosition `Function` - Function to get the current position once;
58
+ * - startTracking `Function` - Function to start tracking location changes;
59
+ * - stopTracking `Function` - Function to stop tracking location;
60
+ * - isTracking `boolean` - Whether location tracking is currently active;
61
+ *
62
+ * @example
63
+ * // Basic usage
64
+ * const {
65
+ * loading,
66
+ * error,
67
+ * data,
68
+ * getCurrentPosition
69
+ * } = useGeolocation();
70
+ *
71
+ * // Automatically fetch location when component mounts
72
+ * const {
73
+ * loading,
74
+ * error,
75
+ * data
76
+ * } = useGeolocation({ mountBehavior: 'get' });
77
+ *
78
+ * // Location tracking
79
+ * const {
80
+ * loading,
81
+ * error,
82
+ * data,
83
+ * startTracking,
84
+ * stopTracking,
85
+ * isTracking
86
+ * } = useGeolocation();
87
+ *
88
+ * const handleStartTracking = () => {
89
+ * startTracking();
90
+ * };
91
+ *
92
+ * const handleStopTracking = () => {
93
+ * stopTracking();
94
+ * };
95
+ */
96
+ declare function useGeolocation(options?: GeolocationOptions): {
97
+ getCurrentPosition: () => void;
98
+ startTracking: () => void;
99
+ stopTracking: () => void;
100
+ isTracking: boolean;
101
+ loading: boolean;
102
+ error: CustomGeoLocationError | null;
103
+ data: GeolocationData | null;
104
+ };
105
+
106
+ export { useGeolocation };
@@ -7,8 +7,8 @@ type UseImpressionRefOptions = Partial<{
7
7
  }>;
8
8
  /**
9
9
  * @description
10
- * `useImpressionRef` is a custom hook that measures the time a specific DOM element is visible on the screen and executes callbacks when the element enters or exits the viewport.
11
- * This hook uses `IntersectionObserver` and the `Visibility API` to track the element's visibility.
10
+ * `useImpressionRef` is a React hook that measures the time a specific DOM element is visible on the screen and executes callbacks when the element enters or exits the viewport.
11
+ * It uses `IntersectionObserver` and the `Visibility API` to track the element's visibility.
12
12
  *
13
13
  * @param {UseImpressionRefOptions} options - Options for tracking the element's visibility.
14
14
  * @param {() => void} [options.onImpressionStart] - Callback function executed when the element enters the view
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @description
3
- * `useIntersectionObserver` is a custom hook that detects whether a specific DOM element is visible on the screen.
4
- * This hook uses the `IntersectionObserver` API to execute a callback when the element enters or exits the viewport.
3
+ * `useIntersectionObserver` is a React hook that detects whether a specific DOM element is visible on the screen.
4
+ * It uses the `IntersectionObserver` API to execute a callback when the element enters or exits the viewport.
5
5
  *
6
6
  * @param {(entry: IntersectionObserverEntry) => void} callback - A callback function that is executed when the visibility of the element changes.
7
7
  * You can check `entry.isIntersecting` to determine if the element is in view.
@@ -2,11 +2,11 @@ import { useEffect } from 'react';
2
2
 
3
3
  /**
4
4
  * @description
5
- * During SSR, there is no DOM to synchronously measure or mutate, so React warns about using useLayoutEffect.
5
+ * `useIsomorphicLayoutEffect` is a React hook that provides the behavior of `useLayoutEffect` without triggering warnings during server-side rendering.
6
+ * During SSR, there is no DOM to synchronously measure or mutate, so React warns about using `useLayoutEffect`.
6
7
  *
7
- * This hook provides the behavior of useLayoutEffect in the browser without triggering SSR warnings.
8
+ * This hook runs synchronously after DOM updates but before paint, making it ideal for:
8
9
  *
9
- * It runs synchronously after DOM updates but before paint, making it ideal for:
10
10
  * - Measuring DOM elements after render
11
11
  * - Applying DOM changes before paint
12
12
  * - Preventing UI flashes or layout shifts