Skip to content

Commit e2073e2

Browse files
chore: experiments app (#1391)
1 parent 78194d1 commit e2073e2

20 files changed

+7316
-3
lines changed

experiments-app/.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
node_modules/
2+
.expo/
3+
dist/
4+
npm-debug.*
5+
*.jks
6+
*.p8
7+
*.p12
8+
*.key
9+
*.mobileprovision
10+
*.orig.*
11+
web-build/
12+
13+
# macOS
14+
.DS_Store
15+
16+
# Temporary files created by Metro to check the health of the file watcher
17+
.metro-health-check*

experiments-app/.prettierrc.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// added for Jest inline snapshots to not use default Prettier config
2+
module.exports = {
3+
singleQuote: true,
4+
trailingComma: "es5"
5+
}

experiments-app/app.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"expo": {
3+
"name": "experiments-app",
4+
"slug": "experiments-app",
5+
"version": "1.0.0",
6+
"orientation": "portrait",
7+
"icon": "./assets/icon.png",
8+
"userInterfaceStyle": "light",
9+
"splash": {
10+
"image": "./assets/splash.png",
11+
"resizeMode": "contain",
12+
"backgroundColor": "#ffffff"
13+
},
14+
"assetBundlePatterns": [
15+
"**/*"
16+
],
17+
"ios": {
18+
"supportsTablet": true
19+
},
20+
"android": {
21+
"adaptiveIcon": {
22+
"foregroundImage": "./assets/adaptive-icon.png",
23+
"backgroundColor": "#ffffff"
24+
}
25+
},
26+
"web": {
27+
"favicon": "./assets/favicon.png"
28+
}
29+
}
30+
}
17.1 KB
Loading

experiments-app/assets/favicon.png

1.43 KB
Loading

experiments-app/assets/icon.png

21.9 KB
Loading

experiments-app/assets/splash.png

46.2 KB
Loading

experiments-app/babel.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = function(api) {
2+
api.cache(true);
3+
return {
4+
presets: ['babel-preset-expo'],
5+
};
6+
};

experiments-app/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import registerRootComponent from 'expo/build/launch/registerRootComponent';
2+
import App from './src/App';
3+
4+
registerRootComponent(App);

experiments-app/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "experiments-app",
3+
"private": true,
4+
"description": "Expo app for conducting experiments of React Native behaviour.",
5+
"version": "1.0.0",
6+
"main": "index.js",
7+
"scripts": {
8+
"typecheck": "tsc -noEmit",
9+
"start": "expo start",
10+
"android": "expo start --android",
11+
"ios": "expo start --ios",
12+
"web": "expo start --web"
13+
},
14+
"dependencies": {
15+
"@react-navigation/native": "^6.1.6",
16+
"@react-navigation/native-stack": "^6.9.12",
17+
"add": "^2.0.6",
18+
"expo": "~48.0.11",
19+
"expo-status-bar": "~1.4.4",
20+
"react": "18.2.0",
21+
"react-native": "0.71.6",
22+
"react-native-safe-area-context": "4.5.0",
23+
"react-native-screens": "~3.20.0",
24+
"yarn": "^1.22.19"
25+
},
26+
"devDependencies": {
27+
"@babel/core": "^7.20.0",
28+
"@types/react": "~18.0.14",
29+
"typescript": "^4.9.4"
30+
}
31+
}

experiments-app/src/App.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as React from 'react';
2+
import { StatusBar } from 'expo-status-bar';
3+
import { NavigationContainer } from '@react-navigation/native';
4+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
5+
import { MainScreen } from './MainScreen';
6+
import { experiments } from './experiments';
7+
8+
const Stack = createNativeStackNavigator();
9+
10+
export default function App() {
11+
return (
12+
<NavigationContainer>
13+
<Stack.Navigator>
14+
<Stack.Screen
15+
name="main"
16+
component={MainScreen}
17+
options={{ title: 'Experiments' }}
18+
/>
19+
{experiments.map((exp) => (
20+
<Stack.Screen
21+
key={exp.key}
22+
name={exp.key}
23+
component={exp.component}
24+
options={{ title: exp.title }}
25+
/>
26+
))}
27+
</Stack.Navigator>
28+
<StatusBar style="auto" />
29+
</NavigationContainer>
30+
);
31+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as React from 'react';
2+
import { StyleSheet, SafeAreaView, TextInput, Pressable } from 'react-native';
3+
import { buildEventLogger } from '../utils/helpers';
4+
5+
const handlePressIn = buildEventLogger('TextInput.pressIn');
6+
const handlePressOut = buildEventLogger('TextInput.pressOut');
7+
const handleFocus = buildEventLogger('TextInput.focus');
8+
const handleBlur = buildEventLogger('TextInput.blur');
9+
const handleChange = buildEventLogger('TextInput.change');
10+
const handleSubmitEditing = buildEventLogger('TextInput.submitEditing');
11+
12+
const handlePressablePress = buildEventLogger('Pressable.press');
13+
14+
export function TextInputEventPropagation() {
15+
const [value, setValue] = React.useState('');
16+
17+
const handleChangeText = (value: string) => {
18+
setValue(value);
19+
console.log(`Event: changeText`, value);
20+
};
21+
22+
return (
23+
<SafeAreaView style={styles.container}>
24+
<Pressable onPress={handlePressablePress}>
25+
<TextInput
26+
style={styles.textInput}
27+
value={value}
28+
editable={true}
29+
onChangeText={handleChangeText}
30+
onPressIn={handlePressIn}
31+
onPressOut={handlePressOut}
32+
onFocus={handleFocus}
33+
onBlur={handleBlur}
34+
onChange={handleChange}
35+
onSubmitEditing={handleSubmitEditing}
36+
/>
37+
</Pressable>
38+
</SafeAreaView>
39+
);
40+
}
41+
42+
const styles = StyleSheet.create({
43+
container: {
44+
flex: 1,
45+
},
46+
textInput: {
47+
backgroundColor: 'white',
48+
margin: 20,
49+
padding: 8,
50+
fontSize: 18,
51+
borderWidth: 1,
52+
borderColor: 'grey',
53+
},
54+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from 'react';
2+
import { StyleSheet, SafeAreaView, TextInput } from 'react-native';
3+
import { buildEventLogger } from '../utils/helpers';
4+
5+
const handlePressIn = buildEventLogger('pressIn');
6+
const handlePressOut = buildEventLogger('pressOut');
7+
const handleFocus = buildEventLogger('focus');
8+
const handleBlur = buildEventLogger('blur');
9+
const handleChange = buildEventLogger('change');
10+
const handleSubmitEditing = buildEventLogger('submitEditing');
11+
12+
export function TextInputEvents() {
13+
const [value, setValue] = React.useState('');
14+
15+
const handleChangeText = (value: string) => {
16+
setValue(value);
17+
console.log(`Event: changeText`, value);
18+
};
19+
20+
return (
21+
<SafeAreaView style={styles.container}>
22+
<TextInput
23+
style={styles.textInput}
24+
value={value}
25+
editable={true}
26+
onChangeText={handleChangeText}
27+
onPressIn={handlePressIn}
28+
onPressOut={handlePressOut}
29+
onFocus={handleFocus}
30+
onBlur={handleBlur}
31+
onChange={handleChange}
32+
onSubmitEditing={handleSubmitEditing}
33+
/>
34+
</SafeAreaView>
35+
);
36+
}
37+
38+
const styles = StyleSheet.create({
39+
container: {
40+
flex: 1,
41+
},
42+
textInput: {
43+
backgroundColor: 'white',
44+
margin: 20,
45+
padding: 8,
46+
fontSize: 18,
47+
borderWidth: 1,
48+
borderColor: 'grey',
49+
},
50+
});

experiments-app/src/MainScreen.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as React from 'react';
2+
import {
3+
StyleSheet,
4+
SafeAreaView,
5+
Text,
6+
FlatList,
7+
Pressable,
8+
} from 'react-native';
9+
import { useNavigation } from '@react-navigation/native';
10+
import { Experiment, experiments } from './experiments';
11+
12+
export function MainScreen() {
13+
return (
14+
<SafeAreaView style={styles.container}>
15+
<FlatList
16+
data={experiments}
17+
renderItem={({ item }) => <ListItem item={item} />}
18+
/>
19+
</SafeAreaView>
20+
);
21+
}
22+
23+
interface ListItemProps {
24+
item: Experiment;
25+
}
26+
27+
function ListItem({ item }: ListItemProps) {
28+
const navigation = useNavigation();
29+
30+
const handlePress = () => {
31+
navigation.navigate(item.key);
32+
};
33+
34+
return (
35+
<Pressable style={styles.item} onPress={handlePress}>
36+
<Text style={styles.itemTitle}>{item.title}</Text>
37+
</Pressable>
38+
);
39+
}
40+
41+
const styles = StyleSheet.create({
42+
container: {
43+
flex: 1,
44+
},
45+
item: {
46+
padding: 20,
47+
},
48+
itemTitle: {
49+
fontSize: 20,
50+
},
51+
});

experiments-app/src/experiments.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { TextInputEventPropagation } from './experiments/TextInputEventPropagation';
2+
import { TextInputEvents } from './experiments/TextInputEvents';
3+
4+
export type Experiment = (typeof experiments)[number];
5+
6+
export const experiments = [
7+
{
8+
key: 'textInputEvents',
9+
title: 'TextInput Events',
10+
component: TextInputEvents,
11+
},
12+
{
13+
key: 'textInputEventPropagation',
14+
title: 'TextInput Event Propagation',
15+
component: TextInputEventPropagation,
16+
},
17+
];

experiments-app/src/utils/helpers.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NativeSyntheticEvent } from 'react-native/types';
2+
3+
export function buildEventLogger(name: string) {
4+
return (event: NativeSyntheticEvent<unknown>) => {
5+
const eventData = event?.nativeEvent ?? event;
6+
console.log(`Event: ${name}`, eventData);
7+
};
8+
}

experiments-app/tsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "expo/tsconfig.base",
3+
"compilerOptions": {
4+
"strict": true
5+
}
6+
}

0 commit comments

Comments
 (0)