@react-stately/virtualizer 4.0.3-nightly.5042 → 4.2.0
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/Layout.main.js +5 -1
- package/dist/Layout.main.js.map +1 -1
- package/dist/Layout.mjs +5 -1
- package/dist/Layout.module.js +5 -1
- package/dist/Layout.module.js.map +1 -1
- package/dist/LayoutInfo.main.js +2 -0
- package/dist/LayoutInfo.main.js.map +1 -1
- package/dist/LayoutInfo.mjs +2 -0
- package/dist/LayoutInfo.module.js +2 -0
- package/dist/LayoutInfo.module.js.map +1 -1
- package/dist/ReusableView.main.js +18 -5
- package/dist/ReusableView.main.js.map +1 -1
- package/dist/ReusableView.mjs +18 -6
- package/dist/ReusableView.module.js +18 -6
- package/dist/ReusableView.module.js.map +1 -1
- package/dist/Virtualizer.main.js +16 -12
- package/dist/Virtualizer.main.js.map +1 -1
- package/dist/Virtualizer.mjs +16 -12
- package/dist/Virtualizer.module.js +16 -12
- package/dist/Virtualizer.module.js.map +1 -1
- package/dist/types.d.ts +26 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/useVirtualizerState.main.js +11 -7
- package/dist/useVirtualizerState.main.js.map +1 -1
- package/dist/useVirtualizerState.mjs +11 -7
- package/dist/useVirtualizerState.module.js +11 -7
- package/dist/useVirtualizerState.module.js.map +1 -1
- package/package.json +5 -5
- package/src/Layout.ts +4 -4
- package/src/LayoutInfo.ts +7 -0
- package/src/ReusableView.ts +28 -13
- package/src/Virtualizer.ts +30 -18
- package/src/types.ts +2 -2
- package/src/useVirtualizerState.ts +12 -8
package/src/ReusableView.ts
CHANGED
|
@@ -28,23 +28,25 @@ export class ReusableView<T extends object, V> {
|
|
|
28
28
|
layoutInfo: LayoutInfo | null;
|
|
29
29
|
|
|
30
30
|
/** The content currently being displayed by this view, set by the virtualizer. */
|
|
31
|
-
content: T;
|
|
31
|
+
content: T | null;
|
|
32
32
|
|
|
33
|
-
rendered: V;
|
|
33
|
+
rendered: V | null;
|
|
34
34
|
|
|
35
35
|
viewType: string;
|
|
36
36
|
key: Key;
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
reusableViews: Map<string, ReusableView<T, V>[]>;
|
|
38
|
+
children: Set<ChildView<T, V>>;
|
|
39
|
+
reusableViews: Map<string, ChildView<T, V>[]>;
|
|
41
40
|
|
|
42
|
-
constructor(virtualizer: Virtualizer<T, V
|
|
41
|
+
constructor(virtualizer: Virtualizer<T, V>, viewType: string) {
|
|
43
42
|
this.virtualizer = virtualizer;
|
|
44
43
|
this.key = ++KEY;
|
|
45
|
-
this.
|
|
44
|
+
this.viewType = viewType;
|
|
46
45
|
this.children = new Set();
|
|
47
46
|
this.reusableViews = new Map();
|
|
47
|
+
this.layoutInfo = null;
|
|
48
|
+
this.content = null;
|
|
49
|
+
this.rendered = null;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
@@ -62,16 +64,14 @@ export class ReusableView<T extends object, V> {
|
|
|
62
64
|
// The cells within a row are removed from their parent in order. If the row is reused, the cells
|
|
63
65
|
// should be reused in the new row in the same order they were before.
|
|
64
66
|
let reusable = this.reusableViews.get(reuseType);
|
|
65
|
-
let view = reusable
|
|
66
|
-
? reusable.shift()
|
|
67
|
-
: new
|
|
67
|
+
let view = reusable && reusable.length > 0
|
|
68
|
+
? reusable.shift()!
|
|
69
|
+
: new ChildView<T, V>(this.virtualizer, this, reuseType);
|
|
68
70
|
|
|
69
|
-
view.viewType = reuseType;
|
|
70
|
-
view.parent = this;
|
|
71
71
|
return view;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
reuseChild(child:
|
|
74
|
+
reuseChild(child: ChildView<T, V>) {
|
|
75
75
|
child.prepareForReuse();
|
|
76
76
|
let reusable = this.reusableViews.get(child.viewType);
|
|
77
77
|
if (!reusable) {
|
|
@@ -81,3 +81,18 @@ export class ReusableView<T extends object, V> {
|
|
|
81
81
|
reusable.push(child);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
export class RootView<T extends object, V> extends ReusableView<T, V> {
|
|
86
|
+
constructor(virtualizer: Virtualizer<T, V>) {
|
|
87
|
+
super(virtualizer, 'root');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class ChildView<T extends object, V> extends ReusableView<T, V> {
|
|
92
|
+
parent: ReusableView<T, V>;
|
|
93
|
+
|
|
94
|
+
constructor(virtualizer: Virtualizer<T, V>, parent: ReusableView<T, V>, viewType: string) {
|
|
95
|
+
super(virtualizer, viewType);
|
|
96
|
+
this.parent = parent;
|
|
97
|
+
}
|
|
98
|
+
}
|
package/src/Virtualizer.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import {ChildView, ReusableView, RootView} from './ReusableView';
|
|
13
14
|
import {Collection, Key} from '@react-types/shared';
|
|
14
15
|
import {InvalidationContext, Mutable, VirtualizerDelegate, VirtualizerRenderOptions} from './types';
|
|
15
16
|
import {isSetEqual} from './utils';
|
|
@@ -18,9 +19,14 @@ import {LayoutInfo} from './LayoutInfo';
|
|
|
18
19
|
import {OverscanManager} from './OverscanManager';
|
|
19
20
|
import {Point} from './Point';
|
|
20
21
|
import {Rect} from './Rect';
|
|
21
|
-
import {ReusableView} from './ReusableView';
|
|
22
22
|
import {Size} from './Size';
|
|
23
23
|
|
|
24
|
+
interface VirtualizerOptions<T extends object, V> {
|
|
25
|
+
delegate: VirtualizerDelegate<T, V>,
|
|
26
|
+
collection: Collection<T>,
|
|
27
|
+
layout: Layout<T>
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
/**
|
|
25
31
|
* The Virtualizer class renders a scrollable collection of data using customizable layouts.
|
|
26
32
|
* It supports very large collections by only rendering visible views to the DOM, reusing
|
|
@@ -55,23 +61,25 @@ export class Virtualizer<T extends object, V> {
|
|
|
55
61
|
/** The set of persisted keys that are always present in the DOM, even if not currently in view. */
|
|
56
62
|
readonly persistedKeys: Set<Key>;
|
|
57
63
|
|
|
58
|
-
private _visibleViews: Map<Key,
|
|
64
|
+
private _visibleViews: Map<Key, ChildView<T, V>>;
|
|
59
65
|
private _renderedContent: WeakMap<T, V>;
|
|
60
|
-
private _rootView:
|
|
66
|
+
private _rootView: RootView<T, V>;
|
|
61
67
|
private _isScrolling: boolean;
|
|
62
|
-
private _invalidationContext: InvalidationContext
|
|
68
|
+
private _invalidationContext: InvalidationContext;
|
|
63
69
|
private _overscanManager: OverscanManager;
|
|
64
70
|
|
|
65
|
-
constructor(
|
|
66
|
-
this.delegate = delegate;
|
|
71
|
+
constructor(options: VirtualizerOptions<T, V>) {
|
|
72
|
+
this.delegate = options.delegate;
|
|
73
|
+
this.collection = options.collection;
|
|
74
|
+
this.layout = options.layout;
|
|
67
75
|
this.contentSize = new Size;
|
|
68
76
|
this.visibleRect = new Rect;
|
|
69
77
|
this.persistedKeys = new Set();
|
|
70
78
|
this._visibleViews = new Map();
|
|
71
79
|
this._renderedContent = new WeakMap();
|
|
72
|
-
this._rootView = new
|
|
80
|
+
this._rootView = new RootView(this);
|
|
73
81
|
this._isScrolling = false;
|
|
74
|
-
this._invalidationContext =
|
|
82
|
+
this._invalidationContext = {};
|
|
75
83
|
this._overscanManager = new OverscanManager();
|
|
76
84
|
}
|
|
77
85
|
|
|
@@ -86,7 +94,7 @@ export class Virtualizer<T extends object, V> {
|
|
|
86
94
|
for (let k of this.persistedKeys) {
|
|
87
95
|
while (k != null) {
|
|
88
96
|
let layoutInfo = this.layout.getLayoutInfo(k);
|
|
89
|
-
if (!layoutInfo) {
|
|
97
|
+
if (!layoutInfo || layoutInfo.parentKey == null) {
|
|
90
98
|
break;
|
|
91
99
|
}
|
|
92
100
|
|
|
@@ -105,7 +113,7 @@ export class Virtualizer<T extends object, V> {
|
|
|
105
113
|
return layoutInfo.parentKey != null ? this._visibleViews.get(layoutInfo.parentKey) : this._rootView;
|
|
106
114
|
}
|
|
107
115
|
|
|
108
|
-
private getReusableView(layoutInfo: LayoutInfo):
|
|
116
|
+
private getReusableView(layoutInfo: LayoutInfo): ChildView<T, V> {
|
|
109
117
|
let parentView = this.getParentView(layoutInfo)!;
|
|
110
118
|
let view = parentView.getReusableView(layoutInfo.type);
|
|
111
119
|
view.layoutInfo = layoutInfo;
|
|
@@ -114,13 +122,15 @@ export class Virtualizer<T extends object, V> {
|
|
|
114
122
|
}
|
|
115
123
|
|
|
116
124
|
private _renderView(reusableView: ReusableView<T, V>) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
if (reusableView.layoutInfo) {
|
|
126
|
+
let {type, key, content} = reusableView.layoutInfo;
|
|
127
|
+
reusableView.content = content || this.collection.getItem(key);
|
|
128
|
+
reusableView.rendered = this._renderContent(type, reusableView.content);
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
|
|
122
|
-
private _renderContent(type: string, content: T) {
|
|
123
|
-
let cached = this._renderedContent.get(content);
|
|
132
|
+
private _renderContent(type: string, content: T | null) {
|
|
133
|
+
let cached = content != null ? this._renderedContent.get(content) : null;
|
|
124
134
|
if (cached != null) {
|
|
125
135
|
return cached;
|
|
126
136
|
}
|
|
@@ -196,7 +206,7 @@ export class Virtualizer<T extends object, V> {
|
|
|
196
206
|
private updateSubviews() {
|
|
197
207
|
let visibleLayoutInfos = this.getVisibleLayoutInfos();
|
|
198
208
|
|
|
199
|
-
let removed = new Set<
|
|
209
|
+
let removed = new Set<ChildView<T, V>>();
|
|
200
210
|
for (let [key, view] of this._visibleViews) {
|
|
201
211
|
let layoutInfo = visibleLayoutInfos.get(key);
|
|
202
212
|
// If a view's parent changed, treat it as a delete and re-create in the new parent.
|
|
@@ -219,7 +229,9 @@ export class Virtualizer<T extends object, V> {
|
|
|
219
229
|
|
|
220
230
|
let item = this.collection.getItem(layoutInfo.key);
|
|
221
231
|
if (view.content !== item) {
|
|
222
|
-
|
|
232
|
+
if (view.content != null) {
|
|
233
|
+
this._renderedContent.delete(view.content);
|
|
234
|
+
}
|
|
223
235
|
this._renderView(view);
|
|
224
236
|
}
|
|
225
237
|
}
|
|
@@ -261,7 +273,7 @@ export class Virtualizer<T extends object, V> {
|
|
|
261
273
|
needsLayout = true;
|
|
262
274
|
}
|
|
263
275
|
|
|
264
|
-
if (opts.layout !== this.layout) {
|
|
276
|
+
if (opts.layout !== this.layout || this.layout.virtualizer !== this) {
|
|
265
277
|
if (this.layout) {
|
|
266
278
|
this.layout.virtualizer = null;
|
|
267
279
|
}
|
package/src/types.ts
CHANGED
|
@@ -24,14 +24,14 @@ export interface InvalidationContext<O = any> {
|
|
|
24
24
|
|
|
25
25
|
export interface VirtualizerDelegate<T extends object, V> {
|
|
26
26
|
setVisibleRect(rect: Rect): void,
|
|
27
|
-
renderView(type: string, content: T): V,
|
|
27
|
+
renderView(type: string, content: T | null): V,
|
|
28
28
|
invalidate(ctx: InvalidationContext): void
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface VirtualizerRenderOptions<T extends object, O = any> {
|
|
32
32
|
layout: Layout<T>,
|
|
33
33
|
collection: Collection<T>,
|
|
34
|
-
persistedKeys?: Set<Key
|
|
34
|
+
persistedKeys?: Set<Key> | null,
|
|
35
35
|
visibleRect: Rect,
|
|
36
36
|
invalidationContext: InvalidationContext,
|
|
37
37
|
isScrolling: boolean,
|
|
@@ -21,7 +21,7 @@ import {useLayoutEffect} from '@react-aria/utils';
|
|
|
21
21
|
import {Virtualizer} from './Virtualizer';
|
|
22
22
|
|
|
23
23
|
interface VirtualizerProps<T extends object, V, O> {
|
|
24
|
-
renderView(type: string, content: T): V,
|
|
24
|
+
renderView(type: string, content: T | null): V,
|
|
25
25
|
layout: Layout<T>,
|
|
26
26
|
collection: Collection<T>,
|
|
27
27
|
onVisibleRectChange(rect: Rect): void,
|
|
@@ -45,13 +45,17 @@ export function useVirtualizerState<T extends object, V, O = any>(opts: Virtuali
|
|
|
45
45
|
let [invalidationContext, setInvalidationContext] = useState<InvalidationContext>({});
|
|
46
46
|
let visibleRectChanged = useRef(false);
|
|
47
47
|
let [virtualizer] = useState(() => new Virtualizer<T, V>({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
collection: opts.collection,
|
|
49
|
+
layout: opts.layout,
|
|
50
|
+
delegate: {
|
|
51
|
+
setVisibleRect(rect) {
|
|
52
|
+
setVisibleRect(rect);
|
|
53
|
+
visibleRectChanged.current = true;
|
|
54
|
+
},
|
|
55
|
+
// TODO: should changing these invalidate the entire cache?
|
|
56
|
+
renderView: opts.renderView,
|
|
57
|
+
invalidate: setInvalidationContext
|
|
58
|
+
}
|
|
55
59
|
}));
|
|
56
60
|
|
|
57
61
|
// onVisibleRectChange must be called from an effect, not during render.
|