@react-stately/layout 4.2.0 → 4.2.2

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/src/ListLayout.ts CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  import {Collection, DropTarget, DropTargetDelegate, ItemDropTarget, Key, Node} from '@react-types/shared';
14
14
  import {getChildNodes} from '@react-stately/collections';
15
- import {InvalidationContext, Layout, LayoutInfo, Point, Rect, Size} from '@react-stately/virtualizer';
15
+ import {InvalidationContext, Layout, LayoutInfo, Rect, Size} from '@react-stately/virtualizer';
16
16
 
17
17
  export interface ListLayoutOptions {
18
18
  /**
@@ -115,12 +115,12 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
115
115
  return this.virtualizer!.collection;
116
116
  }
117
117
 
118
- getLayoutInfo(key: Key) {
118
+ getLayoutInfo(key: Key): LayoutInfo | null {
119
119
  this.ensureLayoutInfo(key);
120
120
  return this.layoutNodes.get(key)?.layoutInfo || null;
121
121
  }
122
122
 
123
- getVisibleLayoutInfos(rect: Rect) {
123
+ getVisibleLayoutInfos(rect: Rect): LayoutInfo[] {
124
124
  // Adjust rect to keep number of visible rows consistent.
125
125
  // (only if height > 1 for getDropTargetFromPoint)
126
126
  if (rect.height > 1) {
@@ -151,7 +151,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
151
151
  return res;
152
152
  }
153
153
 
154
- protected layoutIfNeeded(rect: Rect) {
154
+ protected layoutIfNeeded(rect: Rect): void {
155
155
  if (!this.lastCollection) {
156
156
  return;
157
157
  }
@@ -160,7 +160,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
160
160
  this.requestedRect = this.requestedRect.union(rect);
161
161
  this.rootNodes = this.buildCollection();
162
162
  }
163
-
163
+
164
164
  // Ensure all of the persisted keys are available.
165
165
  for (let key of this.virtualizer!.persistedKeys) {
166
166
  if (this.ensureLayoutInfo(key)) {
@@ -183,7 +183,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
183
183
  return false;
184
184
  }
185
185
 
186
- protected isVisible(node: LayoutNode, rect: Rect) {
186
+ protected isVisible(node: LayoutNode, rect: Rect): boolean {
187
187
  return node.layoutInfo.rect.intersects(rect) || node.layoutInfo.isSticky || node.layoutInfo.type === 'header' || this.virtualizer!.isPersistedKey(node.layoutInfo.key);
188
188
  }
189
189
 
@@ -211,7 +211,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
211
211
  || newOptions.padding !== oldOptions.padding;
212
212
  }
213
213
 
214
- update(invalidationContext: InvalidationContext<O>) {
214
+ update(invalidationContext: InvalidationContext<O>): void {
215
215
  let collection = this.virtualizer!.collection;
216
216
 
217
217
  // Reset valid rect if we will have to invalidate everything.
@@ -281,11 +281,11 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
281
281
  return nodes;
282
282
  }
283
283
 
284
- protected isValid(node: Node<T>, y: number) {
284
+ protected isValid(node: Node<T>, y: number): boolean {
285
285
  let cached = this.layoutNodes.get(node.key);
286
286
  return (
287
287
  !this.invalidateEverything &&
288
- cached &&
288
+ !!cached &&
289
289
  cached.node === node &&
290
290
  y === cached.layoutInfo.rect.y &&
291
291
  cached.layoutInfo.rect.intersects(this.validRect) &&
@@ -446,7 +446,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
446
446
  };
447
447
  }
448
448
 
449
- updateItemSize(key: Key, size: Size) {
449
+ updateItemSize(key: Key, size: Size): boolean {
450
450
  let layoutNode = this.layoutNodes.get(key);
451
451
  // If no layoutInfo, item has been deleted/removed.
452
452
  if (!layoutNode) {
@@ -497,7 +497,7 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
497
497
  }
498
498
  }
499
499
 
500
- getContentSize() {
500
+ getContentSize(): Size {
501
501
  return this.contentSize;
502
502
  }
503
503
 
@@ -505,7 +505,26 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
505
505
  x += this.virtualizer!.visibleRect.x;
506
506
  y += this.virtualizer!.visibleRect.y;
507
507
 
508
- let key = this.virtualizer!.keyAtPoint(new Point(x, y));
508
+ // Find the closest item within on either side of the point using the gap width.
509
+ let searchRect = new Rect(x, Math.max(0, y - this.gap), 1, this.gap * 2);
510
+ let candidates = this.getVisibleLayoutInfos(searchRect);
511
+ let key: Key | null = null;
512
+ let minDistance = Infinity;
513
+ for (let candidate of candidates) {
514
+ // Ignore items outside the search rect, e.g. persisted keys.
515
+ if (!candidate.rect.intersects(searchRect)) {
516
+ continue;
517
+ }
518
+
519
+ let yDist = Math.abs(candidate.rect.y - y);
520
+ let maxYDist = Math.abs(candidate.rect.maxY - y);
521
+ let dist = Math.min(yDist, maxYDist);
522
+ if (dist < minDistance) {
523
+ minDistance = dist;
524
+ key = candidate.key;
525
+ }
526
+ }
527
+
509
528
  if (key == null || this.virtualizer!.collection.size === 0) {
510
529
  return {type: 'root'};
511
530
  }
@@ -367,7 +367,7 @@ export class TableLayout<T, O extends TableLayoutProps = TableLayoutProps> exten
367
367
  };
368
368
  }
369
369
 
370
- getVisibleLayoutInfos(rect: Rect) {
370
+ getVisibleLayoutInfos(rect: Rect): LayoutInfo[] {
371
371
  // Adjust rect to keep number of visible rows consistent.
372
372
  // (only if height > 1 for getDropTargetFromPoint)
373
373
  if (rect.height > 1) {
@@ -542,17 +542,23 @@ export class TableLayout<T, O extends TableLayoutProps = TableLayoutProps> exten
542
542
  x += this.virtualizer!.visibleRect.x;
543
543
  y += this.virtualizer!.visibleRect.y;
544
544
 
545
- // Custom variation of this.virtualizer.keyAtPoint that ignores body
545
+ // Find the closest item within on either side of the point using the gap width.
546
+ let searchRect = new Rect(x, Math.max(0, y - this.gap), 1, this.gap * 2);
547
+ let candidates = this.getVisibleLayoutInfos(searchRect);
546
548
  let key: Key | null = null;
547
- let point = new Point(x, y);
548
- let rectAtPoint = new Rect(point.x, point.y, 1, 1);
549
- let layoutInfos = this.virtualizer!.layout.getVisibleLayoutInfos(rectAtPoint).filter(info => info.type === 'row');
550
-
551
- // Layout may return multiple layout infos in the case of
552
- // persisted keys, so find the first one that actually intersects.
553
- for (let layoutInfo of layoutInfos) {
554
- if (layoutInfo.rect.intersects(rectAtPoint)) {
555
- key = layoutInfo.key;
549
+ let minDistance = Infinity;
550
+ for (let candidate of candidates) {
551
+ // Ignore items outside the search rect, e.g. persisted keys.
552
+ if (candidate.type !== 'row' || !candidate.rect.intersects(searchRect)) {
553
+ continue;
554
+ }
555
+
556
+ let yDist = Math.abs(candidate.rect.y - y);
557
+ let maxYDist = Math.abs(candidate.rect.maxY - y);
558
+ let dist = Math.min(yDist, maxYDist);
559
+ if (dist < minDistance) {
560
+ minDistance = dist;
561
+ key = candidate.key;
556
562
  }
557
563
  }
558
564
 
@@ -184,7 +184,7 @@ export class WaterfallLayout<T extends object, O extends WaterfallLayoutOptions
184
184
  return layoutInfos;
185
185
  }
186
186
 
187
- updateItemSize(key: Key, size: Size) {
187
+ updateItemSize(key: Key, size: Size): boolean {
188
188
  let layoutInfo = this.layoutInfos.get(key);
189
189
  if (!size || !layoutInfo) {
190
190
  return false;