@momo-kits/foundation 0.81.1-beta.6 → 0.81.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 (77) 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 +274 -211
  5. package/Application/ModalScreen.tsx +10 -226
  6. package/Application/Navigation.ts +17 -6
  7. package/Application/NavigationContainer.tsx +66 -65
  8. package/Application/Navigator.ts +106 -53
  9. package/Application/StackScreen.tsx +123 -28
  10. package/Application/index.ts +15 -9
  11. package/Application/types.ts +55 -31
  12. package/Application/utils.tsx +36 -6
  13. package/Assets/icon.json +83 -5
  14. package/Assets/icon_bank.json +506 -0
  15. package/Assets/language.json +3 -1
  16. package/Badge/Badge.tsx +56 -0
  17. package/Badge/BadgeDot.tsx +11 -0
  18. package/Badge/BadgeRibbon.tsx +125 -0
  19. package/Badge/Shape.tsx +29 -0
  20. package/Badge/index.tsx +7 -0
  21. package/Badge/styles.ts +58 -0
  22. package/Badge/types.ts +63 -0
  23. package/Button/index.tsx +60 -24
  24. package/Button/styles.ts +19 -0
  25. package/CheckBox/index.tsx +37 -27
  26. package/CheckBox/types.ts +5 -3
  27. package/Consts/colors+spacing+radius.ts +17 -3
  28. package/Icon/index.tsx +14 -9
  29. package/Icon/types.ts +4 -3
  30. package/IconButton/index.tsx +24 -15
  31. package/Image/index.tsx +61 -55
  32. package/Image/styles.ts +1 -9
  33. package/Image/types.ts +5 -1
  34. package/Input/Input.tsx +102 -25
  35. package/Input/InputDropDown.tsx +32 -23
  36. package/Input/InputMoney.tsx +67 -18
  37. package/Input/InputOTP.tsx +194 -148
  38. package/Input/InputSearch.tsx +72 -36
  39. package/Input/InputTextArea.tsx +33 -18
  40. package/Input/common.tsx +25 -16
  41. package/Input/index.tsx +62 -16
  42. package/Input/styles.ts +5 -8
  43. package/Layout/Card.tsx +20 -11
  44. package/Layout/FloatingButton.tsx +168 -0
  45. package/Layout/GridSystem.tsx +1 -2
  46. package/Layout/Item.tsx +0 -1
  47. package/Layout/ItemList.tsx +39 -40
  48. package/Layout/ItemSectionList.tsx +39 -0
  49. package/Layout/Screen.tsx +151 -65
  50. package/Layout/Section.tsx +17 -19
  51. package/Layout/index.ts +2 -1
  52. package/Layout/styles.ts +20 -15
  53. package/Layout/types.ts +2 -5
  54. package/Layout/utils.ts +2 -2
  55. package/Pagination/PaginationNumber.tsx +1 -1
  56. package/Pagination/PaginationScroll.tsx +0 -1
  57. package/Popup/PopupNotify.tsx +105 -37
  58. package/Popup/PopupPromotion.tsx +44 -9
  59. package/Popup/types.ts +12 -9
  60. package/Radio/index.tsx +35 -21
  61. package/Radio/types.ts +5 -3
  62. package/Skeleton/index.tsx +1 -1
  63. package/Switch/index.tsx +32 -19
  64. package/Switch/types.ts +5 -3
  65. package/Tag/index.tsx +2 -4
  66. package/Text/index.tsx +26 -6
  67. package/Text/styles.ts +38 -0
  68. package/Text/types.ts +25 -13
  69. package/Title/index.tsx +172 -63
  70. package/Title/styles.ts +48 -15
  71. package/Title/types.ts +16 -47
  72. package/code-scanner.js +131 -39
  73. package/index.ts +9 -0
  74. package/migrate_typo.js +56 -0
  75. package/package.json +8 -8
  76. package/verify.js +24 -6
  77. package/Application/BottomTab.tsx +0 -65
@@ -1,37 +1,19 @@
1
- import React, {useContext, useEffect, useMemo, useRef, useState} from 'react';
1
+ import React, {useContext, useEffect, useRef} from 'react';
2
2
  import {
3
- Dimensions,
4
- Keyboard,
5
3
  KeyboardAvoidingView,
6
4
  Platform,
7
5
  Pressable,
8
6
  StyleSheet,
9
7
  View,
10
8
  } from 'react-native';
11
- import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
12
- import {
13
- BottomSheetBackdrop,
14
- BottomSheetModal,
15
- BottomSheetView,
16
- } from '@gorhom/bottom-sheet';
9
+
10
+ import {ApplicationContext} from './index';
11
+ import {Styles} from '../Consts';
17
12
  import Navigation from './Navigation';
18
- import {BottomSheetParams, ModalParams} from './types';
19
- import {Radius, Spacing, Styles} from '../Consts';
20
- import {
21
- ApplicationContext,
22
- HeaderRightAction,
23
- NavigationButton,
24
- NavigationContainer,
25
- } from './index';
26
- import {HeaderBackground, HeaderLeft, HeaderTitle} from './Components';
13
+ import {ModalParams} from './types';
14
+ import BottomSheet from './BottomSheet';
27
15
 
28
16
  const ModalScreen: React.FC<any> = props => {
29
- useEffect(() => {
30
- return () => {
31
- props.route.params?.onDismiss?.();
32
- };
33
- }, []);
34
-
35
17
  if (props.route?.params?.isBottomSheet) {
36
18
  return <BottomSheet {...props} />;
37
19
  }
@@ -39,47 +21,19 @@ const ModalScreen: React.FC<any> = props => {
39
21
  };
40
22
 
41
23
  const Modal: React.FC<ModalParams> = props => {
42
- const TRIGGER_ID = '111012100000000000';
43
- const {theme, navigator, appInfo} = useContext(ApplicationContext);
44
- const {screen, barrierDismissible, modalName}: ModalParams =
45
- props.route.params;
24
+ const {theme, navigator} = useContext(ApplicationContext);
25
+ const {screen, barrierDismissible} = props.route.params;
46
26
  const Component = useRef(screen).current;
47
27
  const navigation = new Navigation(props.navigation, theme);
48
28
  const params = {
49
29
  ...props.route.params,
50
30
  navigation,
51
31
  };
52
-
53
32
  delete params.screen;
54
33
 
55
- const navigationRoutes = props.navigation.getState()?.routes || [];
56
- const routesLength = navigationRoutes.length;
57
- let screen_name = navigationRoutes?.[0]?.params?.screen?.name;
58
- if (routesLength > 1) {
59
- screen_name = navigationRoutes[routesLength - 2]?.params?.screen?.name;
60
- }
61
- const error_code = (screen as Function)?.()?.props?.information;
62
-
63
34
  useEffect(() => {
64
- navigator?.maxApi?.trackEvent('service_component_displayed', {
65
- ...appInfo,
66
- screen_name,
67
- trigger_id: TRIGGER_ID,
68
- component_type: 'popup',
69
- component_name: modalName,
70
- error_code,
71
- });
72
-
73
35
  return () => {
74
- navigator?.maxApi?.trackEvent('service_icon_clicked', {
75
- ...appInfo,
76
- screen_name,
77
- trigger_id: '111154100000000001',
78
- component_type: 'popup',
79
- component_name: modalName,
80
- error_code,
81
- icon_name: 'close',
82
- });
36
+ props.route.params?.onDismiss?.();
83
37
  };
84
38
  }, []);
85
39
 
@@ -104,7 +58,7 @@ const Modal: React.FC<ModalParams> = props => {
104
58
  style={styles.modalSpaceVertical}
105
59
  onPress={() => onDismiss()}
106
60
  />
107
- <View style={styles.modalContent} accessibilityLabel={'Modal'}>
61
+ <View style={styles.modalContent}>
108
62
  <Component {...params} />
109
63
  </View>
110
64
  <Pressable
@@ -121,157 +75,6 @@ const Modal: React.FC<ModalParams> = props => {
121
75
  );
122
76
  };
123
77
 
124
- const BottomSheet: React.FC<BottomSheetParams> = props => {
125
- const insets = useSafeAreaInsets();
126
- const {theme, navigator, appInfo} = useContext(ApplicationContext);
127
- const [keyboardSnap, setKeyboardSnap] = useState(0);
128
- const {screen, options, snapPoint}: BottomSheetParams = props.route.params;
129
- const Component = useRef(screen).current;
130
- const navigation = new Navigation(props.navigation, theme);
131
- const params = {
132
- ...props.route.params,
133
- navigation,
134
- };
135
-
136
- delete params.screen;
137
-
138
- const snapPoints = useMemo(() => {
139
- if (snapPoint) {
140
- const current = parseInt(snapPoint) + keyboardSnap * 100;
141
- return [`${current}%`];
142
- }
143
- return ['50%', '70%', '90%'];
144
- }, [keyboardSnap]);
145
-
146
- const bottomSheetRef = useRef<any>(null);
147
- const mountedRef = useRef(true);
148
-
149
- let backgroundColor = theme.colors.background.default;
150
- let bottomInset = keyboardSnap * Dimensions.get('window').height;
151
- if (bottomInset > 16) {
152
- bottomInset -= 16;
153
- }
154
- if (options?.surface) {
155
- backgroundColor = theme.colors.background.surface;
156
- }
157
-
158
- useEffect(() => {
159
- const keyboardDidShow = Keyboard.addListener('keyboardDidShow', e => {
160
- setKeyboardSnap(
161
- e.endCoordinates.height / Dimensions.get('window').height,
162
- );
163
- bottomSheetRef.current?.expand();
164
- });
165
-
166
- const keyboardDidHide = Keyboard.addListener('keyboardDidHide', () => {
167
- setKeyboardSnap(0);
168
- });
169
-
170
- bottomSheetRef.current?.present();
171
- return () => {
172
- mountedRef.current = false;
173
- keyboardDidShow.remove();
174
- keyboardDidHide.remove();
175
- };
176
- }, []);
177
-
178
- const backdropComponent = (backdropProps: any) => (
179
- <BottomSheetBackdrop
180
- disappearsOnIndex={-1}
181
- appearsOnIndex={0}
182
- {...backdropProps}
183
- />
184
- );
185
-
186
- return (
187
- <SafeAreaView style={Styles.flex}>
188
- <BottomSheetModal
189
- ref={bottomSheetRef}
190
- snapPoints={snapPoints}
191
- onDismiss={() => {
192
- if (mountedRef.current) {
193
- navigator?.pop();
194
- }
195
- }}
196
- bottomInset={Platform.OS === 'ios' ? bottomInset : 0}
197
- handleComponent={null}
198
- backdropComponent={backdropComponent}>
199
- <BottomSheetView accessibilityLabel={'BottomSheet'}>
200
- <View
201
- style={[
202
- styles.sheetContainer,
203
- {
204
- backgroundColor,
205
- paddingBottom: Math.min(insets.bottom, 20) + Spacing.S,
206
- },
207
- ]}>
208
- <View style={styles.indicatorContainer}>
209
- <View
210
- style={[
211
- styles.indicator,
212
- {backgroundColor: theme.colors.text.disable},
213
- ]}
214
- />
215
- </View>
216
- <NavigationContainer
217
- appInfo={appInfo}
218
- maxApi={navigator?.maxApi}
219
- theme={{
220
- ...theme,
221
- assets: {...theme.assets, headerBackground: undefined},
222
- }}
223
- screen={props => <Component {...props} {...params} />}
224
- options={{
225
- ...options,
226
- ...{
227
- headerLeft: (props: any) => {
228
- if (props.canGoBack) {
229
- return (
230
- <HeaderLeft
231
- {...props}
232
- useBorder={false}
233
- backgroundColor="transparent"
234
- accessibilityLabel={'BottomSheet/'}
235
- />
236
- );
237
- }
238
- },
239
- headerTitle: (props: any) => {
240
- return (
241
- <HeaderTitle
242
- {...props}
243
- accessibilityLabel={'BottomSheet/'}
244
- />
245
- );
246
- },
247
- headerTintColor: theme.colors.text.default,
248
- headerBackground: () => (
249
- <HeaderBackground backgroundColor={backgroundColor} />
250
- ),
251
- headerTransparent: false,
252
- },
253
- headerTitleAlign: 'center',
254
- headerRight: props => (
255
- <HeaderRightAction>
256
- <NavigationButton
257
- {...props}
258
- icon="24_navigation_close"
259
- backgroundColor="transparent"
260
- useBorder={false}
261
- onPress={bottomSheetRef.current?.dismiss}
262
- accessibilityLabel={'BottomSheet/Close'}
263
- />
264
- </HeaderRightAction>
265
- ),
266
- }}
267
- />
268
- </View>
269
- </BottomSheetView>
270
- </BottomSheetModal>
271
- </SafeAreaView>
272
- );
273
- };
274
-
275
78
  const styles = StyleSheet.create({
276
79
  container: {flex: 1, flexDirection: 'row'},
277
80
  modalContent: {
@@ -289,25 +92,6 @@ const styles = StyleSheet.create({
289
92
  flex: 1,
290
93
  minHeight: '10%',
291
94
  },
292
- sheetContainer: {
293
- height: '100%',
294
- width: '100%',
295
- borderTopLeftRadius: Radius.M,
296
- borderTopRightRadius: Radius.M,
297
- overflow: 'hidden',
298
- },
299
- indicatorContainer: {
300
- width: '100%',
301
- paddingTop: Spacing.S,
302
- paddingBottom: Spacing.XS,
303
- alignItems: 'center',
304
- justifyContent: 'center',
305
- },
306
- indicator: {
307
- width: 40,
308
- height: 4,
309
- borderRadius: Radius.S,
310
- },
311
95
  });
312
96
 
313
97
  export default ModalScreen;
@@ -6,14 +6,18 @@ import {getOptions} from './utils';
6
6
  import {HeaderToolkitAction} from './Components';
7
7
 
8
8
  class Navigation {
9
- private instance: NavigationProp<any>;
10
- private readonly theme: Theme;
9
+ instance: NavigationProp<any>;
10
+ readonly theme: Theme;
11
11
 
12
12
  constructor(instance: any, theme: Theme) {
13
13
  this.instance = instance;
14
14
  this.theme = theme;
15
15
  }
16
16
 
17
+ /**
18
+ * navigation options filter by design system rule
19
+ * @param params
20
+ */
17
21
  private filterParams = (params: NavigationOptions) => {
18
22
  if (params.headerRight) {
19
23
  const headerRight = params.headerRight?.({}) as React.ReactElement;
@@ -24,14 +28,21 @@ class Navigation {
24
28
  );
25
29
  }
26
30
  }
31
+
32
+ if (params.headerLeft) {
33
+ console.warn('headerLeft not allow override render by design system!');
34
+ delete params.headerLeft;
35
+ }
36
+
27
37
  return params;
28
38
  };
29
39
 
40
+ /**
41
+ * navigation setOptions support props NavigationOptions base on react-navigation options
42
+ * @param params
43
+ */
30
44
  setOptions = (params: NavigationOptions) => {
31
- if (__DEV__) {
32
- params = this.filterParams(params);
33
- }
34
- params = getOptions(params, this.theme);
45
+ params = getOptions(this.filterParams(params), this.theme);
35
46
  this.instance.setOptions(params);
36
47
  };
37
48
  }
@@ -1,18 +1,17 @@
1
1
  import React, {useEffect, useRef, useState} from 'react';
2
- import {BottomSheetModalProvider} from '@gorhom/bottom-sheet';
3
2
  import {SafeAreaProvider} from 'react-native-safe-area-context';
4
3
  import {
5
4
  NavigationContainer as ReactNavigationContainer,
6
5
  NavigationContainerRef,
7
6
  } from '@react-navigation/native';
8
7
  import {createStackNavigator} from '@react-navigation/stack';
8
+ import {DeviceEventEmitter} from 'react-native';
9
9
  import StackScreen from './StackScreen';
10
10
  import ModalScreen from './ModalScreen';
11
11
  import Navigator from './Navigator';
12
12
  import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
13
13
  import {LocalizationObject, NavigationContainerProps} from './types';
14
14
  import {ApplicationContext} from './index';
15
- import {DeviceEventEmitter} from 'react-native';
16
15
  import kitLocalization from '../Assets/language.json';
17
16
 
18
17
  const Stack = createStackNavigator();
@@ -23,13 +22,18 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
23
22
  options,
24
23
  maxApi,
25
24
  localization,
26
- appInfo,
25
+ initialParams,
27
26
  }) => {
28
- const navigationRef = React.useRef<NavigationContainerRef>(null);
29
- const navigator = useRef(new Navigator(navigationRef));
27
+ const navigationRef = useRef<NavigationContainerRef>(null);
28
+ const isReady = useRef(false);
29
+ const navigator = useRef(new Navigator(navigationRef, isReady));
30
30
  const [showGrid, setShowGrid] = useState(false);
31
- const [language, setLanguage] = useState<'vi' | 'en'>('vi');
31
+ const config = useRef<any>();
32
32
 
33
+ /**
34
+ * handle mini language & listen change
35
+ * engine only shake to enable grid view
36
+ */
33
37
  useEffect(() => {
34
38
  const subscription = DeviceEventEmitter.addListener(
35
39
  'onChangeGrid',
@@ -37,26 +41,23 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
37
41
  setShowGrid(!!enable);
38
42
  },
39
43
  );
40
- return () => {
41
- subscription.remove();
42
- };
43
- }, []);
44
44
 
45
- useEffect(() => {
46
- maxApi?.getLanguage?.((lang: 'vi' | 'en') => {
47
- setLanguage(lang);
48
- });
49
- const listener = maxApi?.observer?.('language', (lang: 'vi' | 'en') => {
50
- setLanguage(lang);
51
- });
52
45
  return () => {
53
- listener?.();
46
+ subscription?.remove?.();
54
47
  };
55
48
  }, []);
56
49
 
50
+ /**
51
+ * inject data for navigator
52
+ */
57
53
  navigator.current.maxApi = maxApi;
58
54
 
55
+ /**
56
+ * translate
57
+ * @param key
58
+ */
59
59
  const translate = (key: string) => {
60
+ const language: 'vi' | 'en' = 'vi';
60
61
  const mergedLocalization: LocalizationObject = {
61
62
  vi: {...localization?.vi, ...kitLocalization.vi},
62
63
  en: {...localization?.en, ...kitLocalization.en},
@@ -66,53 +67,53 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
66
67
 
67
68
  return (
68
69
  <SafeAreaProvider>
69
- <BottomSheetModalProvider>
70
- <ApplicationContext.Provider
71
- value={{
72
- theme,
73
- navigator: navigator.current,
74
- showGrid,
75
- language,
76
- translate,
77
- appInfo,
78
- }}>
79
- <ReactNavigationContainer
80
- theme={{
81
- ...theme,
82
- colors: {
83
- ...theme.colors,
84
- background: theme.colors.background.default,
85
- card: theme.colors.background.surface,
86
- text: theme.colors.text.default,
87
- border: theme.colors.border.default,
88
- notification: theme.colors.error.primary,
89
- },
90
- }}
91
- ref={navigator.current?.ref}
92
- independent={true}>
93
- <Stack.Navigator initialRouteName="Stack" headerMode="screen">
94
- <Stack.Screen
95
- name="Stack"
96
- component={StackScreen}
97
- initialParams={{screen}}
98
- options={{...getStackOptions(), ...options}}
99
- />
100
- <Stack.Screen
101
- name="Dialog"
102
- component={StackScreen}
103
- options={getDialogOptions()}
104
- initialParams={{screen}}
105
- />
106
- <Stack.Screen
107
- name="Modal"
108
- component={ModalScreen}
109
- options={getModalOptions()}
110
- initialParams={{screen}}
111
- />
112
- </Stack.Navigator>
113
- </ReactNavigationContainer>
114
- </ApplicationContext.Provider>
115
- </BottomSheetModalProvider>
70
+ <ApplicationContext.Provider
71
+ value={{
72
+ navigator: navigator.current,
73
+ config: config.current,
74
+ theme,
75
+ showGrid,
76
+ translate,
77
+ }}>
78
+ <ReactNavigationContainer
79
+ theme={{
80
+ ...theme,
81
+ colors: {
82
+ ...theme.colors,
83
+ background: theme.colors.background.default,
84
+ card: theme.colors.background.surface,
85
+ text: theme.colors.text.default,
86
+ border: theme.colors.border.default,
87
+ notification: theme.colors.error.primary,
88
+ },
89
+ }}
90
+ ref={navigator.current?.ref}
91
+ onReady={() => {
92
+ isReady.current = true;
93
+ }}
94
+ independent={true}>
95
+ <Stack.Navigator initialRouteName="Stack" headerMode="screen">
96
+ <Stack.Screen
97
+ name="Stack"
98
+ component={StackScreen}
99
+ initialParams={{screen, initialParams}}
100
+ options={{...getStackOptions(), ...options}}
101
+ />
102
+ <Stack.Screen
103
+ name="Dialog"
104
+ component={StackScreen}
105
+ options={getDialogOptions()}
106
+ initialParams={{screen}}
107
+ />
108
+ <Stack.Screen
109
+ name="Modal"
110
+ component={ModalScreen}
111
+ options={getModalOptions()}
112
+ initialParams={{screen}}
113
+ />
114
+ </Stack.Navigator>
115
+ </ReactNavigationContainer>
116
+ </ApplicationContext.Provider>
116
117
  </SafeAreaProvider>
117
118
  );
118
119
  };