@momo-kits/foundation 0.76.1-beta.2 → 0.77.1-optimize.10

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 (100) hide show
  1. package/Application/BottomTab/BottomTabBar.tsx +439 -0
  2. package/Application/BottomTab/index.tsx +138 -0
  3. package/Application/Components.tsx +348 -167
  4. package/Application/ModalScreen.tsx +135 -98
  5. package/Application/Navigation.ts +22 -16
  6. package/Application/NavigationContainer.tsx +99 -48
  7. package/Application/Navigator.ts +110 -41
  8. package/Application/StackScreen.tsx +129 -8
  9. package/Application/index.ts +23 -4
  10. package/Application/types.ts +86 -34
  11. package/Application/utils.tsx +67 -49
  12. package/Assets/DotAnimation.json +256 -0
  13. package/Assets/SpinnerAnimation.json +1027 -0
  14. package/Assets/icon.json +83 -5
  15. package/Assets/icon_bank.json +506 -0
  16. package/Assets/language.json +202 -0
  17. package/Badge/Badge.tsx +56 -0
  18. package/Badge/BadgeDot.tsx +11 -0
  19. package/Badge/BadgeRibbon.tsx +125 -0
  20. package/Badge/Shape.tsx +29 -0
  21. package/Badge/index.tsx +7 -0
  22. package/Badge/styles.ts +58 -0
  23. package/Badge/types.ts +63 -0
  24. package/Button/index.tsx +91 -40
  25. package/Button/styles.ts +19 -0
  26. package/CheckBox/index.tsx +58 -43
  27. package/CheckBox/styles.ts +1 -1
  28. package/CheckBox/types.ts +6 -4
  29. package/Consts/colors+spacing+radius.ts +18 -0
  30. package/Consts/styles.ts +0 -26
  31. package/Consts/theme.ts +4 -0
  32. package/Divider/index.tsx +2 -0
  33. package/Icon/index.tsx +14 -9
  34. package/Icon/types.ts +4 -3
  35. package/IconButton/index.tsx +24 -15
  36. package/Image/index.tsx +63 -47
  37. package/Image/styles.ts +1 -9
  38. package/Image/types.ts +5 -1
  39. package/Input/Input.tsx +227 -116
  40. package/Input/InputDropDown.tsx +132 -0
  41. package/Input/InputMoney.tsx +173 -111
  42. package/Input/InputOTP.tsx +257 -0
  43. package/Input/InputSearch.tsx +160 -132
  44. package/Input/InputTextArea.tsx +150 -123
  45. package/Input/common.tsx +35 -17
  46. package/Input/index.tsx +211 -18
  47. package/Input/styles.ts +44 -7
  48. package/Input/utils.ts +2 -2
  49. package/Layout/Card.tsx +67 -29
  50. package/Layout/FloatingButton.tsx +168 -0
  51. package/Layout/GridSystem.tsx +31 -21
  52. package/Layout/Item.tsx +21 -25
  53. package/Layout/ItemList.tsx +55 -0
  54. package/Layout/ItemSectionList.tsx +39 -0
  55. package/Layout/Screen.tsx +355 -153
  56. package/Layout/Section.tsx +66 -34
  57. package/Layout/index.ts +13 -3
  58. package/Layout/styles.ts +101 -0
  59. package/Layout/types.ts +1 -39
  60. package/Layout/utils.ts +27 -52
  61. package/Loader/DotLoader.tsx +37 -0
  62. package/Loader/Loader.tsx +13 -0
  63. package/Loader/ProgressBar.tsx +44 -0
  64. package/Loader/Spinner.tsx +29 -0
  65. package/Loader/index.tsx +4 -0
  66. package/Loader/styles.ts +10 -0
  67. package/Loader/types.ts +35 -0
  68. package/Loader/utils.ts +25 -0
  69. package/Pagination/PaginationDot.tsx +7 -2
  70. package/Pagination/PaginationNumber.tsx +8 -6
  71. package/Pagination/PaginationScroll.tsx +0 -1
  72. package/Pagination/PaginationWhiteDot.tsx +8 -5
  73. package/Pagination/styles.ts +3 -0
  74. package/Pagination/types.ts +2 -0
  75. package/Popup/PopupNotify.tsx +108 -46
  76. package/Popup/PopupPromotion.tsx +63 -22
  77. package/Popup/types.ts +15 -4
  78. package/Radio/index.tsx +35 -21
  79. package/Radio/types.ts +7 -5
  80. package/Skeleton/index.tsx +1 -1
  81. package/Skeleton/types.ts +3 -0
  82. package/Switch/index.tsx +35 -24
  83. package/Switch/types.ts +5 -3
  84. package/Tag/index.tsx +2 -4
  85. package/Text/index.tsx +27 -22
  86. package/Text/styles.ts +38 -0
  87. package/Text/types.ts +25 -13
  88. package/Text/utils.ts +1 -1
  89. package/Title/index.tsx +186 -0
  90. package/Title/styles.ts +79 -0
  91. package/Title/types.ts +20 -0
  92. package/code-scanner.js +143 -0
  93. package/index.ts +6 -0
  94. package/migrate_typo.js +56 -0
  95. package/package.json +14 -9
  96. package/tsconfig.json +24 -0
  97. package/verify.js +47 -0
  98. package/Application/BottomTab.tsx +0 -52
  99. package/Application/NavigationButton.tsx +0 -54
  100. package/Assets/header-background.png +0 -0
@@ -0,0 +1,439 @@
1
+ import {BottomTabBarProps} from '@react-navigation/bottom-tabs';
2
+ import {LabelPosition} from '@react-navigation/bottom-tabs/src/types';
3
+ import BottomTabBarHeightCallbackContext from '@react-navigation/bottom-tabs/src/utils/BottomTabBarHeightCallbackContext';
4
+ import BottomTabBarItem from '@react-navigation/bottom-tabs/src/views/BottomTabItem';
5
+ import {
6
+ CommonActions,
7
+ NavigationContext,
8
+ NavigationRouteContext,
9
+ ParamListBase,
10
+ TabNavigationState,
11
+ useLinkBuilder,
12
+ useTheme,
13
+ } from '@react-navigation/native';
14
+ import React, {useCallback} from 'react';
15
+ import {
16
+ Animated,
17
+ LayoutChangeEvent,
18
+ Platform,
19
+ StyleProp,
20
+ StyleSheet,
21
+ TouchableOpacity,
22
+ useWindowDimensions,
23
+ View,
24
+ ViewStyle,
25
+ } from 'react-native';
26
+ import {EdgeInsets, useSafeAreaInsets} from 'react-native-safe-area-context';
27
+ import {Radius} from '../../Consts';
28
+ import {Icon} from '../../Icon';
29
+ import {Text} from '../../Text';
30
+ import {FloatingButtonProps} from '../types';
31
+
32
+ type Props = BottomTabBarProps & {
33
+ activeTintColor?: string;
34
+ inactiveTintColor?: string;
35
+ floatingButton?: FloatingButtonProps;
36
+ accessibilityLabel?: string;
37
+ };
38
+
39
+ type Options = {
40
+ state: TabNavigationState<ParamListBase>;
41
+ layout: {height: number; width: number};
42
+ dimensions: {height: number; width: number};
43
+ tabStyle: StyleProp<ViewStyle>;
44
+ labelPosition: LabelPosition | undefined;
45
+ adaptive: boolean | undefined;
46
+ };
47
+
48
+ const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
49
+
50
+ const shouldUseHorizontalLabels = ({
51
+ state,
52
+ layout,
53
+ dimensions,
54
+ adaptive = true,
55
+ labelPosition,
56
+ tabStyle,
57
+ }: Options) => {
58
+ if (labelPosition) {
59
+ return labelPosition === 'beside-icon';
60
+ }
61
+
62
+ if (!adaptive) {
63
+ return false;
64
+ }
65
+
66
+ if (layout.width >= 768) {
67
+ // Screen size matches a tablet
68
+ let maxTabItemWidth = DEFAULT_MAX_TAB_ITEM_WIDTH;
69
+
70
+ const flattenedStyle = StyleSheet.flatten(tabStyle);
71
+
72
+ if (flattenedStyle) {
73
+ if (typeof flattenedStyle.width === 'number') {
74
+ maxTabItemWidth = flattenedStyle.width;
75
+ } else if (typeof flattenedStyle.maxWidth === 'number') {
76
+ maxTabItemWidth = flattenedStyle.maxWidth;
77
+ }
78
+ }
79
+
80
+ return state.routes.length * maxTabItemWidth <= layout.width;
81
+ } else {
82
+ return dimensions.width > dimensions.height;
83
+ }
84
+ };
85
+ const getPaddingBottom = (insets: EdgeInsets) =>
86
+ Math.max(insets.bottom - Platform.select({ios: 4, default: 0}), 0);
87
+
88
+ export default function BottomTabBar({
89
+ state,
90
+ navigation,
91
+ descriptors,
92
+ activeBackgroundColor,
93
+ activeTintColor,
94
+ adaptive,
95
+ allowFontScaling,
96
+ inactiveBackgroundColor,
97
+ inactiveTintColor,
98
+ keyboardHidesTabBar = false,
99
+ labelPosition,
100
+ labelStyle,
101
+ iconStyle,
102
+ safeAreaInsets,
103
+ showLabel,
104
+ style,
105
+ tabStyle,
106
+ floatingButton,
107
+ }: Props) {
108
+ const {routes} = state;
109
+ const dimensions = useWindowDimensions();
110
+ const isFloating = floatingButton?.icon && state.routes.length == 4;
111
+ const itemWidth = isFloating
112
+ ? dimensions.width / 5
113
+ : dimensions.width / state.routes.length;
114
+
115
+ const [layout, setLayout] = React.useState({
116
+ height: 0,
117
+ width: dimensions.width,
118
+ });
119
+ const buildLink = useLinkBuilder();
120
+ const {colors} = useTheme();
121
+
122
+ const hasHorizontalLabels = shouldUseHorizontalLabels({
123
+ state,
124
+ dimensions,
125
+ layout,
126
+ adaptive,
127
+ labelPosition,
128
+ tabStyle,
129
+ });
130
+ const focusedRoute = state.routes[state.index] as any;
131
+ const focusedDescriptor = descriptors[focusedRoute?.key] as any;
132
+ const focusedOptions = focusedDescriptor?.options;
133
+ const shouldShowTabBar =
134
+ focusedOptions?.tabBarVisible !== false && !keyboardHidesTabBar;
135
+ const [visible] = React.useState(
136
+ () => new Animated.Value(shouldShowTabBar ? 1 : 0),
137
+ );
138
+
139
+ const indicatorAnimated = React.useRef(new Animated.Value(0)).current;
140
+
141
+ const visibilityAnimationConfigRef = React.useRef(
142
+ focusedOptions?.tabBarVisibilityAnimationConfig,
143
+ );
144
+ const onHeightChange = React.useContext(BottomTabBarHeightCallbackContext);
145
+ const [isTabBarHidden, setIsTabBarHidden] = React.useState(!shouldShowTabBar);
146
+ React.useEffect(() => {
147
+ visibilityAnimationConfigRef.current =
148
+ focusedOptions?.tabBarVisibilityAnimationConfig;
149
+ });
150
+
151
+ const handleLayout = (e: LayoutChangeEvent) => {
152
+ const {height, width} = e.nativeEvent.layout;
153
+
154
+ onHeightChange?.(height);
155
+
156
+ setLayout(layout => {
157
+ if (height === layout.height && width === layout.width) {
158
+ return layout;
159
+ } else {
160
+ return {
161
+ height,
162
+ width,
163
+ };
164
+ }
165
+ });
166
+ };
167
+
168
+ React.useEffect(() => {
169
+ const visibilityAnimationConfig = visibilityAnimationConfigRef.current;
170
+
171
+ if (shouldShowTabBar) {
172
+ const animation =
173
+ visibilityAnimationConfig?.show?.animation === 'spring'
174
+ ? Animated.spring
175
+ : Animated.timing;
176
+
177
+ animation(visible, {
178
+ toValue: 1,
179
+ useNativeDriver: true,
180
+ duration: 250,
181
+ ...visibilityAnimationConfig?.show?.config,
182
+ }).start(({finished}) => {
183
+ if (finished) {
184
+ setIsTabBarHidden(false);
185
+ }
186
+ });
187
+ } else {
188
+ setIsTabBarHidden(true);
189
+
190
+ const animation =
191
+ visibilityAnimationConfig?.hide?.animation === 'spring'
192
+ ? Animated.spring
193
+ : Animated.timing;
194
+
195
+ animation(visible, {
196
+ toValue: 0,
197
+ useNativeDriver: true,
198
+ duration: 200,
199
+ ...visibilityAnimationConfig?.hide?.config,
200
+ }).start();
201
+ }
202
+ }, [visible, shouldShowTabBar]);
203
+ const defaultInsets = useSafeAreaInsets();
204
+
205
+ const insets = {
206
+ top: safeAreaInsets?.top ?? defaultInsets.top,
207
+ right: safeAreaInsets?.right ?? defaultInsets.right,
208
+ bottom: safeAreaInsets?.bottom ?? defaultInsets.bottom,
209
+ left: safeAreaInsets?.left ?? defaultInsets.left,
210
+ };
211
+ const paddingBottom = getPaddingBottom(insets);
212
+
213
+ const leftArr = routes.slice(0, 2);
214
+ const rightArr = routes.slice(2, routes.length);
215
+ const focusedTab = state?.routes[state.index]?.name || routes[0]?.params;
216
+
217
+ const renderTabItem = useCallback(
218
+ (data: any[]) => {
219
+ return data?.map((route, index) => {
220
+ const focused = route.params.name === focusedTab;
221
+ const {options} = descriptors[route?.key] as any;
222
+ const onPress = () => {
223
+ const event = navigation.emit({
224
+ type: 'tabPress',
225
+ target: route.key,
226
+ canPreventDefault: true,
227
+ });
228
+
229
+ if (!focused && !event.defaultPrevented) {
230
+ navigation.dispatch({
231
+ ...CommonActions.navigate(route.name),
232
+ target: state.key,
233
+ });
234
+ }
235
+ };
236
+
237
+ const onLongPress = () => {
238
+ navigation.emit({
239
+ type: 'tabLongPress',
240
+ target: route.key,
241
+ });
242
+ };
243
+
244
+ const label =
245
+ options.tabBarLabel !== undefined
246
+ ? options.tabBarLabel
247
+ : options.title !== undefined
248
+ ? options.title
249
+ : route.name;
250
+
251
+ const accessibilityLabel =
252
+ options.tabBarAccessibilityLabel !== undefined
253
+ ? options.tabBarAccessibilityLabel
254
+ : typeof label === 'string'
255
+ ? `${label}, tab, ${index + 1} of ${routes.length}`
256
+ : undefined;
257
+
258
+ return (
259
+ <NavigationContext.Provider
260
+ key={route.key}
261
+ value={(descriptors as any)[route.key].navigation}>
262
+ <NavigationRouteContext.Provider value={route}>
263
+ <BottomTabBarItem
264
+ route={route}
265
+ focused={focused}
266
+ horizontal={hasHorizontalLabels}
267
+ onPress={onPress}
268
+ onLongPress={onLongPress}
269
+ accessibilityLabel={accessibilityLabel}
270
+ to={buildLink(route.name, route.params)}
271
+ testID={options.tabBarTestID}
272
+ allowFontScaling={allowFontScaling}
273
+ activeTintColor={activeTintColor}
274
+ inactiveTintColor={inactiveTintColor}
275
+ activeBackgroundColor={activeBackgroundColor}
276
+ inactiveBackgroundColor={inactiveBackgroundColor}
277
+ button={options.tabBarButton}
278
+ icon={options.tabBarIcon}
279
+ badge={options.tabBarBadge}
280
+ badgeStyle={options.tabBarBadgeStyle}
281
+ label={label}
282
+ showLabel={showLabel}
283
+ labelStyle={labelStyle}
284
+ iconStyle={iconStyle}
285
+ style={tabStyle}
286
+ />
287
+ </NavigationRouteContext.Provider>
288
+ </NavigationContext.Provider>
289
+ );
290
+ });
291
+ },
292
+ [JSON.stringify(routes), state, descriptors, focusedTab],
293
+ );
294
+
295
+ const renderCenterComponent = useCallback(() => {
296
+ if (floatingButton?.icon && state.routes.length !== 4) {
297
+ console.warn(
298
+ "Can't render floating button with icon when routes length is not 4",
299
+ );
300
+ return null;
301
+ }
302
+ const renderFloatingButton = () => {
303
+ if (typeof floatingButton?.icon == 'string') {
304
+ return <Icon source={floatingButton?.icon} size={32} color={'white'} />;
305
+ }
306
+ return floatingButton?.icon;
307
+ };
308
+
309
+ return (
310
+ <View style={{flex: 1}}>
311
+ <TouchableOpacity
312
+ onPress={floatingButton?.onPress}
313
+ style={styles.floatingContainer}>
314
+ <View
315
+ style={{
316
+ ...styles.floatingContent,
317
+ backgroundColor: activeTintColor ?? colors.primary,
318
+ }}>
319
+ {renderFloatingButton()}
320
+ </View>
321
+ <View
322
+ style={{
323
+ top: -6,
324
+ backgroundColor: activeTintColor ?? colors.primary,
325
+ borderRadius: Radius.XL,
326
+ paddingHorizontal: 6,
327
+ }}>
328
+ <Text
329
+ numberOfLines={1}
330
+ typography={'description_xs_regular'}
331
+ color={'white'}>
332
+ {floatingButton?.label}
333
+ </Text>
334
+ </View>
335
+ </TouchableOpacity>
336
+ </View>
337
+ );
338
+ }, [floatingButton]);
339
+
340
+ React.useEffect(() => {
341
+ Animated.timing(indicatorAnimated, {
342
+ toValue:
343
+ isFloating && state.index > 1
344
+ ? itemWidth * (state.index + 1)
345
+ : itemWidth * state.index,
346
+ useNativeDriver: false,
347
+ duration: 200,
348
+ }).start();
349
+ }, [state.index, itemWidth, indicatorAnimated, isFloating]);
350
+
351
+ return (
352
+ <Animated.View
353
+ style={[
354
+ styles.tabBar,
355
+ {
356
+ backgroundColor: colors.card,
357
+ borderTopColor: colors.border,
358
+ },
359
+ {
360
+ transform: [
361
+ {
362
+ translateY: visible.interpolate({
363
+ inputRange: [0, 1],
364
+ outputRange: [
365
+ layout.height + paddingBottom + StyleSheet.hairlineWidth,
366
+ 0,
367
+ ],
368
+ }),
369
+ },
370
+ ],
371
+ position: isTabBarHidden ? 'absolute' : (null as any),
372
+ },
373
+ {
374
+ paddingBottom: paddingBottom,
375
+ paddingHorizontal: Math.max(insets.left, insets.right),
376
+ },
377
+ style,
378
+ ]}
379
+ pointerEvents={isTabBarHidden ? 'none' : 'auto'}
380
+ onLayout={handleLayout}>
381
+ <View style={styles.content}>
382
+ {isFloating && floatingButton?.container}
383
+ <Animated.View
384
+ style={{
385
+ width: itemWidth,
386
+ position: 'absolute',
387
+ top: 0,
388
+ transform: [{translateX: indicatorAnimated}],
389
+ }}>
390
+ <View
391
+ style={[
392
+ styles.indicator,
393
+ {backgroundColor: activeTintColor ?? colors.primary},
394
+ ]}
395
+ />
396
+ </Animated.View>
397
+ {isFloating ? renderTabItem(leftArr) : renderTabItem(routes)}
398
+ {isFloating && renderCenterComponent()}
399
+ {isFloating && renderTabItem(rightArr)}
400
+ </View>
401
+ </Animated.View>
402
+ );
403
+ }
404
+
405
+ const styles = StyleSheet.create({
406
+ content: {
407
+ flex: 1,
408
+ flexDirection: 'row',
409
+ },
410
+ tabBar: {
411
+ left: 0,
412
+ right: 0,
413
+ bottom: 0,
414
+ borderTopWidth: StyleSheet.hairlineWidth,
415
+ elevation: 8,
416
+ },
417
+ floatingContainer: {
418
+ position: 'absolute',
419
+ alignItems: 'center',
420
+ left: 0,
421
+ right: 0,
422
+ bottom: Platform.OS === 'ios' ? -6 : 0,
423
+ },
424
+ floatingContent: {
425
+ alignItems: 'center',
426
+ justifyContent: 'center',
427
+ height: 48,
428
+ width: 48,
429
+ borderRadius: 24,
430
+ top: -10,
431
+ },
432
+ indicator: {
433
+ height: 2,
434
+ width: 44,
435
+ alignSelf: 'center',
436
+ borderBottomLeftRadius: 1,
437
+ borderBottomRightRadius: 1,
438
+ },
439
+ });
@@ -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;