@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.
@@ -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, ListLayoutProps} from './ListLayout';
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 TableLayoutOptions<T> extends ListLayoutOptions<T> {
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
- lastCollection: TableCollection<T>;
32
- columnWidths: Map<Key, number>;
33
- stickyColumnIndices: number[];
34
- isLoading = false;
35
- lastPersistedKeys: Set<Key> = null;
36
- persistedIndices: Map<Key, number[]> = new Map();
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<TableLayoutProps>): void {
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 (column.props.isDragButtonCell || column.props.isSelectionCell || this.collection.rowHeaderColumnKeys.has(column.key)) {
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.buildColumnHeader();
93
- let body = this.buildBody(this.scrollContainer === 'body' ? 0 : header.layoutInfo.rect.height);
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
- private buildColumnHeader(): LayoutNode {
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
- private buildHeaderRow(headerRow: GridNode<T>, x: number, y: number): LayoutNode {
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
- private buildColumn(node: GridNode<T>, x: number, y: number): LayoutNode {
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 = !this.disableSticky && (node.props?.isDragButtonCell || node.props?.isSelectionCell);
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
- private buildBody(y: number): LayoutNode {
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 (this.isLoading) {
261
- // Add some margin around the loader to ensure that scrollbars don't flicker in and out.
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
- private buildRow(node: GridNode<T>, x: number, y: number): LayoutNode {
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.layoutInfos.get(this.collection.head?.key ?? 'header').rect.width;
342
- rect.height = height + 1; // +1 for bottom border
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
- private buildCell(node: GridNode<T>, x: number, y: number): LayoutNode {
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 = !this.disableSticky && (node.props?.isDragButtonCell || node.props?.isSelectionCell);
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 = (this.rowHeight ?? this.estimatedRowHeight) + 1; // +1 for border
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.layoutInfos.get(key);
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.layoutInfos.get(layoutInfo.parentKey);
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 {ListLayoutOptions, ListLayoutProps, LayoutNode} from './ListLayout';
13
- export type {TableLayoutOptions, TableLayoutProps} from './TableLayout';
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';