@momo-kits/foundation 0.112.1-rn76.7 → 0.113.0-optimize.1

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.
@@ -16,7 +16,7 @@ import {BottomSheetParams} from './types';
16
16
  import {Colors, Radius, Spacing, Styles} from '../Consts';
17
17
  import {Text} from '../Text';
18
18
  import {Icon} from '../Icon';
19
- import {useHeaderHeight} from '@react-navigation/elements';
19
+ import {useHeaderHeight} from '@react-navigation/stack';
20
20
  import Animated, {Easing, Extrapolate} from 'react-native-reanimated';
21
21
 
22
22
  const BottomSheet: React.FC<BottomSheetParams> = props => {
@@ -82,7 +82,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
82
82
  }).start();
83
83
  }
84
84
  },
85
- }),
85
+ })
86
86
  ).current;
87
87
 
88
88
  let Container: any = View;
@@ -1,11 +1,7 @@
1
1
  import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
2
- import {
3
- NavigationContainer,
4
- NavigationIndependentTree,
5
- useFocusEffect,
6
- } from '@react-navigation/native';
2
+ import {NavigationContainer, useFocusEffect} from '@react-navigation/native';
7
3
  import {createStackNavigator} from '@react-navigation/stack';
8
- import React, {useContext, useEffect, useRef} from 'react';
4
+ import React, {useContext, useEffect} from 'react';
9
5
  import {Animated, Platform, StatusBar} from 'react-native';
10
6
  import {useSafeAreaInsets} from 'react-native-safe-area-context';
11
7
  import {Colors} from '../../Consts';
@@ -15,7 +11,7 @@ import {ApplicationContext} from '../index';
15
11
  import StackScreen from '../StackScreen';
16
12
  import {BottomTabProps} from '../types';
17
13
  import {getOptions, getStackOptions} from '../utils';
18
- // import BottomTabBar from './BottomTabBar';
14
+ import BottomTabBar from './BottomTabBar';
19
15
 
20
16
  const Tab = createBottomTabNavigator();
21
17
  const Stack = createStackNavigator();
@@ -25,19 +21,18 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
25
21
 
26
22
  const opacityValue = 0.3;
27
23
  const scaleValue = 0.97;
28
-
29
- const opacity = useRef(new Animated.Value(opacityValue));
30
- const scale = useRef(new Animated.Value(scaleValue));
24
+ const opacity = new Animated.Value(opacityValue);
25
+ const scale = new Animated.Value(scaleValue);
31
26
 
32
27
  useFocusEffect(
33
28
  React.useCallback(() => {
34
29
  Animated.parallel([
35
- Animated.timing(opacity.current, {
30
+ Animated.timing(opacity, {
36
31
  toValue: 1,
37
32
  duration: 200,
38
33
  useNativeDriver: true,
39
34
  }),
40
- Animated.timing(scale.current, {
35
+ Animated.timing(scale, {
41
36
  toValue: 1,
42
37
  duration: 200,
43
38
  useNativeDriver: true,
@@ -46,12 +41,12 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
46
41
  return () => {
47
42
  if (navigation.getState().index !== route?.params.index) {
48
43
  Animated.parallel([
49
- Animated.timing(opacity.current, {
44
+ Animated.timing(opacity, {
50
45
  toValue: opacityValue,
51
46
  duration: 200,
52
47
  useNativeDriver: true,
53
48
  }),
54
- Animated.timing(scale.current, {
49
+ Animated.timing(scale, {
55
50
  toValue: scaleValue,
56
51
  duration: 200,
57
52
  useNativeDriver: true,
@@ -59,7 +54,7 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
59
54
  ]).start();
60
55
  }
61
56
  };
62
- }, [navigation, route?.params.index]),
57
+ }, [navigation])
63
58
  );
64
59
 
65
60
  let stackOptions = {};
@@ -69,12 +64,7 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
69
64
 
70
65
  if (nested) {
71
66
  return (
72
- <Animated.View
73
- style={{
74
- flex: 1,
75
- opacity: opacity.current,
76
- transform: [{scale: scale.current}],
77
- }}>
67
+ <Animated.View style={{flex: 1, opacity, transform: [{scale}]}}>
78
68
  <Stack.Navigator>
79
69
  <Stack.Screen
80
70
  name="Stack"
@@ -92,28 +82,21 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
92
82
  }
93
83
 
94
84
  return (
95
- <Animated.View
96
- style={{
97
- flex: 1,
98
- opacity: opacity.current,
99
- transform: [{scale: scale.current}],
100
- }}>
101
- <NavigationIndependentTree>
102
- <NavigationContainer>
103
- <Stack.Navigator>
104
- <Stack.Screen
105
- name="Stack"
106
- component={StackScreen}
107
- initialParams={{
108
- screen,
109
- options: stackOptions,
110
- initialParams,
111
- }}
112
- options={{...getStackOptions(), ...options}}
113
- />
114
- </Stack.Navigator>
115
- </NavigationContainer>
116
- </NavigationIndependentTree>
85
+ <Animated.View style={{flex: 1, opacity, transform: [{scale}]}}>
86
+ <NavigationContainer independent={true}>
87
+ <Stack.Navigator>
88
+ <Stack.Screen
89
+ name="Stack"
90
+ component={StackScreen}
91
+ initialParams={{
92
+ screen,
93
+ options: stackOptions,
94
+ initialParams,
95
+ }}
96
+ options={{...getStackOptions(), ...options}}
97
+ />
98
+ </Stack.Navigator>
99
+ </NavigationContainer>
117
100
  </Animated.View>
118
101
  );
119
102
  };
@@ -126,7 +109,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
126
109
  initialRouteName,
127
110
  floatingButton,
128
111
  }) => {
129
- const {theme} = useContext(ApplicationContext);
112
+ const {theme, navigator} = useContext(ApplicationContext);
130
113
  const insets = useSafeAreaInsets();
131
114
 
132
115
  useEffect(() => {
@@ -135,7 +118,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
135
118
  headerTransparent: true,
136
119
  headerBackground: undefined,
137
120
  });
138
- }, [navigation]);
121
+ }, []);
139
122
 
140
123
  const handler: {
141
124
  tabPress?: (e: any) => void;
@@ -144,6 +127,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
144
127
  state?: (e: any) => void;
145
128
  } = {
146
129
  tabPress: e => {
130
+ navigator?.maxApi?.triggerEventVibration?.('light');
147
131
  listeners?.tabPress?.(e);
148
132
  },
149
133
  focus: e => {
@@ -159,13 +143,13 @@ const BottomTab: React.FC<BottomTabProps> = ({
159
143
  <Tab.Navigator
160
144
  initialRouteName={initialRouteName}
161
145
  backBehavior={'firstRoute'}
162
- // tabBar={props => (
163
- // <BottomTabBar
164
- // {...props}
165
- // floatingButton={floatingButton}
166
- // inactiveTintColor={theme.colors.text.hint}
167
- // />
168
- // )}
146
+ tabBar={props => (
147
+ <BottomTabBar
148
+ {...props}
149
+ floatingButton={floatingButton}
150
+ inactiveTintColor={theme.colors.text.hint}
151
+ />
152
+ )}
169
153
  tabBarOptions={{
170
154
  style: {
171
155
  height: 64 + Math.min(insets.bottom, 21),
@@ -1,10 +1,8 @@
1
1
  import React, {useContext, useEffect, useRef, useState} from 'react';
2
- import type {NavigationState} from '@react-navigation/routers';
3
2
  import {SafeAreaProvider} from 'react-native-safe-area-context';
4
3
  import {
5
4
  NavigationContainer as ReactNavigationContainer,
6
5
  NavigationContainerRef,
7
- NavigationIndependentTree,
8
6
  } from '@react-navigation/native';
9
7
  import {
10
8
  createStackNavigator,
@@ -18,7 +16,7 @@ import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
18
16
  import {NavigationContainerProps} from './types';
19
17
  import {ApplicationContext, MiniAppContext} from './index';
20
18
  import Localize from './Localize';
21
- import {Configs, defaultTheme} from '../Consts';
19
+ import {defaultTheme} from '../Consts';
22
20
 
23
21
  const Stack = createStackNavigator();
24
22
 
@@ -31,13 +29,23 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
31
29
  localize = new Localize({vi: {}, en: {}}),
32
30
  }) => {
33
31
  const context = useContext<any>(MiniAppContext);
34
- const navigationRef = useRef<NavigationContainerRef<any>>(null);
32
+ const navigationRef = useRef<NavigationContainerRef>(null);
35
33
  const routes = useRef<any>();
36
34
  const isReady = useRef(false);
37
35
  const navigator = useRef(new Navigator(navigationRef, isReady));
38
36
  const [showGrid, setShowGrid] = useState(false);
39
37
  const [currentContext, setCurrentContext] = useState({});
40
38
 
39
+ let headerBackground = context?.designConfig?.headerBar;
40
+ let headerGradient = theme.colors?.gradient;
41
+
42
+ if (theme.assets?.headerBackground) {
43
+ headerBackground = theme.assets?.headerBackground;
44
+ }
45
+ if (context?.designConfig?.headerGradient) {
46
+ headerGradient = context?.designConfig?.headerGradient;
47
+ }
48
+
41
49
  /**
42
50
  * inject data for navigator
43
51
  */
@@ -52,7 +60,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
52
60
  'onChangeGrid',
53
61
  enable => {
54
62
  setShowGrid(!!enable);
55
- },
63
+ }
56
64
  );
57
65
 
58
66
  return () => {
@@ -60,10 +68,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
60
68
  };
61
69
  }, []);
62
70
 
63
- /**
64
- * translate context method
65
- * @param data
66
- */
67
71
  const translate = (data?: string | {vi: string; en: string}) => {
68
72
  if (data && typeof data !== 'string') {
69
73
  return localize?.translateData(data);
@@ -80,7 +84,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
80
84
  const onScreenNavigated = (
81
85
  preScreenName: string,
82
86
  screenName: string,
83
- action: string,
87
+ action: string
84
88
  ) => {
85
89
  console.log(preScreenName, screenName, action);
86
90
  context?.autoTracking?.({
@@ -92,6 +96,9 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
92
96
  action,
93
97
  });
94
98
 
99
+ /**
100
+ * debug toast
101
+ */
95
102
  maxApi?.showToastDebug?.({
96
103
  appId: context.appId,
97
104
  message: `${screenName} screen_navigated`,
@@ -99,46 +106,8 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
99
106
  });
100
107
  };
101
108
 
102
- /**
103
- * onStateChange
104
- * @param state
105
- */
106
- const onStateChange = (state: Readonly<NavigationState> | undefined) => {
107
- const lastedRoute: any = state?.routes?.[state?.routes?.length - 1];
108
- const oldRoute: any = routes.current?.[routes.current?.length - 1];
109
- const lasted = lastedRoute?.params?.screen;
110
- const previous = oldRoute?.params?.screen;
111
- const preScreenName = previous?.name ?? previous?.type?.name;
112
- const screenName = lasted?.name ?? lasted?.type?.name;
113
-
114
- let action = 'push';
115
- if (routes.current?.length > (state?.routes?.length ?? 0)) {
116
- action = 'back';
117
- }
118
- onScreenNavigated(preScreenName, screenName, action);
119
- maxApi?.setObserver('CURRENT_SCREEN', {screenName});
120
- routes.current = state?.routes;
121
- };
122
-
123
- /**
124
- * onReady
125
- */
126
- const onReady = () => {
127
- isReady.current = true;
128
- routes.current = navigationRef.current?.getRootState?.()?.routes;
129
- maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
130
- onScreenNavigated(data?.screenName, screen?.name, 'push');
131
- maxApi?.setObserver('CURRENT_SCREEN', {
132
- screenName: screen?.name,
133
- });
134
- });
135
- };
136
-
137
109
  navigator.current.setCurrentContext = setCurrentContext;
138
110
 
139
- const headerBackground = theme.assets?.headerBackground || Configs.headerBar;
140
- const headerGradient = Configs?.headerGradient || theme.colors?.gradient;
141
-
142
111
  return (
143
112
  <SafeAreaProvider>
144
113
  <MiniAppContext.Provider
@@ -163,69 +132,72 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
163
132
  showGrid,
164
133
  translate,
165
134
  }}>
166
- <NavigationIndependentTree>
167
- <ReactNavigationContainer
168
- theme={{
169
- dark: false,
170
- colors: {
171
- primary: theme.colors.primary,
172
- background: theme.colors.background.default,
173
- card: theme.colors.background.surface,
174
- text: theme.colors.text.default,
175
- border: theme.colors.border.default,
176
- notification: theme.colors.error.primary,
177
- },
178
- fonts: {
179
- regular: {
180
- fontFamily: 'SFProText',
181
- fontWeight: '400',
182
- },
183
- medium: {
184
- fontFamily: 'SFProText',
185
- fontWeight: '400',
186
- },
187
- bold: {
188
- fontFamily: 'SFProText',
189
- fontWeight: '400',
190
- },
191
- heavy: {
192
- fontFamily: 'SFProText',
193
- fontWeight: '400',
194
- },
195
- },
196
- }}
197
- ref={navigationRef}
198
- onReady={onReady}
199
- onStateChange={onStateChange}>
200
- <Stack.Navigator
201
- initialRouteName="Stack"
202
- screenOptions={{
203
- headerMode: 'screen',
204
- }}>
205
- <Stack.Screen
206
- name="Stack"
207
- component={StackScreen}
208
- initialParams={{screen, initialParams}}
209
- options={{
210
- ...getStackOptions(),
211
- ...(options as StackNavigationOptions),
212
- }}
213
- />
214
- <Stack.Screen
215
- name="Dialog"
216
- component={StackScreen}
217
- options={getDialogOptions()}
218
- initialParams={{screen}}
219
- />
220
- <Stack.Screen
221
- name="Modal"
222
- component={ModalScreen}
223
- options={getModalOptions()}
224
- initialParams={{screen}}
225
- />
226
- </Stack.Navigator>
227
- </ReactNavigationContainer>
228
- </NavigationIndependentTree>
135
+ <ReactNavigationContainer
136
+ theme={{
137
+ ...theme,
138
+ colors: {
139
+ ...theme.colors,
140
+ background: theme.colors.background.default,
141
+ card: theme.colors.background.surface,
142
+ text: theme.colors.text.default,
143
+ border: theme.colors.border.default,
144
+ notification: theme.colors.error.primary,
145
+ },
146
+ }}
147
+ ref={navigationRef}
148
+ onReady={() => {
149
+ isReady.current = true;
150
+ routes.current = navigationRef.current?.getRootState?.()?.routes;
151
+ maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
152
+ onScreenNavigated(data?.screenName, screen?.name, 'push');
153
+ maxApi?.setObserver('CURRENT_SCREEN', {
154
+ screenName: screen?.name,
155
+ });
156
+ });
157
+ }}
158
+ onStateChange={state => {
159
+ const lastedRoute: any =
160
+ state?.routes?.[state?.routes?.length - 1];
161
+ const oldRoute: any =
162
+ routes.current?.[routes.current?.length - 1];
163
+ const lasted = lastedRoute?.params?.screen;
164
+ const previous = oldRoute?.params?.screen;
165
+ const preScreenName = previous?.name ?? previous?.type?.name;
166
+ const screenName = lasted?.name ?? lasted?.type?.name;
167
+
168
+ let action = 'push';
169
+ if (routes.current?.length > (state?.routes?.length ?? 0)) {
170
+ action = 'back';
171
+ }
172
+ onScreenNavigated(preScreenName, screenName, action);
173
+ maxApi?.setObserver('CURRENT_SCREEN', {screenName});
174
+ routes.current = state?.routes;
175
+ }}
176
+ independent={true}>
177
+ <Stack.Navigator initialRouteName="Stack" headerMode="screen">
178
+ <Stack.Screen
179
+ name="Stack"
180
+ component={StackScreen}
181
+ initialParams={{screen, initialParams}}
182
+ options={{
183
+ ...getStackOptions(),
184
+ ...(options as StackNavigationOptions),
185
+ }}
186
+ />
187
+ <Stack.Screen
188
+ name="Dialog"
189
+ component={StackScreen}
190
+ options={getDialogOptions()}
191
+ initialParams={{screen}}
192
+ />
193
+ <Stack.Screen
194
+ name="Modal"
195
+ component={ModalScreen}
196
+ options={getModalOptions()}
197
+ initialParams={{screen}}
198
+ />
199
+ </Stack.Navigator>
200
+ </ReactNavigationContainer>
229
201
  </ApplicationContext.Provider>
230
202
  </MiniAppContext.Provider>
231
203
  </SafeAreaProvider>
@@ -1,11 +1,11 @@
1
1
  import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
+ import {useHeaderHeight} from '@react-navigation/stack';
2
3
  import {Alert, InteractionManager} from 'react-native';
3
- import {useHeaderHeight} from '@react-navigation/elements';
4
- import {ScreenParams} from './types';
4
+ import {ScreenParams, ScreenTrackingParams} from './types';
5
5
  import Navigation from './Navigation';
6
6
  import {ApplicationContext, MiniAppContext, ScreenContext} from './index';
7
7
  import {GridSystem} from '../Layout';
8
-
8
+ import {version} from '../package.json';
9
9
  const runAfterInteractions = InteractionManager.runAfterInteractions;
10
10
 
11
11
  /**
@@ -28,6 +28,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
28
28
  timeLoad: 0,
29
29
  timeInteraction: 0,
30
30
  widgets: [],
31
+ params: undefined,
31
32
  });
32
33
  const widgets = useRef<any>([]);
33
34
  const context = useContext<any>(MiniAppContext);
@@ -77,14 +78,14 @@ const StackScreen: React.FC<ScreenParams> = props => {
77
78
  context,
78
79
  (data: any) => {
79
80
  tracking.current.traceIdLoad = data?.traceId;
80
- },
81
+ }
81
82
  );
82
83
  navigator?.maxApi?.startTraceScreenInteraction?.(
83
84
  screenName,
84
85
  context,
85
86
  (data: any) => {
86
87
  tracking.current.traceIdInteraction = data?.traceId;
87
- },
88
+ }
88
89
  );
89
90
 
90
91
  tracking.current.timeoutTracking = setTimeout(() => {
@@ -117,11 +118,13 @@ const StackScreen: React.FC<ScreenParams> = props => {
117
118
  state: 'load',
118
119
  duration: timeLoad,
119
120
  widgets: tracking.current.widgets,
121
+ params: tracking.current.params,
122
+ version: version,
120
123
  });
121
124
  navigator?.maxApi?.stopTrace?.(
122
125
  tracking.current.traceIdLoad,
123
126
  {value: timeLoad / 1000},
124
- null,
127
+ null
125
128
  );
126
129
  tracking.current.releaseLoad = true;
127
130
 
@@ -139,7 +142,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
139
142
  ) {
140
143
  Alert.alert(
141
144
  `${screenName}- load ${timeLoad}ms`,
142
- JSON.stringify(lastElement.current?.children?.current),
145
+ JSON.stringify(lastElement.current?.children?.current)
143
146
  );
144
147
  }
145
148
  }
@@ -165,11 +168,13 @@ const StackScreen: React.FC<ScreenParams> = props => {
165
168
  state: 'interaction',
166
169
  duration: tracking.current.timeInteraction - timeLoad,
167
170
  totalDuration: tracking.current.timeInteraction,
171
+ params: tracking.current.params,
172
+ version: version,
168
173
  });
169
174
  navigator?.maxApi?.stopTrace?.(
170
175
  tracking.current.traceIdInteraction,
171
176
  {value: tracking.current.timeInteraction / 1000},
172
- null,
177
+ null
173
178
  );
174
179
  tracking.current.releaseInteraction = true;
175
180
 
@@ -254,6 +259,9 @@ const StackScreen: React.FC<ScreenParams> = props => {
254
259
  onScreenInteraction();
255
260
  }, 2000);
256
261
  },
262
+ onSetParams: (data: ScreenTrackingParams) => {
263
+ tracking.current.params = data;
264
+ },
257
265
  }}>
258
266
  <Component heightHeader={heightHeader} {...data} />
259
267
  {showGrid && <GridSystem />}
@@ -16,15 +16,17 @@ import {setAutomationID} from './utils';
16
16
  const Context = createContext({});
17
17
  const ApplicationContext = createContext(defaultContext);
18
18
 
19
- const MiniAppContext = (Platform as any).MiniAppContext ?? createContext({});
20
- const ScreenContext = (Platform as any).ScreenContext ?? createContext({});
19
+ const MiniAppContext = (Platform as any).MiniAppContext ?? Context;
20
+ const ScreenContext = (Platform as any).ScreenContext ?? Context;
21
21
  const ComponentContext = (Platform as any).ComponentContext ?? Context;
22
+ const SkeletonContext = createContext({loading: false});
22
23
 
23
24
  export {
24
25
  ApplicationContext,
25
26
  MiniAppContext,
26
27
  ScreenContext,
27
28
  ComponentContext,
29
+ SkeletonContext,
28
30
  NavigationContainer,
29
31
  Localize,
30
32
  HeaderTitle,
@@ -117,6 +117,11 @@ export type ScreenParams = {
117
117
  options?: NavigationOptions;
118
118
  };
119
119
 
120
+ export type ScreenTrackingParams = {
121
+ value1?: any;
122
+ value2?: any;
123
+ };
124
+
120
125
  export type ModalParams = {
121
126
  [key: string]: any;
122
127
  screen: React.ComponentType;
package/Button/index.tsx CHANGED
@@ -7,13 +7,18 @@ import {
7
7
  View,
8
8
  } from 'react-native';
9
9
  import LinearGradient from 'react-native-linear-gradient';
10
- import {ApplicationContext, ComponentContext} from '../Application';
10
+ import {
11
+ ApplicationContext,
12
+ ComponentContext,
13
+ SkeletonContext,
14
+ } from '../Application';
11
15
  import {Text} from '../Text';
12
16
  import {Typography} from '../Text/types';
13
17
  import {Colors, Spacing} from '../Consts';
14
18
  import styles from './styles';
15
19
  import {Icon} from '../Icon';
16
20
  import {Loader} from '../Loader';
21
+ import {Skeleton} from '../Skeleton';
17
22
 
18
23
  const AnimationLinear = Animated.createAnimatedComponent(LinearGradient);
19
24
 
@@ -88,6 +93,7 @@ const Button: FC<ButtonProps> = ({
88
93
  ...rest
89
94
  }) => {
90
95
  const {theme, config} = useContext(ApplicationContext);
96
+ const skeleton = useContext(SkeletonContext);
91
97
  const {gradient, color} = config?.navigationBar?.buttonColors ?? {};
92
98
  let gradientPros;
93
99
  let state = 'enabled';
@@ -289,6 +295,10 @@ const Button: FC<ButtonProps> = ({
289
295
  full && {width: '100%'},
290
296
  ]);
291
297
 
298
+ if (skeleton?.loading) {
299
+ return <Skeleton style={[buttonStyle, {paddingHorizontal: 0}]} />;
300
+ }
301
+
292
302
  return (
293
303
  <ComponentContext.Provider
294
304
  value={{
@@ -229,34 +229,4 @@ const Shadow = {
229
229
  }),
230
230
  };
231
231
 
232
- const Configs = {
233
- headerGradient: undefined,
234
- headerBar: undefined,
235
- trustBanner: {
236
- content: {
237
- vi: 'Bảo mật thông tin & An toàn tài sản của bạn là ưu tiên hàng đầu của MoMo.',
238
- en: "Your data security and money safety are MoMo's top priorities.",
239
- },
240
- subContent: {
241
- vi: 'Tìm hiểu thêm',
242
- en: 'Learn more',
243
- },
244
- pciImage: 'https://static.momocdn.net/app/img/kits/trustBanner/pci_dss.png',
245
- sslImage: 'https://static.momocdn.net/app/img/kits/trustBanner/ssl.png',
246
- momoImage:
247
- 'https://static.momocdn.net/app/img/kits/trustBanner/ic_secu.png',
248
- urlConfig: 'login_and_security',
249
- icons: [
250
- 'https://static.momocdn.net/app/img/kits/trustBanner/ic_viettinbank.png',
251
- 'https://static.momocdn.net/app/img/kits/trustBanner/ic_agribank.png',
252
- 'https://static.momocdn.net/app/img/kits/trustBanner/ic_vietcombank.png',
253
- 'https://static.momocdn.net/app/img/kits/trustBanner/ic_bidv.png',
254
- ],
255
- titleWeb: {
256
- vi: 'Thông tin',
257
- en: 'Information',
258
- },
259
- },
260
- };
261
-
262
- export {Colors, Spacing, Radius, Shadow, Configs};
232
+ export {Colors, Spacing, Radius, Shadow};
package/Image/index.tsx CHANGED
@@ -2,7 +2,7 @@ import React, {useContext, useRef, useState} from 'react';
2
2
  import {StyleSheet, View} from 'react-native';
3
3
  import FastImage, {Source} from 'react-native-fast-image';
4
4
  import styles from './styles';
5
- import {ApplicationContext} from '../Application';
5
+ import {ApplicationContext, SkeletonContext} from '../Application';
6
6
  import {Skeleton} from '../Skeleton';
7
7
  import {Icon} from '../Icon';
8
8
  import {Styles} from '../Consts';
@@ -19,6 +19,7 @@ const Image: React.FC<ImageProps> = ({
19
19
  ...rest
20
20
  }) => {
21
21
  const {theme} = useContext(ApplicationContext);
22
+ const skeleton = useContext(SkeletonContext);
22
23
  const error = useRef(false);
23
24
  const [status, setStatus] = useState<Status>('success');
24
25
 
@@ -43,6 +44,15 @@ const Image: React.FC<ImageProps> = ({
43
44
  </View>
44
45
  );
45
46
  }
47
+
48
+ if (skeleton.loading) {
49
+ return (
50
+ <View style={[StyleSheet.absoluteFill, Styles.flexCenter]}>
51
+ <Skeleton />
52
+ </View>
53
+ );
54
+ }
55
+
46
56
  return children;
47
57
  };
48
58
 
package/Layout/Screen.tsx CHANGED
@@ -1,5 +1,4 @@
1
- import {StackNavigationOptions} from '@react-navigation/stack';
2
- import {useHeaderHeight} from '@react-navigation/elements';
1
+ import {StackNavigationOptions, useHeaderHeight} from '@react-navigation/stack';
3
2
  import React, {
4
3
  forwardRef,
5
4
  Fragment,
@@ -24,11 +23,12 @@ import {
24
23
  ViewProps,
25
24
  } from 'react-native';
26
25
  import {useSafeAreaInsets} from 'react-native-safe-area-context';
27
- import {ApplicationContext} from '../Application';
26
+ import {ApplicationContext, ScreenContext} from '../Application';
28
27
  import Navigation from '../Application/Navigation';
29
28
  import {
30
29
  AnimatedHeader,
31
30
  NavigationOptions,
31
+ ScreenTrackingParams,
32
32
  SearchHeaderProps,
33
33
  } from '../Application/types';
34
34
  import {Colors, Spacing, Styles} from '../Consts';
@@ -149,6 +149,11 @@ export interface ScreenProps extends ViewProps {
149
149
  * Optional. Custom headerBackground Image
150
150
  */
151
151
  headerBackground?: string;
152
+
153
+ /**
154
+ * Optional. Custom tracking params
155
+ */
156
+ trackingParams?: ScreenTrackingParams;
152
157
  }
153
158
 
154
159
  const Screen = forwardRef(
@@ -175,15 +180,17 @@ const Screen = forwardRef(
175
180
  animatedValue: customAnimatedValue,
176
181
  headerBackground,
177
182
  gradientColor,
183
+ trackingParams,
178
184
  }: ScreenProps,
179
- ref: any,
185
+ ref: any
180
186
  ) => {
181
187
  const screenRef = useRef<View | ScrollView>();
182
188
  const {theme} = useContext(ApplicationContext);
189
+ const screen: any = useContext(ScreenContext);
183
190
  const insets = useSafeAreaInsets();
184
191
  const heightHeader = useHeaderHeight();
185
192
  const animatedValue = useRef<Animated.Value>(
186
- customAnimatedValue || new Animated.Value(0),
193
+ customAnimatedValue || new Animated.Value(0)
187
194
  );
188
195
  const currentTint = useRef<string | undefined>(undefined);
189
196
  const isTab = navigation?.instance?.getState?.()?.type === 'tab';
@@ -196,6 +203,11 @@ const Screen = forwardRef(
196
203
  keyboardOffset = -Math.min(insets.bottom, 21);
197
204
  }
198
205
 
206
+ /**
207
+ * inject params for screen tracking
208
+ */
209
+ screen?.onSetParams?.(trackingParams);
210
+
199
211
  /**
200
212
  * export options for screen
201
213
  * @param headerType
@@ -424,7 +436,7 @@ const Screen = forwardRef(
424
436
  }
425
437
  }
426
438
  },
427
- },
439
+ }
428
440
  );
429
441
  }
430
442
 
@@ -574,7 +586,7 @@ const Screen = forwardRef(
574
586
  </KeyboardAvoidingView>
575
587
  </View>
576
588
  );
577
- },
589
+ }
578
590
  );
579
591
 
580
592
  export default Screen;
package/Layout/index.ts CHANGED
@@ -7,7 +7,6 @@ import {GridContextProps} from './types';
7
7
  import Item from './Item';
8
8
  import ItemList from './ItemList';
9
9
  import ItemSectionList from './ItemSectionList';
10
- import Screen from './Screen';
11
10
 
12
11
  const GridContext = createContext<GridContextProps>({
13
12
  numberOfColumns: 12,
@@ -25,5 +24,4 @@ export {
25
24
  Item,
26
25
  ItemList,
27
26
  ItemSectionList,
28
- Screen,
29
27
  };
@@ -1,9 +1,18 @@
1
1
  import React, {useEffect, useMemo, useRef, useState} from 'react';
2
- import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
2
+ import {
3
+ Animated,
4
+ Easing,
5
+ LayoutAnimation,
6
+ Platform,
7
+ StyleSheet,
8
+ UIManager,
9
+ View,
10
+ } from 'react-native';
3
11
  import LinearGradient from 'react-native-linear-gradient';
4
12
  import {SkeletonTypes} from './types';
5
13
  import {Colors, Styles} from '../Consts';
6
14
  import styles from './styles';
15
+ import {SkeletonContext} from '../Application';
7
16
 
8
17
  const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
9
18
  const [width, setWidth] = useState(0);
@@ -24,7 +33,7 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
24
33
  duration: 1000,
25
34
  easing: Easing.linear,
26
35
  useNativeDriver: Platform.OS !== 'web',
27
- }),
36
+ })
28
37
  );
29
38
  }, [beginShimmerPosition]);
30
39
 
@@ -69,4 +78,50 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
69
78
  );
70
79
  };
71
80
 
72
- export {Skeleton};
81
+ /**
82
+ * SkeletonProvider component provides a context for managing the loading state
83
+ * and applies a layout animation when the loading state changes.
84
+ *
85
+ * @param {boolean} loading - Indicates whether the skeleton loading state is active.
86
+ * @param {React.ReactNode} children - The child components to be rendered within the provider.
87
+ *
88
+ * @example
89
+ * <SkeletonProvider loading={true}>
90
+ * <YourComponent />
91
+ * </SkeletonProvider>
92
+ *
93
+ * The layout animation is configured using LayoutAnimation.configureNext, which animates the opacity of the components over 500 milliseconds with an ease-in-ease-out effect.
94
+ */
95
+
96
+ const SkeletonProvider: React.FC<{loading: boolean}> = ({
97
+ loading = true,
98
+ children,
99
+ }) => {
100
+ const [previous, setPrevious] = useState(loading);
101
+
102
+ useEffect(() => {
103
+ if (previous !== loading) {
104
+ if (Platform.OS === 'android') {
105
+ if (UIManager.setLayoutAnimationEnabledExperimental) {
106
+ UIManager.setLayoutAnimationEnabledExperimental(true);
107
+ }
108
+ }
109
+ LayoutAnimation.configureNext({
110
+ duration: 500,
111
+ create: {
112
+ type: LayoutAnimation.Types.easeInEaseOut,
113
+ property: LayoutAnimation.Properties.opacity,
114
+ },
115
+ });
116
+ setPrevious(loading);
117
+ }
118
+ }, [loading]);
119
+
120
+ return (
121
+ <SkeletonContext.Provider value={{loading: previous}}>
122
+ {children}
123
+ </SkeletonContext.Provider>
124
+ );
125
+ };
126
+
127
+ export {Skeleton, SkeletonProvider};
package/Text/index.tsx CHANGED
@@ -1,9 +1,14 @@
1
1
  import React, {useContext} from 'react';
2
- import {Text as RNText, TextProps as RNTextProps} from 'react-native';
2
+ import {Text as RNText, TextProps as RNTextProps, View} from 'react-native';
3
3
  import styles from './styles';
4
4
  import {Typography, TypographyWeight} from './types';
5
- import {ApplicationContext, setAutomationID} from '../Application';
5
+ import {
6
+ ApplicationContext,
7
+ setAutomationID,
8
+ SkeletonContext,
9
+ } from '../Application';
6
10
  import {scaleSize} from './utils';
11
+ import {Skeleton} from '../Skeleton';
7
12
 
8
13
  const SFProText: TypographyWeight = {
9
14
  100: 'Thin',
@@ -125,7 +130,7 @@ const Text: React.FC<TextProps> = ({
125
130
  ...rest
126
131
  }) => {
127
132
  const {theme} = useContext(ApplicationContext);
128
-
133
+ const skeleton = useContext(SkeletonContext);
129
134
  const textStyle = getTypoStyle(typography, fontFamily);
130
135
 
131
136
  if (deprecatedValues.includes(typography)) {
@@ -134,6 +139,25 @@ const Text: React.FC<TextProps> = ({
134
139
  );
135
140
  }
136
141
 
142
+ if (skeleton.loading) {
143
+ return (
144
+ <View style={style}>
145
+ <RNText
146
+ {...rest}
147
+ allowFontScaling={false}
148
+ style={[
149
+ textStyle,
150
+ {
151
+ color: color ?? theme.colors.text.default,
152
+ },
153
+ ]}>
154
+ {children ?? ''}
155
+ </RNText>
156
+ <Skeleton style={{position: 'absolute'}} />
157
+ </View>
158
+ );
159
+ }
160
+
137
161
  return (
138
162
  <RNText
139
163
  {...rest}
package/index.ts CHANGED
@@ -49,3 +49,10 @@ export * from './Title';
49
49
  export * from './Title/types';
50
50
  export * from './Badge';
51
51
  export * from './Badge/types';
52
+
53
+ /**
54
+ * export trick for keep old mini app working
55
+ * @deprecated
56
+ */
57
+ export * from 'react-native-modalize';
58
+ export * from '@gorhom/bottom-sheet';
package/package.json CHANGED
@@ -1,35 +1,50 @@
1
1
  {
2
- "name": "@momo-kits/foundation",
3
- "version": "0.112.1-rn76.7",
4
- "description": "React Native Component Kits",
5
- "main": "index.ts",
6
- "scripts": {},
7
- "keywords": [
8
- "@momo-kits/foundation"
9
- ],
10
- "dependencies": {
11
- "react-native-safe-area-context": "5.1.0",
12
- "react-native-linear-gradient": "2.8.3",
13
- "react-native-gesture-handler": "2.22.0",
14
- "react-native-fast-image": "8.6.3",
15
- "react-native-reanimated": "3.16.7",
16
- "lottie-react-native": "7.2.2",
17
- "@react-navigation/bottom-tabs": "7.2.0",
18
- "@react-navigation/core": "7.3.1",
19
- "@react-navigation/native": "7.0.14",
20
- "@react-navigation/routers": "7.1.2",
21
- "@react-navigation/stack": "7.1.1",
22
- "@react-navigation/elements": "2.2.5"
23
- },
24
- "peerDependencies": {
25
- "react-native": "*"
26
- },
27
- "devDependencies": {
28
- "@momo-platform/versions": "4.1.11",
29
- "@types/color": "3.0.6"
30
- },
31
- "publishConfig": {
32
- "registry": "https://registry.npmjs.org/"
33
- },
34
- "license": "MoMo"
35
- }
2
+ "name": "@momo-kits/foundation",
3
+ "version": "0.113.0-optimize.1",
4
+ "description": "React Native Component Kits",
5
+ "main": "index.ts",
6
+ "scripts": {},
7
+ "keywords": [
8
+ "@momo-kits/foundation"
9
+ ],
10
+ "dependencies": {
11
+ "@gorhom/bottom-sheet": "2.4.1",
12
+ "react-native-modalize": "2.1.1",
13
+ "react-native-safe-area-context": "3.1.4",
14
+ "react-native-linear-gradient": "2.8.3",
15
+ "react-native-gesture-handler": "1.10.3",
16
+ "react-native-fast-image": "8.1.5",
17
+ "@react-navigation/bottom-tabs": "https://gitlab.mservice.com.vn/momo-platform/react-native-bottom-tabs.git",
18
+ "@react-navigation/core": "5.16.1",
19
+ "@react-navigation/native": "5.9.8",
20
+ "@react-navigation/routers": "5.7.4",
21
+ "react-native-reanimated": "git+https://gitlab.mservice.com.vn/momo-platform/react-native-reanimated.git#v1.13.4_gradle_7",
22
+ "lottie-react-native": "git+https://gitlab.mservice.com.vn/momo-platform/momo-lottie-react-native.git",
23
+ "@react-navigation/stack": "https://gitlab.mservice.com.vn/momo-platform/react-navigation-stack.git"
24
+ },
25
+ "peerDependencies": {
26
+ "react-native": "*"
27
+ },
28
+ "devDependencies": {
29
+ "@babel/core": "^7.12.9",
30
+ "@babel/runtime": "^7.12.5",
31
+ "@react-native-community/eslint-config": "^2.0.0",
32
+ "@types/jest": "26.0.23",
33
+ "@types/react-native": "0.64.4",
34
+ "@types/react-test-renderer": "16.9.2",
35
+ "@types/d3-shape": "1.3.7",
36
+ "babel-jest": "^26.6.3",
37
+ "eslint": "^7.14.0",
38
+ "jest": "^26.6.3",
39
+ "metro-react-native-babel-preset": "^0.64.0",
40
+ "react-test-renderer": "17.0.1",
41
+ "typescript": "^4.0.3",
42
+ "@momo-platform/versions": "4.1.11",
43
+ "react-scanner": "^1.1.0",
44
+ "@types/color": "3.0.6"
45
+ },
46
+ "publishConfig": {
47
+ "registry": "https://registry.npmjs.org/"
48
+ },
49
+ "license": "MoMo"
50
+ }
package/publish.sh CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
 
4
4
  if [ "$1" == "stable" ]; then
5
- #npm version $(npm view @momo-kits/foundation@stable version)
6
- #npm version patch
5
+ npm version $(npm view @momo-kits/foundation@stable version)
6
+ npm version patch
7
7
  npm publish --tag stable --access=public
8
8
  elif [ "$1" == "latest" ]; then
9
- #npm version $(npm view @momo-kits/foundation@latest version)
10
- #npm version prerelease --preid=rc
9
+ npm version $(npm view @momo-kits/foundation@latest version)
10
+ npm version prerelease --preid=rc
11
11
  npm publish --tag latest --access=public
12
12
  else
13
- #npm version $(npm view @momo-kits/foundation@beta version)
14
- #npm version prerelease --preid=beta
13
+ npm version $(npm view @momo-kits/foundation@beta version)
14
+ npm version prerelease --preid=beta
15
15
  npm publish --tag beta --access=public
16
16
  fi
17
17
  PACKAGE_NAME=$(npm pkg get name)