@react-aria/selection 3.15.0 → 3.16.0

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/import.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {useRef as $eCAIO$useRef, useEffect as $eCAIO$useEffect, useMemo as $eCAIO$useMemo} from "react";
2
2
  import {getFocusableTreeWalker as $eCAIO$getFocusableTreeWalker, focusSafely as $eCAIO$focusSafely} from "@react-aria/focus";
3
- import {focusWithoutScrolling as $eCAIO$focusWithoutScrolling, useEvent as $eCAIO$useEvent, scrollIntoView as $eCAIO$scrollIntoView, scrollIntoViewport as $eCAIO$scrollIntoViewport, mergeProps as $eCAIO$mergeProps, isAppleDevice as $eCAIO$isAppleDevice, isMac as $eCAIO$isMac, isScrollable as $eCAIO$isScrollable} from "@react-aria/utils";
3
+ import {focusWithoutScrolling as $eCAIO$focusWithoutScrolling, useEvent as $eCAIO$useEvent, scrollIntoViewport as $eCAIO$scrollIntoViewport, scrollIntoView as $eCAIO$scrollIntoView, mergeProps as $eCAIO$mergeProps, isAppleDevice as $eCAIO$isAppleDevice, isMac as $eCAIO$isMac, isScrollable as $eCAIO$isScrollable} from "@react-aria/utils";
4
4
  import {getInteractionModality as $eCAIO$getInteractionModality, usePress as $eCAIO$usePress, useLongPress as $eCAIO$useLongPress} from "@react-aria/interactions";
5
5
  import {useLocale as $eCAIO$useLocale, useCollator as $eCAIO$useCollator} from "@react-aria/i18n";
6
6
 
@@ -39,7 +39,6 @@ import {useLocale as $eCAIO$useLocale, useCollator as $eCAIO$useCollator} from "
39
39
  * OF ANY KIND, either express or implied. See the License for the specific language
40
40
  * governing permissions and limitations under the License.
41
41
  */
42
-
43
42
  function $feb5ffebff200149$export$d3e3bd3e26688c04(e) {
44
43
  // Ctrl + Arrow Up/Arrow Down has a system wide meaning on macOS, so use Alt instead.
45
44
  // On Windows and Ubuntu, Alt + Space has a system wide meaning.
@@ -147,27 +146,27 @@ function $ae20dd8cbca75726$export$d6daf82dcd84e87c(options) {
147
146
  if (delegate.getKeyAbove) {
148
147
  var _delegate_getLastKey, _delegate_getLastKey1;
149
148
  e.preventDefault();
150
- let nextKey1 = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate);
151
- if (nextKey1 == null && shouldFocusWrap) nextKey1 = (_delegate_getLastKey1 = delegate.getLastKey) === null || _delegate_getLastKey1 === void 0 ? void 0 : _delegate_getLastKey1.call(delegate, manager.focusedKey);
152
- navigateToKey(nextKey1);
149
+ let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate);
150
+ if (nextKey == null && shouldFocusWrap) nextKey = (_delegate_getLastKey1 = delegate.getLastKey) === null || _delegate_getLastKey1 === void 0 ? void 0 : _delegate_getLastKey1.call(delegate, manager.focusedKey);
151
+ navigateToKey(nextKey);
153
152
  }
154
153
  break;
155
154
  case "ArrowLeft":
156
155
  if (delegate.getKeyLeftOf) {
157
156
  var _delegate_getFirstKey2, _delegate_getLastKey2;
158
157
  e.preventDefault();
159
- let nextKey2 = delegate.getKeyLeftOf(manager.focusedKey);
160
- if (nextKey2 == null && shouldFocusWrap) nextKey2 = direction === "rtl" ? (_delegate_getFirstKey2 = delegate.getFirstKey) === null || _delegate_getFirstKey2 === void 0 ? void 0 : _delegate_getFirstKey2.call(delegate, manager.focusedKey) : (_delegate_getLastKey2 = delegate.getLastKey) === null || _delegate_getLastKey2 === void 0 ? void 0 : _delegate_getLastKey2.call(delegate, manager.focusedKey);
161
- navigateToKey(nextKey2, direction === "rtl" ? "first" : "last");
158
+ let nextKey = delegate.getKeyLeftOf(manager.focusedKey);
159
+ if (nextKey == null && shouldFocusWrap) nextKey = direction === "rtl" ? (_delegate_getFirstKey2 = delegate.getFirstKey) === null || _delegate_getFirstKey2 === void 0 ? void 0 : _delegate_getFirstKey2.call(delegate, manager.focusedKey) : (_delegate_getLastKey2 = delegate.getLastKey) === null || _delegate_getLastKey2 === void 0 ? void 0 : _delegate_getLastKey2.call(delegate, manager.focusedKey);
160
+ navigateToKey(nextKey, direction === "rtl" ? "first" : "last");
162
161
  }
163
162
  break;
164
163
  case "ArrowRight":
165
164
  if (delegate.getKeyRightOf) {
166
165
  var _delegate_getLastKey3, _delegate_getFirstKey3;
167
166
  e.preventDefault();
168
- let nextKey3 = delegate.getKeyRightOf(manager.focusedKey);
169
- if (nextKey3 == null && shouldFocusWrap) nextKey3 = direction === "rtl" ? (_delegate_getLastKey3 = delegate.getLastKey) === null || _delegate_getLastKey3 === void 0 ? void 0 : _delegate_getLastKey3.call(delegate, manager.focusedKey) : (_delegate_getFirstKey3 = delegate.getFirstKey) === null || _delegate_getFirstKey3 === void 0 ? void 0 : _delegate_getFirstKey3.call(delegate, manager.focusedKey);
170
- navigateToKey(nextKey3, direction === "rtl" ? "last" : "first");
167
+ let nextKey = delegate.getKeyRightOf(manager.focusedKey);
168
+ if (nextKey == null && shouldFocusWrap) nextKey = direction === "rtl" ? (_delegate_getLastKey3 = delegate.getLastKey) === null || _delegate_getLastKey3 === void 0 ? void 0 : _delegate_getLastKey3.call(delegate, manager.focusedKey) : (_delegate_getFirstKey3 = delegate.getFirstKey) === null || _delegate_getFirstKey3 === void 0 ? void 0 : _delegate_getFirstKey3.call(delegate, manager.focusedKey);
169
+ navigateToKey(nextKey, direction === "rtl" ? "last" : "first");
171
170
  }
172
171
  break;
173
172
  case "Home":
@@ -191,15 +190,15 @@ function $ae20dd8cbca75726$export$d6daf82dcd84e87c(options) {
191
190
  case "PageDown":
192
191
  if (delegate.getKeyPageBelow) {
193
192
  e.preventDefault();
194
- let nextKey4 = delegate.getKeyPageBelow(manager.focusedKey);
195
- navigateToKey(nextKey4);
193
+ let nextKey = delegate.getKeyPageBelow(manager.focusedKey);
194
+ navigateToKey(nextKey);
196
195
  }
197
196
  break;
198
197
  case "PageUp":
199
198
  if (delegate.getKeyPageAbove) {
200
199
  e.preventDefault();
201
- let nextKey5 = delegate.getKeyPageAbove(manager.focusedKey);
202
- navigateToKey(nextKey5);
200
+ let nextKey = delegate.getKeyPageAbove(manager.focusedKey);
201
+ navigateToKey(nextKey);
203
202
  }
204
203
  break;
205
204
  case "a":
@@ -282,7 +281,10 @@ function $ae20dd8cbca75726$export$d6daf82dcd84e87c(options) {
282
281
  if (element) {
283
282
  // This prevents a flash of focus on the first/last element in the collection, or the collection itself.
284
283
  (0, $eCAIO$focusWithoutScrolling)(element);
285
- (0, $eCAIO$scrollIntoView)(scrollRef.current, element);
284
+ let modality = (0, $eCAIO$getInteractionModality)();
285
+ if (modality === "keyboard") (0, $eCAIO$scrollIntoViewport)(element, {
286
+ containingElement: ref.current
287
+ });
286
288
  }
287
289
  }
288
290
  };
@@ -310,17 +312,21 @@ function $ae20dd8cbca75726$export$d6daf82dcd84e87c(options) {
310
312
  }, []);
311
313
  // If not virtualized, scroll the focused element into view when the focusedKey changes.
312
314
  // When virtualized, Virtualizer handles this internally.
315
+ let lastFocusedKey = (0, $eCAIO$useRef)(manager.focusedKey);
313
316
  (0, $eCAIO$useEffect)(()=>{
314
317
  let modality = (0, $eCAIO$getInteractionModality)();
315
- if (!isVirtualized && manager.isFocused && manager.focusedKey != null && (scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current)) {
318
+ if (manager.isFocused && manager.focusedKey != null && (scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current)) {
316
319
  let element = scrollRef.current.querySelector(`[data-key="${manager.focusedKey}"]`);
317
- if (element) {
318
- (0, $eCAIO$scrollIntoView)(scrollRef.current, element);
319
- if (modality === "keyboard") (0, $eCAIO$scrollIntoViewport)(element, {
320
+ if (element && modality === "keyboard") {
321
+ if (!isVirtualized) (0, $eCAIO$scrollIntoView)(scrollRef.current, element);
322
+ (0, $eCAIO$scrollIntoViewport)(element, {
320
323
  containingElement: ref.current
321
324
  });
322
325
  }
323
326
  }
327
+ // If the focused key becomes null (e.g. the last item is deleted), focus the whole collection.
328
+ if (manager.isFocused && manager.focusedKey == null && lastFocusedKey.current != null) (0, $eCAIO$focusSafely)(ref.current);
329
+ lastFocusedKey.current = manager.focusedKey;
324
330
  }, [
325
331
  isVirtualized,
326
332
  scrollRef,
@@ -374,7 +380,7 @@ function $ae20dd8cbca75726$export$d6daf82dcd84e87c(options) {
374
380
 
375
381
 
376
382
  function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
377
- let { selectionManager: manager , key: key , ref: ref , shouldSelectOnPressUp: shouldSelectOnPressUp , isVirtualized: isVirtualized , shouldUseVirtualFocus: shouldUseVirtualFocus , focus: focus , isDisabled: isDisabled , onAction: onAction , allowsDifferentPressOrigin: allowsDifferentPressOrigin } = options;
383
+ let { selectionManager: manager , key: key , ref: ref , shouldSelectOnPressUp: shouldSelectOnPressUp , shouldUseVirtualFocus: shouldUseVirtualFocus , focus: focus , isDisabled: isDisabled , onAction: onAction , allowsDifferentPressOrigin: allowsDifferentPressOrigin } = options;
378
384
  let onSelect = (e)=>{
379
385
  if (e.pointerType === "keyboard" && (0, $feb5ffebff200149$export$d3e3bd3e26688c04)(e)) manager.toggleSelection(key);
380
386
  else {
@@ -480,7 +486,7 @@ function $880e95eb8b93ba9a$export$ecf600387e221c37(options) {
480
486
  }
481
487
  };
482
488
  }
483
- if (!isVirtualized) itemProps["data-key"] = key;
489
+ itemProps["data-key"] = key;
484
490
  itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;
485
491
  let { pressProps: pressProps , isPressed: isPressed } = (0, $eCAIO$usePress)(itemPressProps);
486
492
  // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.
@@ -556,7 +562,7 @@ function $880e95eb8b93ba9a$var$isSelectionKey() {
556
562
  * governing permissions and limitations under the License.
557
563
  */
558
564
  class $2a25aae57d74318e$export$a05409b8bb224a5a {
559
- getKeyBelow(key) {
565
+ getNextKey(key) {
560
566
  key = this.collection.getKeyAfter(key);
561
567
  while(key != null){
562
568
  let item = this.collection.getItem(key);
@@ -565,7 +571,7 @@ class $2a25aae57d74318e$export$a05409b8bb224a5a {
565
571
  }
566
572
  return null;
567
573
  }
568
- getKeyAbove(key) {
574
+ getPreviousKey(key) {
569
575
  key = this.collection.getKeyBefore(key);
570
576
  while(key != null){
571
577
  let item = this.collection.getItem(key);
@@ -574,12 +580,46 @@ class $2a25aae57d74318e$export$a05409b8bb224a5a {
574
580
  }
575
581
  return null;
576
582
  }
583
+ findKey(key, nextKey, shouldSkip) {
584
+ let item = this.getItem(key);
585
+ if (!item) return null;
586
+ // Find the item above or below in the same column.
587
+ let prevRect = item.getBoundingClientRect();
588
+ do {
589
+ key = nextKey(key);
590
+ item = this.getItem(key);
591
+ }while (item && shouldSkip(prevRect, item.getBoundingClientRect()));
592
+ return key;
593
+ }
594
+ isSameRow(prevRect, itemRect) {
595
+ return prevRect.top === itemRect.top || prevRect.left !== itemRect.left;
596
+ }
597
+ isSameColumn(prevRect, itemRect) {
598
+ return prevRect.left === itemRect.left || prevRect.top !== itemRect.top;
599
+ }
600
+ getKeyBelow(key) {
601
+ if (this.layout === "grid" && this.orientation === "vertical") return this.findKey(key, (key)=>this.getNextKey(key), this.isSameRow);
602
+ else return this.getNextKey(key);
603
+ }
604
+ getKeyAbove(key) {
605
+ if (this.layout === "grid" && this.orientation === "vertical") return this.findKey(key, (key)=>this.getPreviousKey(key), this.isSameRow);
606
+ else return this.getPreviousKey(key);
607
+ }
608
+ getNextColumn(key, right) {
609
+ return right ? this.getPreviousKey(key) : this.getNextKey(key);
610
+ }
577
611
  getKeyRightOf(key) {
578
- if (this.orientation === "horizontal") return this.direction === "rtl" ? this.getKeyAbove(key) : this.getKeyBelow(key);
612
+ if (this.layout === "grid") {
613
+ if (this.orientation === "vertical") return this.getNextColumn(key, this.direction === "rtl");
614
+ else return this.findKey(key, (key)=>this.getNextColumn(key, this.direction === "rtl"), this.isSameColumn);
615
+ } else if (this.orientation === "horizontal") return this.getNextColumn(key, this.direction === "rtl");
579
616
  return null;
580
617
  }
581
618
  getKeyLeftOf(key) {
582
- if (this.orientation === "horizontal") return this.direction === "rtl" ? this.getKeyBelow(key) : this.getKeyAbove(key);
619
+ if (this.layout === "grid") {
620
+ if (this.orientation === "vertical") return this.getNextColumn(key, this.direction === "ltr");
621
+ else return this.findKey(key, (key)=>this.getNextColumn(key, this.direction === "ltr"), this.isSameColumn);
622
+ } else if (this.orientation === "horizontal") return this.getNextColumn(key, this.direction === "ltr");
583
623
  return null;
584
624
  }
585
625
  getFirstKey() {
@@ -675,11 +715,20 @@ class $2a25aae57d74318e$export$a05409b8bb224a5a {
675
715
  this.disabledKeys = opts.disabledKeys || new Set();
676
716
  this.orientation = opts.orientation;
677
717
  this.direction = opts.direction;
718
+ this.layout = opts.layout || "stack";
678
719
  } else {
679
720
  this.collection = args[0];
680
721
  this.disabledKeys = args[1];
681
722
  this.ref = args[2];
682
723
  this.collator = args[3];
724
+ this.layout = "stack";
725
+ this.orientation = "vertical";
726
+ }
727
+ // If this is a vertical stack, remove the left/right methods completely
728
+ // so they aren't called by useDroppableCollection.
729
+ if (this.layout === "stack" && this.orientation === "vertical") {
730
+ this.getKeyLeftOf = undefined;
731
+ this.getKeyRightOf = undefined;
683
732
  }
684
733
  }
685
734
  }
package/dist/main.js CHANGED
@@ -48,7 +48,6 @@ $parcel$export(module.exports, "useTypeSelect", () => $a1189052f36475e8$export$e
48
48
  * OF ANY KIND, either express or implied. See the License for the specific language
49
49
  * governing permissions and limitations under the License.
50
50
  */
51
-
52
51
  function $ee0bdf4faa47f2a8$export$d3e3bd3e26688c04(e) {
53
52
  // Ctrl + Arrow Up/Arrow Down has a system wide meaning on macOS, so use Alt instead.
54
53
  // On Windows and Ubuntu, Alt + Space has a system wide meaning.
@@ -156,27 +155,27 @@ function $b6837c2f80a3c32f$export$d6daf82dcd84e87c(options) {
156
155
  if (delegate.getKeyAbove) {
157
156
  var _delegate_getLastKey, _delegate_getLastKey1;
158
157
  e.preventDefault();
159
- let nextKey1 = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate);
160
- if (nextKey1 == null && shouldFocusWrap) nextKey1 = (_delegate_getLastKey1 = delegate.getLastKey) === null || _delegate_getLastKey1 === void 0 ? void 0 : _delegate_getLastKey1.call(delegate, manager.focusedKey);
161
- navigateToKey(nextKey1);
158
+ let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate);
159
+ if (nextKey == null && shouldFocusWrap) nextKey = (_delegate_getLastKey1 = delegate.getLastKey) === null || _delegate_getLastKey1 === void 0 ? void 0 : _delegate_getLastKey1.call(delegate, manager.focusedKey);
160
+ navigateToKey(nextKey);
162
161
  }
163
162
  break;
164
163
  case "ArrowLeft":
165
164
  if (delegate.getKeyLeftOf) {
166
165
  var _delegate_getFirstKey2, _delegate_getLastKey2;
167
166
  e.preventDefault();
168
- let nextKey2 = delegate.getKeyLeftOf(manager.focusedKey);
169
- if (nextKey2 == null && shouldFocusWrap) nextKey2 = direction === "rtl" ? (_delegate_getFirstKey2 = delegate.getFirstKey) === null || _delegate_getFirstKey2 === void 0 ? void 0 : _delegate_getFirstKey2.call(delegate, manager.focusedKey) : (_delegate_getLastKey2 = delegate.getLastKey) === null || _delegate_getLastKey2 === void 0 ? void 0 : _delegate_getLastKey2.call(delegate, manager.focusedKey);
170
- navigateToKey(nextKey2, direction === "rtl" ? "first" : "last");
167
+ let nextKey = delegate.getKeyLeftOf(manager.focusedKey);
168
+ if (nextKey == null && shouldFocusWrap) nextKey = direction === "rtl" ? (_delegate_getFirstKey2 = delegate.getFirstKey) === null || _delegate_getFirstKey2 === void 0 ? void 0 : _delegate_getFirstKey2.call(delegate, manager.focusedKey) : (_delegate_getLastKey2 = delegate.getLastKey) === null || _delegate_getLastKey2 === void 0 ? void 0 : _delegate_getLastKey2.call(delegate, manager.focusedKey);
169
+ navigateToKey(nextKey, direction === "rtl" ? "first" : "last");
171
170
  }
172
171
  break;
173
172
  case "ArrowRight":
174
173
  if (delegate.getKeyRightOf) {
175
174
  var _delegate_getLastKey3, _delegate_getFirstKey3;
176
175
  e.preventDefault();
177
- let nextKey3 = delegate.getKeyRightOf(manager.focusedKey);
178
- if (nextKey3 == null && shouldFocusWrap) nextKey3 = direction === "rtl" ? (_delegate_getLastKey3 = delegate.getLastKey) === null || _delegate_getLastKey3 === void 0 ? void 0 : _delegate_getLastKey3.call(delegate, manager.focusedKey) : (_delegate_getFirstKey3 = delegate.getFirstKey) === null || _delegate_getFirstKey3 === void 0 ? void 0 : _delegate_getFirstKey3.call(delegate, manager.focusedKey);
179
- navigateToKey(nextKey3, direction === "rtl" ? "last" : "first");
176
+ let nextKey = delegate.getKeyRightOf(manager.focusedKey);
177
+ if (nextKey == null && shouldFocusWrap) nextKey = direction === "rtl" ? (_delegate_getLastKey3 = delegate.getLastKey) === null || _delegate_getLastKey3 === void 0 ? void 0 : _delegate_getLastKey3.call(delegate, manager.focusedKey) : (_delegate_getFirstKey3 = delegate.getFirstKey) === null || _delegate_getFirstKey3 === void 0 ? void 0 : _delegate_getFirstKey3.call(delegate, manager.focusedKey);
178
+ navigateToKey(nextKey, direction === "rtl" ? "last" : "first");
180
179
  }
181
180
  break;
182
181
  case "Home":
@@ -200,15 +199,15 @@ function $b6837c2f80a3c32f$export$d6daf82dcd84e87c(options) {
200
199
  case "PageDown":
201
200
  if (delegate.getKeyPageBelow) {
202
201
  e.preventDefault();
203
- let nextKey4 = delegate.getKeyPageBelow(manager.focusedKey);
204
- navigateToKey(nextKey4);
202
+ let nextKey = delegate.getKeyPageBelow(manager.focusedKey);
203
+ navigateToKey(nextKey);
205
204
  }
206
205
  break;
207
206
  case "PageUp":
208
207
  if (delegate.getKeyPageAbove) {
209
208
  e.preventDefault();
210
- let nextKey5 = delegate.getKeyPageAbove(manager.focusedKey);
211
- navigateToKey(nextKey5);
209
+ let nextKey = delegate.getKeyPageAbove(manager.focusedKey);
210
+ navigateToKey(nextKey);
212
211
  }
213
212
  break;
214
213
  case "a":
@@ -291,7 +290,10 @@ function $b6837c2f80a3c32f$export$d6daf82dcd84e87c(options) {
291
290
  if (element) {
292
291
  // This prevents a flash of focus on the first/last element in the collection, or the collection itself.
293
292
  (0, $glPPV$reactariautils.focusWithoutScrolling)(element);
294
- (0, $glPPV$reactariautils.scrollIntoView)(scrollRef.current, element);
293
+ let modality = (0, $glPPV$reactariainteractions.getInteractionModality)();
294
+ if (modality === "keyboard") (0, $glPPV$reactariautils.scrollIntoViewport)(element, {
295
+ containingElement: ref.current
296
+ });
295
297
  }
296
298
  }
297
299
  };
@@ -319,17 +321,21 @@ function $b6837c2f80a3c32f$export$d6daf82dcd84e87c(options) {
319
321
  }, []);
320
322
  // If not virtualized, scroll the focused element into view when the focusedKey changes.
321
323
  // When virtualized, Virtualizer handles this internally.
324
+ let lastFocusedKey = (0, $glPPV$react.useRef)(manager.focusedKey);
322
325
  (0, $glPPV$react.useEffect)(()=>{
323
326
  let modality = (0, $glPPV$reactariainteractions.getInteractionModality)();
324
- if (!isVirtualized && manager.isFocused && manager.focusedKey != null && (scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current)) {
327
+ if (manager.isFocused && manager.focusedKey != null && (scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current)) {
325
328
  let element = scrollRef.current.querySelector(`[data-key="${manager.focusedKey}"]`);
326
- if (element) {
327
- (0, $glPPV$reactariautils.scrollIntoView)(scrollRef.current, element);
328
- if (modality === "keyboard") (0, $glPPV$reactariautils.scrollIntoViewport)(element, {
329
+ if (element && modality === "keyboard") {
330
+ if (!isVirtualized) (0, $glPPV$reactariautils.scrollIntoView)(scrollRef.current, element);
331
+ (0, $glPPV$reactariautils.scrollIntoViewport)(element, {
329
332
  containingElement: ref.current
330
333
  });
331
334
  }
332
335
  }
336
+ // If the focused key becomes null (e.g. the last item is deleted), focus the whole collection.
337
+ if (manager.isFocused && manager.focusedKey == null && lastFocusedKey.current != null) (0, $glPPV$reactariafocus.focusSafely)(ref.current);
338
+ lastFocusedKey.current = manager.focusedKey;
333
339
  }, [
334
340
  isVirtualized,
335
341
  scrollRef,
@@ -383,7 +389,7 @@ function $b6837c2f80a3c32f$export$d6daf82dcd84e87c(options) {
383
389
 
384
390
 
385
391
  function $433b1145b0781e10$export$ecf600387e221c37(options) {
386
- let { selectionManager: manager , key: key , ref: ref , shouldSelectOnPressUp: shouldSelectOnPressUp , isVirtualized: isVirtualized , shouldUseVirtualFocus: shouldUseVirtualFocus , focus: focus , isDisabled: isDisabled , onAction: onAction , allowsDifferentPressOrigin: allowsDifferentPressOrigin } = options;
392
+ let { selectionManager: manager , key: key , ref: ref , shouldSelectOnPressUp: shouldSelectOnPressUp , shouldUseVirtualFocus: shouldUseVirtualFocus , focus: focus , isDisabled: isDisabled , onAction: onAction , allowsDifferentPressOrigin: allowsDifferentPressOrigin } = options;
387
393
  let onSelect = (e)=>{
388
394
  if (e.pointerType === "keyboard" && (0, $ee0bdf4faa47f2a8$export$d3e3bd3e26688c04)(e)) manager.toggleSelection(key);
389
395
  else {
@@ -489,7 +495,7 @@ function $433b1145b0781e10$export$ecf600387e221c37(options) {
489
495
  }
490
496
  };
491
497
  }
492
- if (!isVirtualized) itemProps["data-key"] = key;
498
+ itemProps["data-key"] = key;
493
499
  itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;
494
500
  let { pressProps: pressProps , isPressed: isPressed } = (0, $glPPV$reactariainteractions.usePress)(itemPressProps);
495
501
  // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.
@@ -565,7 +571,7 @@ function $433b1145b0781e10$var$isSelectionKey() {
565
571
  * governing permissions and limitations under the License.
566
572
  */
567
573
  class $836f880b12dcae5c$export$a05409b8bb224a5a {
568
- getKeyBelow(key) {
574
+ getNextKey(key) {
569
575
  key = this.collection.getKeyAfter(key);
570
576
  while(key != null){
571
577
  let item = this.collection.getItem(key);
@@ -574,7 +580,7 @@ class $836f880b12dcae5c$export$a05409b8bb224a5a {
574
580
  }
575
581
  return null;
576
582
  }
577
- getKeyAbove(key) {
583
+ getPreviousKey(key) {
578
584
  key = this.collection.getKeyBefore(key);
579
585
  while(key != null){
580
586
  let item = this.collection.getItem(key);
@@ -583,12 +589,46 @@ class $836f880b12dcae5c$export$a05409b8bb224a5a {
583
589
  }
584
590
  return null;
585
591
  }
592
+ findKey(key, nextKey, shouldSkip) {
593
+ let item = this.getItem(key);
594
+ if (!item) return null;
595
+ // Find the item above or below in the same column.
596
+ let prevRect = item.getBoundingClientRect();
597
+ do {
598
+ key = nextKey(key);
599
+ item = this.getItem(key);
600
+ }while (item && shouldSkip(prevRect, item.getBoundingClientRect()));
601
+ return key;
602
+ }
603
+ isSameRow(prevRect, itemRect) {
604
+ return prevRect.top === itemRect.top || prevRect.left !== itemRect.left;
605
+ }
606
+ isSameColumn(prevRect, itemRect) {
607
+ return prevRect.left === itemRect.left || prevRect.top !== itemRect.top;
608
+ }
609
+ getKeyBelow(key) {
610
+ if (this.layout === "grid" && this.orientation === "vertical") return this.findKey(key, (key)=>this.getNextKey(key), this.isSameRow);
611
+ else return this.getNextKey(key);
612
+ }
613
+ getKeyAbove(key) {
614
+ if (this.layout === "grid" && this.orientation === "vertical") return this.findKey(key, (key)=>this.getPreviousKey(key), this.isSameRow);
615
+ else return this.getPreviousKey(key);
616
+ }
617
+ getNextColumn(key, right) {
618
+ return right ? this.getPreviousKey(key) : this.getNextKey(key);
619
+ }
586
620
  getKeyRightOf(key) {
587
- if (this.orientation === "horizontal") return this.direction === "rtl" ? this.getKeyAbove(key) : this.getKeyBelow(key);
621
+ if (this.layout === "grid") {
622
+ if (this.orientation === "vertical") return this.getNextColumn(key, this.direction === "rtl");
623
+ else return this.findKey(key, (key)=>this.getNextColumn(key, this.direction === "rtl"), this.isSameColumn);
624
+ } else if (this.orientation === "horizontal") return this.getNextColumn(key, this.direction === "rtl");
588
625
  return null;
589
626
  }
590
627
  getKeyLeftOf(key) {
591
- if (this.orientation === "horizontal") return this.direction === "rtl" ? this.getKeyBelow(key) : this.getKeyAbove(key);
628
+ if (this.layout === "grid") {
629
+ if (this.orientation === "vertical") return this.getNextColumn(key, this.direction === "ltr");
630
+ else return this.findKey(key, (key)=>this.getNextColumn(key, this.direction === "ltr"), this.isSameColumn);
631
+ } else if (this.orientation === "horizontal") return this.getNextColumn(key, this.direction === "ltr");
592
632
  return null;
593
633
  }
594
634
  getFirstKey() {
@@ -684,11 +724,20 @@ class $836f880b12dcae5c$export$a05409b8bb224a5a {
684
724
  this.disabledKeys = opts.disabledKeys || new Set();
685
725
  this.orientation = opts.orientation;
686
726
  this.direction = opts.direction;
727
+ this.layout = opts.layout || "stack";
687
728
  } else {
688
729
  this.collection = args[0];
689
730
  this.disabledKeys = args[1];
690
731
  this.ref = args[2];
691
732
  this.collator = args[3];
733
+ this.layout = "stack";
734
+ this.orientation = "vertical";
735
+ }
736
+ // If this is a vertical stack, remove the left/right methods completely
737
+ // so they aren't called by useDroppableCollection.
738
+ if (this.layout === "stack" && this.orientation === "vertical") {
739
+ this.getKeyLeftOf = undefined;
740
+ this.getKeyRightOf = undefined;
692
741
  }
693
742
  }
694
743
  }