Add cancelsJSResponder prop to the gesture handlers#4094
Add cancelsJSResponder prop to the gesture handlers#4094
cancelsJSResponder prop to the gesture handlers#4094Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new preventRecognizers configuration option to gesture handlers to control whether GH activation cancels React Native JS responders (with native iOS/Android plumbing + an example to demonstrate behavior).
Changes:
- Added
preventRecognizersto shared gesture config types/whitelists so it can flow from JS to native. - Implemented native behavior gates on iOS (root recognizer) and Android (orchestrator → root helper interception) with default
true. - Added docs + a new common-app example to showcase responder cancellation differences.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-gesture-handler/src/v3/types/ConfigTypes.ts | Adds preventRecognizers to common gesture config typing. |
| packages/react-native-gesture-handler/src/v3/hooks/utils/propsWhiteList.ts | Allows the new config prop to pass through native config filtering. |
| packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx | Minor formatting-only change near detector initialization. |
| packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts | Adds preventRecognizers to allowed prop list for detector plumbing. |
| packages/react-native-gesture-handler/apple/RNRootViewGestureRecognizer.m | iOS: only trigger RN responder cancellation when preventRecognizers is enabled. |
| packages/react-native-gesture-handler/apple/RNGestureHandler.mm | iOS: default + config parsing for preventRecognizers. |
| packages/react-native-gesture-handler/apple/RNGestureHandler.h | iOS: exposes preventRecognizers on the handler. |
| packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt | Android: intercept/cancel RN touch stream when requested by orchestrator. |
| packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt | Android: emits request/release callbacks based on handler activation + finish. |
| packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt | Android: stores/reads preventRecognizers from config with default true. |
| packages/docs-gesture-handler/docs/fundamentals/root-view.mdx | Doc formatting cleanup (indentation/trailing whitespace). |
| packages/docs-gesture-handler/docs/fundamentals/gesture-detector.mdx | Adds docs for preventRecognizers (but currently includes a broken tag and placement concerns). |
| apps/common-app/src/new_api/tests/rnResponderCancellation/index.tsx | New example screen demonstrating RN responder cancellation vs. concurrent handling. |
| apps/common-app/src/new_api/index.tsx | Registers the new example in the app’s examples list. |
Comments suppressed due to low confidence (1)
packages/docs-gesture-handler/docs/fundamentals/gesture-detector.mdx:206
- The closing tag for
HeaderWithBadgeswas changed to</BadHeaderWithBadgesges>, which is not a valid component/tag and will break MDX rendering/build. Replace it with the correct</HeaderWithBadges>closing tag.
<HeaderWithBadges platforms={['web']}>
### touchAction
</HeaderWithBadges>
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot review? |
Here's the review of the current state of the PR: Overall: The implementation is solid. All 3 previously flagged issues are resolved. Here's a brief summary per area: Android:
iOS:
TypeScript:
Docs: No issues found in the current state. |
preventRecognizers prop to the gesture handlerspreventRecognizers prop to the gesture handlers
j-piasecki
left a comment
There was a problem hiding this comment.
Can you update the title and description with the final prop name?
Also, I don't have an iOS device on hand, so can you check the following scenario?
There are two handlers and js recognizer on the same view. Gesture A with cancelsJSRecognizer: false, and a config that prevents it from activating (like minimumDistance: 100000 on pan). Gesture B has cancelsJSRecognizer: false and requires A to fail before it activates (useExclusiveGestures(A, B)), but should try to activate almost immediately (like pan with minimumDistance: 10). Now, in that scenario, does B trying to activate but getting blocked on A, cancel the JS recognizer, or not?
I've checked Android and there it works as expected (until A fails, the JS recognizer is not interrupted).
preventRecognizers prop to the gesture handlerscancelsJSResponder prop to the gesture handlers
This reverts commit fff3181.
…etector.tsx Co-authored-by: Jakub Piasecki <jakub.piasecki@swmansion.com>
m-bert
left a comment
There was a problem hiding this comment.
Seems like @j-piasecki caught everything
| contentContainerStyle={scrollStyles.content} | ||
| showsVerticalScrollIndicator> | ||
| <View style={scrollStyles.section}> | ||
| <SingleHandlerExample /> |
There was a problem hiding this comment.
What about extracting this (and Multi*) to separate files?
There was a problem hiding this comment.
Yeah I don't actually like this example so will change that a bit.
| <HeaderWithBadges platforms={['ios', 'android']}> | ||
| ### cancelsJSResponder | ||
| </HeaderWithBadges> |
There was a problem hiding this comment.
As far as I remember this is now Badges and HeaderWithBadges no longer exists (and if it does, it shouldn't)
| This option is configured per gesture handler (for example in `usePanGesture({ cancelsJSResponder: ... })`). | ||
|
|
||
| - `true` (default): when this gesture activates, it cancels React Native JS responders in the same root view. | ||
| - `false`: disables that cancellation, so Gesture Handler callbacks and RN responder callbacks can run at the same time. |
There was a problem hiding this comment.
I know this PR is not really about docs, but imo this one would be hard to read. If you quickly look at false to check what it does you see "disables that cancellation (...)" - I'd change it to be more specific.
Also we tend to be more descriptive, e.g.:
Setting this property to
trueensures that the Animated API functions correctly whenuseNativeDriveris set tofalse. The default value is set tofalse.
So maybe something like this would work?
Setting this property to true ensures that the gesture handler cancels any active React Native JS responders in the same root view upon activation. When set to false, both Gesture Handler and React Native responder callbacks can run simultaneously. The default value is set to true.
3a3d592 to
9f24c36
Compare
…ct-native-gesture-handler into prevent-recognizers
Description
Adds a per-gesture
cancelsJSResponder?: booleanprop on both platforms to the v3 handler hooks. It defaults totrueto preserve the behavior of cancelling RN JS responder system.On
Androidit moves the root-view dispatch offonCancelonto new orchestrator callbacksonCancelJSResponderRequestedandonCancelJSResponderReleased. The orchestrator only files the "released" callback when the last active handler withcancelsJSResponder: truefinishes.on
iOStheRNRootViewGestureRecognizerchecks the handler prop before notifying the delegate.Test plan
Added new test example with multiple handlers that might or might not cancel the JS responder.