Skip to content

Commit 250ff45

Browse files
isaacrowntreeclaude
andcommitted
repro: minimal footer touch swallowing repro
Single-screen self-contained repro for lodev09#589. Auto-presents a sheet on mount with: - A content button (CONTENT: 0/10) — control, should always register - A footer button (FOOTER: 0/10) — demonstrates touch swallowing bug - A TextInput in the footer for keyboard-focus testing Tap each button 10 times. On affected builds, the footer counter drops every 2nd tap while the content counter reaches 10/10 cleanly. Rebased on main and stripped of unrelated dep bumps, example-app rewrites, and extra repro variants to keep the reproduction minimal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 626a04c commit 250ff45

1 file changed

Lines changed: 168 additions & 12 deletions

File tree

example/bare/src/App.tsx

Lines changed: 168 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,176 @@
1-
import { NavigationContainer } from '@react-navigation/native';
2-
import { ReanimatedTrueSheetProvider } from '@lodev09/react-native-true-sheet/reanimated';
3-
import { MapProvider } from '@lugg/maps';
4-
const GOOGLE_MAPS_API_KEY = process.env.GOOGLE_MAPS_API_KEY ?? '';
1+
import { useEffect, useRef, useState, useCallback } from 'react';
2+
import { Alert, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
3+
import { TrueSheet, TrueSheetProvider } from '@lodev09/react-native-true-sheet';
4+
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
55

6-
import { RootNavigator } from './navigators';
6+
const DARK = '#1c1c1e';
7+
const DARK_BLUE = '#2c2c3e';
8+
const SPACING = 16;
9+
const GAP = 12;
10+
11+
const FooterRepro = () => {
12+
const sheetRef = useRef<TrueSheet>(null);
13+
const insets = useSafeAreaInsets();
14+
const [footerTaps, setFooterTaps] = useState(0);
15+
const [contentTaps, setContentTaps] = useState(0);
16+
const footerTapsRef = useRef(0);
17+
18+
const handleFooterTap = useCallback(() => {
19+
footerTapsRef.current += 1;
20+
const count = footerTapsRef.current;
21+
setFooterTaps(count);
22+
Alert.alert('Footer Tap', `Count: ${count}`);
23+
}, []);
24+
25+
useEffect(() => {
26+
const timer = setTimeout(() => sheetRef.current?.present(), 500);
27+
return () => clearTimeout(timer);
28+
}, []);
29+
30+
return (
31+
<View style={[styles.container, { paddingTop: insets.top + 16 }]}>
32+
<Text style={styles.title}>Footer Touch Repro</Text>
33+
<Text style={styles.subtitle}>
34+
{'Tap each button 10 times. The counter should reach 10.\n\n' +
35+
'BUG: On physical iOS devices, every 2nd footer tap is ' +
36+
'silently swallowed. The content button (control) works every time.'}
37+
</Text>
38+
<Pressable
39+
style={[styles.button, { backgroundColor: '#007AFF', marginBottom: 16 }]}
40+
onPress={() => sheetRef.current?.present()}
41+
>
42+
<Text style={styles.buttonText}>Present Sheet</Text>
43+
</Pressable>
44+
45+
<TrueSheet
46+
ref={sheetRef}
47+
detents={['auto', 0.5, 1]}
48+
backgroundColor={DARK}
49+
style={styles.sheetContent}
50+
footer={
51+
<View style={styles.footer}>
52+
<Pressable
53+
style={[
54+
styles.button,
55+
footerTaps >= 10
56+
? { backgroundColor: '#2d7d2d' }
57+
: footerTaps > 0 && footerTaps < 10
58+
? { backgroundColor: '#cc3333' }
59+
: undefined,
60+
]}
61+
onPress={handleFooterTap}
62+
>
63+
<Text style={styles.buttonText}>
64+
FOOTER: {footerTaps}/10 {footerTaps >= 10 ? ' PASS' : ''}
65+
</Text>
66+
</Pressable>
67+
<TextInput
68+
style={styles.input}
69+
placeholder="Tap to focus (keyboard test)"
70+
placeholderTextColor="#999"
71+
returnKeyType="done"
72+
/>
73+
</View>
74+
}
75+
>
76+
<Pressable
77+
style={[
78+
styles.demoBlock,
79+
contentTaps >= 10
80+
? { backgroundColor: '#2d7d2d' }
81+
: contentTaps > 0 && contentTaps < 10
82+
? { backgroundColor: '#cc3333' }
83+
: undefined,
84+
]}
85+
onPress={() => setContentTaps((n) => n + 1)}
86+
>
87+
<Text style={styles.demoText}>
88+
CONTENT: {contentTaps}/10 {contentTaps >= 10 ? ' PASS' : ''}
89+
</Text>
90+
<Text style={[styles.demoText, { fontSize: 12, marginTop: 4, opacity: 0.6 }]}>
91+
(control — this should always work)
92+
</Text>
93+
</Pressable>
94+
<View style={styles.demoBlock}>
95+
<Text style={styles.demoText}>Sheet content block 2</Text>
96+
</View>
97+
<View style={styles.demoBlock}>
98+
<Text style={styles.demoText}>Sheet content block 3</Text>
99+
</View>
100+
</TrueSheet>
101+
</View>
102+
);
103+
};
7104

8105
const App = () => {
9106
return (
10-
<MapProvider apiKey={GOOGLE_MAPS_API_KEY}>
11-
<ReanimatedTrueSheetProvider>
12-
<NavigationContainer>
13-
<RootNavigator />
14-
</NavigationContainer>
15-
</ReanimatedTrueSheetProvider>
16-
</MapProvider>
107+
<SafeAreaProvider>
108+
<TrueSheetProvider>
109+
<FooterRepro />
110+
</TrueSheetProvider>
111+
</SafeAreaProvider>
17112
);
18113
};
19114

20115
export default App;
116+
117+
const styles = StyleSheet.create({
118+
container: {
119+
flex: 1,
120+
backgroundColor: '#f5f5f5',
121+
alignItems: 'center',
122+
padding: SPACING,
123+
},
124+
title: {
125+
fontSize: 22,
126+
fontWeight: 'bold',
127+
marginBottom: 8,
128+
},
129+
subtitle: {
130+
fontSize: 14,
131+
color: '#666',
132+
textAlign: 'center',
133+
marginBottom: 24,
134+
paddingHorizontal: 20,
135+
},
136+
sheetContent: {
137+
paddingHorizontal: SPACING,
138+
paddingTop: SPACING,
139+
paddingBottom: 80 + SPACING,
140+
gap: GAP,
141+
},
142+
footer: {
143+
padding: SPACING,
144+
gap: GAP,
145+
},
146+
demoBlock: {
147+
backgroundColor: DARK_BLUE,
148+
borderRadius: 12,
149+
padding: 24,
150+
alignItems: 'center',
151+
},
152+
demoText: {
153+
color: '#fff',
154+
fontSize: 16,
155+
},
156+
button: {
157+
backgroundColor: DARK_BLUE,
158+
height: 48,
159+
borderRadius: 24,
160+
alignItems: 'center',
161+
justifyContent: 'center',
162+
paddingHorizontal: SPACING,
163+
},
164+
buttonText: {
165+
color: '#fff',
166+
fontSize: 16,
167+
},
168+
input: {
169+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
170+
paddingHorizontal: SPACING,
171+
height: 48,
172+
borderRadius: 24,
173+
fontSize: 16,
174+
color: '#fff',
175+
},
176+
});

0 commit comments

Comments
 (0)