|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | import {DropTarget, DropTargetDelegate, ItemDropTarget, Key, Node} from '@react-types/shared';
|
14 |
| -import {InvalidationContext, Layout, LayoutInfo, Point, Rect, Size} from '@react-stately/virtualizer'; |
| 14 | +import {InvalidationContext, Layout, LayoutInfo, Rect, Size} from '@react-stately/virtualizer'; |
15 | 15 |
|
16 | 16 | export interface GridLayoutOptions {
|
17 | 17 | /**
|
@@ -102,6 +102,7 @@ export class GridLayout<T, O extends GridLayoutOptions = GridLayoutOptions> exte
|
102 | 102 | // Compute the number of rows and columns needed to display the content
|
103 | 103 | let columns = Math.floor(visibleWidth / (minItemSize.width + minSpace.width));
|
104 | 104 | let numColumns = Math.max(1, Math.min(maxColumns, columns));
|
| 105 | + this.numColumns = numColumns; |
105 | 106 |
|
106 | 107 | // Compute the available width (minus the space between items)
|
107 | 108 | let width = visibleWidth - (minSpace.width * Math.max(0, numColumns));
|
@@ -223,7 +224,46 @@ export class GridLayout<T, O extends GridLayoutOptions = GridLayoutOptions> exte
|
223 | 224 | x += this.virtualizer!.visibleRect.x;
|
224 | 225 | y += this.virtualizer!.visibleRect.y;
|
225 | 226 |
|
226 |
| - let key = this.virtualizer!.keyAtPoint(new Point(x, y)); |
| 227 | + // Find the closest item within on either side of the point using the gap width. |
| 228 | + let key: Key | null = null; |
| 229 | + if (this.numColumns === 1) { |
| 230 | + let searchRect = new Rect(x, Math.max(0, y - this.gap.height), 1, this.gap.height * 2); |
| 231 | + let candidates = this.getVisibleLayoutInfos(searchRect); |
| 232 | + let minDistance = Infinity; |
| 233 | + for (let candidate of candidates) { |
| 234 | + // Ignore items outside the search rect, e.g. persisted keys. |
| 235 | + if (!candidate.rect.intersects(searchRect)) { |
| 236 | + continue; |
| 237 | + } |
| 238 | + |
| 239 | + let yDist = Math.abs(candidate.rect.y - x); |
| 240 | + let maxYDist = Math.abs(candidate.rect.maxY - x); |
| 241 | + let dist = Math.min(yDist, maxYDist); |
| 242 | + if (dist < minDistance) { |
| 243 | + minDistance = dist; |
| 244 | + key = candidate.key; |
| 245 | + } |
| 246 | + } |
| 247 | + } else { |
| 248 | + let searchRect = new Rect(Math.max(0, x - this.gap.width), y, this.gap.width * 2, 1); |
| 249 | + let candidates = this.getVisibleLayoutInfos(searchRect); |
| 250 | + let minDistance = Infinity; |
| 251 | + for (let candidate of candidates) { |
| 252 | + // Ignore items outside the search rect, e.g. persisted keys. |
| 253 | + if (!candidate.rect.intersects(searchRect)) { |
| 254 | + continue; |
| 255 | + } |
| 256 | + |
| 257 | + let xDist = Math.abs(candidate.rect.x - x); |
| 258 | + let maxXDist = Math.abs(candidate.rect.maxX - x); |
| 259 | + let dist = Math.min(xDist, maxXDist); |
| 260 | + if (dist < minDistance) { |
| 261 | + minDistance = dist; |
| 262 | + key = candidate.key; |
| 263 | + } |
| 264 | + } |
| 265 | + } |
| 266 | + |
227 | 267 | let layoutInfo = key != null ? this.getLayoutInfo(key) : null;
|
228 | 268 | if (!layoutInfo) {
|
229 | 269 | return {type: 'root'};
|
|
0 commit comments