react-virtual-renderer 1.1.3 → 1.1.5
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/dist/App.d.ts.map +1 -1
- package/dist/App.js +65 -3
- package/dist/App.js.map +1 -1
- package/dist/components/VirtualGrid.d.ts +30 -0
- package/dist/components/VirtualGrid.d.ts.map +1 -1
- package/dist/components/VirtualGrid.js +147 -117
- package/dist/components/VirtualGrid.js.map +1 -1
- package/dist/components/VirtualList.d.ts +0 -4
- package/dist/components/VirtualList.d.ts.map +1 -1
- package/dist/components/VirtualList.js +76 -86
- package/dist/components/VirtualList.js.map +1 -1
- package/dist/components/VirtualLiveRegion.d.ts +12 -0
- package/dist/components/VirtualLiveRegion.d.ts.map +1 -0
- package/dist/components/VirtualLiveRegion.js +27 -0
- package/dist/components/VirtualLiveRegion.js.map +1 -0
- package/dist/core/FenwickTree.d.ts +47 -0
- package/dist/core/FenwickTree.d.ts.map +1 -0
- package/dist/core/FenwickTree.js +206 -0
- package/dist/core/FenwickTree.js.map +1 -0
- package/dist/core/GridLayoutEngine.d.ts +64 -0
- package/dist/core/GridLayoutEngine.d.ts.map +1 -0
- package/dist/core/GridLayoutEngine.js +153 -0
- package/dist/core/GridLayoutEngine.js.map +1 -0
- package/dist/core/GroupedListEngine.d.ts +21 -0
- package/dist/core/GroupedListEngine.d.ts.map +1 -0
- package/dist/core/GroupedListEngine.js +22 -0
- package/dist/core/GroupedListEngine.js.map +1 -0
- package/dist/core/ListController.d.ts +31 -0
- package/dist/core/ListController.d.ts.map +1 -0
- package/dist/core/ListController.js +71 -0
- package/dist/core/ListController.js.map +1 -0
- package/dist/core/MeasurementSystem.d.ts +1 -1
- package/dist/core/MeasurementSystem.d.ts.map +1 -1
- package/dist/core/MeasurementSystem.js +22 -10
- package/dist/core/MeasurementSystem.js.map +1 -1
- package/dist/core/VirtualizationEngine.d.ts +24 -13
- package/dist/core/VirtualizationEngine.d.ts.map +1 -1
- package/dist/core/VirtualizationEngine.js +50 -87
- package/dist/core/VirtualizationEngine.js.map +1 -1
- package/dist/examples/DynamicHeightLists.d.ts +2 -0
- package/dist/examples/DynamicHeightLists.d.ts.map +1 -0
- package/dist/examples/DynamicHeightLists.js +42 -0
- package/dist/examples/DynamicHeightLists.js.map +1 -0
- package/dist/examples/FixedGrid.d.ts +2 -0
- package/dist/examples/FixedGrid.d.ts.map +1 -0
- package/dist/examples/FixedGrid.js +40 -0
- package/dist/examples/FixedGrid.js.map +1 -0
- package/dist/examples/GroupedContactList.d.ts +2 -0
- package/dist/examples/GroupedContactList.d.ts.map +1 -0
- package/dist/examples/GroupedContactList.js +20 -0
- package/dist/examples/GroupedContactList.js.map +1 -0
- package/dist/examples/InfiniteScrollLists.d.ts +2 -0
- package/dist/examples/InfiniteScrollLists.d.ts.map +1 -0
- package/dist/examples/InfiniteScrollLists.js +93 -0
- package/dist/examples/InfiniteScrollLists.js.map +1 -0
- package/dist/examples/MasonaryGrid.d.ts +2 -0
- package/dist/examples/MasonaryGrid.d.ts.map +1 -0
- package/dist/examples/MasonaryGrid.js +36 -0
- package/dist/examples/MasonaryGrid.js.map +1 -0
- package/dist/examples/PerfHarness.d.ts +2 -0
- package/dist/examples/PerfHarness.d.ts.map +1 -0
- package/dist/examples/PerfHarness.js +131 -0
- package/dist/examples/PerfHarness.js.map +1 -0
- package/dist/hooks/useBidirectionalInfiniteScroll.d.ts +32 -0
- package/dist/hooks/useBidirectionalInfiniteScroll.d.ts.map +1 -0
- package/dist/hooks/useBidirectionalInfiniteScroll.js +89 -0
- package/dist/hooks/useBidirectionalInfiniteScroll.js.map +1 -0
- package/dist/hooks/useInfiniteScroll.d.ts +36 -12
- package/dist/hooks/useInfiniteScroll.d.ts.map +1 -1
- package/dist/hooks/useInfiniteScroll.js +46 -45
- package/dist/hooks/useInfiniteScroll.js.map +1 -1
- package/dist/hooks/useRevoingTabIndex.d.ts +11 -0
- package/dist/hooks/useRevoingTabIndex.d.ts.map +1 -0
- package/dist/hooks/useRevoingTabIndex.js +28 -0
- package/dist/hooks/useRevoingTabIndex.js.map +1 -0
- package/dist/hooks/useVirtualAllyProps.d.ts +23 -0
- package/dist/hooks/useVirtualAllyProps.d.ts.map +1 -0
- package/dist/hooks/useVirtualAllyProps.js +25 -0
- package/dist/hooks/useVirtualAllyProps.js.map +1 -0
- package/dist/hooks/useVirtualList.d.ts +2 -0
- package/dist/hooks/useVirtualList.d.ts.map +1 -1
- package/dist/hooks/useVirtualList.js +12 -4
- package/dist/hooks/useVirtualList.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/main.js +4 -4
- package/dist/main.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { forwardRef, useEffect, useImperativeHandle, useRef, } from 'react';
|
|
3
3
|
import { useVirtualList } from '../hooks/useVirtualList';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Drop-in replacement for long lists with virtualization support
|
|
7
|
-
*/
|
|
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
|
-
const { virtualItems, isScrolling, scrollOffset, totalSize, containerRef: internalContainerRef, innerRef: internalInnerRef, getItemStyle, } = useVirtualList({
|
|
4
|
+
export const VirtualList = forwardRef(({ items, renderItem, itemWrapper, itemKey, height = 400, width = 500, itemSize, overscan = 5, scrollDirection = 'forward', onScroll, className = '', itemClassName = '', style = {}, innerClassName = '', innerStyle = {}, itemStyle = {}, estimatedItemSize = 35, getItemSize, stickyIndices = [], onScrollEnd, innerRef, scrollOffsetRef, footer, }, containerRef) => {
|
|
5
|
+
const { virtualItems, isScrolling, scrollOffset, totalSize, containerRef: internalContainerRef, innerRef: internalInnerRef, getItemStyle, observeItem, unobserveItem, } = useVirtualList({
|
|
10
6
|
items,
|
|
11
7
|
getItemKey: itemKey,
|
|
12
|
-
containerHeight: typeof height === 'number'
|
|
13
|
-
|
|
14
|
-
: 400,
|
|
15
|
-
containerWidth: typeof width === 'number'
|
|
16
|
-
? width
|
|
17
|
-
: 500,
|
|
8
|
+
containerHeight: typeof height === 'number' ? height : 400,
|
|
9
|
+
containerWidth: typeof width === 'number' ? width : 500,
|
|
18
10
|
itemSize: getItemSize || itemSize,
|
|
19
11
|
overscan,
|
|
20
12
|
scrollDirection,
|
|
@@ -23,31 +15,15 @@ export const VirtualList = forwardRef(({ items, renderItem, itemWrapper, itemKey
|
|
|
23
15
|
onScrollEnd,
|
|
24
16
|
stickyIndices,
|
|
25
17
|
});
|
|
26
|
-
/**
|
|
27
|
-
* Local refs
|
|
28
|
-
*/
|
|
29
18
|
const mergedContainerRef = useRef(null);
|
|
30
19
|
const mergedInnerRef = useRef(null);
|
|
31
|
-
/**
|
|
32
|
-
* Expose container ref
|
|
33
|
-
*/
|
|
34
20
|
useImperativeHandle(containerRef, () => mergedContainerRef.current);
|
|
35
|
-
/**
|
|
36
|
-
* Expose inner ref
|
|
37
|
-
*/
|
|
38
21
|
useImperativeHandle(innerRef, () => mergedInnerRef.current);
|
|
39
|
-
/**
|
|
40
|
-
* Expose current scroll offset
|
|
41
|
-
*/
|
|
42
22
|
useEffect(() => {
|
|
43
23
|
if (scrollOffsetRef) {
|
|
44
|
-
scrollOffsetRef.current =
|
|
45
|
-
scrollOffset;
|
|
24
|
+
scrollOffsetRef.current = scrollOffset;
|
|
46
25
|
}
|
|
47
26
|
}, [scrollOffset, scrollOffsetRef]);
|
|
48
|
-
/**
|
|
49
|
-
* Container styles
|
|
50
|
-
*/
|
|
51
27
|
const containerStyle = {
|
|
52
28
|
height,
|
|
53
29
|
width,
|
|
@@ -55,70 +31,84 @@ export const VirtualList = forwardRef(({ items, renderItem, itemWrapper, itemKey
|
|
|
55
31
|
position: 'relative',
|
|
56
32
|
...style,
|
|
57
33
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const innerStyle = {
|
|
34
|
+
const innerStyleComputed = {
|
|
35
|
+
width: '100%',
|
|
36
|
+
...innerStyle,
|
|
62
37
|
position: 'relative',
|
|
63
38
|
height: totalSize,
|
|
64
|
-
width: '100%',
|
|
65
39
|
};
|
|
40
|
+
const cx = (...parts) => parts.filter(Boolean).join(' ').trim();
|
|
41
|
+
/**
|
|
42
|
+
* FIX: tracks the currently-mounted element per index, so the ref
|
|
43
|
+
* callback below can unobserve the OLD element when it unmounts
|
|
44
|
+
* (React gives you `null` on unmount, not the removed element, so
|
|
45
|
+
* you need to have kept a reference yourself to unobserve it -
|
|
46
|
+
* without this, ResizeObserver keeps a permanent reference to
|
|
47
|
+
* every item that's ever scrolled past = memory leak).
|
|
48
|
+
*/
|
|
49
|
+
const observedElementsRef = useRef(new Map());
|
|
50
|
+
const measureRef = (index) => (el) => {
|
|
51
|
+
const prev = observedElementsRef.current.get(index);
|
|
52
|
+
if (prev && prev !== el) {
|
|
53
|
+
unobserveItem(prev);
|
|
54
|
+
observedElementsRef.current.delete(index);
|
|
55
|
+
}
|
|
56
|
+
if (el) {
|
|
57
|
+
observedElementsRef.current.set(index, el);
|
|
58
|
+
observeItem(index, el);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
// stop observing everything on full unmount
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
return () => {
|
|
64
|
+
observedElementsRef.current.forEach((el) => unobserveItem(el));
|
|
65
|
+
observedElementsRef.current.clear();
|
|
66
|
+
};
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
+
}, []);
|
|
66
69
|
return (_jsx("div", { ref: (el) => {
|
|
67
|
-
mergedContainerRef.current =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
el;
|
|
71
|
-
}, className: `virtualize-container ${className}`, style: containerStyle, onScroll: (e) => {
|
|
70
|
+
mergedContainerRef.current = el;
|
|
71
|
+
internalContainerRef.current = el;
|
|
72
|
+
}, className: cx('virtualize-container', className), style: containerStyle, onScroll: (e) => {
|
|
72
73
|
const target = e.target;
|
|
73
74
|
const handler = renderItem?.__scrollHandler;
|
|
74
|
-
if (handler)
|
|
75
|
+
if (handler)
|
|
75
76
|
handler(e);
|
|
76
|
-
|
|
77
|
-
if (onScroll) {
|
|
77
|
+
if (onScroll)
|
|
78
78
|
onScroll(target.scrollTop, 'auto');
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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));
|
|
121
|
-
}) }) }));
|
|
79
|
+
}, children: _jsxs("div", { ref: (el) => {
|
|
80
|
+
mergedInnerRef.current = el;
|
|
81
|
+
internalInnerRef.current = el;
|
|
82
|
+
}, style: innerStyleComputed, className: cx('virtualize-inner', innerClassName), children: [virtualItems.map((virtualItem) => {
|
|
83
|
+
const item = items[virtualItem.index];
|
|
84
|
+
const key = itemKey ? itemKey(virtualItem.index, item) : virtualItem.index;
|
|
85
|
+
const virtualStyle = getItemStyle(virtualItem.index, virtualItem.size);
|
|
86
|
+
const renderProps = {
|
|
87
|
+
item,
|
|
88
|
+
index: virtualItem.index,
|
|
89
|
+
style: virtualStyle,
|
|
90
|
+
isScrolling,
|
|
91
|
+
};
|
|
92
|
+
const content = renderItem(renderProps);
|
|
93
|
+
if (itemWrapper) {
|
|
94
|
+
// Advanced API: consumer owns the wrapper DOM node, so
|
|
95
|
+
// THEY need to attach measureRef(index) to their root
|
|
96
|
+
// element for dynamic-height measurement to work here -
|
|
97
|
+
// we can't reach into arbitrary returned JSX to do it
|
|
98
|
+
// for them. Documented in types-patch.md.
|
|
99
|
+
return (_jsx(React.Fragment, { children: itemWrapper({
|
|
100
|
+
item,
|
|
101
|
+
index: virtualItem.index,
|
|
102
|
+
style: virtualStyle,
|
|
103
|
+
children: content,
|
|
104
|
+
}) }, key));
|
|
105
|
+
}
|
|
106
|
+
return (_jsx("div", { ref: measureRef(virtualItem.index), "data-virtualize-index": virtualItem.index, className: cx('virtualize-item', itemClassName), style: {
|
|
107
|
+
...itemStyle,
|
|
108
|
+
...virtualStyle,
|
|
109
|
+
boxSizing: 'border-box',
|
|
110
|
+
}, children: content }, key));
|
|
111
|
+
}), footer && (_jsx("div", { style: { position: 'absolute', top: totalSize, left: 0, width: '100%' }, children: footer }))] }) }));
|
|
122
112
|
});
|
|
123
113
|
VirtualList.displayName = 'VirtualList';
|
|
124
114
|
//# sourceMappingURL=VirtualList.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualList.js","sourceRoot":"","sources":["../../src/components/VirtualList.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EACV,UAAU,EACV,SAAS,EACT,mBAAmB,EACnB,MAAM,GACT,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAMzD
|
|
1
|
+
{"version":3,"file":"VirtualList.js","sourceRoot":"","sources":["../../src/components/VirtualList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visually-hidden aria-live region that announces the visible range
|
|
3
|
+
* once scrolling settles (debounced), so screen reader users get
|
|
4
|
+
* "showing items 240 to 260 of 50,000" instead of silence.
|
|
5
|
+
*/
|
|
6
|
+
export declare function VirtualLiveRegion({ start, end, total, isScrolling }: {
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
total: number;
|
|
10
|
+
isScrolling: boolean;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=VirtualLiveRegion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualLiveRegion.d.ts","sourceRoot":"","sources":["../../src/components/VirtualLiveRegion.tsx"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IAClE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;CACnE,2CAyBA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Visually-hidden aria-live region that announces the visible range
|
|
5
|
+
* once scrolling settles (debounced), so screen reader users get
|
|
6
|
+
* "showing items 240 to 260 of 50,000" instead of silence.
|
|
7
|
+
*/
|
|
8
|
+
export function VirtualLiveRegion({ start, end, total, isScrolling }) {
|
|
9
|
+
const [announcement, setAnnouncement] = useState('');
|
|
10
|
+
const timeoutRef = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (isScrolling)
|
|
13
|
+
return; // only announce once scrolling has settled
|
|
14
|
+
if (timeoutRef.current)
|
|
15
|
+
clearTimeout(timeoutRef.current);
|
|
16
|
+
timeoutRef.current = setTimeout(() => {
|
|
17
|
+
setAnnouncement(`Showing items ${start + 1} to ${end + 1} of ${total}`);
|
|
18
|
+
}, 400);
|
|
19
|
+
return () => { if (timeoutRef.current)
|
|
20
|
+
clearTimeout(timeoutRef.current); };
|
|
21
|
+
}, [start, end, total, isScrolling]);
|
|
22
|
+
return (_jsx("div", { "aria-live": "polite", "aria-atomic": "true", style: {
|
|
23
|
+
position: 'absolute', width: 1, height: 1, padding: 0, margin: -1,
|
|
24
|
+
overflow: 'hidden', clip: 'rect(0,0,0,0)', whiteSpace: 'nowrap', border: 0,
|
|
25
|
+
}, children: announcement }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=VirtualLiveRegion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualLiveRegion.js","sourceRoot":"","sources":["../../src/components/VirtualLiveRegion.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAEjE;IACG,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAC;IAEtE,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,WAAW;YAAE,OAAO,CAAC,2CAA2C;QACpE,IAAI,UAAU,CAAC,OAAO;YAAE,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACzD,UAAU,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACjC,eAAe,CAAC,iBAAiB,KAAK,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC5E,CAAC,EAAE,GAAG,CAAC,CAAC;QACR,OAAO,GAAG,EAAE,GAAG,IAAI,UAAU,CAAC,OAAO;YAAE,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;IAErC,OAAO,CACH,2BACc,QAAQ,iBACN,MAAM,EAClB,KAAK,EAAE;YACH,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YACjE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;SAC7E,YAEA,YAAY,GACX,CACT,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare class FenwickTree {
|
|
2
|
+
private capacity;
|
|
3
|
+
private tree;
|
|
4
|
+
private raw;
|
|
5
|
+
private n;
|
|
6
|
+
constructor(initialCount?: number);
|
|
7
|
+
size(): number;
|
|
8
|
+
/**
|
|
9
|
+
* Full linear-time rebuild from `raw[]`, the source of truth. Only
|
|
10
|
+
* called when capacity changes (doubling) - never on the per-item
|
|
11
|
+
* update hot path.
|
|
12
|
+
*/
|
|
13
|
+
private rebuild;
|
|
14
|
+
/**
|
|
15
|
+
* Grow or shrink to hold `count` items. New slots default to
|
|
16
|
+
* `defaultValue` (the estimated item size). Shrinking zeroes the
|
|
17
|
+
* vacated raw slots so a later regrow never resurfaces stale data.
|
|
18
|
+
*/
|
|
19
|
+
resize(count: number, defaultValue: number): void;
|
|
20
|
+
/**
|
|
21
|
+
* Point update: set the value at `index` (0-indexed) to `value`.
|
|
22
|
+
* O(log n) - safe at any time because it never needs to propagate
|
|
23
|
+
* beyond the current (fixed until the next doubling) capacity.
|
|
24
|
+
*/
|
|
25
|
+
update(index: number, value: number): void;
|
|
26
|
+
/** Value currently stored at `index` (0-indexed). O(1). */
|
|
27
|
+
getValue(index: number): number;
|
|
28
|
+
/** Sum of values in [0, index) - the pixel offset at which `index` starts. O(log n). */
|
|
29
|
+
prefixSum(index: number): number;
|
|
30
|
+
/** Sum of all n values - the total content size. O(log n). */
|
|
31
|
+
total(): number;
|
|
32
|
+
/**
|
|
33
|
+
* Locate the index whose range contains cumulative offset `target`.
|
|
34
|
+
* Runs on every scroll frame - an O(log n) walk directly over the
|
|
35
|
+
* tree structure (the classic Fenwick "find by prefix sum" walk),
|
|
36
|
+
* so it never needs a separately-maintained sorted array.
|
|
37
|
+
*/
|
|
38
|
+
findIndexAtOffset(target: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Reset every value to `defaultValue` without changing capacity.
|
|
41
|
+
* Intentionally the one O(n)-ish path in this class (a full rebuild
|
|
42
|
+
* plus n point updates), reserved for explicit full invalidation -
|
|
43
|
+
* never used on the scroll hot path.
|
|
44
|
+
*/
|
|
45
|
+
resetAll(defaultValue: number): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=FenwickTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FenwickTree.d.ts","sourceRoot":"","sources":["../../src/core/FenwickTree.ts"],"names":[],"mappings":"AAqDA,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,CAAC,CAAK;gBAEF,YAAY,SAAI;IAU5B,IAAI,IAAI,MAAM;IAId;;;;OAIG;IACH,OAAO,CAAC,OAAO;IAYf;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAgCjD;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAY1C,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAI/B,wFAAwF;IACxF,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAQhC,8DAA8D;IAC9D,KAAK,IAAI,MAAM;IAIf;;;;;OAKG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAiBzC;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;CASvC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fenwick Tree (Binary Indexed Tree) specialized for virtualization
|
|
3
|
+
* offset math.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS:
|
|
6
|
+
* The previous VirtualizationEngine kept a plain prefix-sum array and
|
|
7
|
+
* rebuilt it in FULL - O(n) - every time a single item's measured size
|
|
8
|
+
* changed. For a dynamic-height list, that's not an edge case, it's the
|
|
9
|
+
* hot path: every batch of newly-measured rows during scroll paid an
|
|
10
|
+
* O(n) cost. That's the exact "gets slower as the list grows" trap
|
|
11
|
+
* virtualization exists to avoid.
|
|
12
|
+
*
|
|
13
|
+
* CORRECTNESS NOTE (read this before changing the growth logic):
|
|
14
|
+
* An earlier version of this class grew the tree by simply extending
|
|
15
|
+
* the array and point-updating only the newly added indices. That is
|
|
16
|
+
* WRONG for a Fenwick tree: a point update only propagates up to
|
|
17
|
+
* whatever `n` (capacity) was AT THE TIME of the update. If the tree
|
|
18
|
+
* later grows past that bound, ancestor nodes that only come into
|
|
19
|
+
* existence at the larger size never receive the earlier elements'
|
|
20
|
+
* contributions, and totals silently undercount. This was caught by
|
|
21
|
+
* a differential test against a naive reference array (see the repo's
|
|
22
|
+
* verify/fenwick_v2.test.mjs) - total() returned 3 instead of 8 in a
|
|
23
|
+
* minimal repro.
|
|
24
|
+
*
|
|
25
|
+
* The fix used here is the standard one: capacity is always a power
|
|
26
|
+
* of two, `raw[]` is kept as the single source of truth, and growth
|
|
27
|
+
* beyond current capacity triggers a full O(capacity) rebuild from
|
|
28
|
+
* raw[] (not from partial tree state). Because capacity doubles each
|
|
29
|
+
* time, the total rebuild work across the tree's lifetime is a
|
|
30
|
+
* geometric series - amortized O(1) extra cost per element, the same
|
|
31
|
+
* argument as dynamic array doubling. Growth WITHIN current capacity,
|
|
32
|
+
* and ordinary re-measurement of existing items, stay O(log n) point
|
|
33
|
+
* updates with no rebuild at all.
|
|
34
|
+
*
|
|
35
|
+
* Complexity summary for a tree of n items:
|
|
36
|
+
* - re-measure one item: O(log n) (O(capacity) amortized O(1) on the rare doubling frame)
|
|
37
|
+
* - cumulative offset of any index: O(log n)
|
|
38
|
+
* - total content size: O(log n)
|
|
39
|
+
* - locate the item under a scroll offset (every scroll frame): O(log n)
|
|
40
|
+
* - append k new items: O(k log n), amortized
|
|
41
|
+
*
|
|
42
|
+
* All indices in the public API are 0-indexed.
|
|
43
|
+
*/
|
|
44
|
+
function lowbit(i) {
|
|
45
|
+
return i & -i;
|
|
46
|
+
}
|
|
47
|
+
function nextPow2(x) {
|
|
48
|
+
let p = 1;
|
|
49
|
+
while (p < x)
|
|
50
|
+
p <<= 1;
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
export class FenwickTree {
|
|
54
|
+
constructor(initialCount = 0) {
|
|
55
|
+
Object.defineProperty(this, "capacity", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: void 0
|
|
60
|
+
});
|
|
61
|
+
Object.defineProperty(this, "tree", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
value: void 0
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(this, "raw", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: void 0
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(this, "n", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
value: 0
|
|
78
|
+
});
|
|
79
|
+
this.capacity = nextPow2(Math.max(1, initialCount));
|
|
80
|
+
this.tree = new Array(this.capacity + 1).fill(0);
|
|
81
|
+
this.raw = new Array(this.capacity).fill(0);
|
|
82
|
+
if (initialCount > 0) {
|
|
83
|
+
this.resize(initialCount, 0);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
size() {
|
|
87
|
+
return this.n;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Full linear-time rebuild from `raw[]`, the source of truth. Only
|
|
91
|
+
* called when capacity changes (doubling) - never on the per-item
|
|
92
|
+
* update hot path.
|
|
93
|
+
*/
|
|
94
|
+
rebuild() {
|
|
95
|
+
this.tree = new Array(this.capacity + 1).fill(0);
|
|
96
|
+
for (let i = 1; i <= this.capacity; i++) {
|
|
97
|
+
this.tree[i] += this.raw[i - 1] ?? 0;
|
|
98
|
+
const parent = i + lowbit(i);
|
|
99
|
+
if (parent <= this.capacity) {
|
|
100
|
+
this.tree[parent] += this.tree[i];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Grow or shrink to hold `count` items. New slots default to
|
|
106
|
+
* `defaultValue` (the estimated item size). Shrinking zeroes the
|
|
107
|
+
* vacated raw slots so a later regrow never resurfaces stale data.
|
|
108
|
+
*/
|
|
109
|
+
resize(count, defaultValue) {
|
|
110
|
+
if (count > this.capacity) {
|
|
111
|
+
const newCapacity = nextPow2(count);
|
|
112
|
+
const oldRaw = this.raw;
|
|
113
|
+
this.raw = new Array(newCapacity).fill(0);
|
|
114
|
+
for (let i = 0; i < oldRaw.length; i++) {
|
|
115
|
+
this.raw[i] = oldRaw[i];
|
|
116
|
+
}
|
|
117
|
+
for (let i = this.n; i < count; i++) {
|
|
118
|
+
this.raw[i] = defaultValue;
|
|
119
|
+
}
|
|
120
|
+
this.capacity = newCapacity;
|
|
121
|
+
this.rebuild();
|
|
122
|
+
this.n = count;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (count > this.n) {
|
|
126
|
+
for (let i = this.n; i < count; i++) {
|
|
127
|
+
this.update(i, defaultValue);
|
|
128
|
+
}
|
|
129
|
+
this.n = count;
|
|
130
|
+
}
|
|
131
|
+
else if (count < this.n) {
|
|
132
|
+
for (let i = count; i < this.n; i++) {
|
|
133
|
+
this.update(i, 0);
|
|
134
|
+
}
|
|
135
|
+
this.n = count;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Point update: set the value at `index` (0-indexed) to `value`.
|
|
140
|
+
* O(log n) - safe at any time because it never needs to propagate
|
|
141
|
+
* beyond the current (fixed until the next doubling) capacity.
|
|
142
|
+
*/
|
|
143
|
+
update(index, value) {
|
|
144
|
+
if (index < 0 || index >= this.capacity)
|
|
145
|
+
return;
|
|
146
|
+
const delta = value - (this.raw[index] ?? 0);
|
|
147
|
+
if (delta === 0)
|
|
148
|
+
return;
|
|
149
|
+
this.raw[index] = value;
|
|
150
|
+
for (let i = index + 1; i <= this.capacity; i += lowbit(i)) {
|
|
151
|
+
this.tree[i] += delta;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** Value currently stored at `index` (0-indexed). O(1). */
|
|
155
|
+
getValue(index) {
|
|
156
|
+
return this.raw[index] ?? 0;
|
|
157
|
+
}
|
|
158
|
+
/** Sum of values in [0, index) - the pixel offset at which `index` starts. O(log n). */
|
|
159
|
+
prefixSum(index) {
|
|
160
|
+
let sum = 0;
|
|
161
|
+
for (let i = Math.min(index, this.n); i > 0; i -= lowbit(i)) {
|
|
162
|
+
sum += this.tree[i];
|
|
163
|
+
}
|
|
164
|
+
return sum;
|
|
165
|
+
}
|
|
166
|
+
/** Sum of all n values - the total content size. O(log n). */
|
|
167
|
+
total() {
|
|
168
|
+
return this.prefixSum(this.n);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Locate the index whose range contains cumulative offset `target`.
|
|
172
|
+
* Runs on every scroll frame - an O(log n) walk directly over the
|
|
173
|
+
* tree structure (the classic Fenwick "find by prefix sum" walk),
|
|
174
|
+
* so it never needs a separately-maintained sorted array.
|
|
175
|
+
*/
|
|
176
|
+
findIndexAtOffset(target) {
|
|
177
|
+
if (this.n === 0)
|
|
178
|
+
return 0;
|
|
179
|
+
let pos = 0;
|
|
180
|
+
let remaining = target;
|
|
181
|
+
for (let pw = this.capacity; pw > 0; pw >>= 1) {
|
|
182
|
+
const next = pos + pw;
|
|
183
|
+
if (next <= this.capacity && this.tree[next] <= remaining) {
|
|
184
|
+
pos = next;
|
|
185
|
+
remaining -= this.tree[next];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return Math.min(pos, this.n - 1);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Reset every value to `defaultValue` without changing capacity.
|
|
192
|
+
* Intentionally the one O(n)-ish path in this class (a full rebuild
|
|
193
|
+
* plus n point updates), reserved for explicit full invalidation -
|
|
194
|
+
* never used on the scroll hot path.
|
|
195
|
+
*/
|
|
196
|
+
resetAll(defaultValue) {
|
|
197
|
+
for (let i = 0; i < this.n; i++) {
|
|
198
|
+
this.raw[i] = 0;
|
|
199
|
+
}
|
|
200
|
+
this.rebuild();
|
|
201
|
+
for (let i = 0; i < this.n; i++) {
|
|
202
|
+
this.update(i, defaultValue);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=FenwickTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FenwickTree.js","sourceRoot":"","sources":["../../src/core/FenwickTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GridPosition } from '../types';
|
|
2
|
+
export type RowHeightInput = number | ((index: number) => number);
|
|
3
|
+
export interface GridLayoutParams {
|
|
4
|
+
cols: number;
|
|
5
|
+
colWidth: number;
|
|
6
|
+
gap: number;
|
|
7
|
+
layout: 'grid' | 'masonry';
|
|
8
|
+
rowHeight: RowHeightInput;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Incremental, append-only masonry/grid position engine.
|
|
12
|
+
*
|
|
13
|
+
* PERFORMANCE: the previous VirtualGrid recomputed EVERY item's
|
|
14
|
+
* position from scratch (a full O(n) pass) whenever the items array
|
|
15
|
+
* changed identity - including the ordinary infinite-scroll case of
|
|
16
|
+
* appending 20 new items to an existing 50,000-item masonry board,
|
|
17
|
+
* which turned a single "load more" into an O(n) pass over everything
|
|
18
|
+
* already laid out.
|
|
19
|
+
*
|
|
20
|
+
* This engine keeps running state - per-column heights for masonry, a
|
|
21
|
+
* running row-offset for dynamic-height grid rows - and only computes
|
|
22
|
+
* positions for items it hasn't seen before. Appending k new items
|
|
23
|
+
* costs O(k), never O(n + k). A full reset (columns/width/gap/layout
|
|
24
|
+
* changed) is the only path that pays an O(n) cost, same as any other
|
|
25
|
+
* virtualization library when the layout itself is invalidated.
|
|
26
|
+
*
|
|
27
|
+
* NOTE ON VIRTUAL_GRID'S FAST PATH: this engine is only used for
|
|
28
|
+
* masonry layout, or grid layout with a per-index rowHeight function.
|
|
29
|
+
* Plain grid layout with a fixed numeric rowHeight never touches this
|
|
30
|
+
* file at all - VirtualGrid computes those positions with direct O(1)
|
|
31
|
+
* arithmetic and no array (see VirtualGrid.tsx), which is faster still.
|
|
32
|
+
*/
|
|
33
|
+
export declare class GridLayoutEngine {
|
|
34
|
+
private positions;
|
|
35
|
+
private colHeights;
|
|
36
|
+
private rowOffsets;
|
|
37
|
+
private currentRowMax;
|
|
38
|
+
private maxBottom;
|
|
39
|
+
private params;
|
|
40
|
+
private sameParams;
|
|
41
|
+
private reset;
|
|
42
|
+
private sizeOf;
|
|
43
|
+
/** Masonry: place each new item in whichever column is currently shortest. */
|
|
44
|
+
private appendMasonry;
|
|
45
|
+
/**
|
|
46
|
+
* Grid with per-index rowHeight function: rows advance by the
|
|
47
|
+
* tallest item seen in that row so far. `rowOffsets[r]` is only
|
|
48
|
+
* ever written once (when row r's first item is appended), reading
|
|
49
|
+
* `currentRowMax` accumulated while row r-1 was being built - so
|
|
50
|
+
* this stays correct across multiple incremental append() calls,
|
|
51
|
+
* not just a single full pass.
|
|
52
|
+
*/
|
|
53
|
+
private appendGrid;
|
|
54
|
+
/**
|
|
55
|
+
* Ensure positions exist for `itemCount` items under the given
|
|
56
|
+
* params. Existing entries are reused by reference - callers get
|
|
57
|
+
* back the same array instances for indices they've already seen,
|
|
58
|
+
* which keeps this cheap to call on every render.
|
|
59
|
+
*/
|
|
60
|
+
sync(itemCount: number, p: GridLayoutParams): GridPosition[];
|
|
61
|
+
/** O(1) - tracked incrementally as items are appended, never rescanned. */
|
|
62
|
+
getTotalHeight(): number;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=GridLayoutEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridLayoutEngine.d.ts","sourceRoot":"","sources":["../../src/core/GridLayoutEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IACzB,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,MAAM;IAId,8EAA8E;IAC9E,OAAO,CAAC,aAAa;IAmBrB;;;;;;;OAOG;IACH,OAAO,CAAC,UAAU;IAyBlB;;;;;OAKG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,gBAAgB,GAAG,YAAY,EAAE;IAiB5D,2EAA2E;IAC3E,cAAc,IAAI,MAAM;CAG3B"}
|