@@ -27,11 +27,15 @@ type PressProps = {
27
27
28
28
type PressState = {
29
29
defaultPrevented : boolean ,
30
+ isActivePressed : boolean ,
31
+ isActivePressStart : boolean ,
30
32
isAnchorTouched : boolean ,
31
33
isLongPressed : boolean ,
32
34
isPressed : boolean ,
33
35
longPressTimeout : null | TimeoutID ,
34
36
pressTarget : null | Element | Document ,
37
+ pressEndTimeout : null | TimeoutID ,
38
+ pressStartTimeout : null | TimeoutID ,
35
39
shouldSkipMouseAfterTouch : boolean ,
36
40
} ;
37
41
@@ -49,9 +53,8 @@ type PressEvent = {|
49
53
type : PressEventType ,
50
54
| } ;
51
55
52
- // const DEFAULT_PRESS_DELAY_MS = 0;
53
- // const DEFAULT_PRESS_END_DELAY_MS = 0;
54
- // const DEFAULT_PRESS_START_DELAY_MS = 0;
56
+ const DEFAULT_PRESS_END_DELAY_MS = 0 ;
57
+ const DEFAULT_PRESS_START_DELAY_MS = 0 ;
55
58
const DEFAULT_LONG_PRESS_DELAY_MS = 500 ;
56
59
57
60
const targetEventTypes = [
@@ -102,7 +105,7 @@ function dispatchPressChangeEvent(
102
105
state : PressState ,
103
106
) : void {
104
107
const listener = ( ) => {
105
- props . onPressChange ( state . isPressed ) ;
108
+ props . onPressChange ( state . isActivePressed ) ;
106
109
} ;
107
110
dispatchEvent ( context , state , 'presschange' , listener ) ;
108
111
}
@@ -118,45 +121,93 @@ function dispatchLongPressChangeEvent(
118
121
dispatchEvent ( context , state , 'longpresschange' , listener ) ;
119
122
}
120
123
124
+ function activate ( context , props , state ) {
125
+ const wasActivePressed = state . isActivePressed ;
126
+ state . isActivePressed = true ;
127
+
128
+ if ( props . onPressStart ) {
129
+ dispatchEvent ( context , state , 'pressstart' , props . onPressStart ) ;
130
+ }
131
+ if ( ! wasActivePressed && props . onPressChange ) {
132
+ dispatchPressChangeEvent ( context , props , state ) ;
133
+ }
134
+ }
135
+
136
+ function deactivate ( context , props , state ) {
137
+ const wasLongPressed = state . isLongPressed ;
138
+ state . isActivePressed = false ;
139
+ state . isLongPressed = false ;
140
+
141
+ if ( props . onPressEnd ) {
142
+ dispatchEvent ( context , state , 'pressend' , props . onPressEnd ) ;
143
+ }
144
+ if ( props . onPressChange ) {
145
+ dispatchPressChangeEvent ( context , props , state ) ;
146
+ }
147
+ if ( wasLongPressed && props . onLongPressChange ) {
148
+ dispatchLongPressChangeEvent ( context , props , state ) ;
149
+ }
150
+ }
151
+
121
152
function dispatchPressStartEvents (
122
153
context : ResponderContext ,
123
154
props : PressProps ,
124
155
state : PressState ,
125
156
) : void {
126
157
state . isPressed = true ;
127
158
128
- if ( props . onPressStart ) {
129
- dispatchEvent ( context , state , 'pressstart' , props . onPressStart ) ;
159
+ if ( state . pressEndTimeout !== null ) {
160
+ clearTimeout ( state . pressEndTimeout ) ;
161
+ state . pressEndTimeout = null ;
130
162
}
131
- if ( props . onPressChange ) {
132
- dispatchPressChangeEvent ( context , props , state ) ;
133
- }
134
- if ( ( props . onLongPress || props . onLongPressChange ) && ! state . isLongPressed ) {
135
- const delayLongPress = calculateDelayMS (
136
- props . delayLongPress ,
137
- 10 ,
138
- DEFAULT_LONG_PRESS_DELAY_MS ,
139
- ) ;
140
163
141
- state . longPressTimeout = context . setTimeout ( ( ) => {
142
- state . isLongPressed = true ;
143
- state . longPressTimeout = null ;
144
-
145
- if ( props . onLongPress ) {
146
- const listener = e => {
147
- props . onLongPress ( e ) ;
148
- // TODO address this again at some point
149
- // if (e.nativeEvent.defaultPrevented) {
150
- // state.defaultPrevented = true;
151
- // }
152
- } ;
153
- dispatchEvent ( context , state , 'longpress' , listener ) ;
154
- }
164
+ const dispatch = ( ) => {
165
+ state . isActivePressStart = true ;
166
+ activate ( context , props , state ) ;
167
+
168
+ if (
169
+ ( props . onLongPress || props . onLongPressChange ) &&
170
+ ! state . isLongPressed
171
+ ) {
172
+ const delayLongPress = calculateDelayMS (
173
+ props . delayLongPress ,
174
+ 10 ,
175
+ DEFAULT_LONG_PRESS_DELAY_MS ,
176
+ ) ;
177
+ state . longPressTimeout = context . setTimeout ( ( ) => {
178
+ state . isLongPressed = true ;
179
+ state . longPressTimeout = null ;
180
+ if ( props . onLongPress ) {
181
+ const listener = e => {
182
+ props . onLongPress ( e ) ;
183
+ // TODO address this again at some point
184
+ // if (e.nativeEvent.defaultPrevented) {
185
+ // state.defaultPrevented = true;
186
+ // }
187
+ } ;
188
+ dispatchEvent ( context , state , 'longpress' , listener ) ;
189
+ }
190
+ if ( props . onLongPressChange ) {
191
+ dispatchLongPressChangeEvent ( context , props , state ) ;
192
+ }
193
+ } , delayLongPress ) ;
194
+ }
195
+ } ;
155
196
156
- if ( props . onLongPressChange ) {
157
- dispatchLongPressChangeEvent ( context , props , state ) ;
158
- }
159
- } , delayLongPress ) ;
197
+ if ( ! state . isActivePressStart ) {
198
+ const delayPressStart = calculateDelayMS (
199
+ props . delayPressStart ,
200
+ 0 ,
201
+ DEFAULT_PRESS_START_DELAY_MS ,
202
+ ) ;
203
+ if ( delayPressStart > 0 ) {
204
+ state . pressStartTimeout = context . setTimeout ( ( ) => {
205
+ state . pressStartTimeout = null ;
206
+ dispatch ( ) ;
207
+ } , delayPressStart ) ;
208
+ } else {
209
+ dispatch ( ) ;
210
+ }
160
211
}
161
212
}
162
213
@@ -165,25 +216,36 @@ function dispatchPressEndEvents(
165
216
props : PressProps ,
166
217
state : PressState ,
167
218
) : void {
219
+ const wasActivePressStart = state . isActivePressStart ;
220
+
221
+ state . isActivePressStart = false ;
222
+ state . isPressed = false ;
223
+
168
224
if ( state . longPressTimeout !== null ) {
169
225
clearTimeout ( state . longPressTimeout ) ;
170
226
state . longPressTimeout = null ;
171
227
}
172
- if ( props . onPressEnd ) {
173
- dispatchEvent ( context , state , 'pressend' , props . onPressEnd ) ;
174
- }
175
228
176
- if ( state . isPressed ) {
177
- state . isPressed = false ;
178
- if ( props . onPressChange ) {
179
- dispatchPressChangeEvent ( context , props , state ) ;
180
- }
229
+ if ( ! wasActivePressStart && state . pressStartTimeout !== null ) {
230
+ clearTimeout ( state . pressStartTimeout ) ;
231
+ state . pressStartTimeout = null ;
232
+ // if we haven't yet activated (due to delays), activate now
233
+ activate ( context , props , state ) ;
181
234
}
182
235
183
- if ( state . isLongPressed ) {
184
- state . isLongPressed = false ;
185
- if ( props . onLongPressChange ) {
186
- dispatchLongPressChangeEvent ( context , props , state ) ;
236
+ if ( state . isActivePressed ) {
237
+ const delayPressEnd = calculateDelayMS (
238
+ props . delayPressEnd ,
239
+ 0 ,
240
+ DEFAULT_PRESS_END_DELAY_MS ,
241
+ ) ;
242
+ if ( delayPressEnd > 0 ) {
243
+ state . pressEndTimeout = context . setTimeout ( ( ) => {
244
+ state . pressEndTimeout = null ;
245
+ deactivate ( context , props , state ) ;
246
+ } , delayPressEnd ) ;
247
+ } else {
248
+ deactivate ( context , props , state ) ;
187
249
}
188
250
}
189
251
}
@@ -208,12 +270,8 @@ function unmountResponder(
208
270
state : PressState ,
209
271
) : void {
210
272
if ( state . isPressed ) {
211
- state . isPressed = false ;
212
273
dispatchPressEndEvents ( context , props , state ) ;
213
- if ( state . longPressTimeout !== null ) {
214
- clearTimeout ( state . longPressTimeout ) ;
215
- state . longPressTimeout = null ;
216
- }
274
+ context . removeRootEventTypes ( rootEventTypes ) ;
217
275
}
218
276
}
219
277
@@ -222,10 +280,14 @@ const PressResponder = {
222
280
createInitialState ( ) : PressState {
223
281
return {
224
282
defaultPrevented : false ,
283
+ isActivePressed : false ,
284
+ isActivePressStart : false ,
225
285
isAnchorTouched : false ,
226
286
isLongPressed : false ,
227
287
isPressed : false ,
228
288
longPressTimeout : null ,
289
+ pressEndTimeout : null ,
290
+ pressStartTimeout : null ,
229
291
pressTarget : null ,
230
292
shouldSkipMouseAfterTouch : false ,
231
293
} ;
0 commit comments