@react-navigation/material-top-tabs 6.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/lib/commonjs/index.js +32 -0
  4. package/lib/commonjs/index.js.map +1 -0
  5. package/lib/commonjs/navigators/createMaterialTopTabNavigator.js +110 -0
  6. package/lib/commonjs/navigators/createMaterialTopTabNavigator.js.map +1 -0
  7. package/lib/commonjs/types.js +6 -0
  8. package/lib/commonjs/types.js.map +1 -0
  9. package/lib/commonjs/views/MaterialTopTabBar.js +174 -0
  10. package/lib/commonjs/views/MaterialTopTabBar.js.map +1 -0
  11. package/lib/commonjs/views/MaterialTopTabView.js +80 -0
  12. package/lib/commonjs/views/MaterialTopTabView.js.map +1 -0
  13. package/lib/module/index.js +14 -0
  14. package/lib/module/index.js.map +1 -0
  15. package/lib/module/navigators/createMaterialTopTabNavigator.js +92 -0
  16. package/lib/module/navigators/createMaterialTopTabNavigator.js.map +1 -0
  17. package/lib/module/types.js +2 -0
  18. package/lib/module/types.js.map +1 -0
  19. package/lib/module/views/MaterialTopTabBar.js +155 -0
  20. package/lib/module/views/MaterialTopTabBar.js.map +1 -0
  21. package/lib/module/views/MaterialTopTabView.js +63 -0
  22. package/lib/module/views/MaterialTopTabView.js.map +1 -0
  23. package/lib/typescript/src/index.d.ts +13 -0
  24. package/lib/typescript/src/navigators/createMaterialTopTabNavigator.d.ts +7 -0
  25. package/lib/typescript/src/types.d.ts +190 -0
  26. package/lib/typescript/src/views/MaterialTopTabBar.d.ts +3 -0
  27. package/lib/typescript/src/views/MaterialTopTabView.d.ts +10 -0
  28. package/package.json +82 -0
  29. package/src/index.tsx +20 -0
  30. package/src/navigators/createMaterialTopTabNavigator.tsx +145 -0
  31. package/src/types.tsx +268 -0
  32. package/src/views/MaterialTopTabBar.tsx +143 -0
  33. package/src/views/MaterialTopTabView.tsx +75 -0
@@ -0,0 +1,145 @@
1
+ import {
2
+ createNavigatorFactory,
3
+ DefaultNavigatorOptions,
4
+ ParamListBase,
5
+ TabActionHelpers,
6
+ TabNavigationState,
7
+ TabRouter,
8
+ TabRouterOptions,
9
+ useNavigationBuilder,
10
+ } from '@react-navigation/native';
11
+ import * as React from 'react';
12
+ import warnOnce from 'warn-once';
13
+
14
+ import type {
15
+ MaterialTopTabNavigationConfig,
16
+ MaterialTopTabNavigationEventMap,
17
+ MaterialTopTabNavigationOptions,
18
+ } from '../types';
19
+ import MaterialTopTabView from '../views/MaterialTopTabView';
20
+
21
+ type Props = DefaultNavigatorOptions<
22
+ ParamListBase,
23
+ TabNavigationState<ParamListBase>,
24
+ MaterialTopTabNavigationOptions,
25
+ MaterialTopTabNavigationEventMap
26
+ > &
27
+ TabRouterOptions &
28
+ MaterialTopTabNavigationConfig;
29
+
30
+ function MaterialTopTabNavigator({
31
+ initialRouteName,
32
+ backBehavior,
33
+ children,
34
+ screenListeners,
35
+ screenOptions,
36
+ // @ts-expect-error: swipeEnabled is deprecated
37
+ swipeEnabled,
38
+ // @ts-expect-error: lazy is deprecated
39
+ lazy,
40
+ // @ts-expect-error: lazyPlaceholder is deprecated
41
+ lazyPlaceholder,
42
+ // @ts-expect-error: lazyPreloadDistance is deprecated
43
+ lazyPreloadDistance,
44
+ // @ts-expect-error: tabBarOptions is deprecated
45
+ tabBarOptions,
46
+ ...rest
47
+ }: Props) {
48
+ let defaultScreenOptions: MaterialTopTabNavigationOptions = {};
49
+
50
+ if (tabBarOptions) {
51
+ Object.assign(defaultScreenOptions, {
52
+ tabBarActiveTintColor: tabBarOptions.activeTintColor,
53
+ tabBarInactiveTintColor: tabBarOptions.inactiveTintColor,
54
+ tabBarPressColor: tabBarOptions.pressColor,
55
+ tabBarPressOpacity: tabBarOptions.pressOpacity,
56
+ tabBarShowLabel: tabBarOptions.showLabel,
57
+ tabBarShowIcon: tabBarOptions.showIcon,
58
+ tabBarAllowFontScaling: tabBarOptions.allowFontScaling,
59
+ tabBarBounces: tabBarOptions.bounces,
60
+ tabBarScrollEnabled: tabBarOptions.scrollEnabled,
61
+ tabBarIconStyle: tabBarOptions.iconStyle,
62
+ tabBarLabelStyle: tabBarOptions.labelStyle,
63
+ tabBarItemStyle: tabBarOptions.tabStyle,
64
+ tabBarBadge: tabBarOptions.renderBadge,
65
+ tabBarIndicator: tabBarOptions.renderIndicator,
66
+ tabBarIndicatorStyle: tabBarOptions.indicatorStyle,
67
+ tabBarIndicatorContainerStyle: tabBarOptions.indicatorContainerStyle,
68
+ tabBarContentContainerStyle: tabBarOptions.contentContainerStyle,
69
+ tabBarStyle: tabBarOptions.style,
70
+ });
71
+
72
+ (
73
+ Object.keys(
74
+ defaultScreenOptions
75
+ ) as (keyof MaterialTopTabNavigationOptions)[]
76
+ ).forEach((key) => {
77
+ if (defaultScreenOptions[key] === undefined) {
78
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
79
+ delete defaultScreenOptions[key];
80
+ }
81
+ });
82
+
83
+ warnOnce(
84
+ tabBarOptions,
85
+ `Material Top Tab Navigator: 'tabBarOptions' is deprecated. Migrate the options to 'screenOptions' instead.\n\nPlace the following in 'screenOptions' in your code to keep current behavior:\n\n${JSON.stringify(
86
+ defaultScreenOptions,
87
+ null,
88
+ 2
89
+ )}\n\nSee https://reactnavigation.org/docs/material-top-tab-navigator#options for more details.`
90
+ );
91
+ }
92
+
93
+ const deprecatedProps = {
94
+ swipeEnabled,
95
+ lazy,
96
+ lazyPlaceholder,
97
+ lazyPreloadDistance,
98
+ } as const;
99
+
100
+ Object.entries(deprecatedProps).forEach(([propName, propValue]) => {
101
+ if (propValue !== undefined) {
102
+ // @ts-expect-error: Object.entries doesn't return strict types
103
+ defaultScreenOptions[propName] = propValue;
104
+
105
+ warnOnce(
106
+ true,
107
+ `Material Top Tab Navigator: '${propName}' in props is deprecated. Move it to 'screenOptions' instead.\n\nSee https://reactnavigation.org/docs/material-top-tab-navigator#${propName.toLowerCase()} for more details.`
108
+ );
109
+ }
110
+ });
111
+
112
+ const { state, descriptors, navigation, NavigationContent } =
113
+ useNavigationBuilder<
114
+ TabNavigationState<ParamListBase>,
115
+ TabRouterOptions,
116
+ TabActionHelpers<ParamListBase>,
117
+ MaterialTopTabNavigationOptions,
118
+ MaterialTopTabNavigationEventMap
119
+ >(TabRouter, {
120
+ initialRouteName,
121
+ backBehavior,
122
+ children,
123
+ screenListeners,
124
+ screenOptions,
125
+ defaultScreenOptions,
126
+ });
127
+
128
+ return (
129
+ <NavigationContent>
130
+ <MaterialTopTabView
131
+ {...rest}
132
+ state={state}
133
+ navigation={navigation}
134
+ descriptors={descriptors}
135
+ />
136
+ </NavigationContent>
137
+ );
138
+ }
139
+
140
+ export default createNavigatorFactory<
141
+ TabNavigationState<ParamListBase>,
142
+ MaterialTopTabNavigationOptions,
143
+ MaterialTopTabNavigationEventMap,
144
+ typeof MaterialTopTabNavigator
145
+ >(MaterialTopTabNavigator);
package/src/types.tsx ADDED
@@ -0,0 +1,268 @@
1
+ import type {
2
+ Descriptor,
3
+ NavigationHelpers,
4
+ NavigationProp,
5
+ ParamListBase,
6
+ Route,
7
+ RouteProp,
8
+ TabActionHelpers,
9
+ TabNavigationState,
10
+ } from '@react-navigation/native';
11
+ import type React from 'react';
12
+ import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
13
+ import type {
14
+ SceneRendererProps,
15
+ TabBar,
16
+ TabViewProps,
17
+ } from 'react-native-tab-view';
18
+
19
+ export type MaterialTopTabNavigationEventMap = {
20
+ /**
21
+ * Event which fires on tapping on the tab in the tab bar.
22
+ */
23
+ tabPress: { data: undefined; canPreventDefault: true };
24
+ /**
25
+ * Event which fires on long press on the tab in the tab bar.
26
+ */
27
+ tabLongPress: { data: undefined };
28
+ /**
29
+ * Event which fires when a swipe gesture starts, i.e. finger touches the screen.
30
+ */
31
+ swipeStart: { data: undefined };
32
+ /**
33
+ * Event which fires when a swipe gesture ends, i.e. finger leaves the screen.
34
+ */
35
+ swipeEnd: { data: undefined };
36
+ };
37
+
38
+ export type MaterialTopTabNavigationHelpers = NavigationHelpers<
39
+ ParamListBase,
40
+ MaterialTopTabNavigationEventMap
41
+ > &
42
+ TabActionHelpers<ParamListBase>;
43
+
44
+ export type MaterialTopTabNavigationProp<
45
+ ParamList extends ParamListBase,
46
+ RouteName extends keyof ParamList = keyof ParamList
47
+ > = NavigationProp<
48
+ ParamList,
49
+ RouteName,
50
+ TabNavigationState<ParamList>,
51
+ MaterialTopTabNavigationOptions,
52
+ MaterialTopTabNavigationEventMap
53
+ > &
54
+ TabActionHelpers<ParamList>;
55
+
56
+ export type MaterialTopTabScreenProps<
57
+ ParamList extends ParamListBase,
58
+ RouteName extends keyof ParamList = keyof ParamList
59
+ > = {
60
+ navigation: MaterialTopTabNavigationProp<ParamList, RouteName>;
61
+ route: RouteProp<ParamList, RouteName>;
62
+ };
63
+
64
+ export type MaterialTopTabNavigationOptions = {
65
+ /**
66
+ * Title text for the screen.
67
+ */
68
+ title?: string;
69
+
70
+ /**
71
+ * Title string of a tab displayed in the tab bar
72
+ * or a function that given { focused: boolean, color: string } returns a React.Node, to display in tab bar.
73
+ *
74
+ * When undefined, scene title is used. Use `tabBarShowLabel` to hide the label.
75
+ */
76
+ tabBarLabel?:
77
+ | string
78
+ | ((props: { focused: boolean; color: string }) => React.ReactNode);
79
+
80
+ /**
81
+ * Accessibility label for the tab button. This is read by the screen reader when the user taps the tab.
82
+ * It's recommended to set this if you don't have a label for the tab.
83
+ */
84
+ tabBarAccessibilityLabel?: string;
85
+
86
+ /**
87
+ * Whether label font should scale to respect Text Size accessibility settings.
88
+ */
89
+ tabBarAllowFontScaling?: boolean;
90
+
91
+ /**
92
+ * Whether the tab label should be visible. Defaults to `true`.
93
+ */
94
+ tabBarShowLabel?: boolean;
95
+
96
+ /**
97
+ * A function that given { focused: boolean, color: string } returns a React.Node to display in the tab bar.
98
+ */
99
+ tabBarIcon?: (props: { focused: boolean; color: string }) => React.ReactNode;
100
+
101
+ /**
102
+ * Whether the tab icon should be visible. Defaults to `false`.
103
+ */
104
+ tabBarShowIcon?: boolean;
105
+
106
+ /**
107
+ * Function that returns a React element to use as a badge for the tab.
108
+ */
109
+ tabBarBadge?: () => React.ReactNode;
110
+
111
+ /**
112
+ * Function that returns a React element as the tab bar indicator.
113
+ */
114
+ tabBarIndicator?: (
115
+ props: Omit<
116
+ Parameters<React.ComponentProps<typeof TabBar>['renderIndicator']>[0],
117
+ 'navigationState'
118
+ > & { state: TabNavigationState<ParamListBase> }
119
+ ) => React.ReactNode;
120
+
121
+ /**
122
+ * Style object for the tab bar indicator.
123
+ */
124
+ tabBarIndicatorStyle?: StyleProp<ViewStyle>;
125
+
126
+ /**
127
+ * Style object for the view containing the tab bar indicator.
128
+ */
129
+ tabBarIndicatorContainerStyle?: StyleProp<ViewStyle>;
130
+
131
+ /**
132
+ * ID to locate this tab button in tests.
133
+ */
134
+ tabBarTestID?: string;
135
+
136
+ /**
137
+ * Color for the icon and label in the active tab.
138
+ */
139
+ tabBarActiveTintColor?: string;
140
+
141
+ /**
142
+ * Color for the icon and label in the inactive tabs.
143
+ */
144
+ tabBarInactiveTintColor?: string;
145
+
146
+ /**
147
+ * Color for material ripple (Android >= 5.0 only).
148
+ */
149
+ tabBarPressColor?: string;
150
+
151
+ /**
152
+ * Opacity for pressed tab (iOS and Android < 5.0 only).
153
+ */
154
+ tabBarPressOpacity?: number;
155
+
156
+ /**
157
+ * Boolean indicating whether the tab bar bounces when overscrolling.
158
+ */
159
+ tabBarBounces?: boolean;
160
+
161
+ /**
162
+ * Boolean indicating whether to make the tab bar scrollable.
163
+ *
164
+ * If you set this to `true`, you should also specify a width in `tabBarItemStyle` to improve the performance of initial render.
165
+ */
166
+ tabBarScrollEnabled?: boolean;
167
+
168
+ /**
169
+ * Style object for the tab icon container.
170
+ */
171
+ tabBarIconStyle?: StyleProp<ViewStyle>;
172
+
173
+ /**
174
+ * Style object for the tab label.
175
+ */
176
+ tabBarLabelStyle?: StyleProp<TextStyle>;
177
+
178
+ /**
179
+ * Style object for the individual tab items.
180
+ */
181
+ tabBarItemStyle?: StyleProp<ViewStyle>;
182
+
183
+ /**
184
+ * Style object for the view containing the tab items.
185
+ */
186
+ tabBarContentContainerStyle?: StyleProp<ViewStyle>;
187
+
188
+ /**
189
+ * Style object for the the tab bar.
190
+ */
191
+ tabBarStyle?: StyleProp<ViewStyle>;
192
+
193
+ /**
194
+ * Whether to enable swipe gestures when this screen is focused.
195
+ * Swipe gestures are enabled by default. Passing `false` will disable swipe gestures,
196
+ * but the user can still switch tabs by pressing the tab bar.
197
+ */
198
+ swipeEnabled?: boolean;
199
+
200
+ /**
201
+ * Whether this screen should be lazily rendered. When this is set to `true`,
202
+ * the screen will be rendered as it comes into the viewport.
203
+ * By default all screens are rendered to provide a smoother swipe experience.
204
+ * But you might want to defer the rendering of screens out of the viewport until the user sees them.
205
+ * To enable lazy rendering for this screen, set `lazy` to `true`.
206
+ *
207
+ * When you enable `lazy`, the lazy loaded screens will usually take some time to render
208
+ * when they come into the viewport. You can use the `lazyPlaceholder` prop to customize
209
+ * what the user sees during this short period.
210
+ */
211
+ lazy?: boolean;
212
+
213
+ /**
214
+ * When `lazy` is enabled, you can specify how many adjacent screens should be preloaded in advance with this prop.
215
+ * This value defaults to `0` which means lazy pages are loaded as they come into the viewport.
216
+ */
217
+ lazyPreloadDistance?: number;
218
+
219
+ /**
220
+ * Function that returns a React element to render if this screen hasn't been rendered yet.
221
+ * The `lazy` option also needs to be enabled for this to work.
222
+ *
223
+ * This view is usually only shown for a split second. Keep it lightweight.
224
+ *
225
+ * By default, this renders `null`.
226
+ */
227
+ lazyPlaceholder?: () => React.ReactNode;
228
+ };
229
+
230
+ export type MaterialTopTabDescriptor = Descriptor<
231
+ MaterialTopTabNavigationOptions,
232
+ MaterialTopTabNavigationProp<ParamListBase>,
233
+ RouteProp<ParamListBase>
234
+ >;
235
+
236
+ export type MaterialTopTabDescriptorMap = Record<
237
+ string,
238
+ MaterialTopTabDescriptor
239
+ >;
240
+
241
+ export type MaterialTopTabNavigationConfig = Omit<
242
+ TabViewProps<Route<string>>,
243
+ | 'navigationState'
244
+ | 'onIndexChange'
245
+ | 'onSwipeStart'
246
+ | 'onSwipeEnd'
247
+ | 'renderScene'
248
+ | 'renderTabBar'
249
+ | 'renderLazyPlaceholder'
250
+ | 'swipeEnabled'
251
+ | 'lazy'
252
+ | 'lazyPreloadDistance'
253
+ | 'lazyPlaceholder'
254
+ > & {
255
+ /**
256
+ * Function that returns a React element to display as the tab bar.
257
+ */
258
+ tabBar?: (props: MaterialTopTabBarProps) => React.ReactNode;
259
+ };
260
+
261
+ export type MaterialTopTabBarProps = SceneRendererProps & {
262
+ state: TabNavigationState<ParamListBase>;
263
+ navigation: NavigationHelpers<
264
+ ParamListBase,
265
+ MaterialTopTabNavigationEventMap
266
+ >;
267
+ descriptors: MaterialTopTabDescriptorMap;
268
+ };
@@ -0,0 +1,143 @@
1
+ import {
2
+ ParamListBase,
3
+ Route,
4
+ TabNavigationState,
5
+ useTheme,
6
+ } from '@react-navigation/native';
7
+ import Color from 'color';
8
+ import * as React from 'react';
9
+ import { StyleSheet, Text, View } from 'react-native';
10
+ import { TabBar, TabBarIndicator } from 'react-native-tab-view';
11
+
12
+ import type { MaterialTopTabBarProps } from '../types';
13
+
14
+ export default function TabBarTop({
15
+ state,
16
+ navigation,
17
+ descriptors,
18
+ ...rest
19
+ }: MaterialTopTabBarProps) {
20
+ const { colors } = useTheme();
21
+
22
+ const focusedOptions = descriptors[state.routes[state.index].key].options;
23
+
24
+ const activeColor = focusedOptions.tabBarActiveTintColor ?? colors.text;
25
+ const inactiveColor =
26
+ focusedOptions.tabBarInactiveTintColor ??
27
+ Color(activeColor).alpha(0.5).rgb().string();
28
+
29
+ return (
30
+ <TabBar
31
+ {...rest}
32
+ navigationState={state}
33
+ scrollEnabled={focusedOptions.tabBarScrollEnabled}
34
+ bounces={focusedOptions.tabBarBounces}
35
+ activeColor={activeColor}
36
+ inactiveColor={inactiveColor}
37
+ pressColor={focusedOptions.tabBarPressColor}
38
+ pressOpacity={focusedOptions.tabBarPressOpacity}
39
+ tabStyle={focusedOptions.tabBarItemStyle}
40
+ indicatorStyle={[
41
+ { backgroundColor: colors.primary },
42
+ focusedOptions.tabBarIndicatorStyle,
43
+ ]}
44
+ indicatorContainerStyle={focusedOptions.tabBarIndicatorContainerStyle}
45
+ contentContainerStyle={focusedOptions.tabBarContentContainerStyle}
46
+ style={[{ backgroundColor: colors.card }, focusedOptions.tabBarStyle]}
47
+ getAccessibilityLabel={({ route }) =>
48
+ descriptors[route.key].options.tabBarAccessibilityLabel
49
+ }
50
+ getTestID={({ route }) => descriptors[route.key].options.tabBarTestID}
51
+ onTabPress={({ route, preventDefault }) => {
52
+ const event = navigation.emit({
53
+ type: 'tabPress',
54
+ target: route.key,
55
+ canPreventDefault: true,
56
+ });
57
+
58
+ if (event.defaultPrevented) {
59
+ preventDefault();
60
+ }
61
+ }}
62
+ onTabLongPress={({ route }) =>
63
+ navigation.emit({
64
+ type: 'tabLongPress',
65
+ target: route.key,
66
+ })
67
+ }
68
+ renderIcon={({ route, focused, color }) => {
69
+ const { options } = descriptors[route.key];
70
+
71
+ if (options.tabBarShowIcon === false) {
72
+ return null;
73
+ }
74
+
75
+ if (options.tabBarIcon !== undefined) {
76
+ const icon = options.tabBarIcon({ focused, color });
77
+
78
+ return (
79
+ <View style={[styles.icon, options.tabBarIconStyle]}>{icon}</View>
80
+ );
81
+ }
82
+
83
+ return null;
84
+ }}
85
+ renderLabel={({ route, focused, color }) => {
86
+ const { options } = descriptors[route.key];
87
+
88
+ if (options.tabBarShowLabel === false) {
89
+ return null;
90
+ }
91
+
92
+ const label =
93
+ options.tabBarLabel !== undefined
94
+ ? options.tabBarLabel
95
+ : options.title !== undefined
96
+ ? options.title
97
+ : (route as Route<string>).name;
98
+
99
+ if (typeof label === 'string') {
100
+ return (
101
+ <Text
102
+ style={[styles.label, { color }, options.tabBarLabelStyle]}
103
+ allowFontScaling={options.tabBarAllowFontScaling}
104
+ >
105
+ {label}
106
+ </Text>
107
+ );
108
+ }
109
+
110
+ return label({ focused, color });
111
+ }}
112
+ renderBadge={({ route }) => {
113
+ const { tabBarBadge } = descriptors[route.key].options;
114
+
115
+ return tabBarBadge?.() ?? null;
116
+ }}
117
+ renderIndicator={({ navigationState: state, ...rest }) => {
118
+ return focusedOptions.tabBarIndicator ? (
119
+ focusedOptions.tabBarIndicator({
120
+ state: state as TabNavigationState<ParamListBase>,
121
+ ...rest,
122
+ })
123
+ ) : (
124
+ <TabBarIndicator navigationState={state} {...rest} />
125
+ );
126
+ }}
127
+ />
128
+ );
129
+ }
130
+
131
+ const styles = StyleSheet.create({
132
+ icon: {
133
+ height: 24,
134
+ width: 24,
135
+ },
136
+ label: {
137
+ textAlign: 'center',
138
+ textTransform: 'uppercase',
139
+ fontSize: 13,
140
+ margin: 4,
141
+ backgroundColor: 'transparent',
142
+ },
143
+ });
@@ -0,0 +1,75 @@
1
+ import {
2
+ CommonActions,
3
+ ParamListBase,
4
+ Route,
5
+ TabNavigationState,
6
+ useTheme,
7
+ } from '@react-navigation/native';
8
+ import * as React from 'react';
9
+ import { SceneRendererProps, TabView } from 'react-native-tab-view';
10
+
11
+ import type {
12
+ MaterialTopTabBarProps,
13
+ MaterialTopTabDescriptorMap,
14
+ MaterialTopTabNavigationConfig,
15
+ MaterialTopTabNavigationHelpers,
16
+ } from '../types';
17
+ import MaterialTopTabBar from './MaterialTopTabBar';
18
+
19
+ type Props = MaterialTopTabNavigationConfig & {
20
+ state: TabNavigationState<ParamListBase>;
21
+ navigation: MaterialTopTabNavigationHelpers;
22
+ descriptors: MaterialTopTabDescriptorMap;
23
+ };
24
+
25
+ export default function MaterialTopTabView({
26
+ tabBar = (props: MaterialTopTabBarProps) => <MaterialTopTabBar {...props} />,
27
+ state,
28
+ navigation,
29
+ descriptors,
30
+ sceneContainerStyle,
31
+ ...rest
32
+ }: Props) {
33
+ const { colors } = useTheme();
34
+
35
+ const renderTabBar = (props: SceneRendererProps) => {
36
+ return tabBar({
37
+ ...props,
38
+ state: state,
39
+ navigation: navigation,
40
+ descriptors: descriptors,
41
+ });
42
+ };
43
+
44
+ const focusedOptions = descriptors[state.routes[state.index].key].options;
45
+
46
+ return (
47
+ <TabView<Route<string>>
48
+ {...rest}
49
+ onIndexChange={(index) =>
50
+ navigation.dispatch({
51
+ ...CommonActions.navigate({
52
+ name: state.routes[index].name,
53
+ merge: true,
54
+ }),
55
+ target: state.key,
56
+ })
57
+ }
58
+ renderScene={({ route }) => descriptors[route.key].render()}
59
+ navigationState={state}
60
+ renderTabBar={renderTabBar}
61
+ renderLazyPlaceholder={({ route }) =>
62
+ descriptors[route.key].options.lazyPlaceholder?.() ?? null
63
+ }
64
+ lazy={({ route }) => descriptors[route.key].options.lazy === true}
65
+ lazyPreloadDistance={focusedOptions.lazyPreloadDistance}
66
+ swipeEnabled={focusedOptions.swipeEnabled}
67
+ onSwipeStart={() => navigation.emit({ type: 'swipeStart' })}
68
+ onSwipeEnd={() => navigation.emit({ type: 'swipeEnd' })}
69
+ sceneContainerStyle={[
70
+ { backgroundColor: colors.background },
71
+ sceneContainerStyle,
72
+ ]}
73
+ />
74
+ );
75
+ }