@react-aria/interactions 3.0.0-nightly.1289 → 3.0.0-nightly.1299

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
@@ -31,51 +31,71 @@ function $parcel$interopDefault(a) {
31
31
  return a && a.__esModule ? a.default : a;
32
32
  }
33
33
 
34
+ // Note that state only matters here for iOS. Non-iOS gets user-select: none applied to the target element
35
+ // rather than at the document level so we just need to apply/remove user-select: none for each pressed element individually
34
36
  let $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'default';
35
37
  let $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect = '';
38
+ let $ce801cc8e3ff24b95c928e0152c7b7f2$var$modifiedElementMap = new WeakMap();
36
39
 
37
- function $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection() {
38
- // Limit this behavior to iOS only. Android devices don't text select nearby element
39
- // when long pressing on a different element.
40
- if (!isIOS()) {
41
- return;
42
- }
40
+ function $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection(target) {
41
+ if (isIOS()) {
42
+ if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state === 'default') {
43
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect = document.documentElement.style.webkitUserSelect;
44
+ document.documentElement.style.webkitUserSelect = 'none';
45
+ }
43
46
 
44
- if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state === 'default') {
45
- $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect = document.documentElement.style.webkitUserSelect;
46
- document.documentElement.style.webkitUserSelect = 'none';
47
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'disabled';
48
+ } else if (target) {
49
+ // If not iOS, store the target's original user-select and change to user-select: none
50
+ // Ignore state since it doesn't apply for non iOS
51
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$modifiedElementMap.set(target, target.style.userSelect);
52
+ target.style.userSelect = 'none';
47
53
  }
48
-
49
- $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'disabled';
50
54
  }
51
55
 
52
- function $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection() {
53
- // If the state is already default, there's nothing to do.
54
- // If it is restoring, then there's no need to queue a second restore.
55
- // Limit this behavior to iOS only. Android devices don't text select nearby element
56
- // when long pressing on a different element.
57
- if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state !== 'disabled' || !isIOS()) {
58
- return;
59
- }
56
+ function $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection(target) {
57
+ if (isIOS()) {
58
+ // If the state is already default, there's nothing to do.
59
+ // If it is restoring, then there's no need to queue a second restore.
60
+ if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state !== 'disabled') {
61
+ return;
62
+ }
60
63
 
61
- $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'restoring'; // There appears to be a delay on iOS where selection still might occur
62
- // after pointer up, so wait a bit before removing user-select.
64
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'restoring'; // There appears to be a delay on iOS where selection still might occur
65
+ // after pointer up, so wait a bit before removing user-select.
66
+
67
+ setTimeout(() => {
68
+ // Wait for any CSS transitions to complete so we don't recompute style
69
+ // for the whole page in the middle of the animation and cause jank.
70
+ runAfterTransition(() => {
71
+ // Avoid race conditions
72
+ if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state === 'restoring') {
73
+ if (document.documentElement.style.webkitUserSelect === 'none') {
74
+ document.documentElement.style.webkitUserSelect = $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect || '';
75
+ }
63
76
 
64
- setTimeout(() => {
65
- // Wait for any CSS transitions to complete so we don't recompute style
66
- // for the whole page in the middle of the animation and cause jank.
67
- runAfterTransition(() => {
68
- // Avoid race conditions
69
- if ($ce801cc8e3ff24b95c928e0152c7b7f2$var$state === 'restoring') {
70
- if (document.documentElement.style.webkitUserSelect === 'none') {
71
- document.documentElement.style.webkitUserSelect = $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect || '';
77
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect = '';
78
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'default';
72
79
  }
80
+ });
81
+ }, 300);
82
+ } else {
83
+ // If not iOS, restore the target's original user-select if any
84
+ // Ignore state since it doesn't apply for non iOS
85
+ if (target && $ce801cc8e3ff24b95c928e0152c7b7f2$var$modifiedElementMap.has(target)) {
86
+ let targetOldUserSelect = $ce801cc8e3ff24b95c928e0152c7b7f2$var$modifiedElementMap.get(target);
73
87
 
74
- $ce801cc8e3ff24b95c928e0152c7b7f2$var$savedUserSelect = '';
75
- $ce801cc8e3ff24b95c928e0152c7b7f2$var$state = 'default';
88
+ if (target.style.userSelect === 'none') {
89
+ target.style.userSelect = targetOldUserSelect;
76
90
  }
77
- });
78
- }, 300);
91
+
92
+ if (target.getAttribute('style') === '') {
93
+ target.removeAttribute('style');
94
+ }
95
+
96
+ $ce801cc8e3ff24b95c928e0152c7b7f2$var$modifiedElementMap.delete(target);
97
+ }
98
+ }
79
99
  }
80
100
 
81
101
  /*
@@ -146,9 +166,10 @@ function usePress(props) {
146
166
  isDisabled,
147
167
  isPressed: isPressedProp,
148
168
  preventFocusOnPress,
149
- shouldCancelOnPointerExit
169
+ shouldCancelOnPointerExit,
170
+ allowTextSelectionOnPress
150
171
  } = _usePressResponderCon,
151
- domProps = _babelRuntimeHelpersObjectWithoutPropertiesLoose(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "onPressUp", "isDisabled", "isPressed", "preventFocusOnPress", "shouldCancelOnPointerExit", "ref"]);
172
+ domProps = _babelRuntimeHelpersObjectWithoutPropertiesLoose(_usePressResponderCon, ["onPress", "onPressChange", "onPressStart", "onPressEnd", "onPressUp", "isDisabled", "isPressed", "preventFocusOnPress", "shouldCancelOnPointerExit", "allowTextSelectionOnPress", "ref"]);
152
173
 
153
174
  let propsRef = useRef(null);
154
175
  propsRef.current = {
@@ -293,7 +314,10 @@ function usePress(props) {
293
314
  state.activePointerId = null;
294
315
  state.pointerType = null;
295
316
  removeAllGlobalListeners();
296
- $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
317
+
318
+ if (!allowTextSelectionOnPress) {
319
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection(state.target);
320
+ }
297
321
  }
298
322
  };
299
323
 
@@ -336,7 +360,7 @@ function usePress(props) {
336
360
  // trigger as if it were a keyboard click.
337
361
 
338
362
 
339
- if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && $eda9c464f45e6c61a293990c493$export$isVirtualClick(e.nativeEvent)) {
363
+ if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && (state.pointerType === 'virtual' || $eda9c464f45e6c61a293990c493$export$isVirtualClick(e.nativeEvent))) {
340
364
  // Ensure the element receives focus (VoiceOver on iOS does not do this)
341
365
  if (!isDisabled && !preventFocusOnPress) {
342
366
  focusWithoutScrolling(e.currentTarget);
@@ -375,17 +399,24 @@ function usePress(props) {
375
399
  // Only handle left clicks, and ignore events that bubbled through portals.
376
400
  if (e.button !== 0 || !e.currentTarget.contains(e.target)) {
377
401
  return;
402
+ } // iOS safari fires pointer events from VoiceOver with incorrect coordinates/target.
403
+ // Ignore and let the onClick handler take care of it instead.
404
+ // https://bugs.webkit.org/show_bug.cgi?id=222627
405
+ // https://bugs.webkit.org/show_bug.cgi?id=223202
406
+
407
+
408
+ if ($ed8d760564e19d8c7d03a6a4$var$isVirtualPointerEvent(e.nativeEvent)) {
409
+ state.pointerType = 'virtual';
410
+ return;
378
411
  } // Due to browser inconsistencies, especially on mobile browsers, we prevent
379
412
  // default on pointer down and handle focusing the pressable element ourselves.
380
413
 
381
414
 
382
415
  if ($ed8d760564e19d8c7d03a6a4$var$shouldPreventDefault(e.target)) {
383
416
  e.preventDefault();
384
- } // iOS safari fires pointer events from VoiceOver (but only when outside an iframe...)
385
- // https://bugs.webkit.org/show_bug.cgi?id=222627
386
-
417
+ }
387
418
 
388
- state.pointerType = $ed8d760564e19d8c7d03a6a4$var$isVirtualPointerEvent(e.nativeEvent) ? 'virtual' : e.pointerType;
419
+ state.pointerType = e.pointerType;
389
420
  e.stopPropagation();
390
421
 
391
422
  if (!state.isPressed) {
@@ -398,7 +429,10 @@ function usePress(props) {
398
429
  focusWithoutScrolling(e.currentTarget);
399
430
  }
400
431
 
401
- $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection();
432
+ if (!allowTextSelectionOnPress) {
433
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection(state.target);
434
+ }
435
+
402
436
  triggerPressStart(e, state.pointerType);
403
437
  addGlobalListener(document, 'pointermove', onPointerMove, false);
404
438
  addGlobalListener(document, 'pointerup', onPointerUp, false);
@@ -424,7 +458,8 @@ function usePress(props) {
424
458
  };
425
459
 
426
460
  pressProps.onPointerUp = e => {
427
- if (!e.currentTarget.contains(e.target)) {
461
+ // iOS fires pointerup with zero width and height, so check the pointerType recorded during pointerdown.
462
+ if (!e.currentTarget.contains(e.target) || state.pointerType === 'virtual') {
428
463
  return;
429
464
  } // Only handle left clicks
430
465
  // Safari on iOS sometimes fires pointerup events, even
@@ -432,7 +467,7 @@ function usePress(props) {
432
467
 
433
468
 
434
469
  if (e.button === 0 && $ed8d760564e19d8c7d03a6a4$var$isOverTarget(e, e.currentTarget)) {
435
- triggerPressUp(e, state.pointerType || ($ed8d760564e19d8c7d03a6a4$var$isVirtualPointerEvent(e.nativeEvent) ? 'virtual' : e.pointerType));
470
+ triggerPressUp(e, state.pointerType || e.pointerType);
436
471
  }
437
472
  }; // Safari on iOS < 13.2 does not implement pointerenter/pointerleave events correctly.
438
473
  // Use pointer move events instead to implement our own hit testing.
@@ -472,7 +507,10 @@ function usePress(props) {
472
507
  state.activePointerId = null;
473
508
  state.pointerType = null;
474
509
  removeAllGlobalListeners();
475
- $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
510
+
511
+ if (!allowTextSelectionOnPress) {
512
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection(state.target);
513
+ }
476
514
  }
477
515
  };
478
516
 
@@ -607,7 +645,10 @@ function usePress(props) {
607
645
  focusWithoutScrolling(e.currentTarget);
608
646
  }
609
647
 
610
- $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection();
648
+ if (!allowTextSelectionOnPress) {
649
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$disableTextSelection(state.target);
650
+ }
651
+
611
652
  triggerPressStart(e, state.pointerType);
612
653
  addGlobalListener(window, 'scroll', onScroll, true);
613
654
  };
@@ -664,7 +705,11 @@ function usePress(props) {
664
705
  state.activePointerId = null;
665
706
  state.isOverTarget = false;
666
707
  state.ignoreEmulatedMouseEvents = true;
667
- $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
708
+
709
+ if (!allowTextSelectionOnPress) {
710
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection(state.target);
711
+ }
712
+
668
713
  removeAllGlobalListeners();
669
714
  };
670
715
 
@@ -702,12 +747,16 @@ function usePress(props) {
702
747
  }
703
748
 
704
749
  return pressProps;
705
- }, [addGlobalListener, isDisabled, preventFocusOnPress, removeAllGlobalListeners]); // Remove user-select: none in case component unmounts immediately after pressStart
750
+ }, [addGlobalListener, isDisabled, preventFocusOnPress, removeAllGlobalListeners, allowTextSelectionOnPress]); // Remove user-select: none in case component unmounts immediately after pressStart
706
751
  // eslint-disable-next-line arrow-body-style
707
752
 
708
753
  useEffect(() => {
709
- return () => $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection();
710
- }, []);
754
+ return () => {
755
+ if (!allowTextSelectionOnPress) {
756
+ $ce801cc8e3ff24b95c928e0152c7b7f2$export$restoreTextSelection(ref.current.target);
757
+ }
758
+ };
759
+ }, [allowTextSelectionOnPress]);
711
760
  return {
712
761
  isPressed: isPressedProp || isPressed,
713
762
  pressProps: mergeProps(domProps, pressProps)
@@ -814,7 +863,11 @@ function $ed8d760564e19d8c7d03a6a4$var$shouldPreventDefault(target) {
814
863
 
815
864
  function $ed8d760564e19d8c7d03a6a4$var$isVirtualPointerEvent(event) {
816
865
  // If the pointer size is zero, then we assume it's from a screen reader.
817
- return event.width === 0 && event.height === 0;
866
+ // Android TalkBack double tap will sometimes return a event with width and height of 1
867
+ // and pointerType === 'mouse' so we need to check for a specific combination of event attributes.
868
+ // Cannot use "event.pressure === 0" as the sole check due to Safari pointer events always returning pressure === 0
869
+ // instead of .5, see https://bugs.webkit.org/show_bug.cgi?id=206216
870
+ return event.width === 0 && event.height === 0 || event.width === 1 && event.height === 1 && event.pressure === 0 && event.detail === 0;
818
871
  }
819
872
 
820
873
  const Pressable = /*#__PURE__*/_react.forwardRef((_ref, ref) => {