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