@react-aria/selection 3.4.1 → 3.7.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/main.js CHANGED
@@ -1,11 +1,19 @@
1
+ var {
2
+ useLongPress,
3
+ usePress
4
+ } = require("@react-aria/interactions");
5
+
1
6
  var {
2
7
  useLocale,
3
8
  useCollator
4
9
  } = require("@react-aria/i18n");
5
10
 
6
11
  var {
7
- isMac,
8
- mergeProps
12
+ focusWithoutScrolling,
13
+ mergeProps,
14
+ useEvent,
15
+ isAppleDevice,
16
+ isMac
9
17
  } = require("@react-aria/utils");
10
18
 
11
19
  var {
@@ -25,6 +33,20 @@ function $parcel$interopDefault(a) {
25
33
  return a && a.__esModule ? a.default : a;
26
34
  }
27
35
 
36
+ function $d220314dfe032b5c2a0f0c46ec981e5$export$isNonContiguousSelectionModifier(e) {
37
+ // Ctrl + Arrow Up/Arrow Down has a system wide meaning on macOS, so use Alt instead.
38
+ // On Windows and Ubuntu, Alt + Space has a system wide meaning.
39
+ return isAppleDevice() ? e.altKey : e.ctrlKey;
40
+ }
41
+
42
+ function $d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e) {
43
+ if (isMac()) {
44
+ return e.metaKey;
45
+ }
46
+
47
+ return e.ctrlKey;
48
+ }
49
+
28
50
  /**
29
51
  * Handles typeahead interactions with collections.
30
52
  */
@@ -104,14 +126,6 @@ function $c2e740eb44846c887b3b88306c61$var$getStringForKey(key) {
104
126
  return '';
105
127
  }
106
128
 
107
- function $f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) {
108
- if (isMac()) {
109
- return e.metaKey;
110
- }
111
-
112
- return e.ctrlKey;
113
- }
114
-
115
129
  /**
116
130
  * Handles interactions with selectable collections.
117
131
  */
@@ -124,48 +138,54 @@ function useSelectableCollection(options) {
124
138
  shouldFocusWrap = false,
125
139
  disallowEmptySelection = false,
126
140
  disallowSelectAll = false,
127
- selectOnFocus = false,
141
+ selectOnFocus = manager.selectionBehavior === 'replace',
128
142
  disallowTypeAhead = false,
129
143
  shouldUseVirtualFocus,
130
- allowsTabNavigation = false
144
+ allowsTabNavigation = false,
145
+ isVirtualized,
146
+ // If no scrollRef is provided, assume the collection ref is the scrollable region
147
+ scrollRef = ref
131
148
  } = options;
132
149
  let {
133
150
  direction
134
151
  } = useLocale();
135
152
 
136
153
  let onKeyDown = e => {
137
- // Let child element (e.g. menu button) handle the event if the Alt key is pressed.
138
- // Keyboard events bubble through portals. Don't handle keyboard events
154
+ // Prevent option + tab from doing anything since it doesn't move focus to the cells, only buttons/checkboxes
155
+ if (e.altKey && e.key === 'Tab') {
156
+ e.preventDefault();
157
+ } // Keyboard events bubble through portals. Don't handle keyboard events
139
158
  // for elements outside the collection (e.g. menus).
140
- if (e.altKey || !ref.current.contains(e.target)) {
159
+
160
+
161
+ if (!ref.current.contains(e.target)) {
141
162
  return;
142
163
  }
143
164
 
165
+ const navigateToKey = (key, childFocus) => {
166
+ if (key != null) {
167
+ manager.setFocusedKey(key, childFocus);
168
+
169
+ if (e.shiftKey && manager.selectionMode === 'multiple') {
170
+ manager.extendSelection(key);
171
+ } else if (selectOnFocus && !$d220314dfe032b5c2a0f0c46ec981e5$export$isNonContiguousSelectionModifier(e)) {
172
+ manager.replaceSelection(key);
173
+ }
174
+ }
175
+ };
176
+
144
177
  switch (e.key) {
145
178
  case 'ArrowDown':
146
179
  {
147
180
  if (delegate.getKeyBelow) {
148
181
  e.preventDefault();
149
- let nextKey = manager.focusedKey != null ? delegate.getKeyBelow(manager.focusedKey) : delegate.getFirstKey();
150
-
151
- if (nextKey != null) {
152
- manager.setFocusedKey(nextKey);
182
+ let nextKey = manager.focusedKey != null ? delegate.getKeyBelow(manager.focusedKey) : delegate.getFirstKey == null ? void 0 : delegate.getFirstKey();
153
183
 
154
- if (manager.selectionMode === 'single' && selectOnFocus) {
155
- manager.replaceSelection(nextKey);
156
- }
157
- } else if (shouldFocusWrap) {
158
- let wrapKey = delegate.getFirstKey(manager.focusedKey);
159
- manager.setFocusedKey(wrapKey);
160
-
161
- if (manager.selectionMode === 'single' && selectOnFocus) {
162
- manager.replaceSelection(wrapKey);
163
- }
184
+ if (nextKey == null && shouldFocusWrap) {
185
+ nextKey = delegate.getFirstKey == null ? void 0 : delegate.getFirstKey(manager.focusedKey);
164
186
  }
165
187
 
166
- if (e.shiftKey && manager.selectionMode === 'multiple') {
167
- manager.extendSelection(nextKey);
168
- }
188
+ navigateToKey(nextKey);
169
189
  }
170
190
 
171
191
  break;
@@ -175,26 +195,13 @@ function useSelectableCollection(options) {
175
195
  {
176
196
  if (delegate.getKeyAbove) {
177
197
  e.preventDefault();
178
- let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : delegate.getLastKey();
179
-
180
- if (nextKey != null) {
181
- manager.setFocusedKey(nextKey);
182
-
183
- if (manager.selectionMode === 'single' && selectOnFocus) {
184
- manager.replaceSelection(nextKey);
185
- }
186
- } else if (shouldFocusWrap) {
187
- let wrapKey = delegate.getLastKey(manager.focusedKey);
188
- manager.setFocusedKey(wrapKey);
198
+ let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : delegate.getLastKey == null ? void 0 : delegate.getLastKey();
189
199
 
190
- if (manager.selectionMode === 'single' && selectOnFocus) {
191
- manager.replaceSelection(wrapKey);
192
- }
200
+ if (nextKey == null && shouldFocusWrap) {
201
+ nextKey = delegate.getLastKey == null ? void 0 : delegate.getLastKey(manager.focusedKey);
193
202
  }
194
203
 
195
- if (e.shiftKey && manager.selectionMode === 'multiple') {
196
- manager.extendSelection(nextKey);
197
- }
204
+ navigateToKey(nextKey);
198
205
  }
199
206
 
200
207
  break;
@@ -205,18 +212,7 @@ function useSelectableCollection(options) {
205
212
  if (delegate.getKeyLeftOf) {
206
213
  e.preventDefault();
207
214
  let nextKey = delegate.getKeyLeftOf(manager.focusedKey);
208
-
209
- if (nextKey != null) {
210
- manager.setFocusedKey(nextKey, direction === 'rtl' ? 'first' : 'last');
211
-
212
- if (manager.selectionMode === 'single' && selectOnFocus) {
213
- manager.replaceSelection(nextKey);
214
- }
215
- }
216
-
217
- if (e.shiftKey && manager.selectionMode === 'multiple') {
218
- manager.extendSelection(nextKey);
219
- }
215
+ navigateToKey(nextKey, direction === 'rtl' ? 'first' : 'last');
220
216
  }
221
217
 
222
218
  break;
@@ -227,18 +223,7 @@ function useSelectableCollection(options) {
227
223
  if (delegate.getKeyRightOf) {
228
224
  e.preventDefault();
229
225
  let nextKey = delegate.getKeyRightOf(manager.focusedKey);
230
-
231
- if (nextKey != null) {
232
- manager.setFocusedKey(nextKey, direction === 'rtl' ? 'last' : 'first');
233
-
234
- if (manager.selectionMode === 'single' && selectOnFocus) {
235
- manager.replaceSelection(nextKey);
236
- }
237
- }
238
-
239
- if (e.shiftKey && manager.selectionMode === 'multiple') {
240
- manager.extendSelection(nextKey);
241
- }
226
+ navigateToKey(nextKey, direction === 'rtl' ? 'last' : 'first');
242
227
  }
243
228
 
244
229
  break;
@@ -247,15 +232,13 @@ function useSelectableCollection(options) {
247
232
  case 'Home':
248
233
  if (delegate.getFirstKey) {
249
234
  e.preventDefault();
250
- let firstKey = delegate.getFirstKey(manager.focusedKey, $f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e));
235
+ let firstKey = delegate.getFirstKey(manager.focusedKey, $d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e));
251
236
  manager.setFocusedKey(firstKey);
252
237
 
253
- if (manager.selectionMode === 'single' && selectOnFocus) {
254
- manager.replaceSelection(firstKey);
255
- }
256
-
257
- if ($f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
238
+ if ($d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
258
239
  manager.extendSelection(firstKey);
240
+ } else if (selectOnFocus) {
241
+ manager.replaceSelection(firstKey);
259
242
  }
260
243
  }
261
244
 
@@ -264,15 +247,13 @@ function useSelectableCollection(options) {
264
247
  case 'End':
265
248
  if (delegate.getLastKey) {
266
249
  e.preventDefault();
267
- let lastKey = delegate.getLastKey(manager.focusedKey, $f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e));
250
+ let lastKey = delegate.getLastKey(manager.focusedKey, $d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e));
268
251
  manager.setFocusedKey(lastKey);
269
252
 
270
- if (manager.selectionMode === 'single' && selectOnFocus) {
271
- manager.replaceSelection(lastKey);
272
- }
273
-
274
- if ($f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
253
+ if ($d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
275
254
  manager.extendSelection(lastKey);
255
+ } else if (selectOnFocus) {
256
+ manager.replaceSelection(lastKey);
276
257
  }
277
258
  }
278
259
 
@@ -282,14 +263,7 @@ function useSelectableCollection(options) {
282
263
  if (delegate.getKeyPageBelow) {
283
264
  e.preventDefault();
284
265
  let nextKey = delegate.getKeyPageBelow(manager.focusedKey);
285
-
286
- if (nextKey != null) {
287
- manager.setFocusedKey(nextKey);
288
-
289
- if (e.shiftKey && manager.selectionMode === 'multiple') {
290
- manager.extendSelection(nextKey);
291
- }
292
- }
266
+ navigateToKey(nextKey);
293
267
  }
294
268
 
295
269
  break;
@@ -298,20 +272,13 @@ function useSelectableCollection(options) {
298
272
  if (delegate.getKeyPageAbove) {
299
273
  e.preventDefault();
300
274
  let nextKey = delegate.getKeyPageAbove(manager.focusedKey);
301
-
302
- if (nextKey != null) {
303
- manager.setFocusedKey(nextKey);
304
-
305
- if (e.shiftKey && manager.selectionMode === 'multiple') {
306
- manager.extendSelection(nextKey);
307
- }
308
- }
275
+ navigateToKey(nextKey);
309
276
  }
310
277
 
311
278
  break;
312
279
 
313
280
  case 'a':
314
- if ($f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) {
281
+ if ($d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) {
315
282
  e.preventDefault();
316
283
  manager.selectAll();
317
284
  }
@@ -354,7 +321,7 @@ function useSelectableCollection(options) {
354
321
  } while (last);
355
322
 
356
323
  if (next && !next.contains(document.activeElement)) {
357
- next.focus();
324
+ focusWithoutScrolling(next);
358
325
  }
359
326
  }
360
327
 
@@ -362,7 +329,19 @@ function useSelectableCollection(options) {
362
329
  }
363
330
  }
364
331
  }
365
- };
332
+ }; // Store the scroll position so we can restore it later.
333
+
334
+
335
+ let scrollPos = useRef({
336
+ top: 0,
337
+ left: 0
338
+ });
339
+ useEvent(scrollRef, 'scroll', isVirtualized ? null : () => {
340
+ scrollPos.current = {
341
+ top: scrollRef.current.scrollTop,
342
+ left: scrollRef.current.scrollLeft
343
+ };
344
+ });
366
345
 
367
346
  let onFocus = e => {
368
347
  if (manager.isFocused) {
@@ -382,19 +361,41 @@ function useSelectableCollection(options) {
382
361
  manager.setFocused(true);
383
362
 
384
363
  if (manager.focusedKey == null) {
385
- // If the user hasn't yet interacted with the collection, there will be no focusedKey set.
364
+ let navigateToFirstKey = key => {
365
+ if (key != null) {
366
+ manager.setFocusedKey(key);
367
+
368
+ if (selectOnFocus) {
369
+ manager.replaceSelection(key);
370
+ }
371
+ }
372
+ }; // If the user hasn't yet interacted with the collection, there will be no focusedKey set.
386
373
  // Attempt to detect whether the user is tabbing forward or backward into the collection
387
374
  // and either focus the first or last item accordingly.
375
+
376
+
388
377
  let relatedTarget = e.relatedTarget;
389
378
 
390
379
  if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) {
391
380
  var _manager$lastSelected;
392
381
 
393
- manager.setFocusedKey((_manager$lastSelected = manager.lastSelectedKey) != null ? _manager$lastSelected : delegate.getLastKey());
382
+ navigateToFirstKey((_manager$lastSelected = manager.lastSelectedKey) != null ? _manager$lastSelected : delegate.getLastKey());
394
383
  } else {
395
384
  var _manager$firstSelecte;
396
385
 
397
- manager.setFocusedKey((_manager$firstSelecte = manager.firstSelectedKey) != null ? _manager$firstSelecte : delegate.getFirstKey());
386
+ navigateToFirstKey((_manager$firstSelecte = manager.firstSelectedKey) != null ? _manager$firstSelecte : delegate.getFirstKey());
387
+ }
388
+ } else if (!isVirtualized) {
389
+ // Restore the scroll position to what it was before.
390
+ scrollRef.current.scrollTop = scrollPos.current.top;
391
+ scrollRef.current.scrollLeft = scrollPos.current.left; // Refocus and scroll the focused item into view if it exists within the scrollable region.
392
+
393
+ let element = scrollRef.current.querySelector("[data-key=\"" + manager.focusedKey + "\"]");
394
+
395
+ if (element) {
396
+ // This prevents a flash of focus on the first/last element in the collection
397
+ focusWithoutScrolling(element);
398
+ $f791fefd7189e0e4d903034fb2925$var$scrollIntoView(scrollRef.current, element);
398
399
  }
399
400
  }
400
401
  };
@@ -406,8 +407,9 @@ function useSelectableCollection(options) {
406
407
  }
407
408
  };
408
409
 
410
+ const autoFocusRef = useRef(autoFocus);
409
411
  useEffect(() => {
410
- if (autoFocus) {
412
+ if (autoFocusRef.current) {
411
413
  let focusedKey = null; // Check focus strategy to determine which item to focus
412
414
 
413
415
  if (autoFocus === 'first') {
@@ -431,17 +433,32 @@ function useSelectableCollection(options) {
431
433
  if (focusedKey == null && !shouldUseVirtualFocus) {
432
434
  focusSafely(ref.current);
433
435
  }
434
- } // eslint-disable-next-line react-hooks/exhaustive-deps
436
+ }
437
+
438
+ autoFocusRef.current = false; // eslint-disable-next-line react-hooks/exhaustive-deps
439
+ }, []); // If not virtualized, scroll the focused element into view when the focusedKey changes.
440
+ // When virtualized, Virtualizer handles this internally.
435
441
 
436
- }, []);
442
+ useEffect(() => {
443
+ if (!isVirtualized && manager.focusedKey && scrollRef != null && scrollRef.current) {
444
+ let element = scrollRef.current.querySelector("[data-key=\"" + manager.focusedKey + "\"]");
445
+
446
+ if (element) {
447
+ $f791fefd7189e0e4d903034fb2925$var$scrollIntoView(scrollRef.current, element);
448
+ }
449
+ }
450
+ }, [isVirtualized, scrollRef, manager.focusedKey]);
437
451
  let handlers = {
438
452
  onKeyDown,
439
453
  onFocus,
440
454
  onBlur,
441
455
 
442
456
  onMouseDown(e) {
443
- // Prevent focus going to the collection when clicking on the scrollbar.
444
- e.preventDefault();
457
+ // Ignore events that bubbled through portals.
458
+ if (e.currentTarget.contains(e.target)) {
459
+ // Prevent focus going to the collection when clicking on the scrollbar.
460
+ e.preventDefault();
461
+ }
445
462
  }
446
463
 
447
464
  };
@@ -472,9 +489,70 @@ function useSelectableCollection(options) {
472
489
  })
473
490
  };
474
491
  }
492
+ /**
493
+ * Scrolls `scrollView` so that `element` is visible.
494
+ * Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),
495
+ * but doesn't affect parents above `scrollView`.
496
+ */
497
+
475
498
 
476
499
  exports.useSelectableCollection = useSelectableCollection;
477
500
 
501
+ function $f791fefd7189e0e4d903034fb2925$var$scrollIntoView(scrollView, element) {
502
+ let offsetX = $f791fefd7189e0e4d903034fb2925$var$relativeOffset(scrollView, element, 'left');
503
+ let offsetY = $f791fefd7189e0e4d903034fb2925$var$relativeOffset(scrollView, element, 'top');
504
+ let width = element.offsetWidth;
505
+ let height = element.offsetHeight;
506
+ let x = scrollView.scrollLeft;
507
+ let y = scrollView.scrollTop;
508
+ let maxX = x + scrollView.offsetWidth;
509
+ let maxY = y + scrollView.offsetHeight;
510
+
511
+ if (offsetX <= x) {
512
+ x = offsetX;
513
+ } else if (offsetX + width > maxX) {
514
+ x += offsetX + width - maxX;
515
+ }
516
+
517
+ if (offsetY <= y) {
518
+ y = offsetY;
519
+ } else if (offsetY + height > maxY) {
520
+ y += offsetY + height - maxY;
521
+ }
522
+
523
+ scrollView.scrollLeft = x;
524
+ scrollView.scrollTop = y;
525
+ }
526
+ /**
527
+ * Computes the offset left or top from child to ancestor by accumulating
528
+ * offsetLeft or offsetTop through intervening offsetParents.
529
+ */
530
+
531
+
532
+ function $f791fefd7189e0e4d903034fb2925$var$relativeOffset(ancestor, child, axis) {
533
+ const prop = axis === 'left' ? 'offsetLeft' : 'offsetTop';
534
+ let sum = 0;
535
+
536
+ while (child.offsetParent) {
537
+ sum += child[prop];
538
+
539
+ if (child.offsetParent === ancestor) {
540
+ // Stop once we have found the ancestor we are interested in.
541
+ break;
542
+ } else if (child.offsetParent.contains(ancestor)) {
543
+ // If the ancestor is not `position:relative`, then we stop at
544
+ // _its_ offset parent, and we subtract off _its_ offset, so that
545
+ // we end up with the proper offset from child to ancestor.
546
+ sum -= ancestor[prop];
547
+ break;
548
+ }
549
+
550
+ child = child.offsetParent;
551
+ }
552
+
553
+ return sum;
554
+ }
555
+
478
556
  /**
479
557
  * Handles interactions with an item in a selectable collection.
480
558
  */
@@ -486,10 +564,35 @@ function useSelectableItem(options) {
486
564
  shouldSelectOnPressUp,
487
565
  isVirtualized,
488
566
  shouldUseVirtualFocus,
489
- focus
567
+ focus,
568
+ isDisabled,
569
+ onAction
490
570
  } = options;
491
571
 
492
- let onSelect = e => manager.select(key, e); // Focus the associated DOM node when this item becomes the focusedKey
572
+ let onSelect = e => {
573
+ if (e.pointerType === 'keyboard' && $d220314dfe032b5c2a0f0c46ec981e5$export$isNonContiguousSelectionModifier(e)) {
574
+ manager.toggleSelection(key);
575
+ } else {
576
+ if (manager.selectionMode === 'none') {
577
+ return;
578
+ }
579
+
580
+ if (manager.selectionMode === 'single') {
581
+ if (manager.isSelected(key) && !manager.disallowEmptySelection) {
582
+ manager.toggleSelection(key);
583
+ } else {
584
+ manager.replaceSelection(key);
585
+ }
586
+ } else if (e && e.shiftKey) {
587
+ manager.extendSelection(key);
588
+ } else if (manager.selectionBehavior === 'toggle' || e && ($d220314dfe032b5c2a0f0c46ec981e5$export$isCtrlKeyPressed(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) {
589
+ // if touch or virtual (VO) then we just want to toggle, otherwise it's impossible to multi select because they don't have modifier keys
590
+ manager.toggleSelection(key);
591
+ } else {
592
+ manager.replaceSelection(key);
593
+ }
594
+ }
595
+ }; // Focus the associated DOM node when this item becomes the focusedKey
493
596
 
494
597
 
495
598
  let isFocused = key === manager.focusedKey;
@@ -518,7 +621,12 @@ function useSelectableItem(options) {
518
621
  }
519
622
 
520
623
  };
521
- } // By default, selection occurs on pointer down. This can be strange if selecting an
624
+ }
625
+
626
+ let modality = useRef(null);
627
+ let hasPrimaryAction = onAction && manager.selectionMode === 'none';
628
+ let hasSecondaryAction = onAction && manager.selectionMode !== 'none' && manager.selectionBehavior === 'replace';
629
+ let allowsSelection = !isDisabled && manager.canSelectItem(key); // By default, selection occurs on pointer down. This can be strange if selecting an
522
630
  // item causes the UI to disappear immediately (e.g. menus).
523
631
  // If shouldSelectOnPressUp is true, we use onPressUp instead of onPressStart.
524
632
  // onPress requires a pointer down event on the same element as pointer up. For menus,
@@ -526,30 +634,43 @@ function useSelectableItem(options) {
526
634
  // the pointer up on the menu item rather than requiring a separate press.
527
635
  // For keyboard events, selection still occurs on key down.
528
636
 
637
+ let itemPressProps = {};
529
638
 
530
639
  if (shouldSelectOnPressUp) {
531
- itemProps.onPressStart = e => {
640
+ itemPressProps.onPressStart = e => {
641
+ modality.current = e.pointerType;
642
+
532
643
  if (e.pointerType === 'keyboard') {
533
644
  onSelect(e);
534
645
  }
535
646
  };
536
647
 
537
- itemProps.onPressUp = e => {
648
+ itemPressProps.onPressUp = e => {
538
649
  if (e.pointerType !== 'keyboard') {
539
650
  onSelect(e);
540
651
  }
541
652
  };
653
+
654
+ itemPressProps.onPress = hasPrimaryAction ? () => onAction() : null;
542
655
  } else {
543
656
  // On touch, it feels strange to select on touch down, so we special case this.
544
- itemProps.onPressStart = e => {
545
- if (e.pointerType !== 'touch') {
657
+ itemPressProps.onPressStart = e => {
658
+ modality.current = e.pointerType;
659
+
660
+ if (e.pointerType !== 'touch' && e.pointerType !== 'virtual') {
546
661
  onSelect(e);
547
662
  }
548
663
  };
549
664
 
550
- itemProps.onPress = e => {
551
- if (e.pointerType === 'touch') {
552
- onSelect(e);
665
+ itemPressProps.onPress = e => {
666
+ if (e.pointerType === 'touch' || e.pointerType === 'virtual' || hasPrimaryAction) {
667
+ // Single tap on touch with selectionBehavior = 'replace' performs an action, i.e. navigation.
668
+ // Also perform action on press up when selectionMode = 'none'.
669
+ if (hasPrimaryAction || hasSecondaryAction) {
670
+ onAction();
671
+ } else {
672
+ onSelect(e);
673
+ }
553
674
  }
554
675
  };
555
676
  }
@@ -558,8 +679,48 @@ function useSelectableItem(options) {
558
679
  itemProps['data-key'] = key;
559
680
  }
560
681
 
682
+ itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;
683
+ let {
684
+ pressProps,
685
+ isPressed
686
+ } = usePress(itemPressProps); // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.
687
+
688
+ let onDoubleClick = hasSecondaryAction ? e => {
689
+ if (modality.current === 'mouse') {
690
+ e.stopPropagation();
691
+ e.preventDefault();
692
+ onAction();
693
+ }
694
+ } : undefined; // Long pressing an item with touch when selectionBehavior = 'replace' switches the selection behavior
695
+ // to 'toggle'. This changes the single tap behavior from performing an action (i.e. navigating) to
696
+ // selecting, and may toggle the appearance of a UI affordance like checkboxes on each item.
697
+ // TODO: what about when drag and drop is also enabled??
698
+
699
+ let {
700
+ longPressProps
701
+ } = useLongPress({
702
+ isDisabled: !hasSecondaryAction,
703
+
704
+ onLongPress(e) {
705
+ if (e.pointerType === 'touch') {
706
+ onSelect(e);
707
+ manager.setSelectionBehavior('toggle');
708
+ }
709
+ }
710
+
711
+ }); // Pressing the Enter key with selectionBehavior = 'replace' performs an action (i.e. navigation).
712
+
713
+ let onKeyUp = hasSecondaryAction ? e => {
714
+ if (e.key === 'Enter') {
715
+ onAction();
716
+ }
717
+ } : undefined;
561
718
  return {
562
- itemProps
719
+ itemProps: mergeProps(itemProps, allowsSelection || hasPrimaryAction ? pressProps : {}, hasSecondaryAction ? longPressProps : {}, {
720
+ onKeyUp,
721
+ onDoubleClick
722
+ }),
723
+ isPressed
563
724
  };
564
725
  }
565
726
 
@@ -735,18 +896,7 @@ function useSelectableList(props) {
735
896
  usage: 'search',
736
897
  sensitivity: 'base'
737
898
  });
738
- let delegate = useMemo(() => keyboardDelegate || new ListKeyboardDelegate(collection, disabledKeys, ref, collator), [keyboardDelegate, collection, disabledKeys, ref, collator]); // If not virtualized, scroll the focused element into view when the focusedKey changes.
739
- // When virtualized, Virtualizer handles this internally.
740
-
741
- useEffect(() => {
742
- if (!isVirtualized && selectionManager.focusedKey && (ref == null ? void 0 : ref.current)) {
743
- let element = ref.current.querySelector("[data-key=\"" + selectionManager.focusedKey + "\"]");
744
-
745
- if (element) {
746
- $e85d8307c59fae2ab45d73201aa19$var$scrollIntoView(ref.current, element);
747
- }
748
- }
749
- }, [isVirtualized, ref, selectionManager.focusedKey]);
899
+ let delegate = useMemo(() => keyboardDelegate || new ListKeyboardDelegate(collection, disabledKeys, ref, collator), [keyboardDelegate, collection, disabledKeys, ref, collator]);
750
900
  let {
751
901
  collectionProps
752
902
  } = useSelectableCollection({
@@ -759,44 +909,14 @@ function useSelectableList(props) {
759
909
  selectOnFocus,
760
910
  disallowTypeAhead,
761
911
  shouldUseVirtualFocus,
762
- allowsTabNavigation
912
+ allowsTabNavigation,
913
+ isVirtualized,
914
+ scrollRef: ref
763
915
  });
764
916
  return {
765
917
  listProps: collectionProps
766
918
  };
767
919
  }
768
- /**
769
- * Scrolls `scrollView` so that `element` is visible.
770
- * Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),
771
- * but doesn't affect parents above `scrollView`.
772
- */
773
-
774
920
 
775
921
  exports.useSelectableList = useSelectableList;
776
-
777
- function $e85d8307c59fae2ab45d73201aa19$var$scrollIntoView(scrollView, element) {
778
- let offsetX = element.offsetLeft - scrollView.offsetLeft;
779
- let offsetY = element.offsetTop - scrollView.offsetTop;
780
- let width = element.offsetWidth;
781
- let height = element.offsetHeight;
782
- let x = scrollView.scrollLeft;
783
- let y = scrollView.scrollTop;
784
- let maxX = x + scrollView.offsetWidth;
785
- let maxY = y + scrollView.offsetHeight;
786
-
787
- if (offsetX <= x) {
788
- x = offsetX;
789
- } else if (offsetX + width > maxX) {
790
- x += offsetX + width - maxX;
791
- }
792
-
793
- if (offsetY <= y) {
794
- y = offsetY;
795
- } else if (offsetY + height > maxY) {
796
- y += offsetY + height - maxY;
797
- }
798
-
799
- scrollView.scrollLeft = x;
800
- scrollView.scrollTop = y;
801
- }
802
922
  //# sourceMappingURL=main.js.map