@react-aria/interactions 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 +152 -145
- package/dist/main.js +151 -144
- package/dist/main.js.map +1 -1
- package/dist/module.js +152 -145
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/PressResponder.tsx +1 -0
- package/src/useHover.ts +1 -2
- package/src/useInteractOutside.ts +25 -22
- package/src/useMove.ts +43 -41
- package/src/usePress.ts +112 -103
- package/src/utils.ts +10 -7
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;AEuBA,2BAA4B,SAAQ,WAAW;IAC7C,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,yEAAyE;IACzE,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED,+BAAgC,SAAQ,UAAU;IAChD,mCAAmC;IACnC,GAAG,CAAC,EAAE,UAAU,OAAO,CAAC,CAAA;CACzB;AAsBD;IACE,+CAA+C;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,UAAU,EAAE,aAAa,CAAA;CAC1B;AAeD;;;;GAIG;AACH,yBAAyB,KAAK,EAAE,cAAc,GAAG,WAAW,
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/textSelection.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/context.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/usePress.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/Pressable.tsx","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/PressResponder.tsx","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/utils.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useFocus.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useFocusVisible.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useFocusWithin.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useHover.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useInteractOutside.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/createEventHandler.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useKeyboard.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useMove.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useScrollWheel.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/useLongPress.ts","packages/@react-aria/interactions/src/packages/@react-aria/interactions/src/index.ts","packages/@react-aria/interactions/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport {Pressable} from './Pressable';\nexport {PressResponder} from './PressResponder';\nexport {useFocus} from './useFocus';\nexport {\n isFocusVisible,\n getInteractionModality,\n setInteractionModality,\n useInteractionModality,\n useFocusVisible,\n useFocusVisibleListener\n} from './useFocusVisible';\nexport {useFocusWithin} from './useFocusWithin';\nexport {useHover} from './useHover';\nexport {useInteractOutside} from './useInteractOutside';\nexport {useKeyboard} from './useKeyboard';\nexport {useMove} from './useMove';\nexport {usePress} from './usePress';\nexport {useScrollWheel} from './useScrollWheel';\nexport {useLongPress} from './useLongPress';\n\nexport type {FocusProps, FocusResult} from './useFocus';\nexport type {FocusVisibleHandler, FocusVisibleProps, FocusVisibleResult, Modality} from './useFocusVisible';\nexport type {FocusWithinProps, FocusWithinResult} from './useFocusWithin';\nexport type {HoverProps, HoverResult} from './useHover';\nexport type {InteractOutsideProps} from './useInteractOutside';\nexport type {KeyboardProps, KeyboardResult} from './useKeyboard';\nexport type {PressProps, PressHookProps, PressResult} from './usePress';\nexport type {MoveEvents} from '@react-types/shared';\nexport type {MoveResult} from './useMove';\nexport type {LongPressProps, LongPressResult} from './useLongPress';\nexport type {ScrollWheelProps} from './useScrollWheel';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/interactions",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-aria/ssr": "^3.
|
|
26
|
-
"@react-aria/utils": "^3.
|
|
27
|
-
"@react-types/shared": "^3.18.
|
|
28
|
-
"@swc/helpers": "^0.
|
|
25
|
+
"@react-aria/ssr": "^3.7.0",
|
|
26
|
+
"@react-aria/utils": "^3.18.0",
|
|
27
|
+
"@react-types/shared": "^3.18.1",
|
|
28
|
+
"@swc/helpers": "^0.5.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "504e40e0a50c1b20ed0fb3ba9561a263b6d5565e"
|
|
37
37
|
}
|
package/src/PressResponder.tsx
CHANGED
|
@@ -42,6 +42,7 @@ export const PressResponder = React.forwardRef(({children, ...props}: PressRespo
|
|
|
42
42
|
'A PressResponder was rendered without a pressable child. ' +
|
|
43
43
|
'Either call the usePress hook, or wrap your DOM node with <Pressable> component.'
|
|
44
44
|
);
|
|
45
|
+
isRegistered.current = true; // only warn once in strict mode.
|
|
45
46
|
}
|
|
46
47
|
}, []);
|
|
47
48
|
|
package/src/useHover.ts
CHANGED
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
// NOTICE file in the root directory of this source tree.
|
|
16
16
|
// See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions
|
|
17
17
|
|
|
18
|
-
import {DOMAttributes} from '@react-types/shared';
|
|
19
|
-
import {HoverEvents} from '@react-types/shared';
|
|
18
|
+
import {DOMAttributes, HoverEvents} from '@react-types/shared';
|
|
20
19
|
import {useEffect, useMemo, useRef, useState} from 'react';
|
|
21
20
|
|
|
22
21
|
export interface HoverProps extends HoverEvents {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions
|
|
17
17
|
|
|
18
18
|
import {RefObject, SyntheticEvent, useEffect, useRef} from 'react';
|
|
19
|
+
import {useEffectEvent} from '@react-aria/utils';
|
|
19
20
|
|
|
20
21
|
export interface InteractOutsideProps {
|
|
21
22
|
ref: RefObject<Element>,
|
|
@@ -33,33 +34,35 @@ export function useInteractOutside(props: InteractOutsideProps) {
|
|
|
33
34
|
let {ref, onInteractOutside, isDisabled, onInteractOutsideStart} = props;
|
|
34
35
|
let stateRef = useRef({
|
|
35
36
|
isPointerDown: false,
|
|
36
|
-
ignoreEmulatedMouseEvents: false
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
ignoreEmulatedMouseEvents: false
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
let onPointerDown = useEffectEvent((e: SyntheticEvent) => {
|
|
41
|
+
if (onInteractOutside && isValidEvent(e, ref)) {
|
|
42
|
+
if (onInteractOutsideStart) {
|
|
43
|
+
onInteractOutsideStart(e);
|
|
44
|
+
}
|
|
45
|
+
stateRef.current.isPointerDown = true;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
let triggerInteractOutside = useEffectEvent((e: SyntheticEvent) => {
|
|
50
|
+
if (onInteractOutside) {
|
|
51
|
+
onInteractOutside(e);
|
|
52
|
+
}
|
|
39
53
|
});
|
|
40
|
-
let state = stateRef.current;
|
|
41
|
-
state.onInteractOutside = onInteractOutside;
|
|
42
|
-
state.onInteractOutsideStart = onInteractOutsideStart;
|
|
43
54
|
|
|
44
55
|
useEffect(() => {
|
|
56
|
+
let state = stateRef.current;
|
|
45
57
|
if (isDisabled) {
|
|
46
58
|
return;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
|
-
let onPointerDown = (e) => {
|
|
50
|
-
if (isValidEvent(e, ref) && state.onInteractOutside) {
|
|
51
|
-
if (state.onInteractOutsideStart) {
|
|
52
|
-
state.onInteractOutsideStart(e);
|
|
53
|
-
}
|
|
54
|
-
state.isPointerDown = true;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
61
|
// Use pointer events if available. Otherwise, fall back to mouse and touch events.
|
|
59
62
|
if (typeof PointerEvent !== 'undefined') {
|
|
60
63
|
let onPointerUp = (e) => {
|
|
61
|
-
if (state.isPointerDown &&
|
|
62
|
-
|
|
64
|
+
if (state.isPointerDown && isValidEvent(e, ref)) {
|
|
65
|
+
triggerInteractOutside(e);
|
|
63
66
|
}
|
|
64
67
|
state.isPointerDown = false;
|
|
65
68
|
};
|
|
@@ -76,16 +79,16 @@ export function useInteractOutside(props: InteractOutsideProps) {
|
|
|
76
79
|
let onMouseUp = (e) => {
|
|
77
80
|
if (state.ignoreEmulatedMouseEvents) {
|
|
78
81
|
state.ignoreEmulatedMouseEvents = false;
|
|
79
|
-
} else if (state.isPointerDown &&
|
|
80
|
-
|
|
82
|
+
} else if (state.isPointerDown && isValidEvent(e, ref)) {
|
|
83
|
+
triggerInteractOutside(e);
|
|
81
84
|
}
|
|
82
85
|
state.isPointerDown = false;
|
|
83
86
|
};
|
|
84
87
|
|
|
85
88
|
let onTouchEnd = (e) => {
|
|
86
89
|
state.ignoreEmulatedMouseEvents = true;
|
|
87
|
-
if (state.
|
|
88
|
-
|
|
90
|
+
if (state.isPointerDown && isValidEvent(e, ref)) {
|
|
91
|
+
triggerInteractOutside(e);
|
|
89
92
|
}
|
|
90
93
|
state.isPointerDown = false;
|
|
91
94
|
};
|
|
@@ -102,7 +105,7 @@ export function useInteractOutside(props: InteractOutsideProps) {
|
|
|
102
105
|
document.removeEventListener('touchend', onTouchEnd, true);
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
|
-
}, [ref,
|
|
108
|
+
}, [ref, isDisabled, onPointerDown, triggerInteractOutside]);
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
function isValidEvent(event, ref) {
|
package/src/useMove.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import {disableTextSelection, restoreTextSelection} from './textSelection';
|
|
14
14
|
import {DOMAttributes, MoveEvents, PointerType} from '@react-types/shared';
|
|
15
15
|
import React, {useMemo, useRef} from 'react';
|
|
16
|
-
import {useGlobalListeners} from '@react-aria/utils';
|
|
16
|
+
import {useEffectEvent, useGlobalListeners} from '@react-aria/utils';
|
|
17
17
|
|
|
18
18
|
export interface MoveResult {
|
|
19
19
|
/** Props to spread on the target element. */
|
|
@@ -43,52 +43,54 @@ export function useMove(props: MoveEvents): MoveResult {
|
|
|
43
43
|
|
|
44
44
|
let {addGlobalListener, removeGlobalListener} = useGlobalListeners();
|
|
45
45
|
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
disableTextSelection();
|
|
51
|
-
state.current.didMove = false;
|
|
52
|
-
};
|
|
53
|
-
let move = (originalEvent: EventBase, pointerType: PointerType, deltaX: number, deltaY: number) => {
|
|
54
|
-
if (deltaX === 0 && deltaY === 0) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
46
|
+
let move = useEffectEvent((originalEvent: EventBase, pointerType: PointerType, deltaX: number, deltaY: number) => {
|
|
47
|
+
if (deltaX === 0 && deltaY === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
57
50
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pointerType,
|
|
63
|
-
shiftKey: originalEvent.shiftKey,
|
|
64
|
-
metaKey: originalEvent.metaKey,
|
|
65
|
-
ctrlKey: originalEvent.ctrlKey,
|
|
66
|
-
altKey: originalEvent.altKey
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
onMove({
|
|
70
|
-
type: 'move',
|
|
51
|
+
if (!state.current.didMove) {
|
|
52
|
+
state.current.didMove = true;
|
|
53
|
+
onMoveStart?.({
|
|
54
|
+
type: 'movestart',
|
|
71
55
|
pointerType,
|
|
72
|
-
deltaX: deltaX,
|
|
73
|
-
deltaY: deltaY,
|
|
74
56
|
shiftKey: originalEvent.shiftKey,
|
|
75
57
|
metaKey: originalEvent.metaKey,
|
|
76
58
|
ctrlKey: originalEvent.ctrlKey,
|
|
77
59
|
altKey: originalEvent.altKey
|
|
78
60
|
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
61
|
+
}
|
|
62
|
+
onMove({
|
|
63
|
+
type: 'move',
|
|
64
|
+
pointerType,
|
|
65
|
+
deltaX: deltaX,
|
|
66
|
+
deltaY: deltaY,
|
|
67
|
+
shiftKey: originalEvent.shiftKey,
|
|
68
|
+
metaKey: originalEvent.metaKey,
|
|
69
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
70
|
+
altKey: originalEvent.altKey
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
let end = useEffectEvent((originalEvent: EventBase, pointerType: PointerType) => {
|
|
75
|
+
restoreTextSelection();
|
|
76
|
+
if (state.current.didMove) {
|
|
77
|
+
onMoveEnd?.({
|
|
78
|
+
type: 'moveend',
|
|
79
|
+
pointerType,
|
|
80
|
+
shiftKey: originalEvent.shiftKey,
|
|
81
|
+
metaKey: originalEvent.metaKey,
|
|
82
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
83
|
+
altKey: originalEvent.altKey
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
let moveProps = useMemo(() => {
|
|
89
|
+
let moveProps: DOMAttributes = {};
|
|
90
|
+
|
|
91
|
+
let start = () => {
|
|
92
|
+
disableTextSelection();
|
|
93
|
+
state.current.didMove = false;
|
|
92
94
|
};
|
|
93
95
|
|
|
94
96
|
if (typeof PointerEvent === 'undefined') {
|
|
@@ -223,7 +225,7 @@ export function useMove(props: MoveEvents): MoveResult {
|
|
|
223
225
|
};
|
|
224
226
|
|
|
225
227
|
return moveProps;
|
|
226
|
-
}, [state,
|
|
228
|
+
}, [state, addGlobalListener, removeGlobalListener, move, end]);
|
|
227
229
|
|
|
228
230
|
return {moveProps};
|
|
229
231
|
}
|
package/src/usePress.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import {disableTextSelection, restoreTextSelection} from './textSelection';
|
|
19
19
|
import {DOMAttributes, FocusableElement, PointerType, PressEvents} from '@react-types/shared';
|
|
20
|
-
import {focusWithoutScrolling, isVirtualClick, isVirtualPointerEvent, mergeProps, useGlobalListeners, useSyncRef} from '@react-aria/utils';
|
|
20
|
+
import {focusWithoutScrolling, isVirtualClick, isVirtualPointerEvent, mergeProps, 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
|
|
|
@@ -105,8 +105,6 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
105
105
|
ref: _, // Removing `ref` from `domProps` because TypeScript is dumb
|
|
106
106
|
...domProps
|
|
107
107
|
} = usePressResponderContext(props);
|
|
108
|
-
let propsRef = useRef<PressHookProps>(null);
|
|
109
|
-
propsRef.current = {onPress, onPressChange, onPressStart, onPressEnd, onPressUp, isDisabled, shouldCancelOnPointerExit};
|
|
110
108
|
|
|
111
109
|
let [isPressed, setPressed] = useState(false);
|
|
112
110
|
let ref = useRef<PressState>({
|
|
@@ -122,109 +120,115 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
122
120
|
|
|
123
121
|
let {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();
|
|
124
122
|
|
|
125
|
-
let
|
|
123
|
+
let triggerPressStart = useEffectEvent((originalEvent: EventBase, pointerType: PointerType) => {
|
|
126
124
|
let state = ref.current;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
125
|
+
if (isDisabled || state.didFirePressStart) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
if (onPressStart) {
|
|
130
|
+
onPressStart({
|
|
131
|
+
type: 'pressstart',
|
|
132
|
+
pointerType,
|
|
133
|
+
target: originalEvent.currentTarget as Element,
|
|
134
|
+
shiftKey: originalEvent.shiftKey,
|
|
135
|
+
metaKey: originalEvent.metaKey,
|
|
136
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
137
|
+
altKey: originalEvent.altKey
|
|
138
|
+
});
|
|
139
|
+
}
|
|
144
140
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
if (onPressChange) {
|
|
142
|
+
onPressChange(true);
|
|
143
|
+
}
|
|
148
144
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
state.didFirePressStart = true;
|
|
146
|
+
setPressed(true);
|
|
147
|
+
});
|
|
152
148
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
let triggerPressEnd = useEffectEvent((originalEvent: EventBase, pointerType: PointerType, wasPressed = true) => {
|
|
150
|
+
let state = ref.current;
|
|
151
|
+
if (!state.didFirePressStart) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
158
154
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
155
|
+
state.ignoreClickAfterPress = true;
|
|
156
|
+
state.didFirePressStart = false;
|
|
157
|
+
|
|
158
|
+
if (onPressEnd) {
|
|
159
|
+
onPressEnd({
|
|
160
|
+
type: 'pressend',
|
|
161
|
+
pointerType,
|
|
162
|
+
target: originalEvent.currentTarget as Element,
|
|
163
|
+
shiftKey: originalEvent.shiftKey,
|
|
164
|
+
metaKey: originalEvent.metaKey,
|
|
165
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
166
|
+
altKey: originalEvent.altKey
|
|
167
|
+
});
|
|
168
|
+
}
|
|
173
169
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
if (onPressChange) {
|
|
171
|
+
onPressChange(false);
|
|
172
|
+
}
|
|
177
173
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
174
|
+
setPressed(false);
|
|
175
|
+
|
|
176
|
+
if (onPress && wasPressed && !isDisabled) {
|
|
177
|
+
onPress({
|
|
178
|
+
type: 'press',
|
|
179
|
+
pointerType,
|
|
180
|
+
target: originalEvent.currentTarget as Element,
|
|
181
|
+
shiftKey: originalEvent.shiftKey,
|
|
182
|
+
metaKey: originalEvent.metaKey,
|
|
183
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
184
|
+
altKey: originalEvent.altKey
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
192
188
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
189
|
+
let triggerPressUp = useEffectEvent((originalEvent: EventBase, pointerType: PointerType) => {
|
|
190
|
+
if (isDisabled) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
198
193
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
194
|
+
if (onPressUp) {
|
|
195
|
+
onPressUp({
|
|
196
|
+
type: 'pressup',
|
|
197
|
+
pointerType,
|
|
198
|
+
target: originalEvent.currentTarget as Element,
|
|
199
|
+
shiftKey: originalEvent.shiftKey,
|
|
200
|
+
metaKey: originalEvent.metaKey,
|
|
201
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
202
|
+
altKey: originalEvent.altKey
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
});
|
|
211
206
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
state.isPressed = false;
|
|
218
|
-
state.isOverTarget = false;
|
|
219
|
-
state.activePointerId = null;
|
|
220
|
-
state.pointerType = null;
|
|
221
|
-
removeAllGlobalListeners();
|
|
222
|
-
if (!allowTextSelectionOnPress) {
|
|
223
|
-
restoreTextSelection(state.target);
|
|
224
|
-
}
|
|
207
|
+
let cancel = useEffectEvent((e: EventBase) => {
|
|
208
|
+
let state = ref.current;
|
|
209
|
+
if (state.isPressed) {
|
|
210
|
+
if (state.isOverTarget) {
|
|
211
|
+
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
225
212
|
}
|
|
226
|
-
|
|
213
|
+
state.isPressed = false;
|
|
214
|
+
state.isOverTarget = false;
|
|
215
|
+
state.activePointerId = null;
|
|
216
|
+
state.pointerType = null;
|
|
217
|
+
removeAllGlobalListeners();
|
|
218
|
+
if (!allowTextSelectionOnPress) {
|
|
219
|
+
restoreTextSelection(state.target);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
227
223
|
|
|
224
|
+
let cancelOnPointerExit = useEffectEvent((e: EventBase) => {
|
|
225
|
+
if (shouldCancelOnPointerExit) {
|
|
226
|
+
cancel(e);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
let pressProps = useMemo(() => {
|
|
231
|
+
let state = ref.current;
|
|
228
232
|
let pressProps: DOMAttributes = {
|
|
229
233
|
onKeyDown(e) {
|
|
230
234
|
if (isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && e.currentTarget.contains(e.target as Element)) {
|
|
@@ -401,9 +405,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
401
405
|
} else if (state.isOverTarget) {
|
|
402
406
|
state.isOverTarget = false;
|
|
403
407
|
triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
|
|
404
|
-
|
|
405
|
-
cancel(e);
|
|
406
|
-
}
|
|
408
|
+
cancelOnPointerExit(e);
|
|
407
409
|
}
|
|
408
410
|
};
|
|
409
411
|
|
|
@@ -491,9 +493,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
491
493
|
if (state.isPressed && !state.ignoreEmulatedMouseEvents) {
|
|
492
494
|
state.isOverTarget = false;
|
|
493
495
|
triggerPressEnd(e, state.pointerType, false);
|
|
494
|
-
|
|
495
|
-
cancel(e);
|
|
496
|
-
}
|
|
496
|
+
cancelOnPointerExit(e);
|
|
497
497
|
}
|
|
498
498
|
};
|
|
499
499
|
|
|
@@ -581,9 +581,7 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
581
581
|
} else if (state.isOverTarget) {
|
|
582
582
|
state.isOverTarget = false;
|
|
583
583
|
triggerPressEnd(e, state.pointerType, false);
|
|
584
|
-
|
|
585
|
-
cancel(e);
|
|
586
|
-
}
|
|
584
|
+
cancelOnPointerExit(e);
|
|
587
585
|
}
|
|
588
586
|
};
|
|
589
587
|
|
|
@@ -648,7 +646,18 @@ export function usePress(props: PressHookProps): PressResult {
|
|
|
648
646
|
}
|
|
649
647
|
|
|
650
648
|
return pressProps;
|
|
651
|
-
}, [
|
|
649
|
+
}, [
|
|
650
|
+
addGlobalListener,
|
|
651
|
+
isDisabled,
|
|
652
|
+
preventFocusOnPress,
|
|
653
|
+
removeAllGlobalListeners,
|
|
654
|
+
allowTextSelectionOnPress,
|
|
655
|
+
cancel,
|
|
656
|
+
cancelOnPointerExit,
|
|
657
|
+
triggerPressEnd,
|
|
658
|
+
triggerPressStart,
|
|
659
|
+
triggerPressUp
|
|
660
|
+
]);
|
|
652
661
|
|
|
653
662
|
// Remove user-select: none in case component unmounts immediately after pressStart
|
|
654
663
|
// eslint-disable-next-line arrow-body-style
|
package/src/utils.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {FocusEvent as ReactFocusEvent, useCallback, useRef} from 'react';
|
|
14
|
-
import {useLayoutEffect} from '@react-aria/utils';
|
|
14
|
+
import {useEffectEvent, useLayoutEffect} from '@react-aria/utils';
|
|
15
15
|
|
|
16
16
|
export class SyntheticFocusEvent<Target = Element> implements ReactFocusEvent<Target> {
|
|
17
17
|
nativeEvent: FocusEvent;
|
|
@@ -64,10 +64,8 @@ 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
|
-
onBlur,
|
|
68
67
|
observer: null as MutationObserver
|
|
69
68
|
});
|
|
70
|
-
stateRef.current.onBlur = onBlur;
|
|
71
69
|
|
|
72
70
|
// Clean up MutationObserver on unmount. See below.
|
|
73
71
|
// eslint-disable-next-line arrow-body-style
|
|
@@ -81,6 +79,10 @@ export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEv
|
|
|
81
79
|
};
|
|
82
80
|
}, []);
|
|
83
81
|
|
|
82
|
+
let dispatchBlur = useEffectEvent((e: SyntheticFocusEvent<Target>) => {
|
|
83
|
+
onBlur?.(e);
|
|
84
|
+
});
|
|
85
|
+
|
|
84
86
|
// This function is called during a React onFocus event.
|
|
85
87
|
return useCallback((e: ReactFocusEvent<Target>) => {
|
|
86
88
|
// React does not fire onBlur when an element is disabled. https://github.com/facebook/react/issues/9142
|
|
@@ -101,7 +103,7 @@ export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEv
|
|
|
101
103
|
|
|
102
104
|
if (target.disabled) {
|
|
103
105
|
// For backward compatibility, dispatch a (fake) React synthetic event.
|
|
104
|
-
|
|
106
|
+
dispatchBlur(new SyntheticFocusEvent('blur', e));
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
// We no longer need the MutationObserver once the target is blurred.
|
|
@@ -116,12 +118,13 @@ export function useSyntheticBlurEvent<Target = Element>(onBlur: (e: ReactFocusEv
|
|
|
116
118
|
stateRef.current.observer = new MutationObserver(() => {
|
|
117
119
|
if (stateRef.current.isFocused && target.disabled) {
|
|
118
120
|
stateRef.current.observer.disconnect();
|
|
119
|
-
target.
|
|
120
|
-
target.dispatchEvent(new FocusEvent('
|
|
121
|
+
let relatedTargetEl = target === document.activeElement ? null : document.activeElement;
|
|
122
|
+
target.dispatchEvent(new FocusEvent('blur', {relatedTarget: relatedTargetEl}));
|
|
123
|
+
target.dispatchEvent(new FocusEvent('focusout', {bubbles: true, relatedTarget: relatedTargetEl}));
|
|
121
124
|
}
|
|
122
125
|
});
|
|
123
126
|
|
|
124
127
|
stateRef.current.observer.observe(target, {attributes: true, attributeFilter: ['disabled']});
|
|
125
128
|
}
|
|
126
|
-
}, []);
|
|
129
|
+
}, [dispatchBlur]);
|
|
127
130
|
}
|