@react-stately/layout 3.13.10-nightly.4685 → 3.13.10-nightly.4694
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/GridLayout.main.js +137 -0
- package/dist/GridLayout.main.js.map +1 -0
- package/dist/GridLayout.mjs +132 -0
- package/dist/GridLayout.module.js +132 -0
- package/dist/GridLayout.module.js.map +1 -0
- package/dist/ListLayout.main.js +23 -63
- package/dist/ListLayout.main.js.map +1 -1
- package/dist/ListLayout.mjs +24 -64
- package/dist/ListLayout.module.js +24 -64
- package/dist/ListLayout.module.js.map +1 -1
- package/dist/TableLayout.main.js +30 -70
- package/dist/TableLayout.main.js.map +1 -1
- package/dist/TableLayout.mjs +30 -70
- package/dist/TableLayout.module.js +30 -70
- package/dist/TableLayout.module.js.map +1 -1
- package/dist/import.mjs +3 -1
- package/dist/main.js +3 -0
- package/dist/main.js.map +1 -1
- package/dist/module.js +3 -1
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +83 -49
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/GridLayout.ts +215 -0
- package/src/ListLayout.ts +50 -104
- package/src/TableLayout.ts +48 -94
- package/src/index.ts +4 -2
package/src/TableLayout.ts
CHANGED
|
@@ -10,38 +10,28 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {DropTarget, Key} from '@react-types/shared';
|
|
13
|
+
import {DropTarget, ItemDropTarget, 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,31 +504,10 @@ 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;
|
|
559
510
|
|
|
560
|
-
// Offset for height of header row
|
|
561
|
-
y -= this.virtualizer.layout.getVisibleLayoutInfos(new Rect(x, y, 1, 1)).find(info => info.type === 'headerrow')?.rect.height;
|
|
562
|
-
|
|
563
511
|
// Custom variation of this.virtualizer.keyAtPoint that ignores body
|
|
564
512
|
let key: Key;
|
|
565
513
|
let point = new Point(x, y);
|
|
@@ -603,4 +551,10 @@ export class TableLayout<T> extends ListLayout<T> {
|
|
|
603
551
|
|
|
604
552
|
return target;
|
|
605
553
|
}
|
|
554
|
+
|
|
555
|
+
getDropTargetLayoutInfo(target: ItemDropTarget): LayoutInfo {
|
|
556
|
+
let layoutInfo = super.getDropTargetLayoutInfo(target);
|
|
557
|
+
layoutInfo.parentKey = this.collection.body.key;
|
|
558
|
+
return layoutInfo;
|
|
559
|
+
}
|
|
606
560
|
}
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
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 {
|
|
13
|
-
export type {
|
|
12
|
+
export type {GridLayoutOptions} from './GridLayout';
|
|
13
|
+
export type {ListLayoutOptions, LayoutNode} from './ListLayout';
|
|
14
|
+
export type {TableLayoutProps} from './TableLayout';
|
|
15
|
+
export {GridLayout} from './GridLayout';
|
|
14
16
|
export {ListLayout} from './ListLayout';
|
|
15
17
|
export {TableLayout} from './TableLayout';
|