@dcl/hooks 0.1.1-20251127124412.commit-425c22a → 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 +50 -0
- package/cjs/hooks/index.d.ts +8 -6
- package/cjs/hooks/index.js +12 -10
- package/cjs/hooks/index.js.map +1 -1
- package/cjs/hooks/useInfiniteScroll.d.ts +25 -0
- package/cjs/hooks/useInfiniteScroll.js +45 -0
- package/cjs/hooks/useInfiniteScroll.js.map +1 -0
- package/esm/hooks/index.d.ts +8 -6
- package/esm/hooks/index.js +5 -4
- package/esm/hooks/index.js.map +1 -1
- package/esm/hooks/useInfiniteScroll.d.ts +25 -0
- package/esm/hooks/useInfiniteScroll.js +42 -0
- package/esm/hooks/useInfiniteScroll.js.map +1 -0
- package/package.json +2 -2
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:
|
package/cjs/hooks/index.d.ts
CHANGED
|
@@ -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 {
|
|
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";
|
package/cjs/hooks/index.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.usePageTracking = exports.
|
|
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
|
|
15
|
-
Object.defineProperty(exports, "
|
|
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
|
package/cjs/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;;
|
|
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"}
|
package/esm/hooks/index.d.ts
CHANGED
|
@@ -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 {
|
|
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";
|
package/esm/hooks/index.js
CHANGED
|
@@ -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 {
|
|
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
|
package/esm/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"
|
|
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.
|
|
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": "
|
|
87
|
+
"commit": "18af8a6f5206c928dea81f87997b5f77db47de32"
|
|
88
88
|
}
|