@react-stately/layout 3.13.10-nightly.4685 → 3.13.10-nightly.4691
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/ListLayout.main.js +14 -63
- package/dist/ListLayout.main.js.map +1 -1
- package/dist/ListLayout.mjs +15 -64
- package/dist/ListLayout.module.js +15 -64
- package/dist/ListLayout.module.js.map +1 -1
- package/dist/TableLayout.main.js +25 -67
- package/dist/TableLayout.main.js.map +1 -1
- package/dist/TableLayout.mjs +25 -67
- package/dist/TableLayout.module.js +25 -67
- package/dist/TableLayout.module.js.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +29 -47
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/ListLayout.ts +32 -104
- package/src/TableLayout.ts +41 -90
- package/src/index.ts +2 -2
package/src/ListLayout.ts
CHANGED
|
@@ -14,66 +14,48 @@ import {Collection, DropTarget, DropTargetDelegate, Key, Node} from '@react-type
|
|
|
14
14
|
import {getChildNodes} from '@react-stately/collections';
|
|
15
15
|
import {InvalidationContext, Layout, LayoutInfo, Point, Rect, Size} from '@react-stately/virtualizer';
|
|
16
16
|
|
|
17
|
-
export
|
|
18
|
-
/** The height of a row in px. */
|
|
17
|
+
export interface ListLayoutOptions {
|
|
18
|
+
/** The fixed height of a row in px. */
|
|
19
19
|
rowHeight?: number,
|
|
20
|
+
/** The estimated height of a row, when row heights are variable. */
|
|
20
21
|
estimatedRowHeight?: number,
|
|
22
|
+
/** The fixed height of a section header in px. */
|
|
21
23
|
headingHeight?: number,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
loaderHeight?: number,
|
|
26
|
-
placeholderHeight?: number,
|
|
27
|
-
forceSectionHeaders?: boolean,
|
|
28
|
-
enableEmptyState?: boolean
|
|
29
|
-
};
|
|
24
|
+
/** The estimated height of a section header, when the height is variable. */
|
|
25
|
+
estimatedHeadingHeight?: number
|
|
26
|
+
}
|
|
30
27
|
|
|
31
28
|
// A wrapper around LayoutInfo that supports hierarchy
|
|
32
29
|
export interface LayoutNode {
|
|
33
30
|
node?: Node<unknown>,
|
|
34
31
|
layoutInfo: LayoutInfo,
|
|
35
|
-
header?: LayoutInfo,
|
|
36
32
|
children?: LayoutNode[],
|
|
37
33
|
validRect: Rect,
|
|
38
34
|
index?: number
|
|
39
35
|
}
|
|
40
36
|
|
|
41
|
-
export interface ListLayoutProps {
|
|
42
|
-
isLoading?: boolean
|
|
43
|
-
}
|
|
44
|
-
|
|
45
37
|
const DEFAULT_HEIGHT = 48;
|
|
46
38
|
|
|
47
39
|
/**
|
|
48
|
-
* The ListLayout class is an implementation of a virtualizer {@link Layout}
|
|
49
|
-
* it is used for creating lists and lists with indented sub-lists.
|
|
50
|
-
*
|
|
40
|
+
* The ListLayout class is an implementation of a virtualizer {@link Layout}.
|
|
51
41
|
* To configure a ListLayout, you can use the properties to define the
|
|
52
42
|
* layouts and/or use the method for defining indentation.
|
|
53
43
|
* The {@link ListKeyboardDelegate} extends the existing virtualizer
|
|
54
44
|
* delegate with an additional method to do this (it uses the same delegate object as
|
|
55
45
|
* the virtualizer itself).
|
|
56
46
|
*/
|
|
57
|
-
export class ListLayout<T> extends Layout<Node<T>,
|
|
47
|
+
export class ListLayout<T, O = any> extends Layout<Node<T>, O> implements DropTargetDelegate {
|
|
58
48
|
protected rowHeight: number;
|
|
59
49
|
protected estimatedRowHeight: number;
|
|
60
50
|
protected headingHeight: number;
|
|
61
51
|
protected estimatedHeadingHeight: number;
|
|
62
|
-
protected forceSectionHeaders: boolean;
|
|
63
|
-
protected padding: number;
|
|
64
|
-
protected indentationForItem?: (collection: Collection<Node<T>>, key: Key) => number;
|
|
65
|
-
protected layoutInfos: Map<Key, LayoutInfo>;
|
|
66
52
|
protected layoutNodes: Map<Key, LayoutNode>;
|
|
67
53
|
protected contentSize: Size;
|
|
68
54
|
protected collection: Collection<Node<T>>;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
protected lastCollection: Collection<Node<T>>;
|
|
55
|
+
private lastCollection: Collection<Node<T>>;
|
|
56
|
+
private lastWidth: number;
|
|
72
57
|
protected rootNodes: LayoutNode[];
|
|
73
|
-
|
|
74
|
-
protected loaderHeight: number;
|
|
75
|
-
protected placeholderHeight: number;
|
|
76
|
-
protected enableEmptyState: boolean;
|
|
58
|
+
private invalidateEverything: boolean;
|
|
77
59
|
/** The rectangle containing currently valid layout infos. */
|
|
78
60
|
protected validRect: Rect;
|
|
79
61
|
/** The rectangle of requested layout infos so far. */
|
|
@@ -83,19 +65,12 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
83
65
|
* Creates a new ListLayout with options. See the list of properties below for a description
|
|
84
66
|
* of the options that can be provided.
|
|
85
67
|
*/
|
|
86
|
-
constructor(options: ListLayoutOptions
|
|
68
|
+
constructor(options: ListLayoutOptions = {}) {
|
|
87
69
|
super();
|
|
88
70
|
this.rowHeight = options.rowHeight;
|
|
89
71
|
this.estimatedRowHeight = options.estimatedRowHeight;
|
|
90
72
|
this.headingHeight = options.headingHeight;
|
|
91
73
|
this.estimatedHeadingHeight = options.estimatedHeadingHeight;
|
|
92
|
-
this.forceSectionHeaders = options.forceSectionHeaders;
|
|
93
|
-
this.padding = options.padding || 0;
|
|
94
|
-
this.indentationForItem = options.indentationForItem;
|
|
95
|
-
this.loaderHeight = options.loaderHeight;
|
|
96
|
-
this.placeholderHeight = options.placeholderHeight;
|
|
97
|
-
this.enableEmptyState = options.enableEmptyState || false;
|
|
98
|
-
this.layoutInfos = new Map();
|
|
99
74
|
this.layoutNodes = new Map();
|
|
100
75
|
this.rootNodes = [];
|
|
101
76
|
this.lastWidth = 0;
|
|
@@ -107,7 +82,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
107
82
|
|
|
108
83
|
getLayoutInfo(key: Key) {
|
|
109
84
|
this.ensureLayoutInfo(key);
|
|
110
|
-
return this.
|
|
85
|
+
return this.layoutNodes.get(key)?.layoutInfo || null;
|
|
111
86
|
}
|
|
112
87
|
|
|
113
88
|
getVisibleLayoutInfos(rect: Rect) {
|
|
@@ -129,9 +104,6 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
129
104
|
for (let node of nodes) {
|
|
130
105
|
if (this.isVisible(node, rect)) {
|
|
131
106
|
res.push(node.layoutInfo);
|
|
132
|
-
if (node.header) {
|
|
133
|
-
res.push(node.header);
|
|
134
|
-
}
|
|
135
107
|
|
|
136
108
|
if (node.children) {
|
|
137
109
|
addNodes(node.children);
|
|
@@ -166,7 +138,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
166
138
|
// If the layout info wasn't found, it might be outside the bounds of the area that we've
|
|
167
139
|
// computed layout for so far. This can happen when accessing a random key, e.g pressing Home/End.
|
|
168
140
|
// Compute the full layout and try again.
|
|
169
|
-
if (!this.
|
|
141
|
+
if (!this.layoutNodes.has(key) && this.requestedRect.area < this.contentSize.area && this.lastCollection) {
|
|
170
142
|
this.requestedRect = new Rect(0, 0, Infinity, Infinity);
|
|
171
143
|
this.rootNodes = this.buildCollection();
|
|
172
144
|
this.requestedRect = new Rect(0, 0, this.contentSize.width, this.contentSize.height);
|
|
@@ -176,19 +148,18 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
176
148
|
return false;
|
|
177
149
|
}
|
|
178
150
|
|
|
179
|
-
|
|
180
|
-
return node.layoutInfo.rect.intersects(rect) || node.layoutInfo.isSticky || this.virtualizer.isPersistedKey(node.layoutInfo.key);
|
|
151
|
+
protected isVisible(node: LayoutNode, rect: Rect) {
|
|
152
|
+
return node.layoutInfo.rect.intersects(rect) || node.layoutInfo.isSticky || node.layoutInfo.type === 'header' || this.virtualizer.isPersistedKey(node.layoutInfo.key);
|
|
181
153
|
}
|
|
182
154
|
|
|
183
|
-
protected shouldInvalidateEverything(invalidationContext: InvalidationContext<
|
|
155
|
+
protected shouldInvalidateEverything(invalidationContext: InvalidationContext<O>) {
|
|
184
156
|
// Invalidate cache if the size of the collection changed.
|
|
185
157
|
// In this case, we need to recalculate the entire layout.
|
|
186
158
|
return invalidationContext.sizeChanged;
|
|
187
159
|
}
|
|
188
160
|
|
|
189
|
-
validate(invalidationContext: InvalidationContext<
|
|
161
|
+
validate(invalidationContext: InvalidationContext<O>) {
|
|
190
162
|
this.collection = this.virtualizer.collection;
|
|
191
|
-
this.isLoading = invalidationContext.layoutOptions?.isLoading || false;
|
|
192
163
|
|
|
193
164
|
// Reset valid rect if we will have to invalidate everything.
|
|
194
165
|
// Otherwise we can reuse cached layout infos outside the current visible rect.
|
|
@@ -205,8 +176,6 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
205
176
|
if (!this.collection.getItem(key)) {
|
|
206
177
|
let layoutNode = this.layoutNodes.get(key);
|
|
207
178
|
if (layoutNode) {
|
|
208
|
-
this.layoutInfos.delete(layoutNode.layoutInfo.key);
|
|
209
|
-
this.layoutInfos.delete(layoutNode.header?.key);
|
|
210
179
|
this.layoutNodes.delete(key);
|
|
211
180
|
}
|
|
212
181
|
}
|
|
@@ -219,12 +188,11 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
219
188
|
this.validRect = this.requestedRect.copy();
|
|
220
189
|
}
|
|
221
190
|
|
|
222
|
-
protected buildCollection(): LayoutNode[] {
|
|
223
|
-
let y = this.padding;
|
|
191
|
+
protected buildCollection(y = 0): LayoutNode[] {
|
|
224
192
|
let skipped = 0;
|
|
225
193
|
let nodes = [];
|
|
226
194
|
for (let node of this.collection) {
|
|
227
|
-
let rowHeight =
|
|
195
|
+
let rowHeight = this.rowHeight ?? this.estimatedRowHeight;
|
|
228
196
|
|
|
229
197
|
// Skip rows before the valid rectangle unless they are already cached.
|
|
230
198
|
if (node.type === 'item' && y + rowHeight < this.requestedRect.y && !this.isValid(node, y)) {
|
|
@@ -243,25 +211,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
243
211
|
}
|
|
244
212
|
}
|
|
245
213
|
|
|
246
|
-
|
|
247
|
-
let rect = new Rect(0, y, this.virtualizer.visibleRect.width,
|
|
248
|
-
this.loaderHeight ?? this.virtualizer.visibleRect.height);
|
|
249
|
-
let loader = new LayoutInfo('loader', 'loader', rect);
|
|
250
|
-
this.layoutInfos.set('loader', loader);
|
|
251
|
-
nodes.push({layoutInfo: loader});
|
|
252
|
-
y = loader.rect.maxY;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (nodes.length === 0 && this.enableEmptyState) {
|
|
256
|
-
let rect = new Rect(0, y, this.virtualizer.visibleRect.width,
|
|
257
|
-
this.placeholderHeight ?? this.virtualizer.visibleRect.height);
|
|
258
|
-
let placeholder = new LayoutInfo('placeholder', 'placeholder', rect);
|
|
259
|
-
this.layoutInfos.set('placeholder', placeholder);
|
|
260
|
-
nodes.push({layoutInfo: placeholder});
|
|
261
|
-
y = placeholder.rect.maxY;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
this.contentSize = new Size(this.virtualizer.visibleRect.width, y + this.padding);
|
|
214
|
+
this.contentSize = new Size(this.virtualizer.visibleRect.width, y);
|
|
265
215
|
return nodes;
|
|
266
216
|
}
|
|
267
217
|
|
|
@@ -271,7 +221,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
271
221
|
!this.invalidateEverything &&
|
|
272
222
|
cached &&
|
|
273
223
|
cached.node === node &&
|
|
274
|
-
y ===
|
|
224
|
+
y === cached.layoutInfo.rect.y &&
|
|
275
225
|
cached.layoutInfo.rect.intersects(this.validRect) &&
|
|
276
226
|
cached.validRect.containsRect(cached.layoutInfo.rect.intersection(this.requestedRect))
|
|
277
227
|
);
|
|
@@ -286,11 +236,6 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
286
236
|
layoutNode.node = node;
|
|
287
237
|
|
|
288
238
|
layoutNode.layoutInfo.parentKey = parentKey ?? null;
|
|
289
|
-
this.layoutInfos.set(layoutNode.layoutInfo.key, layoutNode.layoutInfo);
|
|
290
|
-
if (layoutNode.header) {
|
|
291
|
-
this.layoutInfos.set(layoutNode.header.key, layoutNode.header);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
239
|
this.layoutNodes.set(node.key, layoutNode);
|
|
295
240
|
return layoutNode;
|
|
296
241
|
}
|
|
@@ -306,17 +251,8 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
306
251
|
}
|
|
307
252
|
}
|
|
308
253
|
|
|
309
|
-
|
|
254
|
+
protected buildSection(node: Node<T>, x: number, y: number): LayoutNode {
|
|
310
255
|
let width = this.virtualizer.visibleRect.width;
|
|
311
|
-
let header = null;
|
|
312
|
-
if (node.rendered || this.forceSectionHeaders) {
|
|
313
|
-
let headerNode = this.buildSectionHeader(node, x, y);
|
|
314
|
-
header = headerNode.layoutInfo;
|
|
315
|
-
header.key += ':header';
|
|
316
|
-
header.parentKey = node.key;
|
|
317
|
-
y += header.rect.height;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
256
|
let rect = new Rect(0, y, width, 0);
|
|
321
257
|
let layoutInfo = new LayoutInfo(node.type, node.key, rect);
|
|
322
258
|
|
|
@@ -347,14 +283,13 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
347
283
|
rect.height = y - startY;
|
|
348
284
|
|
|
349
285
|
return {
|
|
350
|
-
header,
|
|
351
286
|
layoutInfo,
|
|
352
287
|
children,
|
|
353
288
|
validRect: layoutInfo.rect.intersection(this.requestedRect)
|
|
354
289
|
};
|
|
355
290
|
}
|
|
356
291
|
|
|
357
|
-
|
|
292
|
+
protected buildSectionHeader(node: Node<T>, x: number, y: number): LayoutNode {
|
|
358
293
|
let width = this.virtualizer.visibleRect.width;
|
|
359
294
|
let rectHeight = this.headingHeight;
|
|
360
295
|
let isEstimated = false;
|
|
@@ -365,7 +300,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
365
300
|
// Mark as estimated if the size of the overall virtualizer changed,
|
|
366
301
|
// or the content of the item changed.
|
|
367
302
|
let previousLayoutNode = this.layoutNodes.get(node.key);
|
|
368
|
-
let previousLayoutInfo = previousLayoutNode?.
|
|
303
|
+
let previousLayoutInfo = previousLayoutNode?.layoutInfo;
|
|
369
304
|
if (previousLayoutInfo) {
|
|
370
305
|
let curNode = this.collection.getItem(node.key);
|
|
371
306
|
let lastNode = this.lastCollection ? this.lastCollection.getItem(node.key) : null;
|
|
@@ -391,7 +326,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
391
326
|
};
|
|
392
327
|
}
|
|
393
328
|
|
|
394
|
-
|
|
329
|
+
protected buildItem(node: Node<T>, x: number, y: number): LayoutNode {
|
|
395
330
|
let width = this.virtualizer.visibleRect.width;
|
|
396
331
|
let rectHeight = this.rowHeight;
|
|
397
332
|
let isEstimated = false;
|
|
@@ -415,14 +350,8 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
415
350
|
rectHeight = DEFAULT_HEIGHT;
|
|
416
351
|
}
|
|
417
352
|
|
|
418
|
-
if (typeof this.indentationForItem === 'function') {
|
|
419
|
-
x += this.indentationForItem(this.collection, node.key) || 0;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
353
|
let rect = new Rect(x, y, width - x, rectHeight);
|
|
423
354
|
let layoutInfo = new LayoutInfo(node.type, node.key, rect);
|
|
424
|
-
// allow overflow so the focus ring/selection ring can extend outside to overlap with the adjacent items borders
|
|
425
|
-
layoutInfo.allowOverflow = true;
|
|
426
355
|
layoutInfo.estimatedSize = isEstimated;
|
|
427
356
|
return {
|
|
428
357
|
layoutInfo,
|
|
@@ -431,18 +360,19 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
431
360
|
}
|
|
432
361
|
|
|
433
362
|
updateItemSize(key: Key, size: Size) {
|
|
434
|
-
let
|
|
363
|
+
let layoutNode = this.layoutNodes.get(key);
|
|
435
364
|
// If no layoutInfo, item has been deleted/removed.
|
|
436
|
-
if (!
|
|
365
|
+
if (!layoutNode) {
|
|
437
366
|
return false;
|
|
438
367
|
}
|
|
439
368
|
|
|
369
|
+
let layoutInfo = layoutNode.layoutInfo;
|
|
440
370
|
layoutInfo.estimatedSize = false;
|
|
441
371
|
if (layoutInfo.rect.height !== size.height) {
|
|
442
372
|
// Copy layout info rather than mutating so that later caches are invalidated.
|
|
443
373
|
let newLayoutInfo = layoutInfo.copy();
|
|
444
374
|
newLayoutInfo.rect.height = size.height;
|
|
445
|
-
|
|
375
|
+
layoutNode.layoutInfo = newLayoutInfo;
|
|
446
376
|
|
|
447
377
|
// Items after this layoutInfo will need to be repositioned to account for the new height.
|
|
448
378
|
// Adjust the validRect so that only items above remain valid.
|
|
@@ -473,9 +403,7 @@ export class ListLayout<T> extends Layout<Node<T>, ListLayoutProps> implements D
|
|
|
473
403
|
n.validRect = n.validRect.intersection(this.validRect);
|
|
474
404
|
|
|
475
405
|
// Replace layout info in LayoutNode
|
|
476
|
-
if (n.
|
|
477
|
-
n.header = newLayoutInfo;
|
|
478
|
-
} else if (n.layoutInfo === oldLayoutInfo) {
|
|
406
|
+
if (n.layoutInfo === oldLayoutInfo) {
|
|
479
407
|
n.layoutInfo = newLayoutInfo;
|
|
480
408
|
}
|
|
481
409
|
}
|
package/src/TableLayout.ts
CHANGED
|
@@ -14,34 +14,24 @@ import {DropTarget, Key} from '@react-types/shared';
|
|
|
14
14
|
import {getChildNodes} from '@react-stately/collections';
|
|
15
15
|
import {GridNode} from '@react-types/grid';
|
|
16
16
|
import {InvalidationContext, LayoutInfo, Point, Rect, Size} from '@react-stately/virtualizer';
|
|
17
|
-
import {LayoutNode, ListLayout, ListLayoutOptions
|
|
17
|
+
import {LayoutNode, ListLayout, ListLayoutOptions} from './ListLayout';
|
|
18
18
|
import {TableCollection} from '@react-types/table';
|
|
19
19
|
import {TableColumnLayout} from '@react-stately/table';
|
|
20
20
|
|
|
21
|
-
export interface
|
|
22
|
-
scrollContainer?: 'table' | 'body'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface TableLayoutProps extends ListLayoutProps {
|
|
21
|
+
export interface TableLayoutProps {
|
|
26
22
|
columnWidths?: Map<Key, number>
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
export class TableLayout<T> extends ListLayout<T> {
|
|
30
|
-
collection: TableCollection<T>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
scrollContainer: 'table' | 'body';
|
|
38
|
-
private disableSticky: boolean;
|
|
39
|
-
|
|
40
|
-
constructor(options: TableLayoutOptions<T>) {
|
|
25
|
+
export class TableLayout<T, O extends TableLayoutProps = TableLayoutProps> extends ListLayout<T, O> {
|
|
26
|
+
protected collection: TableCollection<T>;
|
|
27
|
+
private columnWidths: Map<Key, number>;
|
|
28
|
+
private stickyColumnIndices: number[];
|
|
29
|
+
private lastPersistedKeys: Set<Key> = null;
|
|
30
|
+
private persistedIndices: Map<Key, number[]> = new Map();
|
|
31
|
+
|
|
32
|
+
constructor(options: ListLayoutOptions) {
|
|
41
33
|
super(options);
|
|
42
|
-
this.scrollContainer = options.scrollContainer || 'table';
|
|
43
34
|
this.stickyColumnIndices = [];
|
|
44
|
-
this.disableSticky = this.checkChrome105();
|
|
45
35
|
}
|
|
46
36
|
|
|
47
37
|
private columnsChanged(newCollection: TableCollection<T>, oldCollection: TableCollection<T> | null) {
|
|
@@ -56,7 +46,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
56
46
|
);
|
|
57
47
|
}
|
|
58
48
|
|
|
59
|
-
validate(invalidationContext: InvalidationContext<
|
|
49
|
+
validate(invalidationContext: InvalidationContext<O>): void {
|
|
60
50
|
let newCollection = this.virtualizer.collection as TableCollection<T>;
|
|
61
51
|
|
|
62
52
|
// If columnWidths were provided via layoutOptions, update those.
|
|
@@ -76,21 +66,19 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
76
66
|
}
|
|
77
67
|
|
|
78
68
|
protected buildCollection(): LayoutNode[] {
|
|
79
|
-
// Track whether we were previously loading. This is used to adjust the animations of async loading vs inserts.
|
|
80
|
-
let loadingState = this.collection.body.props.loadingState;
|
|
81
|
-
this.isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
|
|
82
69
|
this.stickyColumnIndices = [];
|
|
83
70
|
|
|
84
71
|
for (let column of this.collection.columns) {
|
|
85
72
|
// The selection cell and any other sticky columns always need to be visible.
|
|
86
73
|
// In addition, row headers need to be in the DOM for accessibility labeling.
|
|
87
|
-
if (
|
|
74
|
+
if (this.isStickyColumn(column) || this.collection.rowHeaderColumnKeys.has(column.key)) {
|
|
88
75
|
this.stickyColumnIndices.push(column.index);
|
|
89
76
|
}
|
|
90
77
|
}
|
|
91
78
|
|
|
92
|
-
let header = this.
|
|
93
|
-
|
|
79
|
+
let header = this.buildTableHeader();
|
|
80
|
+
this.layoutNodes.set(header.layoutInfo.key, header);
|
|
81
|
+
let body = this.buildBody(header.layoutInfo.rect.height);
|
|
94
82
|
this.lastPersistedKeys = null;
|
|
95
83
|
|
|
96
84
|
body.layoutInfo.rect.width = Math.max(header.layoutInfo.rect.width, body.layoutInfo.rect.width);
|
|
@@ -101,7 +89,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
101
89
|
];
|
|
102
90
|
}
|
|
103
91
|
|
|
104
|
-
|
|
92
|
+
protected buildTableHeader(): LayoutNode {
|
|
105
93
|
let rect = new Rect(0, 0, 0, 0);
|
|
106
94
|
let layoutInfo = new LayoutInfo('header', this.collection.head?.key ?? 'header', rect);
|
|
107
95
|
layoutInfo.isSticky = true;
|
|
@@ -122,8 +110,6 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
122
110
|
rect.width = width;
|
|
123
111
|
rect.height = y;
|
|
124
112
|
|
|
125
|
-
this.layoutInfos.set(layoutInfo.key, layoutInfo);
|
|
126
|
-
|
|
127
113
|
return {
|
|
128
114
|
layoutInfo,
|
|
129
115
|
children,
|
|
@@ -131,7 +117,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
131
117
|
};
|
|
132
118
|
}
|
|
133
119
|
|
|
134
|
-
|
|
120
|
+
protected buildHeaderRow(headerRow: GridNode<T>, x: number, y: number): LayoutNode {
|
|
135
121
|
let rect = new Rect(0, y, 0, 0);
|
|
136
122
|
let row = new LayoutInfo('headerrow', headerRow.key, rect);
|
|
137
123
|
|
|
@@ -166,8 +152,6 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
166
152
|
if (child.layoutInfo.rect.height !== height) {
|
|
167
153
|
// Need to copy the layout info before we mutate it.
|
|
168
154
|
child.layoutInfo = child.layoutInfo.copy();
|
|
169
|
-
this.layoutInfos.set(child.layoutInfo.key, child.layoutInfo);
|
|
170
|
-
|
|
171
155
|
child.layoutInfo.rect.height = height;
|
|
172
156
|
}
|
|
173
157
|
}
|
|
@@ -209,15 +193,18 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
209
193
|
return {height, isEstimated};
|
|
210
194
|
}
|
|
211
195
|
|
|
212
|
-
|
|
196
|
+
protected getEstimatedRowHeight(): number {
|
|
197
|
+
return this.rowHeight ?? this.estimatedRowHeight;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected buildColumn(node: GridNode<T>, x: number, y: number): LayoutNode {
|
|
213
201
|
let width = this.getRenderedColumnWidth(node);
|
|
214
202
|
let {height, isEstimated} = this.getEstimatedHeight(node, width, this.headingHeight, this.estimatedHeadingHeight);
|
|
215
203
|
let rect = new Rect(x, y, width, height);
|
|
216
204
|
let layoutInfo = new LayoutInfo(node.type, node.key, rect);
|
|
217
|
-
layoutInfo.isSticky =
|
|
205
|
+
layoutInfo.isSticky = this.isStickyColumn(node);
|
|
218
206
|
layoutInfo.zIndex = layoutInfo.isSticky ? 2 : 1;
|
|
219
207
|
layoutInfo.estimatedSize = isEstimated;
|
|
220
|
-
layoutInfo.allowOverflow = true;
|
|
221
208
|
|
|
222
209
|
return {
|
|
223
210
|
layoutInfo,
|
|
@@ -225,7 +212,13 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
225
212
|
};
|
|
226
213
|
}
|
|
227
214
|
|
|
228
|
-
|
|
215
|
+
// For subclasses.
|
|
216
|
+
// eslint-disable-next-line
|
|
217
|
+
protected isStickyColumn(node: GridNode<T>) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
protected buildBody(y: number): LayoutNode {
|
|
229
222
|
let rect = new Rect(0, y, 0, 0);
|
|
230
223
|
let layoutInfo = new LayoutInfo('rowgroup', this.collection.body.key, rect);
|
|
231
224
|
|
|
@@ -233,9 +226,8 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
233
226
|
let skipped = 0;
|
|
234
227
|
let width = 0;
|
|
235
228
|
let children: LayoutNode[] = [];
|
|
229
|
+
let rowHeight = this.getEstimatedRowHeight();
|
|
236
230
|
for (let [i, node] of [...getChildNodes(this.collection.body, this.collection)].entries()) {
|
|
237
|
-
let rowHeight = (this.rowHeight ?? this.estimatedRowHeight) + 1;
|
|
238
|
-
|
|
239
231
|
// Skip rows before the valid rectangle unless they are already cached.
|
|
240
232
|
if (y + rowHeight < this.requestedRect.y && !this.isValid(node, y)) {
|
|
241
233
|
y += rowHeight;
|
|
@@ -257,36 +249,13 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
257
249
|
}
|
|
258
250
|
}
|
|
259
251
|
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
let rect = new Rect(40, Math.max(y, 40), (width || this.virtualizer.visibleRect.width) - 80, children.length === 0 ? this.virtualizer.visibleRect.height - 80 : 60);
|
|
263
|
-
let loader = new LayoutInfo('loader', 'loader', rect);
|
|
264
|
-
loader.parentKey = layoutInfo.key;
|
|
265
|
-
loader.isSticky = !this.disableSticky && children.length === 0;
|
|
266
|
-
this.layoutInfos.set('loader', loader);
|
|
267
|
-
children.push({layoutInfo: loader, validRect: loader.rect});
|
|
268
|
-
y = loader.rect.maxY;
|
|
269
|
-
width = Math.max(width, rect.width);
|
|
270
|
-
} else if (children.length === 0) {
|
|
271
|
-
if (this.enableEmptyState) {
|
|
272
|
-
let rect = new Rect(40, Math.max(y, 40), this.virtualizer.visibleRect.width - 80, this.virtualizer.visibleRect.height - 80);
|
|
273
|
-
let empty = new LayoutInfo('empty', 'empty', rect);
|
|
274
|
-
empty.parentKey = layoutInfo.key;
|
|
275
|
-
empty.isSticky = !this.disableSticky;
|
|
276
|
-
this.layoutInfos.set('empty', empty);
|
|
277
|
-
children.push({layoutInfo: empty, validRect: empty.rect});
|
|
278
|
-
y = empty.rect.maxY;
|
|
279
|
-
width = Math.max(width, rect.width);
|
|
280
|
-
} else {
|
|
281
|
-
y = this.virtualizer.visibleRect.maxY;
|
|
282
|
-
}
|
|
252
|
+
if (children.length === 0) {
|
|
253
|
+
y = this.virtualizer.visibleRect.maxY;
|
|
283
254
|
}
|
|
284
255
|
|
|
285
256
|
rect.width = width;
|
|
286
257
|
rect.height = y - startY;
|
|
287
258
|
|
|
288
|
-
this.layoutInfos.set(layoutInfo.key, layoutInfo);
|
|
289
|
-
|
|
290
259
|
return {
|
|
291
260
|
layoutInfo,
|
|
292
261
|
children,
|
|
@@ -310,7 +279,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
310
279
|
}
|
|
311
280
|
}
|
|
312
281
|
|
|
313
|
-
|
|
282
|
+
protected buildRow(node: GridNode<T>, x: number, y: number): LayoutNode {
|
|
314
283
|
let rect = new Rect(x, y, 0, 0);
|
|
315
284
|
let layoutInfo = new LayoutInfo('row', node.key, rect);
|
|
316
285
|
|
|
@@ -338,8 +307,8 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
338
307
|
|
|
339
308
|
this.setChildHeights(children, height);
|
|
340
309
|
|
|
341
|
-
rect.width = this.
|
|
342
|
-
rect.height = height
|
|
310
|
+
rect.width = this.layoutNodes.get(this.collection.head?.key ?? 'header').layoutInfo.rect.width;
|
|
311
|
+
rect.height = height;
|
|
343
312
|
|
|
344
313
|
return {
|
|
345
314
|
layoutInfo,
|
|
@@ -348,12 +317,12 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
348
317
|
};
|
|
349
318
|
}
|
|
350
319
|
|
|
351
|
-
|
|
320
|
+
protected buildCell(node: GridNode<T>, x: number, y: number): LayoutNode {
|
|
352
321
|
let width = this.getRenderedColumnWidth(node);
|
|
353
322
|
let {height, isEstimated} = this.getEstimatedHeight(node, width, this.rowHeight, this.estimatedRowHeight);
|
|
354
323
|
let rect = new Rect(x, y, width, height);
|
|
355
324
|
let layoutInfo = new LayoutInfo(node.type, node.key, rect);
|
|
356
|
-
layoutInfo.isSticky =
|
|
325
|
+
layoutInfo.isSticky = this.isStickyColumn(node);
|
|
357
326
|
layoutInfo.zIndex = layoutInfo.isSticky ? 2 : 1;
|
|
358
327
|
layoutInfo.estimatedSize = isEstimated;
|
|
359
328
|
|
|
@@ -367,7 +336,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
367
336
|
// Adjust rect to keep number of visible rows consistent.
|
|
368
337
|
// (only if height > 1 for getDropTargetFromPoint)
|
|
369
338
|
if (rect.height > 1) {
|
|
370
|
-
let rowHeight =
|
|
339
|
+
let rowHeight = this.getEstimatedRowHeight();
|
|
371
340
|
rect.y = Math.floor(rect.y / rowHeight) * rowHeight;
|
|
372
341
|
rect.height = Math.ceil(rect.height / rowHeight) * rowHeight;
|
|
373
342
|
}
|
|
@@ -508,7 +477,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
508
477
|
|
|
509
478
|
// Build a map of parentKey => indices of children to persist.
|
|
510
479
|
for (let key of this.virtualizer.persistedKeys) {
|
|
511
|
-
let layoutInfo = this.
|
|
480
|
+
let layoutInfo = this.layoutNodes.get(key)?.layoutInfo;
|
|
512
481
|
|
|
513
482
|
// Walk up ancestors so parents are also persisted if children are.
|
|
514
483
|
while (layoutInfo && layoutInfo.parentKey) {
|
|
@@ -526,7 +495,7 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
526
495
|
indices.push(index);
|
|
527
496
|
}
|
|
528
497
|
|
|
529
|
-
layoutInfo = this.
|
|
498
|
+
layoutInfo = this.layoutNodes.get(layoutInfo.parentKey)?.layoutInfo;
|
|
530
499
|
}
|
|
531
500
|
}
|
|
532
501
|
|
|
@@ -535,24 +504,6 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
535
504
|
}
|
|
536
505
|
}
|
|
537
506
|
|
|
538
|
-
// Checks if Chrome version is 105 or greater
|
|
539
|
-
private checkChrome105() {
|
|
540
|
-
if (typeof window === 'undefined' || window.navigator == null) {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
let isChrome105;
|
|
545
|
-
if (window.navigator['userAgentData']) {
|
|
546
|
-
isChrome105 = window.navigator['userAgentData']?.brands.some(b => b.brand === 'Chromium' && Number(b.version) === 105);
|
|
547
|
-
} else {
|
|
548
|
-
let regex = /Chrome\/(\d+)/;
|
|
549
|
-
let matches = regex.exec(window.navigator.userAgent);
|
|
550
|
-
isChrome105 = matches && matches.length >= 2 && Number(matches[1]) === 105;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return isChrome105;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
507
|
getDropTargetFromPoint(x: number, y: number, isValidDropTarget: (target: DropTarget) => boolean): DropTarget {
|
|
557
508
|
x += this.virtualizer.visibleRect.x;
|
|
558
509
|
y += this.virtualizer.visibleRect.y;
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
export type {ListLayoutOptions,
|
|
13
|
-
export type {
|
|
12
|
+
export type {ListLayoutOptions, LayoutNode} from './ListLayout';
|
|
13
|
+
export type {TableLayoutProps} from './TableLayout';
|
|
14
14
|
export {ListLayout} from './ListLayout';
|
|
15
15
|
export {TableLayout} from './TableLayout';
|