react-native-gesture-handler 1.2.1 → 1.4.1
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/DrawerLayout.js +5 -4
- package/GestureButtons.js +166 -0
- package/GestureComponents.js +63 -0
- package/GestureComponents.web.js +35 -0
- package/GestureHandler.js +10 -621
- package/GestureHandlerButton.web.js +4 -12
- package/GestureHandlerPropTypes.js +45 -0
- package/Gestures.js +278 -0
- package/NativeViewGestureHandler.js +14 -0
- package/PlatformConstants.web.js +3 -1
- package/RNGestureHandler.podspec +1 -1
- package/RNGestureHandlerModule.web.js +49 -0
- package/State.js +12 -1
- package/Swipeable.js +6 -11
- package/android/build.gradle +3 -7
- package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.java +1 -1
- package/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEnabledRootView.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.java +2 -2
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerPackage.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRegistry.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootInterface.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.java +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.java +2 -2
- package/createHandler.js +46 -20
- package/createNativeWrapper.js +86 -0
- package/ios/RNGestureHandler.xcodeproj/project.pbxproj +4 -4
- package/package.json +20 -17
- package/react-native-gesture-handler.d.ts +25 -3
- package/touchables/GenericTouchable.js +3 -1
- package/touchables/TouchableHighlight.js +1 -3
- package/touchables/TouchableOpacity.web.js +2 -0
- package/touchables/TouchableWithoutFeedback.js +4 -2
- package/web/DiscreteGestureHandler.js +66 -0
- package/web/DraggingGestureHandler.js +22 -0
- package/web/Errors.js +5 -0
- package/web/FlingGestureHandler.js +137 -0
- package/web/GestureHandler.js +442 -0
- package/web/IndiscreteGestureHandler.js +33 -0
- package/web/LongPressGestureHandler.js +50 -0
- package/web/NativeViewGestureHandler.js +38 -0
- package/web/NodeManager.js +24 -0
- package/web/PanGestureHandler.js +213 -0
- package/web/PinchGestureHandler.js +24 -0
- package/web/PressGestureHandler.js +147 -0
- package/web/RotationGestureHandler.js +24 -0
- package/web/TapGestureHandler.js +160 -0
- package/web/constants.js +48 -0
- package/web/utils.js +14 -0
- package/Directions.web.js +0 -6
- package/Swipeable.web.js +0 -4
- package/createHandler.web.js +0 -205
@@ -0,0 +1,442 @@
|
|
1
|
+
import Hammer from 'hammerjs';
|
2
|
+
import { findNodeHandle } from 'react-native';
|
3
|
+
|
4
|
+
import State from '../State';
|
5
|
+
import { EventMap } from './constants';
|
6
|
+
import * as NodeManager from './NodeManager';
|
7
|
+
|
8
|
+
let _gestureInstances = 0;
|
9
|
+
|
10
|
+
class GestureHandler {
|
11
|
+
isGestureRunning = false;
|
12
|
+
hasGestureFailed = false;
|
13
|
+
view = null;
|
14
|
+
config = {};
|
15
|
+
hammer = null;
|
16
|
+
pendingGestures = {};
|
17
|
+
oldState = State.UNDETERMINED;
|
18
|
+
previousState = State.UNDETERMINED;
|
19
|
+
|
20
|
+
get id() {
|
21
|
+
return `${this.name}${this._gestureInstance}`;
|
22
|
+
}
|
23
|
+
|
24
|
+
get isDiscrete() {
|
25
|
+
return false;
|
26
|
+
}
|
27
|
+
|
28
|
+
get shouldEnableGestureOnSetup() {
|
29
|
+
throw new Error('Must override GestureHandler.shouldEnableGestureOnSetup');
|
30
|
+
}
|
31
|
+
|
32
|
+
constructor() {
|
33
|
+
this._gestureInstance = _gestureInstances++;
|
34
|
+
}
|
35
|
+
|
36
|
+
getConfig() {
|
37
|
+
return this.config;
|
38
|
+
}
|
39
|
+
|
40
|
+
onWaitingEnded(gesture) {}
|
41
|
+
|
42
|
+
removePendingGesture(id) {
|
43
|
+
delete this.pendingGestures[id];
|
44
|
+
}
|
45
|
+
|
46
|
+
addPendingGesture(gesture) {
|
47
|
+
this.pendingGestures[gesture.id] = gesture;
|
48
|
+
}
|
49
|
+
|
50
|
+
isGestureEnabledForEvent() {
|
51
|
+
return { success: true };
|
52
|
+
}
|
53
|
+
|
54
|
+
parseNativeEvent(nativeEvent) {
|
55
|
+
return nativeEvent;
|
56
|
+
}
|
57
|
+
|
58
|
+
get NativeGestureClass() {
|
59
|
+
throw new Error('Must override GestureHandler.NativeGestureClass');
|
60
|
+
}
|
61
|
+
|
62
|
+
updateHasCustomActivationCriteria(config) {
|
63
|
+
return true;
|
64
|
+
}
|
65
|
+
|
66
|
+
clearSelfAsPending = () => {
|
67
|
+
if (Array.isArray(this.config.waitFor)) {
|
68
|
+
for (const gesture of this.config.waitFor) {
|
69
|
+
gesture.removePendingGesture(this.id);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
};
|
73
|
+
|
74
|
+
updateGestureConfig({ enabled = true, ...props }) {
|
75
|
+
this.clearSelfAsPending();
|
76
|
+
|
77
|
+
this.config = ensureConfig({ enabled, ...props });
|
78
|
+
this._hasCustomActivationCriteria = this.updateHasCustomActivationCriteria(this.config);
|
79
|
+
if (Array.isArray(this.config.waitFor)) {
|
80
|
+
for (const gesture of this.config.waitFor) {
|
81
|
+
gesture.addPendingGesture(this);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
if (this.hammer) {
|
86
|
+
this.sync();
|
87
|
+
}
|
88
|
+
return this.config;
|
89
|
+
}
|
90
|
+
|
91
|
+
destroy = () => {
|
92
|
+
this.clearSelfAsPending();
|
93
|
+
|
94
|
+
if (this.hammer) {
|
95
|
+
this.hammer.stop();
|
96
|
+
this.hammer.destroy();
|
97
|
+
}
|
98
|
+
this.hammer = null;
|
99
|
+
};
|
100
|
+
|
101
|
+
isPointInView = ({ x, y }) => {
|
102
|
+
const rect = this.view.getBoundingClientRect();
|
103
|
+
const pointerInside = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
104
|
+
return pointerInside;
|
105
|
+
};
|
106
|
+
|
107
|
+
getState(type) {
|
108
|
+
return EventMap[type];
|
109
|
+
}
|
110
|
+
|
111
|
+
transformEventData(event) {
|
112
|
+
const { eventType, maxPointers: numberOfPointers } = event;
|
113
|
+
// const direction = DirectionMap[ev.direction];
|
114
|
+
const changedTouch = event.changedPointers[0];
|
115
|
+
const pointerInside = this.isPointInView({ x: changedTouch.clientX, y: changedTouch.clientY });
|
116
|
+
|
117
|
+
const state = this.getState(eventType);
|
118
|
+
if (state !== this.previousState) {
|
119
|
+
this.oldState = this.previousState;
|
120
|
+
this.previousState = state;
|
121
|
+
}
|
122
|
+
|
123
|
+
return {
|
124
|
+
nativeEvent: {
|
125
|
+
numberOfPointers,
|
126
|
+
state,
|
127
|
+
pointerInside,
|
128
|
+
...this.transformNativeEvent(event),
|
129
|
+
// onHandlerStateChange only
|
130
|
+
handlerTag: this.handlerTag,
|
131
|
+
target: this.ref,
|
132
|
+
oldState: this.oldState,
|
133
|
+
},
|
134
|
+
timeStamp: Date.now(),
|
135
|
+
};
|
136
|
+
}
|
137
|
+
|
138
|
+
transformNativeEvent(event) {
|
139
|
+
return {};
|
140
|
+
}
|
141
|
+
|
142
|
+
sendEvent = nativeEvent => {
|
143
|
+
const {
|
144
|
+
onGestureHandlerStateChange: onHandlerStateChange,
|
145
|
+
onGestureHandlerEvent: onGestureEvent,
|
146
|
+
} = this.ref.props;
|
147
|
+
|
148
|
+
const event = this.transformEventData(nativeEvent);
|
149
|
+
|
150
|
+
// Reset the state for the next gesture
|
151
|
+
if (nativeEvent.isFinal) {
|
152
|
+
this.oldState = State.UNDETERMINED;
|
153
|
+
this.previousState = State.UNDETERMINED;
|
154
|
+
}
|
155
|
+
|
156
|
+
invokeNullableMethod('onGestureEvent', onGestureEvent, event);
|
157
|
+
invokeNullableMethod('onHandlerStateChange', onHandlerStateChange, event);
|
158
|
+
};
|
159
|
+
|
160
|
+
cancelPendingGestures(event) {
|
161
|
+
for (const gesture of Object.values(this.pendingGestures)) {
|
162
|
+
if (gesture && gesture.isGestureRunning) {
|
163
|
+
gesture.hasGestureFailed = true;
|
164
|
+
gesture.cancelEvent(event);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
notifyPendingGestures() {
|
170
|
+
for (const gesture of Object.values(this.pendingGestures)) {
|
171
|
+
if (gesture) {
|
172
|
+
gesture.onWaitingEnded(this);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
onGestureEnded(event) {
|
178
|
+
this.isGestureRunning = false;
|
179
|
+
this.cancelPendingGestures(event);
|
180
|
+
}
|
181
|
+
|
182
|
+
forceInvalidate(event) {
|
183
|
+
if (this.isGestureRunning) {
|
184
|
+
this.hasGestureFailed = true;
|
185
|
+
this.cancelEvent(event);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
cancelEvent(event) {
|
190
|
+
this.notifyPendingGestures();
|
191
|
+
this.sendEvent({
|
192
|
+
...event,
|
193
|
+
eventType: Hammer.INPUT_CANCEL,
|
194
|
+
isFinal: true,
|
195
|
+
});
|
196
|
+
this.onGestureEnded(event);
|
197
|
+
}
|
198
|
+
|
199
|
+
onRawEvent({ isFirst }) {
|
200
|
+
if (isFirst) {
|
201
|
+
this.hasGestureFailed = false;
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
setView(ref) {
|
206
|
+
if (ref == null) {
|
207
|
+
this.destroy();
|
208
|
+
this.view = null;
|
209
|
+
return;
|
210
|
+
}
|
211
|
+
|
212
|
+
this.ref = ref;
|
213
|
+
|
214
|
+
this.view = findNodeHandle(ref);
|
215
|
+
this.hammer = new Hammer.Manager(this.view);
|
216
|
+
|
217
|
+
this.oldState = State.UNDETERMINED;
|
218
|
+
this.previousState = State.UNDETERMINED;
|
219
|
+
|
220
|
+
const { NativeGestureClass } = this;
|
221
|
+
const gesture = new NativeGestureClass(this.getHammerConfig());
|
222
|
+
this.hammer.add(gesture);
|
223
|
+
|
224
|
+
this.hammer.on('hammer.input', ev => {
|
225
|
+
if (!this.config.enabled) {
|
226
|
+
this.hasGestureFailed = false;
|
227
|
+
this.isGestureRunning = false;
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
|
231
|
+
this.onRawEvent(ev);
|
232
|
+
|
233
|
+
// TODO: Bacon: Check against something other than null
|
234
|
+
// The isFirst value is not called when the first rotation is calculated.
|
235
|
+
if (this.initialRotation === null && ev.rotation !== 0) {
|
236
|
+
this.initialRotation = ev.rotation;
|
237
|
+
}
|
238
|
+
if (ev.isFinal) {
|
239
|
+
// in favor of a willFail otherwise the last frame of the gesture will be captured.
|
240
|
+
setTimeout(() => {
|
241
|
+
this.initialRotation = null;
|
242
|
+
this.hasGestureFailed = false;
|
243
|
+
});
|
244
|
+
}
|
245
|
+
});
|
246
|
+
|
247
|
+
this.setupEvents();
|
248
|
+
this.sync();
|
249
|
+
}
|
250
|
+
|
251
|
+
setupEvents() {
|
252
|
+
if (!this.isDiscrete) {
|
253
|
+
this.hammer.on(`${this.name}start`, event => this.onStart(event));
|
254
|
+
this.hammer.on(`${this.name}end ${this.name}cancel`, event => this.onGestureEnded(event));
|
255
|
+
}
|
256
|
+
this.hammer.on(this.name, ev => this.onGestureActivated(ev));
|
257
|
+
}
|
258
|
+
|
259
|
+
onStart({ deltaX, deltaY, rotation }) {
|
260
|
+
this.isGestureRunning = true;
|
261
|
+
this.__initialX = deltaX;
|
262
|
+
this.__initialY = deltaY;
|
263
|
+
this.initialRotation = rotation;
|
264
|
+
}
|
265
|
+
|
266
|
+
onGestureActivated(ev) {
|
267
|
+
this.sendEvent(ev);
|
268
|
+
}
|
269
|
+
|
270
|
+
onSuccess() {}
|
271
|
+
|
272
|
+
_getPendingGestures() {
|
273
|
+
if (Array.isArray(this.config.waitFor) && this.config.waitFor.length) {
|
274
|
+
// Get the list of gestures that this gesture is still waiting for.
|
275
|
+
// Use `=== false` in case a ref that isn't a gesture handler is used.
|
276
|
+
const stillWaiting = this.config.waitFor.filter(
|
277
|
+
({ hasGestureFailed }) => hasGestureFailed === false
|
278
|
+
);
|
279
|
+
return stillWaiting;
|
280
|
+
}
|
281
|
+
return [];
|
282
|
+
}
|
283
|
+
|
284
|
+
getHammerConfig() {
|
285
|
+
const pointers =
|
286
|
+
this.config.minPointers === this.config.maxPointers ? this.config.minPointers : 0;
|
287
|
+
return {
|
288
|
+
pointers,
|
289
|
+
};
|
290
|
+
}
|
291
|
+
|
292
|
+
sync = () => {
|
293
|
+
const gesture = this.hammer.get(this.name);
|
294
|
+
if (!gesture) return;
|
295
|
+
|
296
|
+
const enable = (recognizer, inputData) => {
|
297
|
+
if (!this.config.enabled) {
|
298
|
+
this.isGestureRunning = false;
|
299
|
+
this.hasGestureFailed = false;
|
300
|
+
return false;
|
301
|
+
}
|
302
|
+
|
303
|
+
// Prevent events before the system is ready.
|
304
|
+
if (!inputData || !recognizer.options || typeof inputData.maxPointers === 'undefined') {
|
305
|
+
return this.shouldEnableGestureOnSetup;
|
306
|
+
}
|
307
|
+
|
308
|
+
if (this.hasGestureFailed) {
|
309
|
+
return false;
|
310
|
+
}
|
311
|
+
|
312
|
+
if (!this.isDiscrete) {
|
313
|
+
if (this.isGestureRunning) {
|
314
|
+
return true;
|
315
|
+
}
|
316
|
+
// The built-in hammer.js "waitFor" doesn't work across multiple views.
|
317
|
+
// Only process if there are views to wait for.
|
318
|
+
this._stillWaiting = this._getPendingGestures();
|
319
|
+
// This gesture should continue waiting.
|
320
|
+
if (this._stillWaiting.length) {
|
321
|
+
// Check to see if one of the gestures you're waiting for has started.
|
322
|
+
// If it has then the gesture should fail.
|
323
|
+
for (const gesture of this._stillWaiting) {
|
324
|
+
// When the target gesture has started, this gesture must force fail.
|
325
|
+
if (!gesture.isDiscrete && gesture.isGestureRunning) {
|
326
|
+
this.hasGestureFailed = true;
|
327
|
+
this.isGestureRunning = false;
|
328
|
+
return false;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
// This gesture shouldn't start until the others have finished.
|
332
|
+
return false;
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
// Use default behaviour
|
337
|
+
if (!this._hasCustomActivationCriteria) {
|
338
|
+
return true;
|
339
|
+
}
|
340
|
+
|
341
|
+
const deltaRotation =
|
342
|
+
this.initialRotation == null ? 0 : inputData.rotation - this.initialRotation;
|
343
|
+
const { success, failed } = this.isGestureEnabledForEvent(this.getConfig(), recognizer, {
|
344
|
+
...inputData,
|
345
|
+
deltaRotation,
|
346
|
+
});
|
347
|
+
|
348
|
+
if (failed) {
|
349
|
+
this.simulateCancelEvent(inputData);
|
350
|
+
this.hasGestureFailed = true;
|
351
|
+
}
|
352
|
+
return success;
|
353
|
+
};
|
354
|
+
|
355
|
+
const params = this.getHammerConfig();
|
356
|
+
gesture.set({ ...params, enable });
|
357
|
+
};
|
358
|
+
|
359
|
+
simulateCancelEvent(inputData) {}
|
360
|
+
}
|
361
|
+
|
362
|
+
// Used for sending data to a callback or AnimatedEvent
|
363
|
+
function invokeNullableMethod(name, method, event) {
|
364
|
+
if (method) {
|
365
|
+
if (typeof method === 'function') {
|
366
|
+
method(event);
|
367
|
+
} else {
|
368
|
+
// For use with reanimated's AnimatedEvent
|
369
|
+
if ('__getHandler' in method && typeof method.__getHandler === 'function') {
|
370
|
+
const handler = method.__getHandler();
|
371
|
+
invokeNullableMethod(name, handler, event);
|
372
|
+
} else {
|
373
|
+
if ('__nodeConfig' in method) {
|
374
|
+
const { argMapping } = method.__nodeConfig;
|
375
|
+
if (Array.isArray(argMapping)) {
|
376
|
+
for (const index in argMapping) {
|
377
|
+
const [key] = argMapping[index];
|
378
|
+
if (key in event.nativeEvent) {
|
379
|
+
method.__nodeConfig.argMapping[index] = [key, event.nativeEvent[key]];
|
380
|
+
}
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
}
|
386
|
+
}
|
387
|
+
}
|
388
|
+
|
389
|
+
// Validate the props
|
390
|
+
function ensureConfig(config) {
|
391
|
+
const props = { ...config };
|
392
|
+
|
393
|
+
if ('minDist' in config) {
|
394
|
+
props.minDist = config.minDist;
|
395
|
+
props.minDistSq = props.minDist * props.minDist;
|
396
|
+
}
|
397
|
+
if ('minVelocity' in config) {
|
398
|
+
props.minVelocity = config.minVelocity;
|
399
|
+
props.minVelocitySq = props.minVelocity * props.minVelocity;
|
400
|
+
}
|
401
|
+
if ('maxDist' in config) {
|
402
|
+
props.maxDist = config.maxDist;
|
403
|
+
props.maxDistSq = config.maxDist * config.maxDist;
|
404
|
+
}
|
405
|
+
if ('waitFor' in config) {
|
406
|
+
props.waitFor = asArray(config.waitFor)
|
407
|
+
.map(({ _handlerTag }) => NodeManager.getHandler(_handlerTag))
|
408
|
+
.filter(v => v);
|
409
|
+
} else {
|
410
|
+
props.waitFor = null;
|
411
|
+
}
|
412
|
+
|
413
|
+
[
|
414
|
+
'minPointers',
|
415
|
+
'maxPointers',
|
416
|
+
'minDist',
|
417
|
+
'maxDist',
|
418
|
+
'maxDistSq',
|
419
|
+
'minVelocitySq',
|
420
|
+
'minDistSq',
|
421
|
+
'minVelocity',
|
422
|
+
'failOffsetXStart',
|
423
|
+
'failOffsetYStart',
|
424
|
+
'failOffsetXEnd',
|
425
|
+
'failOffsetYEnd',
|
426
|
+
'activeOffsetXStart',
|
427
|
+
'activeOffsetXEnd',
|
428
|
+
'activeOffsetYStart',
|
429
|
+
'activeOffsetYEnd',
|
430
|
+
].forEach(prop => {
|
431
|
+
if (typeof props[prop] === 'undefined') {
|
432
|
+
props[prop] = Number.NaN;
|
433
|
+
}
|
434
|
+
});
|
435
|
+
return props;
|
436
|
+
}
|
437
|
+
|
438
|
+
function asArray(value) {
|
439
|
+
return value == null ? [] : Array.isArray(value) ? value : [value];
|
440
|
+
}
|
441
|
+
|
442
|
+
export default GestureHandler;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import GestureHandler from './GestureHandler';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* The base class for **Rotation** and **Pinch** gesture handlers.
|
5
|
+
*/
|
6
|
+
class IndiscreteGestureHandler extends GestureHandler {
|
7
|
+
get shouldEnableGestureOnSetup() {
|
8
|
+
return false;
|
9
|
+
}
|
10
|
+
|
11
|
+
updateGestureConfig({ minPointers = 2, maxPointers = 2, ...props }) {
|
12
|
+
return super.updateGestureConfig({
|
13
|
+
minPointers,
|
14
|
+
maxPointers,
|
15
|
+
...props,
|
16
|
+
});
|
17
|
+
}
|
18
|
+
|
19
|
+
isGestureEnabledForEvent(
|
20
|
+
{ minPointers, maxPointers },
|
21
|
+
recognizer,
|
22
|
+
{ maxPointers: pointerLength }
|
23
|
+
) {
|
24
|
+
if (pointerLength > maxPointers) {
|
25
|
+
return { failed: true };
|
26
|
+
}
|
27
|
+
const validPointerCount = pointerLength >= minPointers;
|
28
|
+
return {
|
29
|
+
success: validPointerCount,
|
30
|
+
};
|
31
|
+
}
|
32
|
+
}
|
33
|
+
export default IndiscreteGestureHandler;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import Hammer from 'hammerjs';
|
2
|
+
|
3
|
+
import State from '../State';
|
4
|
+
import PressGestureHandler from './PressGestureHandler';
|
5
|
+
import { isnan } from './utils';
|
6
|
+
|
7
|
+
class LongPressGestureHandler extends PressGestureHandler {
|
8
|
+
get minDurationMs() {
|
9
|
+
return isnan(this.config.minDurationMs) ? 251 : this.config.minDurationMs;
|
10
|
+
}
|
11
|
+
|
12
|
+
get maxDist() {
|
13
|
+
return isnan(this.config.maxDist) ? 9 : this.config.maxDist;
|
14
|
+
}
|
15
|
+
|
16
|
+
updateHasCustomActivationCriteria({ maxDistSq }) {
|
17
|
+
return !isnan(maxDistSq);
|
18
|
+
}
|
19
|
+
|
20
|
+
getConfig() {
|
21
|
+
if (!this._hasCustomActivationCriteria) {
|
22
|
+
// Default config
|
23
|
+
// If no params have been defined then this config should emulate the native gesture as closely as possible.
|
24
|
+
return {
|
25
|
+
shouldCancelWhenOutside: true,
|
26
|
+
maxDistSq: 10,
|
27
|
+
};
|
28
|
+
}
|
29
|
+
return this.config;
|
30
|
+
}
|
31
|
+
|
32
|
+
getHammerConfig() {
|
33
|
+
return {
|
34
|
+
...super.getHammerConfig(),
|
35
|
+
// threshold: this.maxDist,
|
36
|
+
time: this.minDurationMs,
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
getState(type) {
|
41
|
+
return {
|
42
|
+
[Hammer.INPUT_START]: State.ACTIVE,
|
43
|
+
[Hammer.INPUT_MOVE]: State.ACTIVE,
|
44
|
+
[Hammer.INPUT_END]: State.END,
|
45
|
+
[Hammer.INPUT_CANCEL]: State.FAILED,
|
46
|
+
}[type];
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
export default LongPressGestureHandler;
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import DiscreteGestureHandler from './DiscreteGestureHandler';
|
2
|
+
import * as NodeManager from './NodeManager';
|
3
|
+
import PressGestureHandler from './PressGestureHandler';
|
4
|
+
import { TEST_MIN_IF_NOT_NAN, VEC_LEN_SQ } from './utils';
|
5
|
+
|
6
|
+
class NativeViewGestureHandler extends PressGestureHandler {
|
7
|
+
onRawEvent(ev) {
|
8
|
+
super.onRawEvent(ev);
|
9
|
+
if (!ev.isFinal) {
|
10
|
+
// if (this.ref instanceof ScrollView) {
|
11
|
+
if (TEST_MIN_IF_NOT_NAN(VEC_LEN_SQ({ x: ev.deltaX, y: ev.deltaY }), 10)) {
|
12
|
+
if (this.config.disallowInterruption) {
|
13
|
+
const gestures = Object.values(NodeManager.getNodes()).filter(gesture => {
|
14
|
+
const { handlerTag, view, isGestureRunning } = gesture;
|
15
|
+
return (
|
16
|
+
// Check if this gesture isn't self
|
17
|
+
handlerTag !== this.handlerTag &&
|
18
|
+
// Ensure the gesture needs to be cancelled
|
19
|
+
isGestureRunning &&
|
20
|
+
// ScrollView can cancel discrete gestures like taps and presses
|
21
|
+
gesture instanceof DiscreteGestureHandler &&
|
22
|
+
// Ensure a view exists and is a child of the current view
|
23
|
+
view &&
|
24
|
+
this.view.contains(view)
|
25
|
+
);
|
26
|
+
});
|
27
|
+
// Cancel all of the gestures that passed the filter
|
28
|
+
for (const gesture of gestures) {
|
29
|
+
// TODO: Bacon: Send some cached event.
|
30
|
+
gesture.forceInvalidate(ev);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
export default NativeViewGestureHandler;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
let gestures = {};
|
2
|
+
|
3
|
+
export function getHandler(tag) {
|
4
|
+
if (tag in gestures) return gestures[tag];
|
5
|
+
|
6
|
+
throw new Error('No handler for tag ' + tag);
|
7
|
+
}
|
8
|
+
|
9
|
+
export function createGestureHandler(handlerTag, handler) {
|
10
|
+
if (handlerTag in gestures) {
|
11
|
+
throw new Error('Handler with tag ' + handlerTag + ' already exists');
|
12
|
+
}
|
13
|
+
gestures[handlerTag] = handler;
|
14
|
+
gestures[handlerTag].handlerTag = handlerTag;
|
15
|
+
}
|
16
|
+
|
17
|
+
export function dropGestureHandler(handlerTag) {
|
18
|
+
getHandler(handlerTag).destroy();
|
19
|
+
delete gestures[handlerTag];
|
20
|
+
}
|
21
|
+
|
22
|
+
export function getNodes() {
|
23
|
+
return { ...gestures };
|
24
|
+
}
|