@react-aria/interactions 3.19.0 → 3.20.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 +110 -71
- package/dist/main.js +110 -69
- package/dist/main.js.map +1 -1
- package/dist/module.js +110 -71
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +6 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/DOMPropsContext.ts +1 -1
- package/src/DOMPropsResponder.tsx +5 -3
- package/src/PressResponder.tsx +7 -5
- package/src/Pressable.tsx +4 -5
- package/src/context.ts +1 -1
- package/src/createEventHandler.ts +2 -2
- package/src/textSelection.ts +10 -6
- package/src/useFocusVisible.ts +22 -6
- package/src/useFocusWithin.ts +3 -2
- package/src/useInteractOutside.ts +21 -18
- package/src/useLongPress.ts +3 -3
- package/src/useMove.ts +4 -4
- package/src/usePress.ts +50 -40
- package/src/useScrollWheel.ts +1 -1
- package/src/utils.ts +4 -4
package/src/usePress.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import {disableTextSelection, restoreTextSelection} from './textSelection';
|
|
19
19
|
import {DOMAttributes, FocusableElement, PressEvent as IPressEvent, PointerType, PressEvents} from '@react-types/shared';
|
|
20
|
-
import {focusWithoutScrolling, isMac, isVirtualClick, isVirtualPointerEvent, mergeProps, openLink, useEffectEvent, useGlobalListeners, useSyncRef} from '@react-aria/utils';
|
|
20
|
+
import {focusWithoutScrolling, getOwnerDocument, getOwnerWindow, isMac, isVirtualClick, isVirtualPointerEvent, mergeProps, openLink, useEffectEvent, useGlobalListeners, useSyncRef} from '@react-aria/utils';
|
|
21
21
|
import {PressResponderContext} from './context';
|
|
22
22
|
import {RefObject, useContext, useEffect, useMemo, useRef, useState} from 'react';
|
|
23
23
|
|
|
@@ -53,13 +53,13 @@ interface PressState {
|
|
|
53
53
|
activePointerId: any,
|
|
54
54
|
target: FocusableElement | null,
|
|
55
55
|
isOverTarget: boolean,
|
|
56
|
-
pointerType: PointerType,
|
|
56
|
+
pointerType: PointerType | null,
|
|
57
57
|
userSelect?: string,
|
|
58
58
|
metaKeyEvents?: Map<string, KeyboardEvent>
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
interface EventBase {
|
|
62
|
-
currentTarget: EventTarget,
|
|
62
|
+
currentTarget: EventTarget | null,
|
|
63
63
|
shiftKey: boolean,
|
|
64
64
|
ctrlKey: boolean,
|
|
65
65
|
metaKey: boolean,
|
|
@@ -157,7 +157,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
157
157
|
let triggerPressStart = useEffectEvent((originalEvent: EventBase, pointerType: PointerType) => {
|
|
158
158
|
let state = ref.current;
|
|
159
159
|
if (isDisabled || state.didFirePressStart) {
|
|
160
|
-
return;
|
|
160
|
+
return false;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
let shouldStopPropagation = true;
|
|
@@ -181,7 +181,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
181
181
|
let triggerPressEnd = useEffectEvent((originalEvent: EventBase, pointerType: PointerType, wasPressed = true) => {
|
|
182
182
|
let state = ref.current;
|
|
183
183
|
if (!state.didFirePressStart) {
|
|
184
|
-
return;
|
|
184
|
+
return false;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
state.ignoreClickAfterPress = true;
|
|
@@ -214,7 +214,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
214
214
|
let triggerPressUp = useEffectEvent((originalEvent: EventBase, pointerType: PointerType) => {
|
|
215
215
|
let state = ref.current;
|
|
216
216
|
if (isDisabled) {
|
|
217
|
-
return;
|
|
217
|
+
return false;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
if (onPressUp) {
|
|
@@ -230,8 +230,8 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
230
230
|
|
|
231
231
|
let cancel = useEffectEvent((e: EventBase) => {
|
|
232
232
|
let state = ref.current;
|
|
233
|
-
if (state.isPressed) {
|
|
234
|
-
if (state.isOverTarget) {
|
|
233
|
+
if (state.isPressed && state.target) {
|
|
234
|
+
if (state.isOverTarget && state.pointerType != null) {
|
|
235
235
|
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
236
236
|
}
|
|
237
237
|
state.isPressed = false;
|
|
@@ -271,7 +271,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
271
271
|
|
|
272
272
|
// Focus may move before the key up event, so register the event on the document
|
|
273
273
|
// instead of the same element where the key down event occurred.
|
|
274
|
-
addGlobalListener(
|
|
274
|
+
addGlobalListener(getOwnerDocument(e.currentTarget), 'keyup', onKeyUp, false);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
if (shouldStopPropagation) {
|
|
@@ -286,14 +286,14 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
286
286
|
// https://bugs.webkit.org/show_bug.cgi?id=55291
|
|
287
287
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1299553
|
|
288
288
|
if (e.metaKey && isMac()) {
|
|
289
|
-
state.metaKeyEvents
|
|
289
|
+
state.metaKeyEvents?.set(e.key, e.nativeEvent);
|
|
290
290
|
}
|
|
291
291
|
} else if (e.key === 'Meta') {
|
|
292
292
|
state.metaKeyEvents = new Map();
|
|
293
293
|
}
|
|
294
294
|
},
|
|
295
295
|
onKeyUp(e) {
|
|
296
|
-
if (isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && !e.repeat && e.currentTarget.contains(e.target as Element)) {
|
|
296
|
+
if (isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && !e.repeat && e.currentTarget.contains(e.target as Element) && state.target) {
|
|
297
297
|
triggerPressUp(createEvent(state.target, e), 'keyboard');
|
|
298
298
|
}
|
|
299
299
|
},
|
|
@@ -302,7 +302,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
if (e && e.button === 0 && !state.isTriggeringEvent && !openLink.isOpening) {
|
|
305
|
+
if (e && e.button === 0 && !state.isTriggeringEvent && !(openLink as any).isOpening) {
|
|
306
306
|
let shouldStopPropagation = true;
|
|
307
307
|
if (isDisabled) {
|
|
308
308
|
e.preventDefault();
|
|
@@ -332,7 +332,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
332
332
|
};
|
|
333
333
|
|
|
334
334
|
let onKeyUp = (e: KeyboardEvent) => {
|
|
335
|
-
if (state.isPressed && isValidKeyboardEvent(e, state.target)) {
|
|
335
|
+
if (state.isPressed && state.target && isValidKeyboardEvent(e, state.target)) {
|
|
336
336
|
if (shouldPreventDefaultKeyboard(e.target as Element, e.key)) {
|
|
337
337
|
e.preventDefault();
|
|
338
338
|
}
|
|
@@ -362,9 +362,9 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
362
362
|
// and those haven't received keyup events already, fire keyup events ourselves.
|
|
363
363
|
// See comment above for more info about the macOS bug causing this.
|
|
364
364
|
let events = state.metaKeyEvents;
|
|
365
|
-
state.metaKeyEvents =
|
|
365
|
+
state.metaKeyEvents = undefined;
|
|
366
366
|
for (let event of events.values()) {
|
|
367
|
-
state.target
|
|
367
|
+
state.target?.dispatchEvent(new KeyboardEvent('keyup', event));
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
};
|
|
@@ -410,9 +410,9 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
410
410
|
|
|
411
411
|
shouldStopPropagation = triggerPressStart(e, state.pointerType);
|
|
412
412
|
|
|
413
|
-
addGlobalListener(
|
|
414
|
-
addGlobalListener(
|
|
415
|
-
addGlobalListener(
|
|
413
|
+
addGlobalListener(getOwnerDocument(e.currentTarget), 'pointermove', onPointerMove, false);
|
|
414
|
+
addGlobalListener(getOwnerDocument(e.currentTarget), 'pointerup', onPointerUp, false);
|
|
415
|
+
addGlobalListener(getOwnerDocument(e.currentTarget), 'pointercancel', onPointerCancel, false);
|
|
416
416
|
}
|
|
417
417
|
|
|
418
418
|
if (shouldStopPropagation) {
|
|
@@ -459,12 +459,12 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
459
459
|
return;
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
-
if (isOverTarget(e, state.target)) {
|
|
463
|
-
if (!state.isOverTarget) {
|
|
462
|
+
if (state.target && isOverTarget(e, state.target)) {
|
|
463
|
+
if (!state.isOverTarget && state.pointerType != null) {
|
|
464
464
|
state.isOverTarget = true;
|
|
465
465
|
triggerPressStart(createEvent(state.target, e), state.pointerType);
|
|
466
466
|
}
|
|
467
|
-
} else if (state.isOverTarget) {
|
|
467
|
+
} else if (state.target && state.isOverTarget && state.pointerType != null) {
|
|
468
468
|
state.isOverTarget = false;
|
|
469
469
|
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
470
470
|
cancelOnPointerExit(e);
|
|
@@ -472,10 +472,10 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
472
472
|
};
|
|
473
473
|
|
|
474
474
|
let onPointerUp = (e: PointerEvent) => {
|
|
475
|
-
if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0) {
|
|
476
|
-
if (isOverTarget(e, state.target)) {
|
|
475
|
+
if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0 && state.target) {
|
|
476
|
+
if (isOverTarget(e, state.target) && state.pointerType != null) {
|
|
477
477
|
triggerPressEnd(createEvent(state.target, e), state.pointerType);
|
|
478
|
-
} else if (state.isOverTarget) {
|
|
478
|
+
} else if (state.isOverTarget && state.pointerType != null) {
|
|
479
479
|
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
480
480
|
}
|
|
481
481
|
|
|
@@ -534,7 +534,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
534
534
|
e.stopPropagation();
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
-
addGlobalListener(
|
|
537
|
+
addGlobalListener(getOwnerDocument(e.currentTarget), 'mouseup', onMouseUp, false);
|
|
538
538
|
};
|
|
539
539
|
|
|
540
540
|
pressProps.onMouseEnter = (e) => {
|
|
@@ -543,7 +543,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
543
543
|
}
|
|
544
544
|
|
|
545
545
|
let shouldStopPropagation = true;
|
|
546
|
-
if (state.isPressed && !state.ignoreEmulatedMouseEvents) {
|
|
546
|
+
if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
|
|
547
547
|
state.isOverTarget = true;
|
|
548
548
|
shouldStopPropagation = triggerPressStart(e, state.pointerType);
|
|
549
549
|
}
|
|
@@ -559,7 +559,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
559
559
|
}
|
|
560
560
|
|
|
561
561
|
let shouldStopPropagation = true;
|
|
562
|
-
if (state.isPressed && !state.ignoreEmulatedMouseEvents) {
|
|
562
|
+
if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
|
|
563
563
|
state.isOverTarget = false;
|
|
564
564
|
shouldStopPropagation = triggerPressEnd(e, state.pointerType, false);
|
|
565
565
|
cancelOnPointerExit(e);
|
|
@@ -594,9 +594,9 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
594
594
|
return;
|
|
595
595
|
}
|
|
596
596
|
|
|
597
|
-
if (isOverTarget(e, state.target)) {
|
|
597
|
+
if (state.target && isOverTarget(e, state.target) && state.pointerType != null) {
|
|
598
598
|
triggerPressEnd(createEvent(state.target, e), state.pointerType);
|
|
599
|
-
} else if (state.isOverTarget) {
|
|
599
|
+
} else if (state.target && state.isOverTarget && state.pointerType != null) {
|
|
600
600
|
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
601
601
|
}
|
|
602
602
|
|
|
@@ -634,7 +634,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
634
634
|
e.stopPropagation();
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
-
addGlobalListener(
|
|
637
|
+
addGlobalListener(getOwnerWindow(e.currentTarget), 'scroll', onScroll, true);
|
|
638
638
|
};
|
|
639
639
|
|
|
640
640
|
pressProps.onTouchMove = (e) => {
|
|
@@ -650,11 +650,11 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
650
650
|
let touch = getTouchById(e.nativeEvent, state.activePointerId);
|
|
651
651
|
let shouldStopPropagation = true;
|
|
652
652
|
if (touch && isOverTarget(touch, e.currentTarget)) {
|
|
653
|
-
if (!state.isOverTarget) {
|
|
653
|
+
if (!state.isOverTarget && state.pointerType != null) {
|
|
654
654
|
state.isOverTarget = true;
|
|
655
655
|
shouldStopPropagation = triggerPressStart(e, state.pointerType);
|
|
656
656
|
}
|
|
657
|
-
} else if (state.isOverTarget) {
|
|
657
|
+
} else if (state.isOverTarget && state.pointerType != null) {
|
|
658
658
|
state.isOverTarget = false;
|
|
659
659
|
shouldStopPropagation = triggerPressEnd(e, state.pointerType, false);
|
|
660
660
|
cancelOnPointerExit(e);
|
|
@@ -677,10 +677,10 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
677
677
|
|
|
678
678
|
let touch = getTouchById(e.nativeEvent, state.activePointerId);
|
|
679
679
|
let shouldStopPropagation = true;
|
|
680
|
-
if (touch && isOverTarget(touch, e.currentTarget)) {
|
|
680
|
+
if (touch && isOverTarget(touch, e.currentTarget) && state.pointerType != null) {
|
|
681
681
|
triggerPressUp(e, state.pointerType);
|
|
682
682
|
shouldStopPropagation = triggerPressEnd(e, state.pointerType);
|
|
683
|
-
} else if (state.isOverTarget) {
|
|
683
|
+
} else if (state.isOverTarget && state.pointerType != null) {
|
|
684
684
|
shouldStopPropagation = triggerPressEnd(e, state.pointerType, false);
|
|
685
685
|
}
|
|
686
686
|
|
|
@@ -692,7 +692,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
692
692
|
state.activePointerId = null;
|
|
693
693
|
state.isOverTarget = false;
|
|
694
694
|
state.ignoreEmulatedMouseEvents = true;
|
|
695
|
-
if (!allowTextSelectionOnPress) {
|
|
695
|
+
if (state.target && !allowTextSelectionOnPress) {
|
|
696
696
|
restoreTextSelection(state.target);
|
|
697
697
|
}
|
|
698
698
|
removeAllGlobalListeners();
|
|
@@ -750,7 +750,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
750
750
|
return () => {
|
|
751
751
|
if (!allowTextSelectionOnPress) {
|
|
752
752
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
753
|
-
restoreTextSelection(ref.current.target);
|
|
753
|
+
restoreTextSelection(ref.current.target ?? undefined);
|
|
754
754
|
}
|
|
755
755
|
};
|
|
756
756
|
}, [allowTextSelectionOnPress]);
|
|
@@ -773,8 +773,8 @@ function isValidKeyboardEvent(event: KeyboardEvent, currentTarget: Element): boo
|
|
|
773
773
|
// "Spacebar" is for IE 11
|
|
774
774
|
return (
|
|
775
775
|
(key === 'Enter' || key === ' ' || key === 'Spacebar' || code === 'Space') &&
|
|
776
|
-
!((element instanceof HTMLInputElement && !isValidInputKey(element, key)) ||
|
|
777
|
-
element instanceof HTMLTextAreaElement ||
|
|
776
|
+
!((element instanceof getOwnerWindow(element).HTMLInputElement && !isValidInputKey(element, key)) ||
|
|
777
|
+
element instanceof getOwnerWindow(element).HTMLTextAreaElement ||
|
|
778
778
|
element.isContentEditable) &&
|
|
779
779
|
// Links should only trigger with Enter key
|
|
780
780
|
!((role === 'link' || (!role && isHTMLAnchorLink(element))) && key !== 'Enter')
|
|
@@ -830,8 +830,18 @@ interface EventPoint {
|
|
|
830
830
|
}
|
|
831
831
|
|
|
832
832
|
function getPointClientRect(point: EventPoint): Rect {
|
|
833
|
-
let offsetX =
|
|
834
|
-
let offsetY =
|
|
833
|
+
let offsetX = 0;
|
|
834
|
+
let offsetY = 0;
|
|
835
|
+
if (point.width !== undefined) {
|
|
836
|
+
offsetX = (point.width / 2);
|
|
837
|
+
} else if (point.radiusX !== undefined) {
|
|
838
|
+
offsetX = point.radiusX;
|
|
839
|
+
}
|
|
840
|
+
if (point.height !== undefined) {
|
|
841
|
+
offsetY = (point.height / 2);
|
|
842
|
+
} else if (point.radiusY !== undefined) {
|
|
843
|
+
offsetY = point.radiusY;
|
|
844
|
+
}
|
|
835
845
|
|
|
836
846
|
return {
|
|
837
847
|
top: point.clientY - offsetY,
|
package/src/useScrollWheel.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class SyntheticFocusEvent<Target = Element> implements ReactFocusEvent<Ta
|
|
|
64
64
|
export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEvent<Target>) => void) {
|
|
65
65
|
let stateRef = useRef({
|
|
66
66
|
isFocused: false,
|
|
67
|
-
observer: null as MutationObserver
|
|
67
|
+
observer: null as MutationObserver | null
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
// Clean up MutationObserver on unmount. See below.
|
|
@@ -98,12 +98,12 @@ export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEv
|
|
|
98
98
|
stateRef.current.isFocused = true;
|
|
99
99
|
|
|
100
100
|
let target = e.target;
|
|
101
|
-
let onBlurHandler = (e
|
|
101
|
+
let onBlurHandler: EventListenerOrEventListenerObject | null = (e) => {
|
|
102
102
|
stateRef.current.isFocused = false;
|
|
103
103
|
|
|
104
104
|
if (target.disabled) {
|
|
105
105
|
// For backward compatibility, dispatch a (fake) React synthetic event.
|
|
106
|
-
dispatchBlur(new SyntheticFocusEvent('blur', e));
|
|
106
|
+
dispatchBlur(new SyntheticFocusEvent('blur', e as FocusEvent));
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// We no longer need the MutationObserver once the target is blurred.
|
|
@@ -117,7 +117,7 @@ export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEv
|
|
|
117
117
|
|
|
118
118
|
stateRef.current.observer = new MutationObserver(() => {
|
|
119
119
|
if (stateRef.current.isFocused && target.disabled) {
|
|
120
|
-
stateRef.current.observer
|
|
120
|
+
stateRef.current.observer?.disconnect();
|
|
121
121
|
let relatedTargetEl = target === document.activeElement ? null : document.activeElement;
|
|
122
122
|
target.dispatchEvent(new FocusEvent('blur', {relatedTarget: relatedTargetEl}));
|
|
123
123
|
target.dispatchEvent(new FocusEvent('focusout', {bubbles: true, relatedTarget: relatedTargetEl}));
|