10
10
import type { EventResponderContext } from 'events/EventTypes' ;
11
11
import { REACT_EVENT_COMPONENT_TYPE } from 'shared/ReactSymbols' ;
12
12
13
+ // const DEFAULT_PRESS_DELAY_MS = 0;
14
+ // const DEFAULT_PRESS_END_DELAY_MS = 0;
15
+ // const DEFAULT_PRESS_START_DELAY_MS = 0;
16
+ const DEFAULT_LONG_PRESS_DELAY_MS = 1000 ;
17
+
13
18
const targetEventTypes = [
14
19
{ name : 'click' , passive : false } ,
15
20
{ name : 'keydown' , passive : false } ,
@@ -26,6 +31,21 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
26
31
rootEventTypes . push ( { name : 'mouseup' , passive : false } ) ;
27
32
}
28
33
34
+ type PressProps = {
35
+ disabled : boolean ,
36
+ delayLongPress : number ,
37
+ delayPressEnd : number ,
38
+ delayPressStart : number ,
39
+ onLongPress : ( e : Object ) => void ,
40
+ onLongPressChange : boolean => void ,
41
+ onLongPressShouldCancelPress : ( ) => boolean ,
42
+ onPress : ( e : Object ) => void ,
43
+ onPressChange : boolean => void ,
44
+ onPressEnd : ( e : Object ) => void ,
45
+ onPressStart : ( e : Object ) => void ,
46
+ pressRententionOffset : Object ,
47
+ } ;
48
+
29
49
type PressState = {
30
50
defaultPrevented : boolean ,
31
51
isAnchorTouched : boolean ,
@@ -47,7 +67,7 @@ function dispatchPressEvent(
47
67
48
68
function dispatchPressStartEvents (
49
69
context : EventResponderContext ,
50
- props : Object ,
70
+ props : PressProps ,
51
71
state : PressState ,
52
72
) : void {
53
73
function dispatchPressChangeEvent ( bool ) {
@@ -64,7 +84,11 @@ function dispatchPressStartEvents(
64
84
dispatchPressChangeEvent ( true ) ;
65
85
}
66
86
if ( ( props . onLongPress || props . onLongPressChange ) && ! state . isLongPressed ) {
67
- const delayLongPress = calculateDelayMS ( props . delayLongPress , 0 , 1000 ) ;
87
+ const delayLongPress = calculateDelayMS (
88
+ props . delayLongPress ,
89
+ 0 ,
90
+ DEFAULT_LONG_PRESS_DELAY_MS ,
91
+ ) ;
68
92
69
93
state . longPressTimeout = setTimeout ( ( ) => {
70
94
state . isLongPressed = true ;
@@ -105,7 +129,7 @@ function dispatchPressStartEvents(
105
129
106
130
function dispatchPressEndEvents (
107
131
context : EventResponderContext ,
108
- props : Object ,
132
+ props : PressProps ,
109
133
state : PressState ,
110
134
) : void {
111
135
if ( state . longPressTimeout !== null ) {
@@ -138,6 +162,11 @@ function isAnchorTagElement(eventTarget: EventTarget): boolean {
138
162
return ( eventTarget : any ) . nodeName === 'A' ;
139
163
}
140
164
165
+ function isValidKeyPress ( key : string ) : boolean {
166
+ // Accessibility for keyboards. Space and Enter only.
167
+ return key === ' ' || key === 'Enter' ;
168
+ }
169
+
141
170
function calculateDelayMS ( delay : ?number , min = 0 , fallback = 0 ) {
142
171
const maybeNumber = delay == null ? null : delay ;
143
172
return Math . max ( min , maybeNumber != null ? maybeNumber : fallback ) ;
@@ -158,22 +187,18 @@ const PressResponder = {
158
187
} ,
159
188
handleEvent (
160
189
context : EventResponderContext ,
161
- props : Object ,
190
+ props : PressProps ,
162
191
state : PressState ,
163
192
) : void {
164
193
const { eventTarget , eventType , event } = context ;
165
194
166
195
switch ( eventType ) {
167
196
case 'keydown ': {
168
- if ( ! props . onPress || context . isTargetOwned ( eventTarget ) ) {
169
- return ;
170
- }
171
- const isValidKeyPress =
172
- ( event : any ) . which === 13 ||
173
- ( event : any ) . which === 32 ||
174
- ( event : any ) . keyCode === 13 ;
175
-
176
- if ( ! isValidKeyPress ) {
197
+ if (
198
+ ! props . onPress ||
199
+ context . isTargetOwned ( eventTarget ) ||
200
+ ! isValidKeyPress ( ( event : any ) . key )
201
+ ) {
177
202
return ;
178
203
}
179
204
let keyPressEventListener = props . onPress ;
@@ -196,8 +221,12 @@ const PressResponder = {
196
221
dispatchPressEvent ( context , state , 'press' , keyPressEventListener ) ;
197
222
break ;
198
223
}
224
+
225
+ /**
226
+ * Touch event implementations are only needed for Safari, which lacks
227
+ * support for pointer events.
228
+ */
199
229
case 'touchstart' :
200
- // Touch events are for Safari, which lack pointer event support.
201
230
if ( ! state . isPressed && ! context . isTargetOwned ( eventTarget ) ) {
202
231
// We bail out of polyfilling anchor tags, given the same heuristics
203
232
// explained above in regards to needing to use click events.
@@ -213,7 +242,6 @@ const PressResponder = {
213
242
214
243
break ;
215
244
case 'touchend' : {
216
- // Touch events are for Safari, which lack pointer event support
217
245
if ( state . isAnchorTouched ) {
218
246
return ;
219
247
}
@@ -253,14 +281,21 @@ const PressResponder = {
253
281
}
254
282
break ;
255
283
}
284
+
285
+ /**
286
+ * Respond to pointer events and fall back to mouse.
287
+ */
256
288
case 'pointerdown' :
257
289
case 'mousedown ': {
258
290
if (
259
291
! state . isPressed &&
260
292
! context . isTargetOwned ( eventTarget ) &&
261
293
! state . shouldSkipMouseAfterTouch
262
294
) {
263
- if ( ( event : any ) . pointerType === 'mouse' ) {
295
+ if (
296
+ ( event : any ) . pointerType === 'mouse' ||
297
+ eventType === 'mousedown'
298
+ ) {
264
299
// Ignore if we are pressing on hit slop area with mouse
265
300
if (
266
301
context . isPositionWithinTouchHitTarget (
@@ -282,8 +317,8 @@ const PressResponder = {
282
317
}
283
318
break ;
284
319
}
285
- case 'mouseup ' :
286
- case 'pointerup ': {
320
+ case 'pointerup ' :
321
+ case 'mouseup ': {
287
322
if ( state . isPressed ) {
288
323
if ( state . shouldSkipMouseAfterTouch ) {
289
324
state . shouldSkipMouseAfterTouch = false ;
@@ -320,6 +355,7 @@ const PressResponder = {
320
355
state . isAnchorTouched = false ;
321
356
break ;
322
357
}
358
+
323
359
case 'scroll' :
324
360
case 'touchcancel ':
325
361
case 'contextmenu ':
0 commit comments