|
1 | 1 | import React from 'react';
|
2 |
| -import { Text, View, FlatList, StyleSheet, ScrollView } from 'react-native'; |
| 2 | +import { Text, View, StyleSheet, SectionList, Platform } from 'react-native'; |
3 | 3 | import {
|
4 | 4 | createStackNavigator,
|
5 | 5 | StackScreenProps,
|
6 | 6 | } from '@react-navigation/stack';
|
7 | 7 | import { NavigationContainer, ParamListBase } from '@react-navigation/native';
|
8 |
| -import { RectButton } from 'react-native-gesture-handler'; |
9 |
| - |
10 |
| -import Rows from './rows'; |
11 |
| -import Bouncing from './bouncing'; |
12 |
| -import Draggable from './draggable'; |
13 |
| -import Multitap from './multitap'; |
14 |
| -import ScaleAndRotate from './scaleAndRotate'; |
15 |
| -import SwipeableTable from './swipeable'; |
16 |
| -import doubleScalePinchAndRotate from './doubleScalePinchAndRotate'; |
17 |
| -import PagerAndDrawer from './pagerAndDrawer'; |
18 |
| -import HorizontalDrawer from './horizontalDrawer'; |
19 |
| -import PanAndScroll from './panAndScroll'; |
20 |
| -import Fling from './fling'; |
21 |
| -import PanResponder from './panResponder'; |
22 |
| -import DoubleDraggable from './doubleDraggable'; |
23 |
| -import ForceTouch from './forcetouch'; |
24 |
| -import BottomSheet from './bottomSheet'; |
25 |
| -import { TouchablesIndex, TouchableExample } from './touchables'; |
26 |
| -import { ComboWithGHScroll, ComboWithRNScroll } from './combo'; |
27 |
| -import ChatHeads from './chatHeads'; |
| 8 | +import { |
| 9 | + GestureHandlerRootView, |
| 10 | + RectButton, |
| 11 | +} from 'react-native-gesture-handler'; |
| 12 | +import DoublePinchRotate from './release_tests/doubleScalePinchAndRotate'; |
| 13 | +import DoubleDraggable from './release_tests/doubleDraggable'; |
| 14 | +import { ComboWithGHScroll } from './release_tests/combo'; |
| 15 | +import { TouchablesIndex, TouchableExample } from './release_tests/touchables'; |
| 16 | +import Rows from './release_tests/rows'; |
| 17 | +import { PinchableBox } from './recipes/scaleAndRotate'; |
| 18 | +import PanAndScroll from './recipes/panAndScroll'; |
| 19 | +import { BottomSheet } from './showcase/bottomSheet'; |
| 20 | +import Swipeables from './showcase/swipeable'; |
| 21 | +import ChatHeads from './showcase/chatHeads'; |
| 22 | +import { DraggableBox } from './basic/draggable'; |
| 23 | +import MultiTap from './basic/multitap'; |
| 24 | +import BouncingBox from './basic/bouncing'; |
| 25 | +import PanResponder from './basic/panResponder'; |
| 26 | +import HorizontalDrawer from './basic/horizontalDrawer'; |
| 27 | +import PagerAndDrawer from './basic/pagerAndDrawer'; |
| 28 | +import ForceTouch from './basic/forcetouch'; |
28 | 29 |
|
29 |
| -type Screens = Record< |
30 |
| - string, |
31 |
| - // eslint-disable-next-line @typescript-eslint/no-explicit-any |
32 |
| - { component: React.ComponentType<any>; title?: string } |
33 |
| ->; |
| 30 | +interface Example { |
| 31 | + name: string; |
| 32 | + component: React.ComponentType; |
| 33 | +} |
| 34 | +interface ExamplesSection { |
| 35 | + sectionTitle: string; |
| 36 | + data: Example[]; |
| 37 | +} |
34 | 38 |
|
35 |
| -const SCREENS: Screens = { |
36 |
| - Rows: { component: Rows, title: 'Table rows & buttons' }, |
37 |
| - Multitap: { component: Multitap }, |
38 |
| - Draggable: { component: Draggable }, |
39 |
| - ScaleAndRotate: { component: ScaleAndRotate, title: 'Scale, rotate & tilt' }, |
40 |
| - ScaleAndRotateSimultaneously: { |
41 |
| - component: doubleScalePinchAndRotate, |
42 |
| - title: 'Scale, rotate & tilt & more', |
43 |
| - }, |
44 |
| - PagerAndDrawer: { |
45 |
| - component: PagerAndDrawer, |
46 |
| - title: 'Android pager & drawer', |
47 |
| - }, |
48 |
| - HorizontalDrawer: { |
49 |
| - component: HorizontalDrawer, |
50 |
| - title: 'Gesture handler based DrawerLayout', |
51 |
| - }, |
52 |
| - SwipeableTable: { |
53 |
| - component: SwipeableTable, |
54 |
| - title: 'Gesture handler based SwipeableRow', |
55 |
| - }, |
56 |
| - PanAndScroll: { |
57 |
| - component: PanAndScroll, |
58 |
| - title: 'Horizontal pan or tap in ScrollView', |
59 |
| - }, |
60 |
| - Fling: { |
61 |
| - component: Fling, |
62 |
| - title: 'Flinghandler', |
63 |
| - }, |
64 |
| - PanResponder: { component: PanResponder }, |
65 |
| - Bouncing: { component: Bouncing, title: 'Twist & bounce back animation' }, |
66 |
| - ChatHeads: { |
67 |
| - component: ChatHeads, |
68 |
| - title: 'Chat Heads (no native animated support yet)', |
69 |
| - }, |
70 |
| - Combo: { component: ComboWithGHScroll }, |
71 |
| - BottomSheet: { |
72 |
| - title: 'BottomSheet gestures interactions', |
73 |
| - component: BottomSheet, |
74 |
| - }, |
75 |
| - ComboWithRNScroll: { |
76 |
| - component: ComboWithRNScroll, |
77 |
| - title: "Combo with RN's ScrollView", |
78 |
| - }, |
79 |
| - DoubleDraggable: { |
80 |
| - component: DoubleDraggable, |
81 |
| - title: 'Two handlers simultaneously', |
82 |
| - }, |
83 |
| - Touchables: { |
84 |
| - component: TouchablesIndex, |
85 |
| - title: 'Touchables', |
86 |
| - }, |
87 |
| - ForceTouch: { |
88 |
| - component: ForceTouch, |
89 |
| - title: 'Force touch', |
90 |
| - }, |
91 |
| -}; |
| 39 | +const EXAMPLES: ExamplesSection[] = [ |
| 40 | + { |
| 41 | + sectionTitle: 'Basic examples', |
| 42 | + data: [ |
| 43 | + { name: 'Draggable', component: DraggableBox }, |
| 44 | + { name: 'Multitap', component: MultiTap }, |
| 45 | + { name: 'Bouncing box', component: BouncingBox }, |
| 46 | + { name: 'Pan responder', component: PanResponder }, |
| 47 | + { name: 'Horizontal drawer', component: HorizontalDrawer }, |
| 48 | + { name: 'Pager & drawer', component: PagerAndDrawer }, |
| 49 | + { name: 'Force touch', component: ForceTouch }, |
| 50 | + ], |
| 51 | + }, |
| 52 | + { |
| 53 | + sectionTitle: 'Recipes', |
| 54 | + data: [ |
| 55 | + { name: 'Pinch & rotate', component: PinchableBox }, |
| 56 | + { name: 'Pan & scroll', component: PanAndScroll }, |
| 57 | + ], |
| 58 | + }, |
| 59 | + { |
| 60 | + sectionTitle: 'Showcase', |
| 61 | + data: [ |
| 62 | + { name: 'Bottom sheet', component: BottomSheet }, |
| 63 | + { name: 'Swipeables', component: Swipeables }, |
| 64 | + { name: 'Chat heads', component: ChatHeads }, |
| 65 | + ], |
| 66 | + }, |
| 67 | + { |
| 68 | + sectionTitle: 'Release tests', |
| 69 | + data: [ |
| 70 | + { name: 'Double pinch & rotate', component: DoublePinchRotate }, |
| 71 | + { name: 'Double draggable', component: DoubleDraggable }, |
| 72 | + { name: 'Rows', component: Rows }, |
| 73 | + { name: 'Combo', component: ComboWithGHScroll }, |
| 74 | + { name: 'Touchables', component: TouchablesIndex as React.ComponentType }, |
| 75 | + ], |
| 76 | + }, |
| 77 | +]; |
92 | 78 |
|
93 | 79 | type RootStackParamList = {
|
94 | 80 | Home: undefined;
|
95 | 81 | } & {
|
96 |
| - [P in keyof typeof SCREENS]: undefined; |
| 82 | + [Screen: string]: undefined; |
97 | 83 | };
|
98 | 84 |
|
99 | 85 | const Stack = createStackNavigator<RootStackParamList>();
|
100 | 86 |
|
101 | 87 | export default function App() {
|
102 | 88 | return (
|
103 |
| - <NavigationContainer> |
104 |
| - <Stack.Navigator> |
105 |
| - <Stack.Screen |
106 |
| - name="Home" |
107 |
| - options={{ title: '✌️ Gesture Handler Demo' }} |
108 |
| - component={MainScreen} |
109 |
| - /> |
110 |
| - {Object.keys(SCREENS).map((name) => ( |
| 89 | + <GestureHandlerRootView style={{ flex: 1 }}> |
| 90 | + <NavigationContainer> |
| 91 | + <Stack.Navigator> |
111 | 92 | <Stack.Screen
|
112 |
| - key={name} |
113 |
| - name={name} |
114 |
| - getComponent={() => SCREENS[name].component} |
115 |
| - options={{ title: SCREENS[name].title || name }} |
| 93 | + name="Home" |
| 94 | + options={{ title: '✌️ Gesture Handler Demo' }} |
| 95 | + component={MainScreen} |
116 | 96 | />
|
117 |
| - ))} |
118 |
| - <Stack.Screen name="TouchableExample" component={TouchableExample} /> |
119 |
| - </Stack.Navigator> |
120 |
| - </NavigationContainer> |
| 97 | + {EXAMPLES.flatMap(({ data }) => data).flatMap( |
| 98 | + ({ name, component }) => ( |
| 99 | + <Stack.Screen |
| 100 | + key={name} |
| 101 | + name={name} |
| 102 | + getComponent={() => component} |
| 103 | + options={{ title: name }} |
| 104 | + /> |
| 105 | + ) |
| 106 | + )} |
| 107 | + <Stack.Screen name="TouchableExample" component={TouchableExample} /> |
| 108 | + </Stack.Navigator> |
| 109 | + </NavigationContainer> |
| 110 | + </GestureHandlerRootView> |
121 | 111 | );
|
122 | 112 | }
|
123 | 113 |
|
124 | 114 | function MainScreen({ navigation }: StackScreenProps<ParamListBase>) {
|
125 |
| - const data = Object.keys(SCREENS).map((key) => { |
126 |
| - const item = SCREENS[key]; |
127 |
| - return { key, title: item.title || key }; |
128 |
| - }); |
129 |
| - |
130 | 115 | return (
|
131 |
| - <FlatList |
| 116 | + <SectionList |
132 | 117 | style={styles.list}
|
133 |
| - data={data} |
134 |
| - ItemSeparatorComponent={ItemSeparator} |
135 |
| - renderItem={(props) => ( |
| 118 | + sections={EXAMPLES} |
| 119 | + keyExtractor={(example) => example.name} |
| 120 | + renderItem={({ item }) => ( |
136 | 121 | <MainScreenItem
|
137 |
| - {...props} |
138 |
| - onPressItem={({ key }) => navigation.navigate(key)} |
| 122 | + name={item.name} |
| 123 | + onPressItem={(name) => navigation.navigate(name)} |
139 | 124 | />
|
140 | 125 | )}
|
141 |
| - renderScrollComponent={(props) => <ScrollView {...props} />} |
| 126 | + renderSectionHeader={({ section: { sectionTitle } }) => ( |
| 127 | + <Text style={styles.sectionTitle}>{sectionTitle}</Text> |
| 128 | + )} |
| 129 | + ItemSeparatorComponent={() => <View style={styles.separator} />} |
142 | 130 | />
|
143 | 131 | );
|
144 | 132 | }
|
145 | 133 |
|
146 |
| -function ItemSeparator() { |
147 |
| - return <View style={styles.separator} />; |
| 134 | +interface MainScreenItemProps { |
| 135 | + name: string; |
| 136 | + onPressItem: (name: string) => void; |
148 | 137 | }
|
149 | 138 |
|
150 |
| -type MainScreenItemProps = { |
151 |
| - item: { key: string; title: string }; |
152 |
| - onPressItem: (item: { key: string }) => void; |
153 |
| -}; |
154 |
| - |
155 |
| -function MainScreenItem(props: MainScreenItemProps) { |
156 |
| - const { title } = props.item; |
| 139 | +function MainScreenItem({ name, onPressItem }: MainScreenItemProps) { |
157 | 140 | return (
|
158 |
| - <RectButton |
159 |
| - style={[styles.button]} |
160 |
| - onPress={() => props.onPressItem(props.item)}> |
161 |
| - <Text style={styles.buttonText}>{title}</Text> |
| 141 | + <RectButton style={[styles.button]} onPress={() => onPressItem(name)}> |
| 142 | + <Text>{name}</Text> |
162 | 143 | </RectButton>
|
163 | 144 | );
|
164 | 145 | }
|
165 | 146 |
|
166 | 147 | const styles = StyleSheet.create({
|
167 |
| - list: { |
168 |
| - backgroundColor: '#EFEFF4', |
169 |
| - }, |
| 148 | + sectionTitle: { |
| 149 | + ...Platform.select({ |
| 150 | + ios: { |
| 151 | + fontSize: 17, |
| 152 | + fontWeight: '500', |
| 153 | + }, |
| 154 | + android: { |
| 155 | + fontSize: 19, |
| 156 | + fontFamily: 'sans-serif-medium', |
| 157 | + }, |
| 158 | + }), |
| 159 | + paddingTop: 10, |
| 160 | + paddingBottom: 5, |
| 161 | + paddingLeft: 10, |
| 162 | + backgroundColor: '#efefef', |
| 163 | + }, |
| 164 | + list: {}, |
170 | 165 | separator: {
|
171 |
| - height: 1, |
172 |
| - backgroundColor: '#DBDBE0', |
173 |
| - }, |
174 |
| - buttonText: { |
175 |
| - backgroundColor: 'transparent', |
| 166 | + height: 2, |
176 | 167 | },
|
177 | 168 | button: {
|
178 | 169 | flex: 1,
|
179 |
| - height: 60, |
| 170 | + height: 50, |
180 | 171 | padding: 10,
|
181 | 172 | flexDirection: 'row',
|
182 | 173 | alignItems: 'center',
|
|
0 commit comments