Fix handling keyboard should persists taps#4158
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adjusts RNGH v3 components to better align with React Native’s ScrollView keyboardShouldPersistTaps="handled" behavior by ensuring tap-capable children can claim the JS responder in the bubble phase, preventing ScrollView’s release-time keyboard dismissal. It also adds a new common-app demo screen to validate the behavior differences across modes.
Changes:
- Add
onStartShouldSetRespondertov3Pressableto claim the JS responder during touch start. - Add
onStartShouldSetRespondertoNativeDetectorwhen the provided gesture is a single Tap gesture. - Add a new
keyboardShouldPersistTapstest screen inapps/common-appand register it in the examples list.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx | Claims JS responder for single Tap gestures to influence keyboardShouldPersistTaps behavior. |
| packages/react-native-gesture-handler/src/v3/components/Pressable.tsx | Claims JS responder on touch start to prevent ancestor ScrollView keyboard dismissal for handled/always modes. |
| packages/docs-gesture-handler/src/components/Hero/StartScreen/index.tsx | Import ordering cleanup. |
| apps/common-app/src/new_api/tests/keyboardShouldPersistTaps/index.tsx | Adds an interactive demo comparing RN vs RNGH behavior for keyboardShouldPersistTaps modes. |
| apps/common-app/src/new_api/index.tsx | Registers the new demo screen in the examples list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot one more round? |
Done — I made one more pass in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
j-piasecki
left a comment
There was a problem hiding this comment.
Do we need to integrate with the js responder here?
| onStartShouldSetResponder={ | ||
| isTapGesture ? handleStartShouldSetResponder : undefined | ||
| } |
| const handleStartShouldSetResponder = useCallback(() => { | ||
| return !isComposedGesture(gesture) && isGestureEnabled(gesture); | ||
| }, [gesture]); |
There was a problem hiding this comment.
This will not react to changes if a shared value is passed to the config. Also, I think reading the value of SVs on the JS thread will result in a warning.
| const isTapGesture = | ||
| !isComposedGesture(gesture) && gesture.type === SingleGestureName.Tap; |
There was a problem hiding this comment.
Why restrict it only to a tap gesture? And why skip composed gestures?
Even if we only allow tap, then tap + double tap should be fine.
Description
The
keyboardShouldPersistTaps="handled"on the ScrollView persists the keyboard if there is a target that could claim the JS responder event in the bubble phase (bottom-up). The diff addsonStartShouldSetRespondermethod that returnstrue(indicating that the target is willing to claim touch event) toGHPressableand to theNativeDetectorwhenever the single tap gesture is passed.For the
nevercase, the keyboard is always dropped by the touch event captured by the React Native ScrollView. This is done on the JS side, hence the touch is still handled by the Gesture Handler Pressable, which is opposite to the React Native Pressable for which the touch dismissing the keyboard is dropped.Test plan
keyboardShouldPersist-video.mov