react-virtual-renderer 1.0.5 → 1.0.7

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 (41) hide show
  1. package/README.md +56 -122
  2. package/dist/components/VirtualGrid.d.ts +2 -6
  3. package/dist/components/VirtualGrid.d.ts.map +1 -1
  4. package/dist/components/VirtualGrid.js +131 -143
  5. package/dist/components/VirtualGrid.js.map +1 -1
  6. package/dist/components/VirtualList.d.ts.map +1 -1
  7. package/dist/components/VirtualList.js +51 -29
  8. package/dist/components/VirtualList.js.map +1 -1
  9. package/dist/core/MeasurementSystem.d.ts +18 -24
  10. package/dist/core/MeasurementSystem.d.ts.map +1 -1
  11. package/dist/core/MeasurementSystem.js +100 -71
  12. package/dist/core/MeasurementSystem.js.map +1 -1
  13. package/dist/core/VirtualizationEngine.d.ts +9 -54
  14. package/dist/core/VirtualizationEngine.d.ts.map +1 -1
  15. package/dist/core/VirtualizationEngine.js +70 -153
  16. package/dist/core/VirtualizationEngine.js.map +1 -1
  17. package/dist/hooks/useInfiniteScroll.d.ts +28 -10
  18. package/dist/hooks/useInfiniteScroll.d.ts.map +1 -1
  19. package/dist/hooks/useInfiniteScroll.js +31 -14
  20. package/dist/hooks/useInfiniteScroll.js.map +1 -1
  21. package/dist/hooks/useLazyLoad.d.ts +32 -11
  22. package/dist/hooks/useLazyLoad.d.ts.map +1 -1
  23. package/dist/hooks/useLazyLoad.js +44 -21
  24. package/dist/hooks/useLazyLoad.js.map +1 -1
  25. package/dist/hooks/useScrollRestoration.d.ts +46 -5
  26. package/dist/hooks/useScrollRestoration.d.ts.map +1 -1
  27. package/dist/hooks/useScrollRestoration.js +138 -41
  28. package/dist/hooks/useScrollRestoration.js.map +1 -1
  29. package/dist/hooks/useVirtualList.js +1 -1
  30. package/dist/hooks/useVirtualList.js.map +1 -1
  31. package/dist/hooks/useVirtualizedSearch.d.ts +29 -29
  32. package/dist/hooks/useVirtualizedSearch.d.ts.map +1 -1
  33. package/dist/hooks/useVirtualizedSearch.js +63 -149
  34. package/dist/hooks/useVirtualizedSearch.js.map +1 -1
  35. package/dist/index.cjs.js +1 -1
  36. package/dist/index.cjs.js.map +1 -1
  37. package/dist/index.esm.js +1 -1
  38. package/dist/index.esm.js.map +1 -1
  39. package/dist/types.d.ts +28 -11
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +5 -2
@@ -1,11 +1,3 @@
1
- /**
2
- * Core virtualization engine
3
- * Handles:
4
- * - visible range calculation
5
- * - dynamic item sizing
6
- * - item measurements
7
- * - scroll positioning
8
- */
9
1
  export class VirtualizationEngine {
10
2
  constructor(estimatedItemSize = 35) {
11
3
  Object.defineProperty(this, "itemSizeMap", {
@@ -14,190 +6,115 @@ export class VirtualizationEngine {
14
6
  writable: true,
15
7
  value: {}
16
8
  });
17
- Object.defineProperty(this, "itemOffsets", {
9
+ Object.defineProperty(this, "estimatedItemSize", {
18
10
  enumerable: true,
19
11
  configurable: true,
20
12
  writable: true,
21
- value: [0]
13
+ value: void 0
22
14
  });
23
- Object.defineProperty(this, "totalSize", {
15
+ Object.defineProperty(this, "itemCount", {
24
16
  enumerable: true,
25
17
  configurable: true,
26
18
  writable: true,
27
19
  value: 0
28
20
  });
29
- Object.defineProperty(this, "estimatedItemSize", {
21
+ // 🔥 NEW: prefix sum cache (critical fix)
22
+ Object.defineProperty(this, "prefix", {
30
23
  enumerable: true,
31
24
  configurable: true,
32
25
  writable: true,
33
- value: void 0
26
+ value: [0]
27
+ });
28
+ Object.defineProperty(this, "dirty", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: true
34
33
  });
35
34
  this.estimatedItemSize = estimatedItemSize;
36
35
  }
37
- /**
38
- * Record measured item size
39
- */
36
+ setItemCount(count) {
37
+ this.itemCount = count;
38
+ this.dirty = true;
39
+ }
40
40
  recordItemSize(index, size) {
41
- if (this.itemSizeMap[index] === size) {
41
+ if (this.itemSizeMap[index] === size)
42
42
  return;
43
- }
44
43
  this.itemSizeMap[index] = size;
45
- this.recalculateOffsets();
44
+ this.dirty = true;
46
45
  }
47
- /**
48
- * Recalculate item offsets
49
- */
50
- recalculateOffsets() {
51
- let offset = 0;
52
- this.itemOffsets = [0];
53
- const indexes = Object.keys(this.itemSizeMap)
54
- .map(Number)
55
- .sort((a, b) => a - b);
56
- for (const index of indexes) {
57
- const size = this.itemSizeMap[index] ??
58
- this.estimatedItemSize;
59
- offset += size;
60
- this.itemOffsets[index + 1] = offset;
46
+ rebuildPrefix() {
47
+ let sum = 0;
48
+ this.prefix = [0];
49
+ for (let i = 0; i < this.itemCount; i++) {
50
+ sum += this.itemSizeMap[i] ?? this.estimatedItemSize;
51
+ this.prefix[i + 1] = sum;
61
52
  }
62
- this.totalSize = offset;
53
+ this.dirty = false;
63
54
  }
64
- /**
65
- * Get item size
66
- */
67
55
  getItemSize(index) {
68
- return (this.itemSizeMap[index] ??
69
- this.estimatedItemSize);
56
+ return this.itemSizeMap[index] ?? this.estimatedItemSize;
70
57
  }
71
- /**
72
- * Get item offset
73
- */
74
58
  getItemOffset(index) {
75
- if (this.itemOffsets[index] !== undefined) {
76
- return this.itemOffsets[index];
77
- }
78
- let offset = 0;
79
- for (let i = 0; i < index; i++) {
80
- offset += this.getItemSize(i);
81
- }
82
- return offset;
59
+ if (this.dirty)
60
+ this.rebuildPrefix();
61
+ return this.prefix[index] ?? 0;
83
62
  }
84
- /**
85
- * Get total size
86
- */
87
63
  getTotalSize() {
88
- return this.totalSize;
64
+ if (this.dirty)
65
+ this.rebuildPrefix();
66
+ return this.prefix[this.itemCount] || 0;
89
67
  }
90
- /**
91
- * Calculate visible range
92
- */
93
- getVisibleRange(scrollOffset, containerSize, itemCount, overscan = 5, scrollDirection = 'forward') {
94
- /**
95
- * Reverse scrolling support
96
- */
97
- if (scrollDirection === 'reverse') {
98
- return this.getVisibleRangeReverse(scrollOffset, containerSize, itemCount, overscan);
99
- }
100
- let startIndex = 0;
101
- let endIndex = itemCount - 1;
102
- /**
103
- * Find start index
104
- */
105
- for (let i = 0; i < itemCount; i++) {
106
- const itemOffset = this.getItemOffset(i);
107
- const itemSize = this.getItemSize(i);
108
- if (itemOffset + itemSize >=
109
- scrollOffset) {
110
- startIndex = i;
111
- break;
112
- }
113
- }
114
- /**
115
- * Find end index
116
- */
117
- for (let i = startIndex; i < itemCount; i++) {
118
- const itemOffset = this.getItemOffset(i);
119
- if (itemOffset >=
120
- scrollOffset + containerSize) {
121
- endIndex = i;
122
- break;
123
- }
68
+ binarySearch(offset) {
69
+ if (this.dirty)
70
+ this.rebuildPrefix();
71
+ let low = 0;
72
+ let high = this.itemCount - 1;
73
+ while (low <= high) {
74
+ const mid = (low + high) >> 1;
75
+ const value = this.prefix[mid];
76
+ if (value === offset)
77
+ return mid;
78
+ if (value < offset)
79
+ low = mid + 1;
80
+ else
81
+ high = mid - 1;
124
82
  }
83
+ return Math.max(0, low - 1);
84
+ }
85
+ getVisibleRange(scrollOffset, containerSize, itemCount, overscan = 5) {
86
+ this.setItemCount(itemCount);
87
+ const start = this.binarySearch(scrollOffset);
88
+ const end = this.binarySearch(scrollOffset + containerSize);
125
89
  return {
126
- startIndex: Math.max(0, startIndex - overscan),
127
- endIndex: Math.min(itemCount - 1, endIndex + overscan),
128
- overscanStartIndex: startIndex,
129
- overscanEndIndex: endIndex,
90
+ startIndex: Math.max(0, start - overscan),
91
+ endIndex: Math.min(itemCount - 1, end + overscan),
92
+ overscanStartIndex: start,
93
+ overscanEndIndex: end,
130
94
  };
131
95
  }
132
- /**
133
- * Reverse scrolling support
134
- */
135
- getVisibleRangeReverse(scrollOffset, containerSize, itemCount, overscan) {
136
- const totalSize = this.getTotalSize();
137
- const reversedScrollOffset = Math.max(0, totalSize -
138
- scrollOffset -
139
- containerSize);
140
- return this.getVisibleRange(reversedScrollOffset, containerSize, itemCount, overscan, 'forward');
141
- }
142
- /**
143
- * Get visible items
144
- */
145
- getVisibleItems(scrollOffset, containerSize, itemCount, overscan, scrollDirection = 'forward') {
146
- const range = this.getVisibleRange(scrollOffset, containerSize, itemCount, overscan, scrollDirection);
147
- const visibleItems = [];
148
- for (let i = range.startIndex; i <= range.endIndex &&
149
- i < itemCount; i++) {
150
- visibleItems.push({
96
+ getVisibleItems(scrollOffset, containerSize, itemCount, overscan) {
97
+ const range = this.getVisibleRange(scrollOffset, containerSize, itemCount, overscan);
98
+ const items = [];
99
+ for (let i = range.startIndex; i <= range.endIndex; i++) {
100
+ items.push({
151
101
  index: i,
152
102
  size: this.getItemSize(i),
153
103
  offset: this.getItemOffset(i),
154
104
  });
155
105
  }
156
- return visibleItems;
106
+ return items;
157
107
  }
158
- /**
159
- * Scroll offset for item index
160
- */
161
108
  getScrollOffsetForIndex(index, containerSize, alignment = 'start') {
162
- const itemOffset = this.getItemOffset(index);
163
- const itemSize = this.getItemSize(index);
164
- switch (alignment) {
165
- case 'center':
166
- return Math.max(0, itemOffset -
167
- (containerSize -
168
- itemSize) /
169
- 2);
170
- case 'end':
171
- return Math.max(0, itemOffset -
172
- containerSize +
173
- itemSize);
174
- case 'start':
175
- default:
176
- return Math.max(0, itemOffset);
109
+ const offset = this.getItemOffset(index);
110
+ const size = this.getItemSize(index);
111
+ if (alignment === 'center') {
112
+ return Math.max(0, offset - (containerSize - size) / 2);
177
113
  }
178
- }
179
- /**
180
- * Clear cache
181
- */
182
- clearCache() {
183
- this.itemSizeMap = {};
184
- this.itemOffsets = [0];
185
- this.totalSize = 0;
186
- }
187
- /**
188
- * Get cache
189
- */
190
- getCache() {
191
- return {
192
- ...this.itemSizeMap,
193
- };
194
- }
195
- /**
196
- * Adaptive overscan
197
- */
198
- getAdaptiveOverscan(scrollVelocity, baseOverscan = 5) {
199
- const velocityFactor = Math.min(3, Math.max(1, scrollVelocity / 10));
200
- return Math.ceil(baseOverscan * velocityFactor);
114
+ if (alignment === 'end') {
115
+ return Math.max(0, offset - containerSize + size);
116
+ }
117
+ return Math.max(0, offset);
201
118
  }
202
119
  }
203
120
  //# sourceMappingURL=VirtualizationEngine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizationEngine.js","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VirtualizationEngine.js","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,34 @@
1
- interface UseInfiniteScrollParams {
2
- onLoadMore: () => Promise<void>;
1
+ export interface UseInfiniteScrollParams {
2
+ /**
3
+ * Callback triggered when user reaches threshold.
4
+ */
5
+ onLoadMore: () => void | Promise<void>;
6
+ /**
7
+ * Distance from bottom before triggering load.
8
+ * Default: 500px
9
+ */
3
10
  threshold?: number;
11
+ /**
12
+ * External loading state.
13
+ */
4
14
  isLoading?: boolean;
15
+ /**
16
+ * Enable/disable infinite scroll.
17
+ * Default: true
18
+ */
19
+ enabled?: boolean;
5
20
  }
6
- /**
7
- * Hook for infinite scroll pagination
8
- * Automatically loads more items when user scrolls near the bottom
9
- */
10
- export declare function useInfiniteScroll({ onLoadMore, threshold, isLoading, }: UseInfiniteScrollParams): {
11
- containerRef: import("react").RefObject<HTMLDivElement>;
21
+ export interface UseInfiniteScrollReturn<T extends HTMLElement = HTMLDivElement> {
22
+ containerRef: React.RefObject<T>;
12
23
  isAtBottom: boolean;
13
24
  isLoading: boolean;
14
- };
15
- export {};
25
+ checkIfAtBottom: () => void;
26
+ }
27
+ /**
28
+ * Infinite Scroll Hook
29
+ *
30
+ * Automatically triggers `onLoadMore`
31
+ * when user scrolls near the bottom.
32
+ */
33
+ export declare function useInfiniteScroll<T extends HTMLElement = HTMLDivElement>({ onLoadMore, threshold, isLoading, enabled, }: UseInfiniteScrollParams): UseInfiniteScrollReturn<T>;
16
34
  //# sourceMappingURL=useInfiniteScroll.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useInfiniteScroll.d.ts","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAEA,UAAU,uBAAuB;IAC7B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,UAAU,EACV,SAAe,EACf,SAAiB,GACpB,EAAE,uBAAuB;;;;EAwCzB"}
1
+ {"version":3,"file":"useInfiniteScroll.d.ts","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACpC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB,CACpC,CAAC,SAAS,WAAW,GAAG,cAAc;IAEtC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,CAAC,SAAS,WAAW,GAAG,cAAc,EACxC,EACE,UAAU,EACV,SAAe,EACf,SAAiB,EACjB,OAAc,GACjB,EAAE,uBAAuB,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAiFtD"}
@@ -1,41 +1,58 @@
1
- import { useCallback, useRef, useEffect, useState } from 'react';
1
+ import { useCallback, useRef, useEffect, useState, } from 'react';
2
2
  /**
3
- * Hook for infinite scroll pagination
4
- * Automatically loads more items when user scrolls near the bottom
3
+ * Infinite Scroll Hook
4
+ *
5
+ * Automatically triggers `onLoadMore`
6
+ * when user scrolls near the bottom.
5
7
  */
6
- export function useInfiniteScroll({ onLoadMore, threshold = 500, isLoading = false, }) {
8
+ export function useInfiniteScroll({ onLoadMore, threshold = 500, isLoading = false, enabled = true, }) {
7
9
  const containerRef = useRef(null);
8
10
  const [isAtBottom, setIsAtBottom] = useState(false);
9
11
  const hasCalledRef = useRef(false);
12
+ const onLoadMoreRef = useRef(onLoadMore);
13
+ useEffect(() => {
14
+ onLoadMoreRef.current = onLoadMore;
15
+ }, [onLoadMore]);
10
16
  const checkIfAtBottom = useCallback(() => {
11
- if (!containerRef.current || isLoading)
17
+ if (!enabled || isLoading)
18
+ return;
19
+ const container = containerRef.current;
20
+ if (!container)
12
21
  return;
13
- const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
22
+ const { scrollTop, scrollHeight, clientHeight, } = container;
14
23
  const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
15
- const atBottom = distanceFromBottom < threshold;
24
+ const atBottom = distanceFromBottom <= threshold;
16
25
  setIsAtBottom(atBottom);
17
- // Trigger load when at bottom
18
- if (atBottom && !hasCalledRef.current && !isLoading) {
26
+ if (atBottom &&
27
+ !hasCalledRef.current &&
28
+ !isLoading) {
19
29
  hasCalledRef.current = true;
20
- onLoadMore().finally(() => {
30
+ Promise.resolve(onLoadMoreRef.current()).finally(() => {
21
31
  hasCalledRef.current = false;
22
32
  });
23
33
  }
24
- }, [onLoadMore, threshold, isLoading]);
34
+ }, [threshold, isLoading, enabled]);
25
35
  useEffect(() => {
36
+ if (!enabled)
37
+ return;
26
38
  const container = containerRef.current;
27
39
  if (!container)
28
40
  return;
29
41
  const handleScroll = () => {
30
42
  checkIfAtBottom();
31
43
  };
32
- container.addEventListener('scroll', handleScroll);
33
- return () => container.removeEventListener('scroll', handleScroll);
34
- }, [checkIfAtBottom]);
44
+ container.addEventListener('scroll', handleScroll, { passive: true });
45
+ // Initial check
46
+ checkIfAtBottom();
47
+ return () => {
48
+ container.removeEventListener('scroll', handleScroll);
49
+ };
50
+ }, [checkIfAtBottom, enabled]);
35
51
  return {
36
52
  containerRef,
37
53
  isAtBottom,
38
54
  isLoading,
55
+ checkIfAtBottom,
39
56
  };
40
57
  }
41
58
  //# sourceMappingURL=useInfiniteScroll.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAQjE;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAC9B,UAAU,EACV,SAAS,GAAG,GAAG,EACf,SAAS,GAAG,KAAK,GACK;IACtB,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,SAAS;YAAE,OAAO;QAE/C,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC;QACvE,MAAM,kBAAkB,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY,CAAC;QAEnE,MAAM,QAAQ,GAAG,kBAAkB,GAAG,SAAS,CAAC;QAChD,aAAa,CAAC,QAAQ,CAAC,CAAC;QAExB,8BAA8B;QAC9B,IAAI,QAAQ,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;YAClD,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;YAC5B,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACtB,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAEvC,SAAS,CAAC,GAAG,EAAE;QACX,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,eAAe,EAAE,CAAC;QACtB,CAAC,CAAC;QAEF,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACnD,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACvE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,OAAO;QACH,YAAY;QACZ,UAAU;QACV,SAAS;KACZ,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,MAAM,EACN,SAAS,EACT,QAAQ,GACX,MAAM,OAAO,CAAC;AAmCf;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAE/B,EACE,UAAU,EACV,SAAS,GAAG,GAAG,EACf,SAAS,GAAG,KAAK,EACjB,OAAO,GAAG,IAAI,GACQ;IACtB,MAAM,YAAY,GAAG,MAAM,CAAW,IAAI,CAAC,CAAC;IAE5C,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAEzC,SAAS,CAAC,GAAG,EAAE;QACX,aAAa,CAAC,OAAO,GAAG,UAAU,CAAC;IACvC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,OAAO,IAAI,SAAS;YAAE,OAAO;QAElC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QAEvC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,EACF,SAAS,EACT,YAAY,EACZ,YAAY,GACf,GAAG,SAAS,CAAC;QAEd,MAAM,kBAAkB,GACpB,YAAY,GAAG,SAAS,GAAG,YAAY,CAAC;QAE5C,MAAM,QAAQ,GAAG,kBAAkB,IAAI,SAAS,CAAC;QAEjD,aAAa,CAAC,QAAQ,CAAC,CAAC;QAExB,IACI,QAAQ;YACR,CAAC,YAAY,CAAC,OAAO;YACrB,CAAC,SAAS,EACZ,CAAC;YACC,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;YAE5B,OAAO,CAAC,OAAO,CACX,aAAa,CAAC,OAAO,EAAE,CAC1B,CAAC,OAAO,CAAC,GAAG,EAAE;gBACX,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAEpC,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QAEvC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,eAAe,EAAE,CAAC;QACtB,CAAC,CAAC;QAEF,SAAS,CAAC,gBAAgB,CACtB,QAAQ,EACR,YAAY,EACZ,EAAE,OAAO,EAAE,IAAI,EAAE,CACpB,CAAC;QAEF,gBAAgB;QAChB,eAAe,EAAE,CAAC;QAElB,OAAO,GAAG,EAAE;YACR,SAAS,CAAC,mBAAmB,CACzB,QAAQ,EACR,YAAY,CACf,CAAC;QACN,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/B,OAAO;QACH,YAAY;QACZ,UAAU;QACV,SAAS;QACT,eAAe;KAClB,CAAC;AACN,CAAC"}
@@ -1,15 +1,36 @@
1
- interface UseLazyLoadParams {
2
- threshold?: number;
1
+ import { RefObject } from 'react';
2
+ export interface UseLazyLoadParams {
3
+ /**
4
+ * Percentage of element that must be visible.
5
+ * Default: 0.1
6
+ */
7
+ threshold?: number | number[];
8
+ /**
9
+ * Callback fired when element becomes visible.
10
+ */
3
11
  onVisible?: () => void;
12
+ /**
13
+ * Root element for intersection.
14
+ */
15
+ root?: Element | null;
16
+ /**
17
+ * Root margin.
18
+ */
19
+ rootMargin?: string;
20
+ /**
21
+ * Enable/disable observer.
22
+ */
23
+ enabled?: boolean;
24
+ /**
25
+ * Stop observing after first visibility.
26
+ * Default: true
27
+ */
28
+ once?: boolean;
4
29
  }
5
- /**
6
- * Hook for lazy loading items as they become visible
7
- * Integrates with IntersectionObserver for efficiency
8
- */
9
- export declare function useLazyLoad({ threshold, onVisible }: UseLazyLoadParams): {
10
- ref: import("react").RefObject<HTMLDivElement>;
30
+ export interface UseLazyLoadReturn<T extends HTMLElement = HTMLDivElement> {
31
+ ref: RefObject<T | null>;
11
32
  isVisible: boolean;
12
- setupObserver: () => (() => void) | undefined;
13
- };
14
- export {};
33
+ entry: IntersectionObserverEntry | null;
34
+ }
35
+ export declare function useLazyLoad<T extends HTMLElement = HTMLDivElement>({ threshold, onVisible, root, rootMargin, enabled, once, }?: UseLazyLoadParams): UseLazyLoadReturn<T>;
15
36
  //# sourceMappingURL=useLazyLoad.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLazyLoad.d.ts","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":"AAEA,UAAU,iBAAiB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAe,EAAE,SAAS,EAAE,EAAE,iBAAiB;;;;EAmC5E"}
1
+ {"version":3,"file":"useLazyLoad.d.ts","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,SAAS,EACZ,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,iBAAiB;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE9B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB,CAC9B,CAAC,SAAS,WAAW,GAAG,cAAc;IAEtC,GAAG,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,WAAW,CACvB,CAAC,SAAS,WAAW,GAAG,cAAc,EACxC,EACE,SAAe,EACf,SAAS,EACT,IAAW,EACX,UAAkB,EAClB,OAAc,EACd,IAAW,GACd,GAAE,iBAAsB,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAsE/C"}
@@ -1,34 +1,57 @@
1
- import { useState, useCallback, useRef } from 'react';
2
- /**
3
- * Hook for lazy loading items as they become visible
4
- * Integrates with IntersectionObserver for efficiency
5
- */
6
- export function useLazyLoad({ threshold = 0.1, onVisible }) {
1
+ import { useState, useEffect, useRef, } from 'react';
2
+ export function useLazyLoad({ threshold = 0.1, onVisible, root = null, rootMargin = '0px', enabled = true, once = true, } = {}) {
7
3
  const [isVisible, setIsVisible] = useState(false);
4
+ const [entry, setEntry] = useState(null);
8
5
  const elementRef = useRef(null);
9
- const setupObserver = useCallback(() => {
10
- if (!elementRef.current || !('IntersectionObserver' in window)) {
11
- // Fallback: consider visible if IntersectionObserver not supported
6
+ const callbackRef = useRef(onVisible);
7
+ useEffect(() => {
8
+ callbackRef.current = onVisible;
9
+ }, [onVisible]);
10
+ useEffect(() => {
11
+ if (!enabled)
12
+ return;
13
+ const element = elementRef.current;
14
+ if (!element)
15
+ return;
16
+ // SSR / Legacy browser fallback
17
+ if (typeof window === 'undefined' ||
18
+ !('IntersectionObserver' in window)) {
12
19
  setIsVisible(true);
13
- onVisible?.();
20
+ callbackRef.current?.();
14
21
  return;
15
22
  }
16
- const observer = new IntersectionObserver(([entry]) => {
17
- if (entry.isIntersecting) {
23
+ const observer = new IntersectionObserver(([observerEntry]) => {
24
+ setEntry(observerEntry);
25
+ if (observerEntry.isIntersecting) {
18
26
  setIsVisible(true);
19
- onVisible?.();
20
- observer.unobserve(entry.target);
27
+ callbackRef.current?.();
28
+ if (once) {
29
+ observer.unobserve(observerEntry.target);
30
+ }
31
+ }
32
+ else if (!once) {
33
+ setIsVisible(false);
21
34
  }
22
- }, { threshold });
23
- observer.observe(elementRef.current);
24
- return () => observer.disconnect();
25
- }, [threshold, onVisible]);
26
- // Setup observer when component mounts
27
- // (This would be in useEffect in actual usage)
35
+ }, {
36
+ threshold,
37
+ root,
38
+ rootMargin,
39
+ });
40
+ observer.observe(element);
41
+ return () => {
42
+ observer.disconnect();
43
+ };
44
+ }, [
45
+ threshold,
46
+ root,
47
+ rootMargin,
48
+ enabled,
49
+ once,
50
+ ]);
28
51
  return {
29
52
  ref: elementRef,
30
53
  isVisible,
31
- setupObserver,
54
+ entry,
32
55
  };
33
56
  }
34
57
  //# sourceMappingURL=useLazyLoad.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLazyLoad.js","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAOtD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG,EAAE,SAAS,EAAqB;IACzE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEhD,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EAAE,CAAC;YAC7D,mEAAmE;YACnE,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,SAAS,EAAE,EAAE,CAAC;YACd,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACrC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YACR,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,YAAY,CAAC,IAAI,CAAC,CAAC;gBACnB,SAAS,EAAE,EAAE,CAAC;gBACd,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrC,CAAC;QACL,CAAC,EACD,EAAE,SAAS,EAAE,CAChB,CAAC;QAEF,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAErC,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAE3B,uCAAuC;IACvC,+CAA+C;IAC/C,OAAO;QACH,GAAG,EAAE,UAAU;QACf,SAAS;QACT,aAAa;KAChB,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"useLazyLoad.js","sourceRoot":"","sources":["../../src/hooks/useLazyLoad.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,SAAS,EACT,MAAM,GAET,MAAM,OAAO,CAAC;AA4Cf,MAAM,UAAU,WAAW,CAEzB,EACE,SAAS,GAAG,GAAG,EACf,SAAS,EACT,IAAI,GAAG,IAAI,EACX,UAAU,GAAG,KAAK,EAClB,OAAO,GAAG,IAAI,EACd,IAAI,GAAG,IAAI,MACQ,EAAE;IACrB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GACnB,QAAQ,CAAmC,IAAI,CAAC,CAAC;IAErD,MAAM,UAAU,GAAG,MAAM,CAAI,IAAI,CAAC,CAAC;IAEnC,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACX,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC;IACpC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;QAEnC,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,gCAAgC;QAChC,IACI,OAAO,MAAM,KAAK,WAAW;YAC7B,CAAC,CAAC,sBAAsB,IAAI,MAAM,CAAC,EACrC,CAAC;YACC,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACxB,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACrC,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE;YAChB,QAAQ,CAAC,aAAa,CAAC,CAAC;YAExB,IAAI,aAAa,CAAC,cAAc,EAAE,CAAC;gBAC/B,YAAY,CAAC,IAAI,CAAC,CAAC;gBACnB,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;gBAExB,IAAI,IAAI,EAAE,CAAC;oBACP,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC7C,CAAC;YACL,CAAC;iBAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;QACL,CAAC,EACD;YACI,SAAS;YACT,IAAI;YACJ,UAAU;SACb,CACJ,CAAC;QAEF,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1B,OAAO,GAAG,EAAE;YACR,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC,CAAC;IACN,CAAC,EAAE;QACC,SAAS;QACT,IAAI;QACJ,UAAU;QACV,OAAO;QACP,IAAI;KACP,CAAC,CAAC;IAEH,OAAO;QACH,GAAG,EAAE,UAAU;QACf,SAAS;QACT,KAAK;KACR,CAAC;AACN,CAAC"}
@@ -1,8 +1,49 @@
1
- /**
2
- * Hook for restoring scroll position on navigation
3
- * Useful when navigating away and coming back to a list
4
- */
5
- export declare function useScrollRestoration(key: string, containerRef: React.RefObject<HTMLDivElement>): {
1
+ export interface ScrollPosition {
2
+ key: string;
3
+ top: number;
4
+ left: number;
5
+ timestamp: number;
6
+ }
7
+ export interface UseScrollRestorationOptions {
8
+ /**
9
+ * Persist positions in storage.
10
+ * Default: true
11
+ */
12
+ persist?: boolean;
13
+ /**
14
+ * Storage key.
15
+ */
16
+ storageKey?: string;
17
+ /**
18
+ * Storage provider.
19
+ * Default: localStorage
20
+ */
21
+ storage?: Storage;
22
+ /**
23
+ * Automatically save during scrolling.
24
+ * Default: false (preserves existing behavior)
25
+ */
26
+ autoSave?: boolean;
27
+ /**
28
+ * Maximum entries retained.
29
+ * Default: 100
30
+ */
31
+ maxEntries?: number;
32
+ /**
33
+ * Delay restoration until next animation frame.
34
+ * Default: true
35
+ */
36
+ useRAF?: boolean;
37
+ /**
38
+ * Disable hook.
39
+ */
40
+ enabled?: boolean;
41
+ /**
42
+ * Error handler.
43
+ */
44
+ onError?: (error: unknown) => void;
45
+ }
46
+ export declare function useScrollRestoration<T extends HTMLElement = HTMLDivElement>(key: string, containerRef: React.RefObject<T | null>, { persist, storageKey, storage, autoSave, maxEntries, useRAF, enabled, onError, }?: UseScrollRestorationOptions): {
6
47
  savePosition: () => void;
7
48
  restorePosition: () => void;
8
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useScrollRestoration.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollRestoration.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC;;;EA6D9F"}
1
+ {"version":3,"file":"useScrollRestoration.d.ts","sourceRoot":"","sources":["../../src/hooks/useScrollRestoration.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAoBD,wBAAgB,oBAAoB,CAChC,CAAC,SAAS,WAAW,GAAG,cAAc,EAEtC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EACvC,EACI,OAAc,EACd,UAAgC,EAChC,OAAO,EACP,QAAgB,EAChB,UAAgB,EAChB,MAAa,EACb,OAAc,EACd,OAAO,GACV,GAAE,2BAAgC;;;EA4MtC"}