Skip to content

Commit 317cc95

Browse files
authored
[Web] Allow GestureStateManager.activate from the first onTouchesDown (#4537)
## Summary `GestureStateManager.activate` called from the first `onTouchesDown` was a silent no-op on web. `onPointerDown` dispatches the touch event before `begin()`, so the handler is still `UNDETERMINED` when the callback runs, and `activate(true)` requires `BEGAN`. ## Test plan <details> <summary>Tested on the following code:</summary> ```tsx import React from 'react'; import { StyleSheet, View } from 'react-native'; import { GestureDetector, GestureStateManager, useManualGesture, } from 'react-native-gesture-handler'; // Android + iOS. `GestureStateManager.activate` from the first `onTouchesDown` // is a silent no-op: the native guard meant to block activation without // touches checks the handler's state (Android `state == BEGAN`, iOS // `_lastState != Undetermined`), and the first touch event reaches JS before // that state is recorded, although a pointer is already tracked. // // Steps: press the box. Expected console: down, activated, up, deactivated. // Bug: down, up, the gesture never activates. export default function EmptyExample() { const manual = useManualGesture({ onTouchesDown: (e) => { console.log('down, state', e.state); GestureStateManager.activate(e.handlerTag); }, onTouchesUp: (e) => { console.log('up, state', e.state); GestureStateManager.deactivate(e.handlerTag); }, onActivate: () => { console.log('activated'); }, onDeactivate: () => { console.log('deactivated'); }, }); return ( <View style={styles.container}> <GestureDetector gesture={manual}> <View style={styles.box} /> </GestureDetector> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, box: { width: 160, height: 160, borderRadius: 16, backgroundColor: '#21a37c', }, }); ``` </details>
1 parent 5be866a commit 317cc95

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

‎packages/react-native-gesture-handler/src/v3/gestureStateManager.web.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { State } from '../State';
12
import { tagMessage } from '../utils';
23
import type IGestureHandler from '../web/handlers/IGestureHandler';
3-
import GestureHandlerOrchestrator from '../web/tools/GestureHandlerOrchestrator';
44
import NodeManager from '../web/tools/NodeManager';
55
import type { GestureStateManagerType } from './types/GestureStateManagerTypes';
66

@@ -20,7 +20,17 @@ export const GestureStateManager: GestureStateManagerType = {
2020
const handler = NodeManager.getHandler(handlerTag);
2121
ensureHandlerAttached(handler);
2222

23-
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(handler);
23+
if (
24+
handler.state === State.UNDETERMINED &&
25+
handler.tracker.trackedPointersCount > 0
26+
) {
27+
handler.begin();
28+
}
29+
30+
if (handler.state !== State.BEGAN) {
31+
return;
32+
}
33+
2434
handler.activate(true);
2535
},
2636

0 commit comments

Comments
 (0)