@react-aria/interactions 3.23.0 → 3.24.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.
Files changed (84) hide show
  1. package/dist/Pressable.main.js +28 -4
  2. package/dist/Pressable.main.js.map +1 -1
  3. package/dist/Pressable.mjs +30 -6
  4. package/dist/Pressable.module.js +30 -6
  5. package/dist/Pressable.module.js.map +1 -1
  6. package/dist/focusSafely.main.js +40 -0
  7. package/dist/focusSafely.main.js.map +1 -0
  8. package/dist/focusSafely.mjs +35 -0
  9. package/dist/focusSafely.module.js +35 -0
  10. package/dist/focusSafely.module.js.map +1 -0
  11. package/dist/import.mjs +5 -1
  12. package/dist/main.js +9 -0
  13. package/dist/main.js.map +1 -1
  14. package/dist/module.js +5 -1
  15. package/dist/module.js.map +1 -1
  16. package/dist/textSelection.main.js +5 -3
  17. package/dist/textSelection.main.js.map +1 -1
  18. package/dist/textSelection.mjs +5 -3
  19. package/dist/textSelection.module.js +5 -3
  20. package/dist/textSelection.module.js.map +1 -1
  21. package/dist/types.d.ts +59 -25
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/useFocus.main.js +2 -1
  24. package/dist/useFocus.main.js.map +1 -1
  25. package/dist/useFocus.mjs +3 -2
  26. package/dist/useFocus.module.js +3 -2
  27. package/dist/useFocus.module.js.map +1 -1
  28. package/dist/useFocusVisible.main.js +9 -3
  29. package/dist/useFocusVisible.main.js.map +1 -1
  30. package/dist/useFocusVisible.mjs +9 -3
  31. package/dist/useFocusVisible.module.js +9 -3
  32. package/dist/useFocusVisible.module.js.map +1 -1
  33. package/dist/useFocusWithin.main.js +33 -4
  34. package/dist/useFocusWithin.main.js.map +1 -1
  35. package/dist/useFocusWithin.mjs +34 -5
  36. package/dist/useFocusWithin.module.js +34 -5
  37. package/dist/useFocusWithin.module.js.map +1 -1
  38. package/dist/useFocusable.main.js +112 -0
  39. package/dist/useFocusable.main.js.map +1 -0
  40. package/dist/useFocusable.mjs +100 -0
  41. package/dist/useFocusable.module.js +100 -0
  42. package/dist/useFocusable.module.js.map +1 -0
  43. package/dist/useHover.main.js +18 -3
  44. package/dist/useHover.main.js.map +1 -1
  45. package/dist/useHover.mjs +18 -3
  46. package/dist/useHover.module.js +18 -3
  47. package/dist/useHover.module.js.map +1 -1
  48. package/dist/useInteractOutside.main.js +6 -1
  49. package/dist/useInteractOutside.main.js.map +1 -1
  50. package/dist/useInteractOutside.mjs +6 -1
  51. package/dist/useInteractOutside.module.js +6 -1
  52. package/dist/useInteractOutside.module.js.map +1 -1
  53. package/dist/useLongPress.main.js +2 -0
  54. package/dist/useLongPress.main.js.map +1 -1
  55. package/dist/useLongPress.mjs +3 -1
  56. package/dist/useLongPress.module.js +3 -1
  57. package/dist/useLongPress.module.js.map +1 -1
  58. package/dist/usePress.main.js +85 -80
  59. package/dist/usePress.main.js.map +1 -1
  60. package/dist/usePress.mjs +86 -81
  61. package/dist/usePress.module.js +86 -81
  62. package/dist/usePress.module.js.map +1 -1
  63. package/dist/utils.main.js +57 -1
  64. package/dist/utils.main.js.map +1 -1
  65. package/dist/utils.mjs +55 -2
  66. package/dist/utils.module.js +55 -2
  67. package/dist/utils.module.js.map +1 -1
  68. package/package.json +5 -4
  69. package/src/Pressable.tsx +66 -6
  70. package/src/focusSafely.ts +45 -0
  71. package/src/index.ts +3 -0
  72. package/src/textSelection.ts +6 -4
  73. package/src/useFocus.ts +3 -3
  74. package/src/useFocusVisible.ts +14 -4
  75. package/src/useFocusWithin.ts +34 -5
  76. package/src/useFocusable.tsx +183 -0
  77. package/src/useHover.ts +17 -3
  78. package/src/useInteractOutside.ts +9 -3
  79. package/src/useLongPress.ts +8 -2
  80. package/src/usePress.ts +117 -115
  81. package/src/utils.ts +80 -1
  82. package/src/DOMPropsContext.ts +0 -39
  83. package/src/DOMPropsResponder.tsx +0 -47
  84. package/src/useDOMPropsResponder.ts +0 -27
package/dist/usePress.mjs CHANGED
@@ -1,9 +1,11 @@
1
1
  import {disableTextSelection as $14c0b72509d70225$export$16a4697467175487, restoreTextSelection as $14c0b72509d70225$export$b0d6fa1ab32e3295} from "./textSelection.mjs";
2
2
  import {PressResponderContext as $ae1eeba8b9eafd08$export$5165eccb35aaadb5} from "./context.mjs";
3
+ import {preventFocus as $8a9cb279dc87e130$export$cabe61c495ee3649} from "./utils.mjs";
3
4
  import {_ as $7mdmh$_} from "@swc/helpers/_/_class_private_field_get";
4
5
  import {_ as $7mdmh$_1} from "@swc/helpers/_/_class_private_field_init";
5
6
  import {_ as $7mdmh$_2} from "@swc/helpers/_/_class_private_field_set";
6
- import {mergeProps as $7mdmh$mergeProps, useSyncRef as $7mdmh$useSyncRef, useGlobalListeners as $7mdmh$useGlobalListeners, useEffectEvent as $7mdmh$useEffectEvent, getOwnerDocument as $7mdmh$getOwnerDocument, chain as $7mdmh$chain, isMac as $7mdmh$isMac, openLink as $7mdmh$openLink, isVirtualClick as $7mdmh$isVirtualClick, focusWithoutScrolling as $7mdmh$focusWithoutScrolling, isVirtualPointerEvent as $7mdmh$isVirtualPointerEvent, getOwnerWindow as $7mdmh$getOwnerWindow} from "@react-aria/utils";
7
+ import {mergeProps as $7mdmh$mergeProps, useSyncRef as $7mdmh$useSyncRef, useGlobalListeners as $7mdmh$useGlobalListeners, useEffectEvent as $7mdmh$useEffectEvent, nodeContains as $7mdmh$nodeContains, getEventTarget as $7mdmh$getEventTarget, getOwnerDocument as $7mdmh$getOwnerDocument, chain as $7mdmh$chain, isMac as $7mdmh$isMac, openLink as $7mdmh$openLink, isVirtualClick as $7mdmh$isVirtualClick, isVirtualPointerEvent as $7mdmh$isVirtualPointerEvent, focusWithoutScrolling as $7mdmh$focusWithoutScrolling, getOwnerWindow as $7mdmh$getOwnerWindow} from "@react-aria/utils";
8
+ import {flushSync as $7mdmh$flushSync} from "react-dom";
7
9
  import {useContext as $7mdmh$useContext, useState as $7mdmh$useState, useRef as $7mdmh$useRef, useMemo as $7mdmh$useMemo, useEffect as $7mdmh$useEffect} from "react";
8
10
 
9
11
  /*
@@ -27,6 +29,8 @@ import {useContext as $7mdmh$useContext, useState as $7mdmh$useState, useRef as
27
29
 
28
30
 
29
31
 
32
+
33
+
30
34
  function $f6c31cce2adf654f$var$usePressResponderContext(props) {
31
35
  // Consume context from <PressResponder> and merge with props.
32
36
  let context = (0, $7mdmh$useContext)((0, $ae1eeba8b9eafd08$export$5165eccb35aaadb5));
@@ -89,13 +93,13 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
89
93
  let ref = (0, $7mdmh$useRef)({
90
94
  isPressed: false,
91
95
  ignoreEmulatedMouseEvents: false,
92
- ignoreClickAfterPress: false,
93
96
  didFirePressStart: false,
94
97
  isTriggeringEvent: false,
95
98
  activePointerId: null,
96
99
  target: null,
97
100
  isOverTarget: false,
98
- pointerType: null
101
+ pointerType: null,
102
+ disposables: []
99
103
  });
100
104
  let { addGlobalListener: addGlobalListener, removeAllGlobalListeners: removeAllGlobalListeners } = (0, $7mdmh$useGlobalListeners)();
101
105
  let triggerPressStart = (0, $7mdmh$useEffectEvent)((originalEvent, pointerType)=>{
@@ -117,7 +121,6 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
117
121
  let triggerPressEnd = (0, $7mdmh$useEffectEvent)((originalEvent, pointerType, wasPressed = true)=>{
118
122
  let state = ref.current;
119
123
  if (!state.didFirePressStart) return false;
120
- state.ignoreClickAfterPress = true;
121
124
  state.didFirePressStart = false;
122
125
  state.isTriggeringEvent = true;
123
126
  let shouldStopPropagation = true;
@@ -151,13 +154,15 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
151
154
  let cancel = (0, $7mdmh$useEffectEvent)((e)=>{
152
155
  let state = ref.current;
153
156
  if (state.isPressed && state.target) {
154
- if (state.isOverTarget && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false);
157
+ if (state.didFirePressStart && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false);
155
158
  state.isPressed = false;
156
159
  state.isOverTarget = false;
157
160
  state.activePointerId = null;
158
161
  state.pointerType = null;
159
162
  removeAllGlobalListeners();
160
163
  if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(state.target);
164
+ for (let dispose of state.disposables)dispose();
165
+ state.disposables = [];
161
166
  }
162
167
  });
163
168
  let cancelOnPointerExit = (0, $7mdmh$useEffectEvent)((e)=>{
@@ -167,9 +172,9 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
167
172
  let state = ref.current;
168
173
  let pressProps = {
169
174
  onKeyDown (e) {
170
- if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && e.currentTarget.contains(e.target)) {
175
+ if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && (0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) {
171
176
  var _state_metaKeyEvents;
172
- if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard(e.target, e.key)) e.preventDefault();
177
+ if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard((0, $7mdmh$getEventTarget)(e.nativeEvent), e.key)) e.preventDefault();
173
178
  // If the event is repeating, it may have started on a different element
174
179
  // after which focus moved to the current element. Ignore these events and
175
180
  // only handle the first key down event.
@@ -177,13 +182,14 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
177
182
  if (!state.isPressed && !e.repeat) {
178
183
  state.target = e.currentTarget;
179
184
  state.isPressed = true;
185
+ state.pointerType = 'keyboard';
180
186
  shouldStopPropagation = triggerPressStart(e, 'keyboard');
181
187
  // Focus may move before the key up event, so register the event on the document
182
188
  // instead of the same element where the key down event occurred. Make it capturing so that it will trigger
183
189
  // before stopPropagation from useKeyboard on a child element may happen and thus we can still call triggerPress for the parent element.
184
190
  let originalTarget = e.currentTarget;
185
191
  let pressUp = (e)=>{
186
- if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e, originalTarget) && !e.repeat && originalTarget.contains(e.target) && state.target) triggerPressUp($f6c31cce2adf654f$var$createEvent(state.target, e), 'keyboard');
192
+ if ($f6c31cce2adf654f$var$isValidKeyboardEvent(e, originalTarget) && !e.repeat && (0, $7mdmh$nodeContains)(originalTarget, (0, $7mdmh$getEventTarget)(e)) && state.target) triggerPressUp($f6c31cce2adf654f$var$createEvent(state.target, e), 'keyboard');
187
193
  };
188
194
  addGlobalListener((0, $7mdmh$getOwnerDocument)(e.currentTarget), 'keyup', (0, $7mdmh$chain)(pressUp, onKeyUp), true);
189
195
  }
@@ -199,22 +205,24 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
199
205
  } else if (e.key === 'Meta') state.metaKeyEvents = new Map();
200
206
  },
201
207
  onClick (e) {
202
- if (e && !e.currentTarget.contains(e.target)) return;
208
+ if (e && !(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
203
209
  if (e && e.button === 0 && !state.isTriggeringEvent && !(0, $7mdmh$openLink).isOpening) {
204
210
  let shouldStopPropagation = true;
205
211
  if (isDisabled) e.preventDefault();
206
212
  // If triggered from a screen reader or by using element.click(),
207
213
  // trigger as if it were a keyboard click.
208
- if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && !state.isPressed && (state.pointerType === 'virtual' || (0, $7mdmh$isVirtualClick)(e.nativeEvent))) {
209
- // Ensure the element receives focus (VoiceOver on iOS does not do this)
210
- if (!isDisabled && !preventFocusOnPress) (0, $7mdmh$focusWithoutScrolling)(e.currentTarget);
214
+ if (!state.ignoreEmulatedMouseEvents && !state.isPressed && (state.pointerType === 'virtual' || (0, $7mdmh$isVirtualClick)(e.nativeEvent))) {
211
215
  let stopPressStart = triggerPressStart(e, 'virtual');
212
216
  let stopPressUp = triggerPressUp(e, 'virtual');
213
217
  let stopPressEnd = triggerPressEnd(e, 'virtual');
214
218
  shouldStopPropagation = stopPressStart && stopPressUp && stopPressEnd;
219
+ } else if (state.isPressed && state.pointerType !== 'keyboard') {
220
+ let pointerType = state.pointerType || e.nativeEvent.pointerType || 'virtual';
221
+ shouldStopPropagation = triggerPressEnd($f6c31cce2adf654f$var$createEvent(e.currentTarget, e), pointerType, true);
222
+ state.isOverTarget = false;
223
+ cancel(e);
215
224
  }
216
225
  state.ignoreEmulatedMouseEvents = false;
217
- state.ignoreClickAfterPress = false;
218
226
  if (shouldStopPropagation) e.stopPropagation();
219
227
  }
220
228
  }
@@ -223,14 +231,14 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
223
231
  var _state_metaKeyEvents;
224
232
  if (state.isPressed && state.target && $f6c31cce2adf654f$var$isValidKeyboardEvent(e, state.target)) {
225
233
  var _state_metaKeyEvents1;
226
- if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard(e.target, e.key)) e.preventDefault();
227
- let target = e.target;
228
- triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), 'keyboard', state.target.contains(target));
234
+ if ($f6c31cce2adf654f$var$shouldPreventDefaultKeyboard((0, $7mdmh$getEventTarget)(e), e.key)) e.preventDefault();
235
+ let target = (0, $7mdmh$getEventTarget)(e);
236
+ triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), 'keyboard', (0, $7mdmh$nodeContains)(state.target, (0, $7mdmh$getEventTarget)(e)));
229
237
  removeAllGlobalListeners();
230
238
  // If a link was triggered with a key other than Enter, open the URL ourselves.
231
239
  // This means the link has a role override, and the default browser behavior
232
240
  // only applies when using the Enter key.
233
- if (e.key !== 'Enter' && $f6c31cce2adf654f$var$isHTMLAnchorLink(state.target) && state.target.contains(target) && !e[$f6c31cce2adf654f$var$LINK_CLICKED]) {
241
+ if (e.key !== 'Enter' && $f6c31cce2adf654f$var$isHTMLAnchorLink(state.target) && (0, $7mdmh$nodeContains)(state.target, target) && !e[$f6c31cce2adf654f$var$LINK_CLICKED]) {
234
242
  // Store a hidden property on the event so we only trigger link click once,
235
243
  // even if there are multiple usePress instances attached to the element.
236
244
  e[$f6c31cce2adf654f$var$LINK_CLICKED] = true;
@@ -251,7 +259,7 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
251
259
  if (typeof PointerEvent !== 'undefined') {
252
260
  pressProps.onPointerDown = (e)=>{
253
261
  // Only handle left clicks, and ignore events that bubbled through portals.
254
- if (e.button !== 0 || !e.currentTarget.contains(e.target)) return;
262
+ if (e.button !== 0 || !(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
255
263
  // iOS safari fires pointer events from VoiceOver with incorrect coordinates/target.
256
264
  // Ignore and let the onClick handler take care of it instead.
257
265
  // https://bugs.webkit.org/show_bug.cgi?id=222627
@@ -260,9 +268,6 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
260
268
  state.pointerType = 'virtual';
261
269
  return;
262
270
  }
263
- // Due to browser inconsistencies, especially on mobile browsers, we prevent
264
- // default on pointer down and handle focusing the pressable element ourselves.
265
- if ($f6c31cce2adf654f$var$shouldPreventDefaultDown(e.currentTarget)) e.preventDefault();
266
271
  state.pointerType = e.pointerType;
267
272
  let shouldStopPropagation = true;
268
273
  if (!state.isPressed) {
@@ -270,12 +275,11 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
270
275
  state.isOverTarget = true;
271
276
  state.activePointerId = e.pointerId;
272
277
  state.target = e.currentTarget;
273
- if (!isDisabled && !preventFocusOnPress) (0, $7mdmh$focusWithoutScrolling)(e.currentTarget);
274
278
  if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$16a4697467175487)(state.target);
275
279
  shouldStopPropagation = triggerPressStart(e, state.pointerType);
276
280
  // Release pointer capture so that touch interactions can leave the original target.
277
281
  // This enables onPointerLeave and onPointerEnter to fire.
278
- let target = e.target;
282
+ let target = (0, $7mdmh$getEventTarget)(e.nativeEvent);
279
283
  if ('releasePointerCapture' in target) target.releasePointerCapture(e.pointerId);
280
284
  addGlobalListener((0, $7mdmh$getOwnerDocument)(e.currentTarget), 'pointerup', onPointerUp, false);
281
285
  addGlobalListener((0, $7mdmh$getOwnerDocument)(e.currentTarget), 'pointercancel', onPointerCancel, false);
@@ -283,18 +287,18 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
283
287
  if (shouldStopPropagation) e.stopPropagation();
284
288
  };
285
289
  pressProps.onMouseDown = (e)=>{
286
- if (!e.currentTarget.contains(e.target)) return;
290
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
287
291
  if (e.button === 0) {
288
- // Chrome and Firefox on touch Windows devices require mouse down events
289
- // to be canceled in addition to pointer events, or an extra asynchronous
290
- // focus event will be fired.
291
- if ($f6c31cce2adf654f$var$shouldPreventDefaultDown(e.currentTarget)) e.preventDefault();
292
+ if (preventFocusOnPress) {
293
+ let dispose = (0, $8a9cb279dc87e130$export$cabe61c495ee3649)(e.target);
294
+ if (dispose) state.disposables.push(dispose);
295
+ }
292
296
  e.stopPropagation();
293
297
  }
294
298
  };
295
299
  pressProps.onPointerUp = (e)=>{
296
300
  // iOS fires pointerup with zero width and height, so check the pointerType recorded during pointerdown.
297
- if (!e.currentTarget.contains(e.target) || state.pointerType === 'virtual') return;
301
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent)) || state.pointerType === 'virtual') return;
298
302
  // Only handle left clicks
299
303
  if (e.button === 0) triggerPressUp(e, state.pointerType || e.pointerType);
300
304
  };
@@ -313,46 +317,50 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
313
317
  };
314
318
  let onPointerUp = (e)=>{
315
319
  if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0 && state.target) {
316
- if (state.target.contains(e.target) && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType);
317
- else if (state.isOverTarget && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false);
318
- state.isPressed = false;
320
+ if ((0, $7mdmh$nodeContains)(state.target, (0, $7mdmh$getEventTarget)(e)) && state.pointerType != null) {
321
+ // Wait for onClick to fire onPress. This avoids browser issues when the DOM
322
+ // is mutated between onPointerUp and onClick, and is more compatible with third party libraries.
323
+ // https://github.com/adobe/react-spectrum/issues/1513
324
+ // https://issues.chromium.org/issues/40732224
325
+ // However, iOS and Android do not focus or fire onClick after a long press.
326
+ // We work around this by triggering a click ourselves after a timeout.
327
+ // This timeout is canceled during the click event in case the real one fires first.
328
+ // The timeout must be at least 32ms, because Safari on iOS delays the click event on
329
+ // non-form elements without certain ARIA roles (for hover emulation).
330
+ // https://github.com/WebKit/WebKit/blob/dccfae42bb29bd4bdef052e469f604a9387241c0/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm#L875-L892
331
+ let clicked = false;
332
+ let timeout = setTimeout(()=>{
333
+ if (state.isPressed && state.target instanceof HTMLElement) {
334
+ if (clicked) cancel(e);
335
+ else {
336
+ (0, $7mdmh$focusWithoutScrolling)(state.target);
337
+ state.target.click();
338
+ }
339
+ }
340
+ }, 80);
341
+ // Use a capturing listener to track if a click occurred.
342
+ // If stopPropagation is called it may never reach our handler.
343
+ addGlobalListener(e.currentTarget, 'click', ()=>clicked = true, true);
344
+ state.disposables.push(()=>clearTimeout(timeout));
345
+ } else cancel(e);
346
+ // Ignore subsequent onPointerLeave event before onClick on touch devices.
319
347
  state.isOverTarget = false;
320
- state.activePointerId = null;
321
- state.pointerType = null;
322
- removeAllGlobalListeners();
323
- if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)(state.target);
324
- // Prevent subsequent touchend event from triggering onClick on unrelated elements on Android. See below.
325
- // Both 'touch' and 'pen' pointerTypes trigger onTouchEnd, but 'mouse' does not.
326
- if ('ontouchend' in state.target && e.pointerType !== 'mouse') addGlobalListener(state.target, 'touchend', onTouchEnd, {
327
- once: true
328
- });
329
348
  }
330
349
  };
331
- // This is a workaround for an Android Chrome/Firefox issue where click events are fired on an incorrect element
332
- // if the original target is removed during onPointerUp (before onClick).
333
- // https://github.com/adobe/react-spectrum/issues/1513
334
- // https://issues.chromium.org/issues/40732224
335
- // Note: this event must be registered directly on the element, not via React props in order to work.
336
- // https://github.com/facebook/react/issues/9809
337
- let onTouchEnd = (e)=>{
338
- // Don't preventDefault if we actually want the default (e.g. submit/link click).
339
- if ($f6c31cce2adf654f$var$shouldPreventDefaultUp(e.currentTarget)) e.preventDefault();
340
- };
341
350
  let onPointerCancel = (e)=>{
342
351
  cancel(e);
343
352
  };
344
353
  pressProps.onDragStart = (e)=>{
345
- if (!e.currentTarget.contains(e.target)) return;
354
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
346
355
  // Safari does not call onPointerCancel when a drag starts, whereas Chrome and Firefox do.
347
356
  cancel(e);
348
357
  };
349
358
  } else {
359
+ // NOTE: this fallback branch is almost entirely used by unit tests.
360
+ // All browsers now support pointer events, but JSDOM still does not.
350
361
  pressProps.onMouseDown = (e)=>{
351
362
  // Only handle left clicks
352
- if (e.button !== 0 || !e.currentTarget.contains(e.target)) return;
353
- // Due to browser inconsistencies, especially on mobile browsers, we prevent
354
- // default on mouse down and handle focusing the pressable element ourselves.
355
- if ($f6c31cce2adf654f$var$shouldPreventDefaultDown(e.currentTarget)) e.preventDefault();
363
+ if (e.button !== 0 || !(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
356
364
  if (state.ignoreEmulatedMouseEvents) {
357
365
  e.stopPropagation();
358
366
  return;
@@ -361,13 +369,17 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
361
369
  state.isOverTarget = true;
362
370
  state.target = e.currentTarget;
363
371
  state.pointerType = (0, $7mdmh$isVirtualClick)(e.nativeEvent) ? 'virtual' : 'mouse';
364
- if (!isDisabled && !preventFocusOnPress) (0, $7mdmh$focusWithoutScrolling)(e.currentTarget);
365
- let shouldStopPropagation = triggerPressStart(e, state.pointerType);
372
+ // Flush sync so that focus moved during react re-renders occurs before we yield back to the browser.
373
+ let shouldStopPropagation = (0, $7mdmh$flushSync)(()=>triggerPressStart(e, state.pointerType));
366
374
  if (shouldStopPropagation) e.stopPropagation();
375
+ if (preventFocusOnPress) {
376
+ let dispose = (0, $8a9cb279dc87e130$export$cabe61c495ee3649)(e.target);
377
+ if (dispose) state.disposables.push(dispose);
378
+ }
367
379
  addGlobalListener((0, $7mdmh$getOwnerDocument)(e.currentTarget), 'mouseup', onMouseUp, false);
368
380
  };
369
381
  pressProps.onMouseEnter = (e)=>{
370
- if (!e.currentTarget.contains(e.target)) return;
382
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
371
383
  let shouldStopPropagation = true;
372
384
  if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
373
385
  state.isOverTarget = true;
@@ -376,7 +388,7 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
376
388
  if (shouldStopPropagation) e.stopPropagation();
377
389
  };
378
390
  pressProps.onMouseLeave = (e)=>{
379
- if (!e.currentTarget.contains(e.target)) return;
391
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
380
392
  let shouldStopPropagation = true;
381
393
  if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
382
394
  state.isOverTarget = false;
@@ -386,24 +398,22 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
386
398
  if (shouldStopPropagation) e.stopPropagation();
387
399
  };
388
400
  pressProps.onMouseUp = (e)=>{
389
- if (!e.currentTarget.contains(e.target)) return;
401
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
390
402
  if (!state.ignoreEmulatedMouseEvents && e.button === 0) triggerPressUp(e, state.pointerType || 'mouse');
391
403
  };
392
404
  let onMouseUp = (e)=>{
393
405
  // Only handle left clicks
394
406
  if (e.button !== 0) return;
395
- state.isPressed = false;
396
- removeAllGlobalListeners();
397
407
  if (state.ignoreEmulatedMouseEvents) {
398
408
  state.ignoreEmulatedMouseEvents = false;
399
409
  return;
400
410
  }
401
- if (state.target && $f6c31cce2adf654f$var$isOverTarget(e, state.target) && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType);
402
- else if (state.target && state.isOverTarget && state.pointerType != null) triggerPressEnd($f6c31cce2adf654f$var$createEvent(state.target, e), state.pointerType, false);
411
+ if (state.target && state.target.contains(e.target) && state.pointerType != null) ;
412
+ else cancel(e);
403
413
  state.isOverTarget = false;
404
414
  };
405
415
  pressProps.onTouchStart = (e)=>{
406
- if (!e.currentTarget.contains(e.target)) return;
416
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
407
417
  let touch = $f6c31cce2adf654f$var$getTouchFromEvent(e.nativeEvent);
408
418
  if (!touch) return;
409
419
  state.activePointerId = touch.identifier;
@@ -412,16 +422,13 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
412
422
  state.isPressed = true;
413
423
  state.target = e.currentTarget;
414
424
  state.pointerType = 'touch';
415
- // Due to browser inconsistencies, especially on mobile browsers, we prevent default
416
- // on the emulated mouse event and handle focusing the pressable element ourselves.
417
- if (!isDisabled && !preventFocusOnPress) (0, $7mdmh$focusWithoutScrolling)(e.currentTarget);
418
425
  if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$16a4697467175487)(state.target);
419
426
  let shouldStopPropagation = triggerPressStart($f6c31cce2adf654f$var$createTouchEvent(state.target, e), state.pointerType);
420
427
  if (shouldStopPropagation) e.stopPropagation();
421
428
  addGlobalListener((0, $7mdmh$getOwnerWindow)(e.currentTarget), 'scroll', onScroll, true);
422
429
  };
423
430
  pressProps.onTouchMove = (e)=>{
424
- if (!e.currentTarget.contains(e.target)) return;
431
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
425
432
  if (!state.isPressed) {
426
433
  e.stopPropagation();
427
434
  return;
@@ -441,7 +448,7 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
441
448
  if (shouldStopPropagation) e.stopPropagation();
442
449
  };
443
450
  pressProps.onTouchEnd = (e)=>{
444
- if (!e.currentTarget.contains(e.target)) return;
451
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
445
452
  if (!state.isPressed) {
446
453
  e.stopPropagation();
447
454
  return;
@@ -461,12 +468,12 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
461
468
  removeAllGlobalListeners();
462
469
  };
463
470
  pressProps.onTouchCancel = (e)=>{
464
- if (!e.currentTarget.contains(e.target)) return;
471
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
465
472
  e.stopPropagation();
466
473
  if (state.isPressed) cancel($f6c31cce2adf654f$var$createTouchEvent(state.target, e));
467
474
  };
468
475
  let onScroll = (e)=>{
469
- if (state.isPressed && e.target.contains(state.target)) cancel({
476
+ if (state.isPressed && (0, $7mdmh$nodeContains)((0, $7mdmh$getEventTarget)(e), state.target)) cancel({
470
477
  currentTarget: state.target,
471
478
  shiftKey: false,
472
479
  ctrlKey: false,
@@ -475,7 +482,7 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
475
482
  });
476
483
  };
477
484
  pressProps.onDragStart = (e)=>{
478
- if (!e.currentTarget.contains(e.target)) return;
485
+ if (!(0, $7mdmh$nodeContains)(e.currentTarget, (0, $7mdmh$getEventTarget)(e.nativeEvent))) return;
479
486
  cancel(e);
480
487
  };
481
488
  }
@@ -494,10 +501,12 @@ function $f6c31cce2adf654f$export$45712eceda6fad21(props) {
494
501
  ]);
495
502
  // Remove user-select: none in case component unmounts immediately after pressStart
496
503
  (0, $7mdmh$useEffect)(()=>{
504
+ let state = ref.current;
497
505
  return ()=>{
498
- var _ref_current_target;
499
- if (!allowTextSelectionOnPress) // eslint-disable-next-line react-hooks/exhaustive-deps
500
- (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)((_ref_current_target = ref.current.target) !== null && _ref_current_target !== void 0 ? _ref_current_target : undefined);
506
+ var _state_target;
507
+ if (!allowTextSelectionOnPress) (0, $14c0b72509d70225$export$b0d6fa1ab32e3295)((_state_target = state.target) !== null && _state_target !== void 0 ? _state_target : undefined);
508
+ for (let dispose of state.disposables)dispose();
509
+ state.disposables = [];
501
510
  };
502
511
  }, [
503
512
  allowTextSelectionOnPress
@@ -588,10 +597,6 @@ function $f6c31cce2adf654f$var$isOverTarget(point, target) {
588
597
  let pointRect = $f6c31cce2adf654f$var$getPointClientRect(point);
589
598
  return $f6c31cce2adf654f$var$areRectanglesOverlapping(rect, pointRect);
590
599
  }
591
- function $f6c31cce2adf654f$var$shouldPreventDefaultDown(target) {
592
- // We cannot prevent default if the target is a draggable element.
593
- return !(target instanceof HTMLElement) || !target.hasAttribute('draggable');
594
- }
595
600
  function $f6c31cce2adf654f$var$shouldPreventDefaultUp(target) {
596
601
  if (target instanceof HTMLInputElement) return false;
597
602
  if (target instanceof HTMLButtonElement) return target.type !== 'submit' && target.type !== 'reset';