@momo-kits/foundation 0.75.1-beta.9 → 0.75.3-beta.0

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 (113) hide show
  1. package/Application/BottomSheet.tsx +225 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +291 -0
  3. package/Application/BottomTab/index.tsx +138 -0
  4. package/Application/Components.tsx +555 -0
  5. package/Application/ModalScreen.tsx +97 -0
  6. package/Application/Navigation.ts +50 -0
  7. package/Application/NavigationContainer.tsx +121 -0
  8. package/Application/Navigator.ts +151 -0
  9. package/Application/StackScreen.tsx +148 -0
  10. package/Application/index.ts +37 -0
  11. package/{Navigation → Application}/types.ts +101 -33
  12. package/Application/utils.tsx +153 -0
  13. package/Assets/DotAnimation.json +256 -0
  14. package/Assets/SpinnerAnimation.json +1027 -0
  15. package/Assets/icon.json +89 -5
  16. package/Assets/icon_bank.json +506 -0
  17. package/Assets/language.json +202 -0
  18. package/Badge/Badge.tsx +56 -0
  19. package/Badge/BadgeDot.tsx +11 -0
  20. package/Badge/BadgeRibbon.tsx +125 -0
  21. package/Badge/Shape.tsx +29 -0
  22. package/Badge/index.tsx +7 -0
  23. package/Badge/styles.ts +58 -0
  24. package/Badge/types.ts +63 -0
  25. package/Button/index.tsx +91 -40
  26. package/Button/styles.ts +19 -0
  27. package/CheckBox/index.tsx +58 -43
  28. package/CheckBox/styles.ts +1 -1
  29. package/CheckBox/types.ts +6 -4
  30. package/Consts/colors+spacing+radius.ts +18 -0
  31. package/Consts/styles.ts +0 -26
  32. package/Consts/theme.ts +5 -1
  33. package/Divider/index.tsx +3 -1
  34. package/Icon/index.tsx +15 -10
  35. package/Icon/types.ts +4 -3
  36. package/IconButton/index.tsx +24 -15
  37. package/Image/index.tsx +63 -45
  38. package/Image/styles.ts +1 -9
  39. package/Image/types.ts +5 -1
  40. package/Input/Input.tsx +227 -115
  41. package/Input/InputDropDown.tsx +132 -0
  42. package/Input/InputMoney.tsx +173 -110
  43. package/Input/InputOTP.tsx +257 -0
  44. package/Input/InputSearch.tsx +160 -130
  45. package/Input/InputTextArea.tsx +149 -121
  46. package/Input/common.tsx +36 -18
  47. package/Input/index.tsx +212 -17
  48. package/Input/styles.ts +44 -7
  49. package/Input/utils.ts +2 -2
  50. package/Layout/Card.tsx +76 -37
  51. package/Layout/FloatingButton.tsx +168 -0
  52. package/Layout/GridSystem.tsx +35 -23
  53. package/Layout/Item.tsx +29 -33
  54. package/Layout/ItemList.tsx +55 -0
  55. package/Layout/ItemSectionList.tsx +39 -0
  56. package/Layout/Screen.tsx +390 -0
  57. package/Layout/Section.tsx +73 -35
  58. package/Layout/index.ts +13 -3
  59. package/Layout/styles.ts +101 -0
  60. package/Layout/types.ts +1 -37
  61. package/Layout/utils.ts +38 -43
  62. package/Loader/DotLoader.tsx +37 -0
  63. package/Loader/Loader.tsx +13 -0
  64. package/Loader/ProgressBar.tsx +44 -0
  65. package/Loader/Spinner.tsx +29 -0
  66. package/Loader/index.tsx +4 -0
  67. package/Loader/styles.ts +10 -0
  68. package/Loader/types.ts +35 -0
  69. package/Loader/utils.ts +25 -0
  70. package/Pagination/Dot.tsx +1 -1
  71. package/Pagination/PaginationDot.tsx +8 -3
  72. package/Pagination/PaginationNumber.tsx +8 -7
  73. package/Pagination/PaginationScroll.tsx +1 -1
  74. package/Pagination/PaginationWhiteDot.tsx +8 -5
  75. package/Pagination/styles.ts +3 -0
  76. package/Pagination/types.ts +2 -0
  77. package/Popup/PopupNotify.tsx +108 -46
  78. package/Popup/PopupPromotion.tsx +63 -22
  79. package/Popup/types.ts +15 -4
  80. package/Radio/index.tsx +35 -21
  81. package/Radio/types.ts +7 -5
  82. package/Skeleton/index.tsx +1 -1
  83. package/Skeleton/types.ts +3 -0
  84. package/Switch/index.tsx +35 -24
  85. package/Switch/types.ts +5 -3
  86. package/Tag/index.tsx +1 -1
  87. package/Text/index.tsx +32 -26
  88. package/Text/styles.ts +38 -0
  89. package/Text/types.ts +25 -13
  90. package/Text/utils.ts +14 -0
  91. package/Title/index.tsx +197 -0
  92. package/Title/styles.ts +79 -0
  93. package/Title/types.ts +20 -0
  94. package/code-scanner.js +143 -0
  95. package/index.ts +22 -2
  96. package/migrate_typo.js +56 -0
  97. package/package.json +44 -39
  98. package/publish.sh +2 -5
  99. package/tsconfig.json +24 -0
  100. package/verify.js +47 -0
  101. package/Assets/header-background.png +0 -0
  102. package/Layout/ScreenContainer.tsx +0 -121
  103. package/Navigation/BottomTab.tsx +0 -39
  104. package/Navigation/Components.tsx +0 -365
  105. package/Navigation/ModalScreen.tsx +0 -226
  106. package/Navigation/Navigation.ts +0 -44
  107. package/Navigation/NavigationButton.tsx +0 -54
  108. package/Navigation/NavigationContainer.tsx +0 -77
  109. package/Navigation/Navigator.ts +0 -82
  110. package/Navigation/Observer.ts +0 -79
  111. package/Navigation/StackScreen.tsx +0 -27
  112. package/Navigation/index.ts +0 -14
  113. package/Navigation/utils.tsx +0 -137
@@ -0,0 +1,225 @@
1
+ import React, {useContext, useEffect, useRef, useState} from 'react';
2
+ import {
3
+ Animated,
4
+ Dimensions,
5
+ KeyboardAvoidingView,
6
+ Modal,
7
+ PanResponder,
8
+ Platform,
9
+ StyleSheet,
10
+ TouchableOpacity,
11
+ View,
12
+ } from 'react-native';
13
+ import {ApplicationContext} from './index';
14
+ import {BottomSheetParams} from './types';
15
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
16
+ import {Colors, Radius, Spacing, Styles} from '../Consts';
17
+ import {Text} from '../Text';
18
+ import {Icon} from '../Icon';
19
+
20
+ const BottomSheet: React.FC<BottomSheetParams> = props => {
21
+ const {theme, navigator} = useContext(ApplicationContext);
22
+ const heightDevice = Dimensions.get('screen').height;
23
+ const insets = useSafeAreaInsets();
24
+ const {
25
+ screen: Screen,
26
+ options,
27
+ surface,
28
+ barrierDismissible = false,
29
+ snapPoint = 'content',
30
+ draggable = true,
31
+ dragOnContent = false,
32
+ }: BottomSheetParams = props.route.params;
33
+ const [modalVisible, setModalVisible] = useState(false);
34
+ const animatedHeight = useRef(new Animated.Value(0)).current;
35
+ const pan = useRef(new Animated.ValueXY()).current;
36
+ const panResponder = useRef(
37
+ PanResponder.create({
38
+ onStartShouldSetPanResponder: () => draggable,
39
+ onMoveShouldSetPanResponder: (_, gestureState) => {
40
+ return draggable && dragOnContent && gestureState.dy > 0;
41
+ },
42
+ onPanResponderMove: (e, gestureState) => {
43
+ gestureState.dy > 0 &&
44
+ Animated.event([null, {dy: pan.y}], {useNativeDriver: false})(
45
+ e,
46
+ gestureState,
47
+ );
48
+ },
49
+ onPanResponderRelease: (_, gestureState) => {
50
+ if (gestureState.dy > 100) {
51
+ onDismiss();
52
+ } else {
53
+ Animated.spring(pan, {
54
+ toValue: {x: 0, y: 0},
55
+ useNativeDriver: false,
56
+ }).start();
57
+ }
58
+ },
59
+ }),
60
+ ).current;
61
+ const estimate = useRef(0.9);
62
+
63
+ let backgroundColor = theme.colors.background.default;
64
+ if (surface) {
65
+ backgroundColor = theme.colors.background.surface;
66
+ }
67
+
68
+ /**
69
+ * handle open & emit dismiss event
70
+ */
71
+ useEffect(() => {
72
+ setTimeout(() => {
73
+ const mapSnapPoint: any = {
74
+ '30%': 0.3,
75
+ '50%': 0.5,
76
+ '70%': 0.7,
77
+ '90%': 0.9,
78
+ };
79
+ const point = mapSnapPoint[snapPoint] ?? estimate.current;
80
+ setModalVisible(true);
81
+ Animated.timing(animatedHeight, {
82
+ useNativeDriver: false,
83
+ toValue: heightDevice * point,
84
+ duration: 300,
85
+ }).start();
86
+ }, 100);
87
+
88
+ return () => {
89
+ props.route.params?.onDismiss?.();
90
+ };
91
+ }, []);
92
+
93
+ /**
94
+ * handler dismiss
95
+ */
96
+ const onDismiss = (force = false) => {
97
+ if (barrierDismissible && !force) {
98
+ return;
99
+ }
100
+ Animated.timing(animatedHeight, {
101
+ useNativeDriver: false,
102
+ toValue: 0,
103
+ duration: 200,
104
+ }).start(() => {
105
+ pan.setValue({x: 0, y: 0});
106
+ navigator?.pop();
107
+ });
108
+ };
109
+
110
+ return (
111
+ <>
112
+ <Modal
113
+ transparent
114
+ visible={modalVisible}
115
+ onRequestClose={() => onDismiss()}>
116
+ <KeyboardAvoidingView
117
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
118
+ keyboardVerticalOffset={-20}
119
+ style={Styles.flex}>
120
+ <TouchableOpacity
121
+ style={Styles.flex}
122
+ activeOpacity={1}
123
+ onPress={() => onDismiss()}
124
+ />
125
+ <Animated.View
126
+ {...(dragOnContent && panResponder.panHandlers)}
127
+ style={[
128
+ styles.container,
129
+ {transform: pan.getTranslateTransform()},
130
+ {
131
+ height: animatedHeight,
132
+ backgroundColor,
133
+ },
134
+ ]}>
135
+ {draggable && (
136
+ <View
137
+ {...(!dragOnContent && panResponder.panHandlers)}
138
+ style={styles.draggableContainer}>
139
+ <View style={{height: 16}}>
140
+ <View style={styles.indicator} />
141
+ </View>
142
+ <View
143
+ style={[
144
+ styles.header,
145
+ surface && {
146
+ borderBottomColor: theme.colors.border.default,
147
+ borderBottomWidth: 1,
148
+ },
149
+ ]}>
150
+ <View style={styles.iconButton} />
151
+ <Text
152
+ style={[Styles.flex, {textAlign: 'center'}]}
153
+ numberOfLines={1}
154
+ typography="header_default_bold">
155
+ {options.title ?? ''}
156
+ </Text>
157
+ <TouchableOpacity
158
+ style={styles.iconButton}
159
+ onPress={() => onDismiss(true)}>
160
+ <Icon source="navigation_close" />
161
+ </TouchableOpacity>
162
+ </View>
163
+ </View>
164
+ )}
165
+ <Screen {...props} {...props.route.params} />
166
+ <View style={{height: Math.min(insets.bottom, 21)}} />
167
+ </Animated.View>
168
+ </KeyboardAvoidingView>
169
+ </Modal>
170
+ {snapPoint == 'content' && (
171
+ <View
172
+ style={styles.estimate}
173
+ onLayout={e => {
174
+ estimate.current =
175
+ (e.nativeEvent.layout.height + 68) / heightDevice;
176
+ }}>
177
+ <Screen {...props} {...props.route.params} />
178
+ <View style={{height: Math.min(insets.bottom, 21)}} />
179
+ </View>
180
+ )}
181
+ </>
182
+ );
183
+ };
184
+ export default BottomSheet;
185
+
186
+ const styles = StyleSheet.create({
187
+ container: {
188
+ width: '100%',
189
+ height: 0,
190
+ overflow: 'hidden',
191
+ borderTopLeftRadius: Radius.M,
192
+ borderTopRightRadius: Radius.M,
193
+ },
194
+ draggableContainer: {
195
+ width: '100%',
196
+ alignItems: 'center',
197
+ },
198
+ indicator: {
199
+ width: 40,
200
+ height: 4,
201
+ borderRadius: Radius.S,
202
+ backgroundColor: Colors.black_06,
203
+ position: 'absolute',
204
+ alignSelf: 'center',
205
+ top: Spacing.S,
206
+ },
207
+ header: {
208
+ height: 56,
209
+ flexDirection: 'row',
210
+ alignItems: 'center',
211
+ },
212
+ iconButton: {
213
+ width: 24,
214
+ height: 24,
215
+ alignItems: 'center',
216
+ justifyContent: 'center',
217
+ marginHorizontal: Spacing.M,
218
+ },
219
+ estimate: {
220
+ position: 'absolute',
221
+ top: -9999,
222
+ left: -9999,
223
+ opacity: 0,
224
+ },
225
+ });
@@ -0,0 +1,291 @@
1
+ import {BottomTabBarProps} from '@react-navigation/bottom-tabs';
2
+ import BottomTabBarItem from '@react-navigation/bottom-tabs/src/views/BottomTabItem';
3
+ import {
4
+ CommonActions,
5
+ NavigationContext,
6
+ NavigationRouteContext,
7
+ useLinkBuilder,
8
+ } from '@react-navigation/native';
9
+ import React, {useCallback, useContext} from 'react';
10
+ import {
11
+ Animated,
12
+ Platform,
13
+ StyleSheet,
14
+ TouchableOpacity,
15
+ useWindowDimensions,
16
+ View,
17
+ } from 'react-native';
18
+ import {EdgeInsets, useSafeAreaInsets} from 'react-native-safe-area-context';
19
+ import {Radius} from '../../Consts';
20
+ import {Icon} from '../../Icon';
21
+ import {Text} from '../../Text';
22
+ import {FloatingButtonProps} from '../types';
23
+ import {ApplicationContext} from '../index';
24
+
25
+ type Props = BottomTabBarProps & {
26
+ activeTintColor?: string;
27
+ inactiveTintColor?: string;
28
+ floatingButton?: FloatingButtonProps;
29
+ accessibilityLabel?: string;
30
+ };
31
+
32
+ const getPaddingBottom = (insets: EdgeInsets) => {
33
+ return Math.max(insets.bottom - Platform.select({ios: 4, default: 0}), 0);
34
+ };
35
+
36
+ export default function BottomTabBar({
37
+ state,
38
+ navigation,
39
+ descriptors,
40
+ activeBackgroundColor,
41
+ activeTintColor,
42
+ allowFontScaling,
43
+ inactiveBackgroundColor,
44
+ inactiveTintColor,
45
+ labelStyle,
46
+ iconStyle,
47
+ showLabel,
48
+ style,
49
+ tabStyle,
50
+ floatingButton,
51
+ }: Props) {
52
+ const {theme} = useContext(ApplicationContext);
53
+ const {routes} = state;
54
+ const widthDevice = useWindowDimensions()?.width;
55
+ const useFloating = floatingButton && state.routes.length % 2 === 0;
56
+ const itemWidth = widthDevice / (state.routes.length + (useFloating ? 1 : 0));
57
+ const buildLink = useLinkBuilder();
58
+ const indicatorAnimated = React.useRef(new Animated.Value(0)).current;
59
+ const insets = useSafeAreaInsets();
60
+ const paddingBottom = getPaddingBottom(insets);
61
+ const focusedTab = state?.routes[state.index]?.name || routes[0]?.params;
62
+
63
+ /**
64
+ * render tab item
65
+ */
66
+ const renderTabItem = useCallback(
67
+ (data: any[]) => {
68
+ return data?.map((route, index) => {
69
+ const focused = route.params.name === focusedTab;
70
+ const {options} = descriptors[route?.key] as any;
71
+ const onPress = () => {
72
+ const event = navigation.emit({
73
+ type: 'tabPress',
74
+ target: route.key,
75
+ canPreventDefault: true,
76
+ });
77
+
78
+ if (!focused && !event.defaultPrevented) {
79
+ navigation.dispatch({
80
+ ...CommonActions.navigate(route.name),
81
+ target: state.key,
82
+ });
83
+ }
84
+ };
85
+
86
+ const onLongPress = () => {
87
+ navigation.emit({
88
+ type: 'tabLongPress',
89
+ target: route.key,
90
+ });
91
+ };
92
+
93
+ const label =
94
+ options.tabBarLabel !== undefined
95
+ ? options.tabBarLabel
96
+ : options.title !== undefined
97
+ ? options.title
98
+ : route.name;
99
+
100
+ const accessibilityLabel =
101
+ options.tabBarAccessibilityLabel !== undefined
102
+ ? options.tabBarAccessibilityLabel
103
+ : typeof label === 'string'
104
+ ? `${label}, tab, ${index + 1} of ${routes.length}`
105
+ : undefined;
106
+
107
+ return (
108
+ <NavigationContext.Provider
109
+ key={route.key}
110
+ value={(descriptors as any)[route.key].navigation}>
111
+ <NavigationRouteContext.Provider value={route}>
112
+ <BottomTabBarItem
113
+ route={route}
114
+ focused={focused}
115
+ horizontal={false}
116
+ onPress={onPress}
117
+ onLongPress={onLongPress}
118
+ accessibilityLabel={accessibilityLabel}
119
+ to={buildLink(route.name, route.params)}
120
+ testID={options.tabBarTestID}
121
+ allowFontScaling={allowFontScaling}
122
+ activeTintColor={activeTintColor}
123
+ inactiveTintColor={inactiveTintColor}
124
+ activeBackgroundColor={activeBackgroundColor}
125
+ inactiveBackgroundColor={inactiveBackgroundColor}
126
+ button={options.tabBarButton}
127
+ icon={options.tabBarIcon}
128
+ badge={options.tabBarBadge}
129
+ badgeStyle={options.tabBarBadgeStyle}
130
+ label={label}
131
+ showLabel={showLabel}
132
+ labelStyle={labelStyle}
133
+ iconStyle={iconStyle}
134
+ style={tabStyle}
135
+ />
136
+ </NavigationRouteContext.Provider>
137
+ </NavigationContext.Provider>
138
+ );
139
+ });
140
+ },
141
+ [JSON.stringify(routes), state, descriptors, focusedTab],
142
+ );
143
+
144
+ /**
145
+ * render floating button
146
+ */
147
+ const renderFloatingButton = useCallback(() => {
148
+ const renderFloatingButton = () => {
149
+ if (typeof floatingButton?.icon == 'string') {
150
+ return <Icon source={floatingButton?.icon} size={32} color={'white'} />;
151
+ }
152
+ return floatingButton?.icon;
153
+ };
154
+
155
+ return (
156
+ <View style={{flex: 1}}>
157
+ <TouchableOpacity
158
+ onPress={floatingButton?.onPress}
159
+ style={styles.floatingContainer}>
160
+ <View
161
+ style={{
162
+ ...styles.floatingContent,
163
+ backgroundColor: activeTintColor ?? theme.colors.primary,
164
+ }}>
165
+ {renderFloatingButton()}
166
+ </View>
167
+ <View
168
+ style={{
169
+ top: -6,
170
+ backgroundColor: activeTintColor ?? theme.colors.primary,
171
+ borderRadius: Radius.XL,
172
+ paddingHorizontal: 6,
173
+ }}>
174
+ <Text
175
+ numberOfLines={1}
176
+ typography={'description_xs_regular'}
177
+ color={'white'}>
178
+ {floatingButton?.label}
179
+ </Text>
180
+ </View>
181
+ </TouchableOpacity>
182
+ </View>
183
+ );
184
+ }, [useFloating]);
185
+
186
+ /**
187
+ * animated indicator
188
+ */
189
+ React.useEffect(() => {
190
+ let index = state.index;
191
+ if (useFloating && index > (state.routes.length - 1) / 2) {
192
+ index += 1;
193
+ }
194
+ Animated.timing(indicatorAnimated, {
195
+ toValue: itemWidth * index,
196
+ useNativeDriver: true,
197
+ duration: 200,
198
+ }).start();
199
+ }, [state.index, itemWidth, indicatorAnimated, useFloating]);
200
+
201
+ /**
202
+ * render tab bar
203
+ */
204
+ const renderTabBar = () => {
205
+ if (useFloating) {
206
+ const middleIndex = routes.length / 2;
207
+ const leftArr = routes.slice(0, middleIndex);
208
+ const rightArr = routes.slice(middleIndex);
209
+ return (
210
+ <>
211
+ {renderTabItem(leftArr)}
212
+ {renderFloatingButton()}
213
+ {renderTabItem(rightArr)}
214
+ </>
215
+ );
216
+ }
217
+ return renderTabItem(routes);
218
+ };
219
+
220
+ return (
221
+ <Animated.View
222
+ style={[
223
+ styles.tabBar,
224
+ {
225
+ backgroundColor: theme.colors.background.surface,
226
+ borderTopColor: theme.colors.border.default,
227
+ },
228
+ {
229
+ paddingBottom: paddingBottom,
230
+ paddingHorizontal: Math.max(insets.left, insets.right),
231
+ },
232
+ style,
233
+ ]}
234
+ pointerEvents={'auto'}>
235
+ <View style={styles.content}>
236
+ {useFloating && floatingButton?.container}
237
+ <Animated.View
238
+ style={{
239
+ width: itemWidth,
240
+ position: 'absolute',
241
+ top: 0,
242
+ transform: [{translateX: indicatorAnimated}],
243
+ }}>
244
+ <View
245
+ style={[
246
+ styles.indicator,
247
+ {backgroundColor: activeTintColor ?? theme.colors.primary},
248
+ ]}
249
+ />
250
+ </Animated.View>
251
+ {renderTabBar()}
252
+ </View>
253
+ </Animated.View>
254
+ );
255
+ }
256
+
257
+ const styles = StyleSheet.create({
258
+ content: {
259
+ flex: 1,
260
+ flexDirection: 'row',
261
+ },
262
+ tabBar: {
263
+ left: 0,
264
+ right: 0,
265
+ bottom: 0,
266
+ borderTopWidth: StyleSheet.hairlineWidth,
267
+ elevation: 8,
268
+ },
269
+ floatingContainer: {
270
+ position: 'absolute',
271
+ alignItems: 'center',
272
+ left: 0,
273
+ right: 0,
274
+ bottom: Platform.OS === 'ios' ? -6 : 0,
275
+ },
276
+ floatingContent: {
277
+ alignItems: 'center',
278
+ justifyContent: 'center',
279
+ height: 48,
280
+ width: 48,
281
+ borderRadius: 24,
282
+ top: -10,
283
+ },
284
+ indicator: {
285
+ height: 2,
286
+ width: 44,
287
+ alignSelf: 'center',
288
+ borderBottomLeftRadius: 1,
289
+ borderBottomRightRadius: 1,
290
+ },
291
+ });
@@ -0,0 +1,138 @@
1
+ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
2
+ import {NavigationContainer} from '@react-navigation/native';
3
+ import {createStackNavigator} from '@react-navigation/stack';
4
+ import React, {useContext, useEffect} from 'react';
5
+ import {Platform} from 'react-native';
6
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
7
+ import {Colors} from '../../Consts';
8
+ import {Icon} from '../../Icon';
9
+ import {Text} from '../../Text';
10
+ import {ApplicationContext} from '../index';
11
+ import StackScreen from '../StackScreen';
12
+ import {BottomTabProps, NavigationScreenProps} from '../types';
13
+ import {getOptions, getStackOptions} from '../utils';
14
+ import BottomTabBar from './BottomTabBar';
15
+
16
+ const Tab = createBottomTabNavigator();
17
+ const Stack = createStackNavigator();
18
+
19
+ const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
20
+ const {theme} = useContext(ApplicationContext);
21
+ let options = {};
22
+ if (route.params?.options) {
23
+ options = getOptions(route.params?.options, theme);
24
+ }
25
+ if (route.params?.nested) {
26
+ return (
27
+ <Stack.Navigator>
28
+ <Stack.Screen
29
+ name="Stack"
30
+ component={StackScreen}
31
+ initialParams={{screen: route.params?.screen, options}}
32
+ options={{...getStackOptions()}}
33
+ />
34
+ </Stack.Navigator>
35
+ );
36
+ }
37
+ return (
38
+ <NavigationContainer independent={true}>
39
+ <Stack.Navigator>
40
+ <Stack.Screen
41
+ name="Stack"
42
+ component={StackScreen}
43
+ initialParams={{screen: route.params?.screen, options}}
44
+ options={{...getStackOptions(), ...route.params?.options}}
45
+ />
46
+ </Stack.Navigator>
47
+ </NavigationContainer>
48
+ );
49
+ };
50
+
51
+ const BottomTab: React.FC<BottomTabProps> = ({
52
+ nested,
53
+ tabs,
54
+ listeners,
55
+ navigation,
56
+ initialRouteName,
57
+ floatingButton,
58
+ }) => {
59
+ const {theme} = useContext(ApplicationContext);
60
+ const insets = useSafeAreaInsets();
61
+
62
+ useEffect(() => {
63
+ navigation?.setOptions({
64
+ headerShown: false,
65
+ headerTransparent: true,
66
+ headerBackground: undefined,
67
+ });
68
+ }, []);
69
+
70
+ return (
71
+ <Tab.Navigator
72
+ initialRouteName={initialRouteName}
73
+ backBehavior={'firstRoute'}
74
+ tabBar={props => (
75
+ <BottomTabBar
76
+ {...props}
77
+ accessibilityLabel={'BottomTabBar'}
78
+ floatingButton={floatingButton}
79
+ />
80
+ )}
81
+ tabBarOptions={{
82
+ style: {
83
+ height: 64 + Math.min(insets.bottom, 21),
84
+ },
85
+ tabStyle: {
86
+ height: 68,
87
+ paddingVertical: 10,
88
+ },
89
+ }}>
90
+ {tabs.map(item => {
91
+ const isNum = !isNaN(parseInt(`${item?.badgeLabel}`));
92
+ const isDot = typeof item?.badgeLabel == 'string' && !item?.badgeLabel;
93
+ return (
94
+ <Tab.Screen
95
+ key={item.name}
96
+ name={item.name}
97
+ component={TabScreen}
98
+ initialParams={{...item, nested}}
99
+ listeners={listeners}
100
+ options={{
101
+ tabBarLabel: ({color, focused}) => {
102
+ return (
103
+ <Text
104
+ numberOfLines={1}
105
+ typography={
106
+ focused ? 'label_xs_medium' : 'description_xs_regular'
107
+ }
108
+ color={color}
109
+ style={{width: '90%', textAlign: 'center'}}>
110
+ {item.label}
111
+ </Text>
112
+ );
113
+ },
114
+ tabBarBadge: item?.badgeLabel,
115
+ tabBarBadgeStyle: {
116
+ borderColor: 'white',
117
+ borderWidth: 2,
118
+ fontSize: 10,
119
+ lineHeight: Platform.OS === 'android' ? 17 : 14,
120
+ fontWeight: 'bold',
121
+ alignSelf: 'center',
122
+ fontFamily: `${theme.font}-Bold`,
123
+ left: isDot ? 8 : 4,
124
+ top: isDot ? -2 : -6,
125
+ backgroundColor: isNum ? Colors.red_03 : Colors.orange_03,
126
+ },
127
+ tabBarIcon: ({color}) => (
128
+ <Icon source={item.icon} color={color} size={28} />
129
+ ),
130
+ }}
131
+ />
132
+ );
133
+ })}
134
+ </Tab.Navigator>
135
+ );
136
+ };
137
+
138
+ export default BottomTab;