@dcl/hooks 0.1.1 → 0.1.2-20251128115325.commit-18af8a6

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/README.md CHANGED
@@ -19,6 +19,7 @@ npm install @dcl/hooks
19
19
  - `usePatchState`: Partial state updates for complex objects
20
20
  - `useAsyncEffect`: Async version of useEffect
21
21
  - `useAsyncMemo`: Async version of useMemo
22
+ - `useInfiniteScroll`: Infinite scroll functionality for loading more content
22
23
 
23
24
  ## Examples
24
25
 
@@ -66,6 +67,55 @@ function BrowserInfo() {
66
67
  }
67
68
  ```
68
69
 
70
+ ### useInfiniteScroll
71
+
72
+ ```typescript
73
+ import { useInfiniteScroll } from '@dcl/hooks'
74
+ import { useState, useEffect } from 'react'
75
+
76
+ function InfiniteList() {
77
+ const [items, setItems] = useState<string[]>([])
78
+ const [hasMore, setHasMore] = useState(true)
79
+ const [isLoading, setIsLoading] = useState(false)
80
+
81
+ const loadMore = async () => {
82
+ if (isLoading) return
83
+
84
+ setIsLoading(true)
85
+ try {
86
+ // Simulate API call
87
+ const newItems = await fetchMoreItems(items.length)
88
+ setItems((prev) => [...prev, ...newItems])
89
+
90
+ // Check if there's more data
91
+ setHasMore(newItems.length > 0)
92
+ } catch (error) {
93
+ console.error('Failed to load more items:', error)
94
+ } finally {
95
+ setIsLoading(false)
96
+ }
97
+ }
98
+
99
+ useInfiniteScroll({
100
+ onLoadMore: loadMore,
101
+ hasMore,
102
+ isLoading,
103
+ threshold: 500, // Trigger when 500px from bottom
104
+ debounceMs: 500, // Minimum time between triggers (default: 500ms)
105
+ })
106
+
107
+ return (
108
+ <div>
109
+ {items.map((item, index) => (
110
+ <div key={index}>{item}</div>
111
+ ))}
112
+ {isLoading && <div>Loading more...</div>}
113
+ {!hasMore && <div>No more items</div>}
114
+ </div>
115
+ )
116
+ }
117
+ ```
118
+
69
119
  ### Analytics Hooks
70
120
 
71
121
  The package provides a set of hooks for analytics tracking using Segment. Here's how to use them:
@@ -1,12 +1,14 @@
1
- export type { AsyncStateResult, AsyncStateResultState } from "./useAsyncState";
2
- export type { AsyncMemoResult, AsyncMemoResultState } from "./useAsyncMemo";
3
1
  export type { AdvancedNavigatorUAData } from "./useAdvancedUserAgentData";
2
+ export type { AsyncMemoResult, AsyncMemoResultState } from "./useAsyncMemo";
3
+ export type { AsyncStateResult, AsyncStateResultState } from "./useAsyncState";
4
+ export type { UseInfiniteScrollOptions } from "./useInfiniteScroll";
4
5
  export { useAdvancedUserAgentData } from "./useAdvancedUserAgentData";
6
+ export { useAnalytics } from "./useAnalytics";
7
+ export { useAsyncEffect } from "./useAsyncEffect";
8
+ export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
5
9
  export { useAsyncState, createAsyncStateState } from "./useAsyncState";
6
10
  export { useAsyncTask } from "./useAsyncTask";
7
11
  export { useAsyncTasks } from "./useAsyncTasks";
8
- export { usePatchState } from "./usePatchState";
9
- export { useAsyncEffect } from "./useAsyncEffect";
10
- export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
11
- export { useAnalytics } from "./useAnalytics";
12
+ export { useInfiniteScroll } from "./useInfiniteScroll";
12
13
  export { usePageTracking } from "./usePageTracking";
14
+ export { usePatchState } from "./usePatchState";
@@ -1,9 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.usePageTracking = exports.useAnalytics = exports.createAsyncMemoState = exports.useAsyncMemo = exports.useAsyncEffect = exports.usePatchState = exports.useAsyncTasks = exports.useAsyncTask = exports.createAsyncStateState = exports.useAsyncState = exports.useAdvancedUserAgentData = void 0;
3
+ exports.usePatchState = exports.usePageTracking = exports.useInfiniteScroll = exports.useAsyncTasks = exports.useAsyncTask = exports.createAsyncStateState = exports.useAsyncState = exports.createAsyncMemoState = exports.useAsyncMemo = exports.useAsyncEffect = exports.useAnalytics = exports.useAdvancedUserAgentData = void 0;
4
4
  // Hooks
5
5
  var useAdvancedUserAgentData_1 = require("./useAdvancedUserAgentData");
6
6
  Object.defineProperty(exports, "useAdvancedUserAgentData", { enumerable: true, get: function () { return useAdvancedUserAgentData_1.useAdvancedUserAgentData; } });
7
+ var useAnalytics_1 = require("./useAnalytics");
8
+ Object.defineProperty(exports, "useAnalytics", { enumerable: true, get: function () { return useAnalytics_1.useAnalytics; } });
9
+ var useAsyncEffect_1 = require("./useAsyncEffect");
10
+ Object.defineProperty(exports, "useAsyncEffect", { enumerable: true, get: function () { return useAsyncEffect_1.useAsyncEffect; } });
11
+ var useAsyncMemo_1 = require("./useAsyncMemo");
12
+ Object.defineProperty(exports, "useAsyncMemo", { enumerable: true, get: function () { return useAsyncMemo_1.useAsyncMemo; } });
13
+ Object.defineProperty(exports, "createAsyncMemoState", { enumerable: true, get: function () { return useAsyncMemo_1.createAsyncMemoState; } });
7
14
  var useAsyncState_1 = require("./useAsyncState");
8
15
  Object.defineProperty(exports, "useAsyncState", { enumerable: true, get: function () { return useAsyncState_1.useAsyncState; } });
9
16
  Object.defineProperty(exports, "createAsyncStateState", { enumerable: true, get: function () { return useAsyncState_1.createAsyncStateState; } });
@@ -11,15 +18,10 @@ var useAsyncTask_1 = require("./useAsyncTask");
11
18
  Object.defineProperty(exports, "useAsyncTask", { enumerable: true, get: function () { return useAsyncTask_1.useAsyncTask; } });
12
19
  var useAsyncTasks_1 = require("./useAsyncTasks");
13
20
  Object.defineProperty(exports, "useAsyncTasks", { enumerable: true, get: function () { return useAsyncTasks_1.useAsyncTasks; } });
14
- var usePatchState_1 = require("./usePatchState");
15
- Object.defineProperty(exports, "usePatchState", { enumerable: true, get: function () { return usePatchState_1.usePatchState; } });
16
- var useAsyncEffect_1 = require("./useAsyncEffect");
17
- Object.defineProperty(exports, "useAsyncEffect", { enumerable: true, get: function () { return useAsyncEffect_1.useAsyncEffect; } });
18
- var useAsyncMemo_1 = require("./useAsyncMemo");
19
- Object.defineProperty(exports, "useAsyncMemo", { enumerable: true, get: function () { return useAsyncMemo_1.useAsyncMemo; } });
20
- Object.defineProperty(exports, "createAsyncMemoState", { enumerable: true, get: function () { return useAsyncMemo_1.createAsyncMemoState; } });
21
- var useAnalytics_1 = require("./useAnalytics");
22
- Object.defineProperty(exports, "useAnalytics", { enumerable: true, get: function () { return useAnalytics_1.useAnalytics; } });
21
+ var useInfiniteScroll_1 = require("./useInfiniteScroll");
22
+ Object.defineProperty(exports, "useInfiniteScroll", { enumerable: true, get: function () { return useInfiniteScroll_1.useInfiniteScroll; } });
23
23
  var usePageTracking_1 = require("./usePageTracking");
24
24
  Object.defineProperty(exports, "usePageTracking", { enumerable: true, get: function () { return usePageTracking_1.usePageTracking; } });
25
+ var usePatchState_1 = require("./usePatchState");
26
+ Object.defineProperty(exports, "usePatchState", { enumerable: true, get: function () { return usePatchState_1.usePatchState; } });
25
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;;AAKA,QAAQ;AACR,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA;AACjC,iDAAsE;AAA7D,8GAAA,aAAa,OAAA;AAAE,sHAAA,qBAAqB,OAAA;AAC7C,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,+CAAmE;AAA1D,4GAAA,YAAY,OAAA;AAAE,oHAAA,oBAAoB,OAAA;AAC3C,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,qDAAmD;AAA1C,kHAAA,eAAe,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;;AAMA,QAAQ;AACR,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA;AACjC,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,+CAAmE;AAA1D,4GAAA,YAAY,OAAA;AAAE,oHAAA,oBAAoB,OAAA;AAC3C,iDAAsE;AAA7D,8GAAA,aAAa,OAAA;AAAE,sHAAA,qBAAqB,OAAA;AAC7C,+CAA6C;AAApC,4GAAA,YAAY,OAAA;AACrB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA;AACtB,yDAAuD;AAA9C,sHAAA,iBAAiB,OAAA;AAC1B,qDAAmD;AAA1C,kHAAA,eAAe,OAAA;AACxB,iDAA+C;AAAtC,8GAAA,aAAa,OAAA"}
@@ -0,0 +1,25 @@
1
+ interface UseInfiniteScrollOptions {
2
+ /** Callback to trigger when user scrolls near the end */
3
+ onLoadMore: () => void;
4
+ /** Whether more data is available to load */
5
+ hasMore: boolean;
6
+ /** Whether data is currently loading */
7
+ isLoading: boolean;
8
+ /** Distance from bottom (in pixels) to trigger load. Default: 500 */
9
+ threshold?: number;
10
+ /** Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500 */
11
+ debounceMs?: number;
12
+ }
13
+ /**
14
+ * Hook to implement infinite scroll functionality
15
+ * Triggers onLoadMore callback when user scrolls near the bottom of the page
16
+ * @param options - Configuration options for infinite scroll
17
+ * @param options.onLoadMore - Callback to trigger when user scrolls near the end
18
+ * @param options.hasMore - Whether more data is available to load
19
+ * @param options.isLoading - Whether data is currently loading
20
+ * @param options.threshold - Distance from bottom (in pixels) to trigger load. Default: 500
21
+ * @param options.debounceMs - Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500
22
+ */
23
+ declare const useInfiniteScroll: ({ onLoadMore, hasMore, isLoading, threshold, debounceMs, }: UseInfiniteScrollOptions) => void;
24
+ export { useInfiniteScroll };
25
+ export type { UseInfiniteScrollOptions };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useInfiniteScroll = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook to implement infinite scroll functionality
7
+ * Triggers onLoadMore callback when user scrolls near the bottom of the page
8
+ * @param options - Configuration options for infinite scroll
9
+ * @param options.onLoadMore - Callback to trigger when user scrolls near the end
10
+ * @param options.hasMore - Whether more data is available to load
11
+ * @param options.isLoading - Whether data is currently loading
12
+ * @param options.threshold - Distance from bottom (in pixels) to trigger load. Default: 500
13
+ * @param options.debounceMs - Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500
14
+ */
15
+ const useInfiniteScroll = ({ onLoadMore, hasMore, isLoading, threshold = 500, debounceMs = 500, }) => {
16
+ const onLoadMoreRef = (0, react_1.useRef)(onLoadMore);
17
+ const lastTriggerRef = (0, react_1.useRef)(0);
18
+ (0, react_1.useEffect)(() => {
19
+ onLoadMoreRef.current = onLoadMore;
20
+ }, [onLoadMore]);
21
+ (0, react_1.useEffect)(() => {
22
+ const handleScroll = () => {
23
+ const now = Date.now();
24
+ if (now - lastTriggerRef.current < debounceMs) {
25
+ return;
26
+ }
27
+ const scrollHeight = document.documentElement.scrollHeight;
28
+ const scrollTop = document.documentElement.scrollTop;
29
+ const clientHeight = document.documentElement.clientHeight;
30
+ const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
31
+ if (distanceFromBottom < threshold && hasMore && !isLoading) {
32
+ lastTriggerRef.current = now;
33
+ onLoadMoreRef.current();
34
+ }
35
+ };
36
+ window.addEventListener("scroll", handleScroll, { passive: true });
37
+ const timeoutId = setTimeout(handleScroll, 500);
38
+ return () => {
39
+ window.removeEventListener("scroll", handleScroll);
40
+ clearTimeout(timeoutId);
41
+ };
42
+ }, [hasMore, isLoading, threshold, debounceMs]);
43
+ };
44
+ exports.useInfiniteScroll = useInfiniteScroll;
45
+ //# sourceMappingURL=useInfiniteScroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":";;;AAAA,iCAAyC;AAezC;;;;;;;;;GASG;AACH,MAAM,iBAAiB,GAAG,CAAC,EACzB,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,GAAG,GAAG,EACf,UAAU,GAAG,GAAG,GACS,EAAE,EAAE;IAC7B,MAAM,aAAa,GAAG,IAAA,cAAM,EAAC,UAAU,CAAC,CAAA;IACxC,MAAM,cAAc,GAAG,IAAA,cAAM,EAAC,CAAC,CAAC,CAAA;IAEhC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,aAAa,CAAC,OAAO,GAAG,UAAU,CAAA;IACpC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,IAAI,GAAG,GAAG,cAAc,CAAC,OAAO,GAAG,UAAU,EAAE,CAAC;gBAC9C,OAAM;YACR,CAAC;YAED,MAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAA;YAC1D,MAAM,SAAS,GAAG,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAA;YACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAA;YAE1D,MAAM,kBAAkB,GAAG,YAAY,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC,CAAA;YAEpE,IAAI,kBAAkB,GAAG,SAAS,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC5D,cAAc,CAAC,OAAO,GAAG,GAAG,CAAA;gBAC5B,aAAa,CAAC,OAAO,EAAE,CAAA;YACzB,CAAC;QACH,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAElE,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,CAAA;QAE/C,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;YAClD,YAAY,CAAC,SAAS,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;AACjD,CAAC,CAAA;AAEQ,8CAAiB"}
@@ -1,12 +1,14 @@
1
- export type { AsyncStateResult, AsyncStateResultState } from "./useAsyncState";
2
- export type { AsyncMemoResult, AsyncMemoResultState } from "./useAsyncMemo";
3
1
  export type { AdvancedNavigatorUAData } from "./useAdvancedUserAgentData";
2
+ export type { AsyncMemoResult, AsyncMemoResultState } from "./useAsyncMemo";
3
+ export type { AsyncStateResult, AsyncStateResultState } from "./useAsyncState";
4
+ export type { UseInfiniteScrollOptions } from "./useInfiniteScroll";
4
5
  export { useAdvancedUserAgentData } from "./useAdvancedUserAgentData";
6
+ export { useAnalytics } from "./useAnalytics";
7
+ export { useAsyncEffect } from "./useAsyncEffect";
8
+ export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
5
9
  export { useAsyncState, createAsyncStateState } from "./useAsyncState";
6
10
  export { useAsyncTask } from "./useAsyncTask";
7
11
  export { useAsyncTasks } from "./useAsyncTasks";
8
- export { usePatchState } from "./usePatchState";
9
- export { useAsyncEffect } from "./useAsyncEffect";
10
- export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
11
- export { useAnalytics } from "./useAnalytics";
12
+ export { useInfiniteScroll } from "./useInfiniteScroll";
12
13
  export { usePageTracking } from "./usePageTracking";
14
+ export { usePatchState } from "./usePatchState";
@@ -1,11 +1,12 @@
1
1
  // Hooks
2
2
  export { useAdvancedUserAgentData } from "./useAdvancedUserAgentData";
3
+ export { useAnalytics } from "./useAnalytics";
4
+ export { useAsyncEffect } from "./useAsyncEffect";
5
+ export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
3
6
  export { useAsyncState, createAsyncStateState } from "./useAsyncState";
4
7
  export { useAsyncTask } from "./useAsyncTask";
5
8
  export { useAsyncTasks } from "./useAsyncTasks";
6
- export { usePatchState } from "./usePatchState";
7
- export { useAsyncEffect } from "./useAsyncEffect";
8
- export { useAsyncMemo, createAsyncMemoState } from "./useAsyncMemo";
9
- export { useAnalytics } from "./useAnalytics";
9
+ export { useInfiniteScroll } from "./useInfiniteScroll";
10
10
  export { usePageTracking } from "./usePageTracking";
11
+ export { usePatchState } from "./usePatchState";
11
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAKA,QAAQ;AACR,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAMA,QAAQ;AACR,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,25 @@
1
+ interface UseInfiniteScrollOptions {
2
+ /** Callback to trigger when user scrolls near the end */
3
+ onLoadMore: () => void;
4
+ /** Whether more data is available to load */
5
+ hasMore: boolean;
6
+ /** Whether data is currently loading */
7
+ isLoading: boolean;
8
+ /** Distance from bottom (in pixels) to trigger load. Default: 500 */
9
+ threshold?: number;
10
+ /** Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500 */
11
+ debounceMs?: number;
12
+ }
13
+ /**
14
+ * Hook to implement infinite scroll functionality
15
+ * Triggers onLoadMore callback when user scrolls near the bottom of the page
16
+ * @param options - Configuration options for infinite scroll
17
+ * @param options.onLoadMore - Callback to trigger when user scrolls near the end
18
+ * @param options.hasMore - Whether more data is available to load
19
+ * @param options.isLoading - Whether data is currently loading
20
+ * @param options.threshold - Distance from bottom (in pixels) to trigger load. Default: 500
21
+ * @param options.debounceMs - Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500
22
+ */
23
+ declare const useInfiniteScroll: ({ onLoadMore, hasMore, isLoading, threshold, debounceMs, }: UseInfiniteScrollOptions) => void;
24
+ export { useInfiniteScroll };
25
+ export type { UseInfiniteScrollOptions };
@@ -0,0 +1,42 @@
1
+ import { useEffect, useRef } from "react";
2
+ /**
3
+ * Hook to implement infinite scroll functionality
4
+ * Triggers onLoadMore callback when user scrolls near the bottom of the page
5
+ * @param options - Configuration options for infinite scroll
6
+ * @param options.onLoadMore - Callback to trigger when user scrolls near the end
7
+ * @param options.hasMore - Whether more data is available to load
8
+ * @param options.isLoading - Whether data is currently loading
9
+ * @param options.threshold - Distance from bottom (in pixels) to trigger load. Default: 500
10
+ * @param options.debounceMs - Minimum time (in milliseconds) between triggers to prevent multiple calls. Default: 500
11
+ */
12
+ const useInfiniteScroll = ({ onLoadMore, hasMore, isLoading, threshold = 500, debounceMs = 500, }) => {
13
+ const onLoadMoreRef = useRef(onLoadMore);
14
+ const lastTriggerRef = useRef(0);
15
+ useEffect(() => {
16
+ onLoadMoreRef.current = onLoadMore;
17
+ }, [onLoadMore]);
18
+ useEffect(() => {
19
+ const handleScroll = () => {
20
+ const now = Date.now();
21
+ if (now - lastTriggerRef.current < debounceMs) {
22
+ return;
23
+ }
24
+ const scrollHeight = document.documentElement.scrollHeight;
25
+ const scrollTop = document.documentElement.scrollTop;
26
+ const clientHeight = document.documentElement.clientHeight;
27
+ const distanceFromBottom = scrollHeight - (scrollTop + clientHeight);
28
+ if (distanceFromBottom < threshold && hasMore && !isLoading) {
29
+ lastTriggerRef.current = now;
30
+ onLoadMoreRef.current();
31
+ }
32
+ };
33
+ window.addEventListener("scroll", handleScroll, { passive: true });
34
+ const timeoutId = setTimeout(handleScroll, 500);
35
+ return () => {
36
+ window.removeEventListener("scroll", handleScroll);
37
+ clearTimeout(timeoutId);
38
+ };
39
+ }, [hasMore, isLoading, threshold, debounceMs]);
40
+ };
41
+ export { useInfiniteScroll };
42
+ //# sourceMappingURL=useInfiniteScroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAezC;;;;;;;;;GASG;AACH,MAAM,iBAAiB,GAAG,CAAC,EACzB,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,GAAG,GAAG,EACf,UAAU,GAAG,GAAG,GACS,EAAE,EAAE;IAC7B,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;IACxC,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IAEhC,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,OAAO,GAAG,UAAU,CAAA;IACpC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,IAAI,GAAG,GAAG,cAAc,CAAC,OAAO,GAAG,UAAU,EAAE,CAAC;gBAC9C,OAAM;YACR,CAAC;YAED,MAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAA;YAC1D,MAAM,SAAS,GAAG,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAA;YACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAA;YAE1D,MAAM,kBAAkB,GAAG,YAAY,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC,CAAA;YAEpE,IAAI,kBAAkB,GAAG,SAAS,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC5D,cAAc,CAAC,OAAO,GAAG,GAAG,CAAA;gBAC5B,aAAa,CAAC,OAAO,EAAE,CAAA;YACzB,CAAC;QACH,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAElE,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,CAAA;QAE/C,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;YAClD,YAAY,CAAC,SAAS,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;AACjD,CAAC,CAAA;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcl/hooks",
3
- "version": "0.1.1",
3
+ "version": "0.1.2-20251128115325.commit-18af8a6",
4
4
  "main": "cjs/index.js",
5
5
  "module": "esm/index.js",
6
6
  "exports": {
@@ -84,5 +84,5 @@
84
84
  "<rootDir>/test/setup.ts"
85
85
  ]
86
86
  },
87
- "commit": "425c22a552fd70b399fc418eb1bef091cccc4fe9"
87
+ "commit": "18af8a6f5206c928dea81f87997b5f77db47de32"
88
88
  }