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.
- package/README.md +56 -122
- package/dist/components/VirtualGrid.d.ts +2 -6
- package/dist/components/VirtualGrid.d.ts.map +1 -1
- package/dist/components/VirtualGrid.js +131 -143
- package/dist/components/VirtualGrid.js.map +1 -1
- package/dist/components/VirtualList.d.ts.map +1 -1
- package/dist/components/VirtualList.js +51 -29
- package/dist/components/VirtualList.js.map +1 -1
- package/dist/core/MeasurementSystem.d.ts +18 -24
- package/dist/core/MeasurementSystem.d.ts.map +1 -1
- package/dist/core/MeasurementSystem.js +100 -71
- package/dist/core/MeasurementSystem.js.map +1 -1
- package/dist/core/VirtualizationEngine.d.ts +9 -54
- package/dist/core/VirtualizationEngine.d.ts.map +1 -1
- package/dist/core/VirtualizationEngine.js +70 -153
- package/dist/core/VirtualizationEngine.js.map +1 -1
- package/dist/hooks/useInfiniteScroll.d.ts +28 -10
- package/dist/hooks/useInfiniteScroll.d.ts.map +1 -1
- package/dist/hooks/useInfiniteScroll.js +31 -14
- package/dist/hooks/useInfiniteScroll.js.map +1 -1
- package/dist/hooks/useLazyLoad.d.ts +32 -11
- package/dist/hooks/useLazyLoad.d.ts.map +1 -1
- package/dist/hooks/useLazyLoad.js +44 -21
- package/dist/hooks/useLazyLoad.js.map +1 -1
- package/dist/hooks/useScrollRestoration.d.ts +46 -5
- package/dist/hooks/useScrollRestoration.d.ts.map +1 -1
- package/dist/hooks/useScrollRestoration.js +138 -41
- package/dist/hooks/useScrollRestoration.js.map +1 -1
- package/dist/hooks/useVirtualList.js +1 -1
- package/dist/hooks/useVirtualList.js.map +1 -1
- package/dist/hooks/useVirtualizedSearch.d.ts +29 -29
- package/dist/hooks/useVirtualizedSearch.d.ts.map +1 -1
- package/dist/hooks/useVirtualizedSearch.js +63 -149
- package/dist/hooks/useVirtualizedSearch.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/types.d.ts +28 -11
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -2
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef,
|
|
2
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useRef, } from 'react';
|
|
3
3
|
import { useVirtualList } from '../hooks/useVirtualList';
|
|
4
4
|
/**
|
|
5
5
|
* VirtualList Component
|
|
6
6
|
* Drop-in replacement for long lists with virtualization support
|
|
7
7
|
*/
|
|
8
|
-
export const VirtualList = forwardRef(({ items, renderItem, itemKey, height = 400, width = 500, itemSize, overscan = 5, scrollDirection = 'forward', onScroll, className = '', style = {}, estimatedItemSize = 35, getItemSize, stickyIndices = [], onScrollEnd, innerRef, scrollOffsetRef, }, containerRef) => {
|
|
8
|
+
export const VirtualList = forwardRef(({ items, renderItem, itemWrapper, itemKey, height = 400, width = 500, itemSize, overscan = 5, scrollDirection = 'forward', onScroll, className = '', itemClassName = '', style = {}, estimatedItemSize = 35, getItemSize, stickyIndices = [], onScrollEnd, innerRef, scrollOffsetRef, }, containerRef) => {
|
|
9
9
|
const { virtualItems, isScrolling, scrollOffset, totalSize, containerRef: internalContainerRef, innerRef: internalInnerRef, getItemStyle, } = useVirtualList({
|
|
10
10
|
items,
|
|
11
11
|
getItemKey: itemKey,
|
|
12
|
-
containerHeight: height
|
|
13
|
-
|
|
12
|
+
containerHeight: typeof height === 'number'
|
|
13
|
+
? height
|
|
14
|
+
: 400,
|
|
15
|
+
containerWidth: typeof width === 'number'
|
|
16
|
+
? width
|
|
17
|
+
: 500,
|
|
14
18
|
itemSize: getItemSize || itemSize,
|
|
15
19
|
overscan,
|
|
16
20
|
scrollDirection,
|
|
@@ -18,7 +22,6 @@ export const VirtualList = forwardRef(({ items, renderItem, itemKey, height = 40
|
|
|
18
22
|
onScroll,
|
|
19
23
|
onScrollEnd,
|
|
20
24
|
stickyIndices,
|
|
21
|
-
// scrollMargin,
|
|
22
25
|
});
|
|
23
26
|
/**
|
|
24
27
|
* Local refs
|
|
@@ -26,30 +29,22 @@ export const VirtualList = forwardRef(({ items, renderItem, itemKey, height = 40
|
|
|
26
29
|
const mergedContainerRef = useRef(null);
|
|
27
30
|
const mergedInnerRef = useRef(null);
|
|
28
31
|
/**
|
|
29
|
-
* Expose
|
|
32
|
+
* Expose container ref
|
|
30
33
|
*/
|
|
31
34
|
useImperativeHandle(containerRef, () => mergedContainerRef.current);
|
|
35
|
+
/**
|
|
36
|
+
* Expose inner ref
|
|
37
|
+
*/
|
|
32
38
|
useImperativeHandle(innerRef, () => mergedInnerRef.current);
|
|
33
39
|
/**
|
|
34
|
-
* Expose scroll offset
|
|
40
|
+
* Expose current scroll offset
|
|
35
41
|
*/
|
|
36
42
|
useEffect(() => {
|
|
37
43
|
if (scrollOffsetRef) {
|
|
38
|
-
scrollOffsetRef.current =
|
|
44
|
+
scrollOffsetRef.current =
|
|
45
|
+
scrollOffset;
|
|
39
46
|
}
|
|
40
47
|
}, [scrollOffset, scrollOffsetRef]);
|
|
41
|
-
/**
|
|
42
|
-
* Store measured DOM elements
|
|
43
|
-
*/
|
|
44
|
-
const measurementRef = useRef(new Map());
|
|
45
|
-
const handleItemRef = useCallback((element, index) => {
|
|
46
|
-
if (element) {
|
|
47
|
-
measurementRef.current.set(index, element);
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
measurementRef.current.delete(index);
|
|
51
|
-
}
|
|
52
|
-
}, []);
|
|
53
48
|
/**
|
|
54
49
|
* Container styles
|
|
55
50
|
*/
|
|
@@ -69,33 +64,60 @@ export const VirtualList = forwardRef(({ items, renderItem, itemKey, height = 40
|
|
|
69
64
|
width: '100%',
|
|
70
65
|
};
|
|
71
66
|
return (_jsx("div", { ref: (el) => {
|
|
72
|
-
mergedContainerRef.current =
|
|
73
|
-
|
|
67
|
+
mergedContainerRef.current =
|
|
68
|
+
el;
|
|
69
|
+
internalContainerRef.current =
|
|
70
|
+
el;
|
|
74
71
|
}, className: `virtualize-container ${className}`, style: containerStyle, onScroll: (e) => {
|
|
72
|
+
const target = e.target;
|
|
75
73
|
const handler = renderItem?.__scrollHandler;
|
|
76
74
|
if (handler) {
|
|
77
75
|
handler(e);
|
|
78
76
|
}
|
|
79
77
|
if (onScroll) {
|
|
80
|
-
onScroll(
|
|
78
|
+
onScroll(target.scrollTop, 'auto');
|
|
81
79
|
}
|
|
82
80
|
}, children: _jsx("div", { ref: (el) => {
|
|
83
|
-
mergedInnerRef.current =
|
|
84
|
-
|
|
81
|
+
mergedInnerRef.current =
|
|
82
|
+
el;
|
|
83
|
+
internalInnerRef.current =
|
|
84
|
+
el;
|
|
85
85
|
}, style: innerStyle, className: "virtualize-inner", children: virtualItems.map((virtualItem) => {
|
|
86
86
|
const item = items[virtualItem.index];
|
|
87
87
|
const key = itemKey
|
|
88
88
|
? itemKey(virtualItem.index, item)
|
|
89
89
|
: virtualItem.index;
|
|
90
|
+
const virtualStyle = getItemStyle(virtualItem.index, virtualItem.size);
|
|
90
91
|
const renderProps = {
|
|
91
92
|
item,
|
|
92
93
|
index: virtualItem.index,
|
|
93
|
-
|
|
94
|
+
/**
|
|
95
|
+
* @deprecated
|
|
96
|
+
* Kept only for backwards compatibility.
|
|
97
|
+
* Avoid spreading this style in renderItem.
|
|
98
|
+
*/
|
|
99
|
+
style: virtualStyle,
|
|
94
100
|
isScrolling,
|
|
95
101
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
const content = renderItem(renderProps);
|
|
103
|
+
/**
|
|
104
|
+
* Advanced wrapper API
|
|
105
|
+
*/
|
|
106
|
+
if (itemWrapper) {
|
|
107
|
+
return (_jsx(React.Fragment, { children: itemWrapper({
|
|
108
|
+
item,
|
|
109
|
+
index: virtualItem.index,
|
|
110
|
+
style: virtualStyle,
|
|
111
|
+
children: content,
|
|
112
|
+
}) }, key));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Default wrapper
|
|
116
|
+
*/
|
|
117
|
+
return (_jsx("div", { "data-virtualize-index": virtualItem.index, className: itemClassName, style: {
|
|
118
|
+
...virtualStyle,
|
|
119
|
+
boxSizing: 'border-box',
|
|
120
|
+
}, children: content }, key));
|
|
99
121
|
}) }) }));
|
|
100
122
|
});
|
|
101
123
|
VirtualList.displayName = 'VirtualList';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.js","sourceRoot":"","sources":["../../src/components/VirtualList.tsx"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"VirtualList.js","sourceRoot":"","sources":["../../src/components/VirtualList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,52 +1,46 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handles automatic measurement of item sizes using ResizeObserver
|
|
3
|
-
* Integrates with VirtualizationEngine to track dynamic sizes
|
|
4
|
-
*/
|
|
5
1
|
export declare class MeasurementSystem {
|
|
6
2
|
private resizeObserver;
|
|
7
3
|
private measurements;
|
|
8
|
-
private
|
|
4
|
+
private observedElements;
|
|
5
|
+
private pendingUpdates;
|
|
6
|
+
private rafId;
|
|
9
7
|
private onMeasure;
|
|
10
8
|
constructor();
|
|
11
9
|
/**
|
|
12
|
-
* Start measuring
|
|
10
|
+
* Start measuring container
|
|
13
11
|
*/
|
|
14
12
|
startMeasuring(container: HTMLElement, onMeasure: (index: number, size: number) => void): void;
|
|
15
13
|
/**
|
|
16
|
-
*
|
|
14
|
+
* Observe item
|
|
17
15
|
*/
|
|
18
|
-
|
|
16
|
+
observeItem(index: number, element: HTMLElement): void;
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
18
|
+
* Unobserve item
|
|
21
19
|
*/
|
|
22
|
-
|
|
20
|
+
unobserveItem(element: HTMLElement): void;
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
22
|
+
* ResizeObserver callback
|
|
25
23
|
*/
|
|
26
|
-
|
|
24
|
+
private handleResize;
|
|
27
25
|
/**
|
|
28
|
-
*
|
|
26
|
+
* Batch updates using RAF
|
|
29
27
|
*/
|
|
30
|
-
|
|
28
|
+
private flushPendingUpdates;
|
|
31
29
|
/**
|
|
32
|
-
*
|
|
30
|
+
* Fallback measurement
|
|
33
31
|
*/
|
|
34
|
-
|
|
32
|
+
syncMeasure(index: number, element: HTMLElement): void;
|
|
35
33
|
/**
|
|
36
|
-
*
|
|
34
|
+
* Preserve measurements
|
|
37
35
|
*/
|
|
36
|
+
stopMeasuring(): void;
|
|
38
37
|
getMeasurement(index: number): number | undefined;
|
|
39
|
-
/**
|
|
40
|
-
* Get all measurements
|
|
41
|
-
*/
|
|
42
38
|
getAllMeasurements(): Map<number, number>;
|
|
43
|
-
/**
|
|
44
|
-
* Clear pending measurements
|
|
45
|
-
*/
|
|
46
39
|
clearPending(): void;
|
|
47
40
|
/**
|
|
48
|
-
*
|
|
41
|
+
* Explicit cache clear
|
|
49
42
|
*/
|
|
43
|
+
clearMeasurements(): void;
|
|
50
44
|
destroy(): void;
|
|
51
45
|
}
|
|
52
46
|
//# sourceMappingURL=MeasurementSystem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeasurementSystem.d.ts","sourceRoot":"","sources":["../../src/core/MeasurementSystem.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MeasurementSystem.d.ts","sourceRoot":"","sources":["../../src/core/MeasurementSystem.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,gBAAgB,CACe;IAEvC,OAAO,CAAC,cAAc,CACQ;IAE9B,OAAO,CAAC,KAAK,CAAuB;IAEpC,OAAO,CAAC,SAAS,CAEC;;IAclB;;OAEG;IACH,cAAc,CACV,SAAS,EAAE,WAAW,EACtB,SAAS,EAAE,CACP,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,KACX,IAAI,GACV,IAAI;IA4BP;;OAEG;IACH,WAAW,CACP,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,IAAI;IAmBP;;OAEG;IACH,aAAa,CACT,OAAO,EAAE,WAAW,GACrB,IAAI;IAUP;;OAEG;IACH,OAAO,CAAC,YAAY,CAwClB;IAEF;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;OAEG;IACH,WAAW,CACP,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,IAAI;IA+BP;;OAEG;IACH,aAAa,IAAI,IAAI;IAYrB,cAAc,CACV,KAAK,EAAE,MAAM,GACd,MAAM,GAAG,SAAS;IAMrB,kBAAkB,IAAI,GAAG,CACrB,MAAM,EACN,MAAM,CACT;IAMD,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB,OAAO,IAAI,IAAI;CAWlB"}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handles automatic measurement of item sizes using ResizeObserver
|
|
3
|
-
* Integrates with VirtualizationEngine to track dynamic sizes
|
|
4
|
-
*/
|
|
5
1
|
export class MeasurementSystem {
|
|
6
2
|
constructor() {
|
|
7
3
|
Object.defineProperty(this, "resizeObserver", {
|
|
@@ -16,11 +12,23 @@ export class MeasurementSystem {
|
|
|
16
12
|
writable: true,
|
|
17
13
|
value: new Map()
|
|
18
14
|
});
|
|
19
|
-
Object.defineProperty(this, "
|
|
15
|
+
Object.defineProperty(this, "observedElements", {
|
|
20
16
|
enumerable: true,
|
|
21
17
|
configurable: true,
|
|
22
18
|
writable: true,
|
|
23
|
-
value: new
|
|
19
|
+
value: new WeakMap()
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "pendingUpdates", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: new Map()
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "rafId", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: null
|
|
24
32
|
});
|
|
25
33
|
Object.defineProperty(this, "onMeasure", {
|
|
26
34
|
enumerable: true,
|
|
@@ -28,110 +36,131 @@ export class MeasurementSystem {
|
|
|
28
36
|
writable: true,
|
|
29
37
|
value: null
|
|
30
38
|
});
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
/**
|
|
40
|
+
* ResizeObserver callback
|
|
41
|
+
*/
|
|
42
|
+
Object.defineProperty(this, "handleResize", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
configurable: true,
|
|
45
|
+
writable: true,
|
|
46
|
+
value: (entries) => {
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
const element = entry.target;
|
|
49
|
+
const index = this.observedElements.get(element);
|
|
50
|
+
if (index === undefined) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const size = Math.round(entry.contentRect.height);
|
|
54
|
+
if (this.measurements.get(index) === size) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
this.measurements.set(index, size);
|
|
58
|
+
this.pendingUpdates.set(index, size);
|
|
59
|
+
}
|
|
60
|
+
this.flushPendingUpdates();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (typeof window !== 'undefined' &&
|
|
64
|
+
'ResizeObserver' in window) {
|
|
65
|
+
this.resizeObserver =
|
|
66
|
+
new ResizeObserver(this.handleResize);
|
|
33
67
|
}
|
|
34
68
|
}
|
|
35
69
|
/**
|
|
36
|
-
* Start measuring
|
|
70
|
+
* Start measuring container
|
|
37
71
|
*/
|
|
38
72
|
startMeasuring(container, onMeasure) {
|
|
39
73
|
this.onMeasure = onMeasure;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
74
|
+
const items = container.querySelectorAll('[data-virtualize-index]');
|
|
75
|
+
items.forEach((item) => {
|
|
76
|
+
const indexAttr = item.dataset.virtualizeIndex;
|
|
77
|
+
if (indexAttr === undefined) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const index = Number(indexAttr);
|
|
81
|
+
this.observeItem(index, item);
|
|
82
|
+
});
|
|
47
83
|
}
|
|
48
84
|
/**
|
|
49
|
-
*
|
|
85
|
+
* Observe item
|
|
50
86
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
87
|
+
observeItem(index, element) {
|
|
88
|
+
element.dataset.virtualizeIndex =
|
|
89
|
+
String(index);
|
|
90
|
+
this.observedElements.set(element, index);
|
|
91
|
+
this.resizeObserver?.observe(element);
|
|
92
|
+
this.syncMeasure(index, element);
|
|
57
93
|
}
|
|
58
94
|
/**
|
|
59
|
-
*
|
|
95
|
+
* Unobserve item
|
|
60
96
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const index = element.getAttribute('data-virtualize-index');
|
|
65
|
-
if (index) {
|
|
66
|
-
const size = entry.contentRect.height || element.offsetHeight;
|
|
67
|
-
const indexNum = parseInt(index, 10);
|
|
68
|
-
// Only trigger update if size changed
|
|
69
|
-
if (this.measurements.get(indexNum) !== size) {
|
|
70
|
-
this.measurements.set(indexNum, size);
|
|
71
|
-
this.pendingMeasurements.add(indexNum);
|
|
72
|
-
if (this.onMeasure) {
|
|
73
|
-
this.onMeasure(indexNum, size);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
97
|
+
unobserveItem(element) {
|
|
98
|
+
this.resizeObserver?.unobserve(element);
|
|
99
|
+
this.observedElements.delete(element);
|
|
78
100
|
}
|
|
79
101
|
/**
|
|
80
|
-
*
|
|
102
|
+
* Batch updates using RAF
|
|
81
103
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.resizeObserver.observe(element);
|
|
104
|
+
flushPendingUpdates() {
|
|
105
|
+
if (this.rafId !== null) {
|
|
106
|
+
return;
|
|
86
107
|
}
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
this.rafId =
|
|
109
|
+
requestAnimationFrame(() => {
|
|
110
|
+
this.pendingUpdates.forEach((size, index) => {
|
|
111
|
+
this.onMeasure?.(index, size);
|
|
112
|
+
});
|
|
113
|
+
this.pendingUpdates.clear();
|
|
114
|
+
this.rafId = null;
|
|
115
|
+
});
|
|
89
116
|
}
|
|
90
117
|
/**
|
|
91
|
-
*
|
|
118
|
+
* Fallback measurement
|
|
92
119
|
*/
|
|
93
120
|
syncMeasure(index, element) {
|
|
94
|
-
const size = element.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.onMeasure(index, size);
|
|
99
|
-
}
|
|
121
|
+
const size = element.getBoundingClientRect()
|
|
122
|
+
.height;
|
|
123
|
+
if (size <= 0) {
|
|
124
|
+
return;
|
|
100
125
|
}
|
|
126
|
+
const rounded = Math.round(size);
|
|
127
|
+
if (this.measurements.get(index) === rounded) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.measurements.set(index, rounded);
|
|
131
|
+
this.onMeasure?.(index, rounded);
|
|
101
132
|
}
|
|
102
133
|
/**
|
|
103
|
-
*
|
|
134
|
+
* Preserve measurements
|
|
104
135
|
*/
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
136
|
+
stopMeasuring() {
|
|
137
|
+
this.resizeObserver?.disconnect();
|
|
138
|
+
this.pendingUpdates.clear();
|
|
139
|
+
if (this.rafId !== null) {
|
|
140
|
+
cancelAnimationFrame(this.rafId);
|
|
108
141
|
}
|
|
109
142
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Get measured size for an item
|
|
112
|
-
*/
|
|
113
143
|
getMeasurement(index) {
|
|
114
144
|
return this.measurements.get(index);
|
|
115
145
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Get all measurements
|
|
118
|
-
*/
|
|
119
146
|
getAllMeasurements() {
|
|
120
147
|
return new Map(this.measurements);
|
|
121
148
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Clear pending measurements
|
|
124
|
-
*/
|
|
125
149
|
clearPending() {
|
|
126
|
-
this.
|
|
150
|
+
this.pendingUpdates.clear();
|
|
127
151
|
}
|
|
128
152
|
/**
|
|
129
|
-
*
|
|
153
|
+
* Explicit cache clear
|
|
130
154
|
*/
|
|
155
|
+
clearMeasurements() {
|
|
156
|
+
this.measurements.clear();
|
|
157
|
+
}
|
|
131
158
|
destroy() {
|
|
132
159
|
this.stopMeasuring();
|
|
133
160
|
this.measurements.clear();
|
|
134
|
-
this.
|
|
161
|
+
this.pendingUpdates.clear();
|
|
162
|
+
this.observedElements =
|
|
163
|
+
new WeakMap();
|
|
135
164
|
this.onMeasure = null;
|
|
136
165
|
}
|
|
137
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeasurementSystem.js","sourceRoot":"","sources":["../../src/core/MeasurementSystem.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MeasurementSystem.js","sourceRoot":"","sources":["../../src/core/MeasurementSystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,65 +1,20 @@
|
|
|
1
|
-
import { ItemSize, VirtualRange
|
|
2
|
-
/**
|
|
3
|
-
* Core virtualization engine
|
|
4
|
-
* Handles:
|
|
5
|
-
* - visible range calculation
|
|
6
|
-
* - dynamic item sizing
|
|
7
|
-
* - item measurements
|
|
8
|
-
* - scroll positioning
|
|
9
|
-
*/
|
|
1
|
+
import { ItemSize, VirtualRange } from '../types';
|
|
10
2
|
export declare class VirtualizationEngine {
|
|
11
3
|
private itemSizeMap;
|
|
12
|
-
private itemOffsets;
|
|
13
|
-
private totalSize;
|
|
14
4
|
private estimatedItemSize;
|
|
5
|
+
private itemCount;
|
|
6
|
+
private prefix;
|
|
7
|
+
private dirty;
|
|
15
8
|
constructor(estimatedItemSize?: number);
|
|
16
|
-
|
|
17
|
-
* Record measured item size
|
|
18
|
-
*/
|
|
9
|
+
setItemCount(count: number): void;
|
|
19
10
|
recordItemSize(index: number, size: number): void;
|
|
20
|
-
|
|
21
|
-
* Recalculate item offsets
|
|
22
|
-
*/
|
|
23
|
-
private recalculateOffsets;
|
|
24
|
-
/**
|
|
25
|
-
* Get item size
|
|
26
|
-
*/
|
|
11
|
+
private rebuildPrefix;
|
|
27
12
|
getItemSize(index: number): number;
|
|
28
|
-
/**
|
|
29
|
-
* Get item offset
|
|
30
|
-
*/
|
|
31
13
|
getItemOffset(index: number): number;
|
|
32
|
-
/**
|
|
33
|
-
* Get total size
|
|
34
|
-
*/
|
|
35
14
|
getTotalSize(): number;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
getVisibleRange(scrollOffset: number, containerSize: number, itemCount: number, overscan?: number, scrollDirection?: ScrollDirection): VirtualRange;
|
|
40
|
-
/**
|
|
41
|
-
* Reverse scrolling support
|
|
42
|
-
*/
|
|
43
|
-
private getVisibleRangeReverse;
|
|
44
|
-
/**
|
|
45
|
-
* Get visible items
|
|
46
|
-
*/
|
|
47
|
-
getVisibleItems(scrollOffset: number, containerSize: number, itemCount: number, overscan: number, scrollDirection?: ScrollDirection): ItemSize[];
|
|
48
|
-
/**
|
|
49
|
-
* Scroll offset for item index
|
|
50
|
-
*/
|
|
15
|
+
private binarySearch;
|
|
16
|
+
getVisibleRange(scrollOffset: number, containerSize: number, itemCount: number, overscan?: number): VirtualRange;
|
|
17
|
+
getVisibleItems(scrollOffset: number, containerSize: number, itemCount: number, overscan: number): ItemSize[];
|
|
51
18
|
getScrollOffsetForIndex(index: number, containerSize: number, alignment?: 'start' | 'center' | 'end'): number;
|
|
52
|
-
/**
|
|
53
|
-
* Clear cache
|
|
54
|
-
*/
|
|
55
|
-
clearCache(): void;
|
|
56
|
-
/**
|
|
57
|
-
* Get cache
|
|
58
|
-
*/
|
|
59
|
-
getCache(): MeasurementCache;
|
|
60
|
-
/**
|
|
61
|
-
* Adaptive overscan
|
|
62
|
-
*/
|
|
63
|
-
getAdaptiveOverscan(scrollVelocity: number, baseOverscan?: number): number;
|
|
64
19
|
}
|
|
65
20
|
//# sourceMappingURL=VirtualizationEngine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualizationEngine.d.ts","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,YAAY,
|
|
1
|
+
{"version":3,"file":"VirtualizationEngine.d.ts","sourceRoot":"","sources":["../../src/core/VirtualizationEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,YAAY,EAEf,MAAM,UAAU,CAAC;AAElB,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,SAAS,CAAK;IAGtB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAQ;gBAET,iBAAiB,SAAK;IAIlC,YAAY,CAAC,KAAK,EAAE,MAAM;IAK1B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAO1C,OAAO,CAAC,aAAa;IAYrB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIlC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAKpC,YAAY,IAAI,MAAM;IAKtB,OAAO,CAAC,YAAY;IAkBpB,eAAe,CACX,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAI,GACb,YAAY;IAcf,eAAe,CACX,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACjB,QAAQ,EAAE;IAqBb,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,GAAG,QAAQ,GAAG,KAAe;CAchH"}
|