Commit 33c4f28
authored
Fix dead presses in
## Description
With a Gesture Handler `ScrollView` in the default (`never`)
`keyboardShouldPersistTaps` mode, a keyboard opened by a native field
(e.g. a native-stack `headerSearchBarOptions` search bar) made every
RNGH `Pressable`/`Touchable` inside dead, with no way to dismiss the
keyboard by tapping. The keyboard-dismissing tap drop (#992) checks only
keyboard visibility, but the dismissal blurs
`TextInput.State.currentlyFocusedInput()`, which is `null` for native
fields - the tap was consumed while nothing could be dismissed.
Now the tap is dropped only when an RN `TextInput` is focused, mirroring
RN ScrollView's `_keyboardIsDismissible`. Focus is snapshotted when the
keyboard shows, since the dismissal blurs the input at touch-down,
before the press events are checked; a live check is OR-ed in for focus
moving to an RN input while the keyboard is already up. With a
native-field keyboard, presses now behave like RN's `Pressable`: they
fire and the keyboard stays.
## Test plan
- `yarn test` — added cases: no drop when the keyboard is up without a
focused RN input; the drop verdict survives the input being blurred
mid-tap; existing `never`-drop tests updated to mock a focused input.
- iOS simulator and Android emulator, repro below with RNGH and RN
`Pressable` side by side:
- search bar active: both fire, keyboard stays (previously the RNGH one
was dead)
- RN `TextInput` focused: both are dropped and the tap dismisses the
keyboard (#992 behavior unchanged)
<details>
<summary>Repro</summary>
```tsx
import React, { useState } from 'react';
import { Pressable as RNPressable, StyleSheet, Text, TextInput, View } from 'react-native';
import { NavigationContainer, NavigationIndependentTree } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Pressable, ScrollView } from 'react-native-gesture-handler';
const ROUTES = ['12', '17', '25', '42', '58', '73', '81', '99'];
function RoutesScreen() {
const [pressCount, setPressCount] = useState(0);
const [lastPressed, setLastPressed] = useState<string | null>(null);
const press = (label: string) => () => {
setPressCount((c) => c + 1);
setLastPressed(label);
};
return (
<ScrollView contentInsetAdjustmentBehavior="automatic">
<TextInput placeholder="RN TextInput (control)" style={styles.input} />
<Text style={styles.status}>
{`onPress count: ${pressCount}` + (lastPressed ? ` (last: ${lastPressed})` : '')}
</Text>
{ROUTES.map((route) => (
<View key={route} style={styles.routeRow}>
<Pressable style={styles.row} onPress={press(`GH ${route}`)}>
<Text>{`GH ${route}`}</Text>
</Pressable>
<RNPressable style={styles.row} onPress={press(`RN ${route}`)}>
<Text>{`RN ${route}`}</Text>
</RNPressable>
</View>
))}
</ScrollView>
);
}
const Stack = createNativeStackNavigator();
export default function Example() {
return (
<NavigationIndependentTree>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Routes"
component={RoutesScreen}
options={{
headerSearchBarOptions: { placeholder: 'Search routes', hideWhenScrolling: false },
}}
/>
</Stack.Navigator>
</NavigationContainer>
</NavigationIndependentTree>
);
}
const styles = StyleSheet.create({
status: { fontSize: 16, fontWeight: 'bold', padding: 16 },
input: { borderColor: '#ccd', borderRadius: 8, borderWidth: 1, margin: 16, padding: 12 },
routeRow: { flexDirection: 'row', gap: 8, marginHorizontal: 16, marginVertical: 4 },
row: { backgroundColor: '#eef', borderRadius: 8, flex: 1, padding: 16 },
});
```
</details>"never" mode when the keyboard belongs to a native field (#4439)1 parent d29545a commit 33c4f28
2 files changed
Lines changed: 64 additions & 2 deletions
Lines changed: 47 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
454 | 454 | | |
455 | 455 | | |
456 | 456 | | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
457 | 465 | | |
458 | 466 | | |
| 467 | + | |
459 | 468 | | |
460 | 469 | | |
461 | 470 | | |
| |||
477 | 486 | | |
478 | 487 | | |
479 | 488 | | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
480 | 493 | | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
481 | 521 | | |
482 | 522 | | |
483 | 523 | | |
| |||
500 | 540 | | |
501 | 541 | | |
502 | 542 | | |
| 543 | + | |
503 | 544 | | |
504 | 545 | | |
505 | 546 | | |
| |||
519 | 560 | | |
520 | 561 | | |
521 | 562 | | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
522 | 567 | | |
523 | 568 | | |
524 | 569 | | |
| |||
535 | 580 | | |
536 | 581 | | |
537 | 582 | | |
| 583 | + | |
538 | 584 | | |
539 | 585 | | |
540 | 586 | | |
| |||
Lines changed: 17 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| 31 | + | |
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
33 | 40 | | |
34 | 41 | | |
35 | 42 | | |
| |||
42 | 49 | | |
43 | 50 | | |
44 | 51 | | |
45 | | - | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
46 | 62 | | |
0 commit comments