@momo-kits/foundation 0.92.7-rc.21 → 0.92.7-rc.22

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 (57) hide show
  1. package/Application/BottomSheet.tsx +216 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +62 -223
  3. package/Application/BottomTab/index.tsx +15 -11
  4. package/Application/Components.tsx +291 -45
  5. package/Application/Localize.ts +44 -0
  6. package/Application/ModalScreen.tsx +11 -181
  7. package/Application/Navigation.ts +4 -18
  8. package/Application/NavigationContainer.tsx +10 -28
  9. package/Application/Navigator.ts +14 -16
  10. package/Application/StackScreen.tsx +222 -42
  11. package/Application/index.ts +5 -3
  12. package/Application/types.ts +47 -29
  13. package/Application/utils.tsx +61 -19
  14. package/Assets/icon_bank.json +1 -1
  15. package/Badge/BadgeDotAnimation.tsx +95 -0
  16. package/Badge/index.tsx +2 -1
  17. package/Badge/styles.ts +50 -6
  18. package/Button/index.tsx +7 -8
  19. package/Icon/index.tsx +1 -1
  20. package/Icon/types.ts +1 -2
  21. package/Image/index.tsx +0 -1
  22. package/Input/Input.tsx +51 -17
  23. package/Input/InputDropDown.tsx +42 -45
  24. package/Input/InputMoney.tsx +65 -6
  25. package/Input/InputOTP.tsx +14 -13
  26. package/Input/InputSearch.tsx +259 -146
  27. package/Input/InputTextArea.tsx +0 -1
  28. package/Input/TextTyping.tsx +113 -0
  29. package/Input/common.tsx +29 -10
  30. package/Input/index.tsx +84 -89
  31. package/Input/styles.ts +44 -7
  32. package/Input/utils.ts +1 -1
  33. package/Layout/Card.tsx +4 -3
  34. package/Layout/FloatingButton.tsx +3 -3
  35. package/Layout/GridSystem.tsx +1 -1
  36. package/Layout/ItemList.tsx +3 -2
  37. package/Layout/Screen.tsx +188 -102
  38. package/Layout/Section.tsx +4 -3
  39. package/Layout/styles.ts +0 -6
  40. package/Layout/types.ts +1 -1
  41. package/Layout/utils.ts +2 -2
  42. package/Loader/index.tsx +2 -0
  43. package/Pagination/PaginationScroll.tsx +2 -2
  44. package/Pagination/styles.ts +1 -1
  45. package/Popup/PopupNotify.tsx +7 -7
  46. package/Popup/PopupPromotion.tsx +1 -1
  47. package/Popup/types.ts +1 -1
  48. package/Tag/index.tsx +9 -2
  49. package/Tag/styles.ts +3 -2
  50. package/Tag/types.ts +12 -0
  51. package/Title/index.tsx +20 -7
  52. package/Title/styles.ts +4 -4
  53. package/code-scanner.js +141 -124
  54. package/index.ts +7 -0
  55. package/package.json +5 -4
  56. package/publish.sh +16 -21
  57. package/tsconfig.json +1 -1
@@ -1,29 +1,37 @@
1
1
  import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
+ import {useHeaderHeight} from '@react-navigation/stack';
3
+ import {Alert, InteractionManager, Linking, View} from 'react-native';
2
4
  import {ScreenParams} from './types';
3
5
  import Navigation from './Navigation';
4
6
  import {ApplicationContext, MiniAppContext, ScreenContext} from './index';
5
7
  import {GridSystem} from '../Layout';
6
- import {useHeaderHeight} from '@react-navigation/stack';
7
- import {Alert, InteractionManager} from 'react-native';
8
+ import {Text} from '../Text';
9
+ import {Colors, Radius, Spacing} from '../Consts';
8
10
 
11
+ /**
12
+ * container for stack screen
13
+ * @param props
14
+ * @constructor
15
+ */
9
16
  const StackScreen: React.FC<ScreenParams> = props => {
10
- const {theme, showGrid, navigator} = useContext(ApplicationContext);
11
- const startTime = useRef(Date.now());
12
- const endTime = useRef(Date.now());
13
- const timeLoad = useRef(0);
14
- const timeInteraction = useRef(0);
15
- const timeoutLoad = useRef<any>();
16
- const tracked = useRef<any>({
17
- releaseLoad: undefined,
18
- releaseInteraction: undefined,
17
+ const {showGrid, navigator} = useContext(ApplicationContext);
18
+ const tracking = useRef<any>({
19
19
  timeoutLoad: undefined,
20
20
  timeoutInteraction: undefined,
21
+ timeoutTracking: undefined,
22
+ startTime: Date.now(),
23
+ endTime: Date.now(),
24
+ traceIdLoad: undefined,
25
+ traceIdInteraction: undefined,
26
+ releaseLoad: undefined,
27
+ releaseInteraction: undefined,
28
+ timeLoad: 0,
29
+ timeInteraction: 0,
21
30
  });
22
- const interaction = useRef<any>();
23
- const context = useContext<any>(MiniAppContext);
24
31
 
32
+ const context = useContext<any>(MiniAppContext);
25
33
  const {screen: Component, options, initialParams} = props.route.params;
26
- const navigation = new Navigation(props.navigation, theme);
34
+ const navigation = new Navigation(props.navigation);
27
35
  const heightHeader = useHeaderHeight();
28
36
 
29
37
  const data = {
@@ -36,36 +44,68 @@ const StackScreen: React.FC<ScreenParams> = props => {
36
44
  delete data.initialParams;
37
45
 
38
46
  const screenName = Component?.name || Component?.type?.name || 'Invalid';
47
+ const routes = props.navigation.getState()?.routes || [];
39
48
 
40
49
  /**
41
50
  * set options for screen
42
51
  */
43
52
  useLayoutEffect(() => {
53
+ let defaultOptions = {
54
+ headerRight: {
55
+ type: 'toolkit',
56
+ },
57
+ };
44
58
  if (options) {
45
- navigation.setOptions(options);
59
+ defaultOptions = {
60
+ ...defaultOptions,
61
+ ...options,
62
+ };
46
63
  }
64
+ navigation.setOptions(defaultOptions);
47
65
  }, [options]);
48
66
 
49
67
  /**
50
68
  * tracking for screen
51
69
  */
52
70
  useEffect(() => {
53
- if (__DEV__ && (!screenName || screenName == 'Invalid')) {
54
- Alert.alert('Design system', `Unvalidated screen name "${screenName}" !`);
71
+ if (['Invalid', 'screen'].includes(screenName) && context.enableAutoId) {
72
+ setTimeout(() => {
73
+ navigator?.showModal({screen: EmptyScreen});
74
+ }, 300);
55
75
  }
56
76
 
57
- navigator?.maxApi?.of?.({screenName});
77
+ const subscription = props.navigation?.addListener?.('focus', () => {
78
+ navigator?.maxApi?.of?.({screenName});
79
+ navigator?.maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
80
+ let preScreenName = data?.screenName;
81
+ if (routes?.length > 1) {
82
+ const screen = routes?.[routes?.length - 2]?.params?.screen;
83
+ preScreenName = screen?.name || screen?.type?.name || 'Invalid';
84
+ }
85
+ onScreenNavigated(preScreenName);
86
+ navigator?.maxApi?.setObserver('CURRENT_SCREEN', {screenName});
87
+ });
88
+ });
89
+ navigator?.maxApi?.startTraceScreenLoad?.(screenName, (data: any) => {
90
+ tracking.current.traceIdLoad = data?.traceId;
91
+ });
92
+ navigator?.maxApi?.startTraceScreenInteraction?.(
93
+ screenName,
94
+ (data: any) => {
95
+ tracking.current.traceIdInteraction = data?.traceId;
96
+ }
97
+ );
58
98
 
59
- tracked.current.timeoutLoad = setTimeout(() => {
99
+ tracking.current.timeoutTracking = setTimeout(() => {
60
100
  onScreenLoad();
61
- }, 5000);
62
- tracked.current.timeoutInteraction = setTimeout(() => {
63
101
  onScreenInteraction();
64
102
  }, 5000);
65
103
 
66
104
  return () => {
67
105
  onScreenLoad();
68
106
  onScreenInteraction();
107
+ clearTimeout(tracking.current.timeoutTracking);
108
+ subscription?.();
69
109
  };
70
110
  }, []);
71
111
 
@@ -73,8 +113,12 @@ const StackScreen: React.FC<ScreenParams> = props => {
73
113
  * tracking for screen load
74
114
  */
75
115
  const onScreenLoad = () => {
76
- clearTimeout(tracked.current.timeoutLoad);
77
- if (!tracked.current?.releaseLoad) {
116
+ if (!tracking.current?.releaseLoad) {
117
+ if (tracking.current.timeLoad === 0) {
118
+ tracking.current.timeLoad =
119
+ tracking.current.endTime - tracking.current.startTime;
120
+ }
121
+
78
122
  context.autoTracking?.({
79
123
  appId: context.appId,
80
124
  code: context.code,
@@ -82,13 +126,26 @@ const StackScreen: React.FC<ScreenParams> = props => {
82
126
  screenName,
83
127
  componentName: 'Screen',
84
128
  state: 'load',
85
- duration: timeLoad.current,
129
+ duration: tracking.current.timeLoad,
86
130
  });
131
+ navigator?.maxApi?.stopTrace?.(
132
+ tracking.current.traceIdLoad,
133
+ {value: tracking.current.timeLoad / 1000},
134
+ null
135
+ );
136
+ tracking.current.releaseLoad = true;
137
+
138
+ /**
139
+ * debug
140
+ */
87
141
  navigator?.maxApi?.showToastDebug?.({
88
- appId: `auto - ${context.appId}`,
89
- message: `${screenName} screen_load_time ${timeLoad.current}`,
142
+ appId: context.appId,
143
+ message: `${screenName} screen_load_time ${tracking.current.timeLoad}`,
144
+ type: 'ERROR',
90
145
  });
91
- tracked.current.releaseLoad = true;
146
+ if (tracking.current.timeLoad <= 0 && context.enableAutoId) {
147
+ Alert.alert(screenName, "Can't get screen load time");
148
+ }
92
149
  }
93
150
  };
94
151
 
@@ -96,8 +153,15 @@ const StackScreen: React.FC<ScreenParams> = props => {
96
153
  * tracking for screen load
97
154
  */
98
155
  const onScreenInteraction = () => {
99
- clearTimeout(tracked.current.timeoutInteraction);
100
- if (!tracked.current?.releaseInteraction) {
156
+ if (!tracking.current?.releaseInteraction) {
157
+ if (tracking.current.timeLoad === 0) {
158
+ tracking.current.timeLoad =
159
+ tracking.current.endTime - tracking.current.startTime;
160
+ }
161
+ if (tracking.current.timeInteraction === 0) {
162
+ tracking.current.timeInteraction = tracking.current.timeLoad;
163
+ }
164
+
101
165
  context.autoTracking?.({
102
166
  appId: context.appId,
103
167
  code: context.code,
@@ -105,32 +169,74 @@ const StackScreen: React.FC<ScreenParams> = props => {
105
169
  screenName,
106
170
  componentName: 'Screen',
107
171
  state: 'interaction',
108
- duration: timeInteraction.current - timeLoad.current,
172
+ duration: tracking.current.timeInteraction - tracking.current.timeLoad,
173
+ totalDuration: tracking.current.timeInteraction,
109
174
  });
175
+ navigator?.maxApi?.stopTrace?.(
176
+ tracking.current.traceIdInteraction,
177
+ {value: tracking.current.timeInteraction / 1000},
178
+ null
179
+ );
180
+ tracking.current.releaseInteraction = true;
110
181
 
182
+ /**
183
+ * debug toast
184
+ */
111
185
  navigator?.maxApi?.showToastDebug?.({
112
- appId: `auto - ${context.appId}`,
113
- message: `${screenName} screen_interaction_time ${timeInteraction.current}`,
186
+ appId: context.appId,
187
+ message: `${screenName} screen_interaction_time ${tracking.current.timeInteraction}`,
188
+ type: 'ERROR',
114
189
  });
115
- tracked.current.releaseInteraction = true;
190
+ if (tracking.current.timeInteraction <= 0 && context.enableAutoId) {
191
+ Alert.alert(screenName, "Can't get screen interaction time");
192
+ }
116
193
  }
117
194
  };
118
195
 
196
+ /**
197
+ * tracking for screen navigated
198
+ */
199
+ const onScreenNavigated = (preScreenName: string) => {
200
+ context.autoTracking?.({
201
+ appId: context.appId,
202
+ code: context.code,
203
+ buildNumber: context.buildNumber,
204
+ preScreenName,
205
+ screenName,
206
+ componentName: 'Screen',
207
+ state: 'navigated',
208
+ });
209
+
210
+ /**
211
+ * debug toast
212
+ */
213
+ navigator?.maxApi?.showToastDebug?.({
214
+ appId: context.appId,
215
+ message: `${screenName} screen_navigated`,
216
+ type: 'ERROR',
217
+ });
218
+ };
219
+
119
220
  return (
120
221
  <ScreenContext.Provider
121
222
  value={{
122
223
  screenName,
123
224
  onElementLoad: () => {
124
- endTime.current = Date.now();
125
- interaction.current?.cancel?.();
126
- interaction.current = InteractionManager.runAfterInteractions(() => {
127
- timeInteraction.current = Date.now() - startTime.current;
128
- });
129
- clearTimeout(timeoutLoad.current);
130
- timeoutLoad.current = setTimeout(() => {
131
- if (timeLoad.current === 0) {
132
- timeLoad.current = endTime.current - startTime.current;
225
+ clearTimeout(tracking.current.timeoutLoad);
226
+ tracking.current.endTime = Date.now();
227
+ tracking.current.timeoutInteraction?.cancel?.();
228
+ tracking.current.timeoutInteraction =
229
+ InteractionManager.runAfterInteractions(() => {
230
+ tracking.current.timeInteraction =
231
+ Date.now() - tracking.current.startTime;
232
+ });
233
+ tracking.current.timeoutLoad = setTimeout(() => {
234
+ if (tracking.current.timeLoad === 0) {
235
+ tracking.current.timeLoad =
236
+ tracking.current.endTime - tracking.current.startTime;
133
237
  }
238
+ onScreenLoad();
239
+ onScreenInteraction();
134
240
  }, 2000);
135
241
  },
136
242
  }}>
@@ -145,4 +251,78 @@ const StackScreen: React.FC<ScreenParams> = props => {
145
251
  );
146
252
  };
147
253
 
254
+ /**
255
+ * Empty screen for unvalidated screen name
256
+ * @constructor
257
+ */
258
+ const EmptyScreen: React.FC = () => {
259
+ return (
260
+ <View
261
+ style={{
262
+ backgroundColor: Colors.black_01,
263
+ padding: Spacing.M,
264
+ borderRadius: Radius.M,
265
+ }}>
266
+ <Text typography={'header_m_bold'}>Unvalidated screen name</Text>
267
+ <Text
268
+ typography={'description_default_regular'}
269
+ style={{paddingVertical: Spacing.S}}>
270
+ Your screen has not been rendered because Platform has not detected the
271
+ screen name. Please migrate to support this feature.
272
+ </Text>
273
+ <Text typography={'header_default'} style={{width: '100%'}}>
274
+ Possible fixes:
275
+ </Text>
276
+ <View style={{marginLeft: Spacing.S}}>
277
+ <Text typography={'body_default_regular'}>1. Off webpack config</Text>
278
+ <Text typography={'body_default_regular'}>
279
+ 2. Screen name refactoring
280
+ </Text>
281
+ <View style={{marginLeft: Spacing.S}}>
282
+ <Text
283
+ typography={'description_default_regular'}
284
+ style={{marginBottom: Spacing.S}}>
285
+ - Với các screen push/import dạng arrow function ={'>'} đổi thành
286
+ named function
287
+ </Text>
288
+ <Text
289
+ typography={'description_default_regular'}
290
+ style={{marginBottom: Spacing.S}}>
291
+ - Với các screen import dạng High Order Component ={'>'} rename
292
+ generic function thành named function
293
+ </Text>
294
+ <Text
295
+ typography={'description_default_regular'}
296
+ style={{marginBottom: Spacing.S}}>
297
+ - Với Tab Navigator, Platform sẽ lấy Tab Container làm screen name.
298
+ Trong trường hợp miniapp muốn track riêng action cho từng tab, tham
299
+ khảo theo docs
300
+ </Text>
301
+ </View>
302
+ </View>
303
+ <Text typography={'header_s_semibold'}>More information: </Text>
304
+ <Text
305
+ typography={'body_default_regular'}
306
+ color={Colors.blue_01}
307
+ onPress={() => {
308
+ Linking.openURL(
309
+ 'https://gitlab.mservice.com.vn/momo-platform/mini-app/-/tree/vn.momo.uikits/dev/app'
310
+ );
311
+ }}>
312
+ Mini App: vn.momo.uikits/dev
313
+ </Text>
314
+ <Text
315
+ typography={'body_default_regular'}
316
+ color={Colors.blue_01}
317
+ onPress={() => {
318
+ Linking.openURL(
319
+ 'https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing'
320
+ );
321
+ }}>
322
+ https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing
323
+ </Text>
324
+ </View>
325
+ );
326
+ };
327
+
148
328
  export default StackScreen;
@@ -1,16 +1,17 @@
1
1
  import {Platform} from 'react-native';
2
+ import {createContext} from 'react';
2
3
  import {NavigationContainer} from './NavigationContainer';
4
+ import Localize from './Localize';
3
5
  import Screen from '../Layout/Screen';
4
6
  import {
5
7
  HeaderAnimated,
6
8
  HeaderBackground,
7
9
  HeaderCustom,
8
- HeaderRightAction,
9
10
  HeaderTitle,
10
11
  NavigationButton,
12
+ HeaderRightAction,
11
13
  } from './Components';
12
14
  import BottomTab from './BottomTab';
13
- import {createContext} from 'react';
14
15
  import {defaultContext} from '../Consts';
15
16
 
16
17
  const Context = createContext({});
@@ -26,12 +27,13 @@ export {
26
27
  ScreenContext,
27
28
  ComponentContext,
28
29
  NavigationContainer,
30
+ Localize,
29
31
  Screen,
30
32
  BottomTab,
31
33
  NavigationButton,
34
+ HeaderRightAction,
32
35
  HeaderTitle,
33
36
  HeaderBackground,
34
- HeaderRightAction,
35
37
  HeaderCustom,
36
38
  HeaderAnimated,
37
39
  };
@@ -1,7 +1,9 @@
1
+ import {EventArg} from '@react-navigation/core';
1
2
  import {StackNavigationOptions} from '@react-navigation/stack';
2
3
  import React from 'react';
3
- import {Animated, ScrollViewProps, ViewProps} from 'react-native';
4
+ import {Animated, ViewProps} from 'react-native';
4
5
  import {PopupNotifyProps} from '../Popup/types';
6
+ import Localize from './Localize';
5
7
  import Navigation from './Navigation';
6
8
  import Navigator from './Navigator';
7
9
 
@@ -70,16 +72,6 @@ export type Context = {
70
72
  translate?: (key: string) => string;
71
73
  };
72
74
 
73
- export type MiniAppInfo = {
74
- [key: string]: any;
75
- code: string;
76
- appId: string;
77
- buildNumber: number;
78
- flowPartnerId?: string;
79
- toolkitConfig?: any;
80
- fromCode?: string;
81
- };
82
-
83
75
  export type LocalizationObject = {
84
76
  vi: {
85
77
  [key: string]: string;
@@ -94,8 +86,8 @@ export type NavigationContainerProps = {
94
86
  options?: NavigationOptions;
95
87
  theme: Theme;
96
88
  maxApi: any;
97
- localization?: LocalizationObject;
98
89
  initialParams?: any;
90
+ localize: Localize;
99
91
  };
100
92
 
101
93
  export type NavigationScreenProps = {
@@ -110,26 +102,35 @@ export type ScreenParams = {
110
102
  options?: NavigationOptions;
111
103
  };
112
104
 
113
- export interface ModalParams extends ScreenParams {
105
+ export type ModalParams = {
114
106
  [key: string]: any;
107
+ screen: React.ComponentType;
115
108
  onDismiss?: () => void;
116
109
  barrierDismissible?: boolean;
117
- }
110
+ };
118
111
 
119
- export interface BottomSheetParams extends ScreenParams {
112
+ export type BottomSheetParams = {
120
113
  [key: string]: any;
121
- onDismiss?: () => void;
114
+ screen: React.ComponentType;
115
+ options: {
116
+ title: string;
117
+ surface?: boolean;
118
+ };
119
+ useNativeModal?: boolean;
122
120
  surface?: boolean;
123
- footerComponent?: React.ReactNode;
124
- scrollViewProps?: ScrollViewProps;
125
- }
121
+ onDismiss?: (type?: string) => void;
122
+ barrierDismissible?: boolean;
123
+ draggable?: boolean;
124
+ useBottomInset?: boolean;
125
+ keyboardVerticalOffset?: number;
126
+ };
126
127
 
127
128
  export type NavigationButtonProps = {
128
129
  icon: string;
129
130
  tintColor?: string;
130
131
  useBorder?: boolean;
131
132
  onPress: () => void;
132
- badgeType?: 'dot' | 'number';
133
+ badgeType?: 'dot' | 'number' | 'dot-animation';
133
134
  badgeValue?: number;
134
135
  accessibilityLabel?: string;
135
136
  };
@@ -137,7 +138,7 @@ export type NavigationButtonProps = {
137
138
  export type PinnedToolType = {
138
139
  key: string;
139
140
  badgeValue?: number;
140
- badgeType?: 'number' | 'dot';
141
+ badgeType?: 'number' | 'dot' | 'dot-animation';
141
142
  };
142
143
 
143
144
  export type RuntimeToolType = {
@@ -146,19 +147,29 @@ export type RuntimeToolType = {
146
147
  key: string;
147
148
  };
148
149
 
149
- export interface NavigationOptions extends StackNavigationOptions {
150
+ export interface NavigationOptions
151
+ extends Omit<StackNavigationOptions, 'headerRight'> {
150
152
  preventBack?: PopupNotifyProps;
151
153
  onPressLeftHeader?: () => void;
152
154
  surface?: boolean;
153
155
  hiddenBack?: boolean;
154
156
  customTitle?: TitleCustomProps;
155
- toolkitParams?: {
156
- pinnedTool?: PinnedToolType;
157
- runtimeTools?: RuntimeToolType[];
158
- preventClose?: PopupNotifyProps;
159
- };
157
+ headerRight?: HeaderRightToolkit | HeaderRightActions | any;
160
158
  }
161
159
 
160
+ export type HeaderRightToolkit = {
161
+ type?: 'toolkit';
162
+ pinnedTool?: PinnedToolType;
163
+ runtimeTools?: RuntimeToolType[];
164
+ preventClose?: PopupNotifyProps;
165
+ useMore?: boolean;
166
+ };
167
+
168
+ export type HeaderRightActions = {
169
+ type?: 'icon';
170
+ buttons: NavigationButtonProps[];
171
+ };
172
+
162
173
  export interface HeaderBackProps extends NavigationButtonProps {
163
174
  preventBack?: PopupNotifyProps;
164
175
  onPressLeftHeader?: () => void;
@@ -199,6 +210,12 @@ export type BottomTabItemProps = {
199
210
  badgeLabel?: string | number;
200
211
  screen: Screen;
201
212
  options: NavigationOptions;
213
+ initialParams?: any;
214
+ listeners?: {
215
+ tabPress?: (e: EventArg<'tabPress', true, undefined>) => void;
216
+ focus?: (e: EventArg<'focus', false, unknown>) => void;
217
+ blur?: (e: EventArg<'blur', false, unknown>) => void;
218
+ };
202
219
  };
203
220
 
204
221
  export type BottomTabProps = {
@@ -207,8 +224,9 @@ export type BottomTabProps = {
207
224
  initialRouteName?: string;
208
225
  navigation: Navigation;
209
226
  listeners?: {
210
- tabPress?: any;
211
- focus?: any;
227
+ tabPress?: (e: EventArg<'tabPress', true, undefined>) => void;
228
+ focus?: (e: EventArg<'focus', false, unknown>) => void;
229
+ blur?: (e: EventArg<'blur', false, unknown>) => void;
212
230
  };
213
231
  floatingButton?: FloatingButtonProps;
214
232
  };
@@ -7,11 +7,13 @@ import {
7
7
  HeaderBackground,
8
8
  HeaderCustom,
9
9
  HeaderLeft,
10
+ HeaderRight,
10
11
  HeaderTitle,
11
- HeaderToolkitAction,
12
12
  } from './Components';
13
- import {NavigationOptions, Theme} from './types';
13
+ import {NavigationOptions} from './types';
14
14
  import {Colors} from '../Consts';
15
+ import Navigation from './Navigation';
16
+ import {LayoutChangeEvent} from 'react-native';
15
17
 
16
18
  /**
17
19
  * default options for stack screen
@@ -22,7 +24,7 @@ const getStackOptions = (): StackNavigationOptions => {
22
24
  headerTitle: HeaderTitle,
23
25
  headerBackground: (props: any) => <HeaderBackground {...props} />,
24
26
  headerLeft: (props: any) => <HeaderLeft {...props} />,
25
- headerRight: (props: any) => <HeaderToolkitAction {...props} />,
27
+ headerRight: (props: any) => <HeaderRight {...props} />,
26
28
  headerTintColor: Colors.black_01,
27
29
  };
28
30
  };
@@ -72,33 +74,42 @@ const getModalOptions = (): StackNavigationOptions => {
72
74
  /**
73
75
  * build react-navigation options
74
76
  */
75
- const getOptions = (params: NavigationOptions, theme: Theme) => {
77
+ const getOptions = (params: NavigationOptions, navigation?: Navigation) => {
76
78
  let options = {};
77
79
 
80
+ /**
81
+ * left header factory
82
+ */
78
83
  if (
79
84
  typeof params.onPressLeftHeader === 'function' ||
80
85
  params.preventBack !== undefined ||
81
86
  typeof params.hiddenBack === 'boolean'
82
87
  ) {
88
+ let headerLeft: any = (props: any) => (
89
+ <HeaderLeft
90
+ {...props}
91
+ preventBack={params.preventBack}
92
+ onPressLeftHeader={params.onPressLeftHeader}
93
+ />
94
+ );
95
+ if (params.hiddenBack) {
96
+ headerLeft = null;
97
+ }
83
98
  options = {
84
99
  ...options,
85
- headerLeft: params.hiddenBack
86
- ? null
87
- : (props: any) => (
88
- <HeaderLeft
89
- {...props}
90
- preventBack={params.preventBack}
91
- onPressLeftHeader={params.onPressLeftHeader}
92
- />
93
- ),
100
+ headerLeft,
94
101
  };
95
102
  }
96
103
 
97
- if (typeof params.surface == 'boolean') {
104
+ /**
105
+ * surface header style
106
+ */
107
+ if (typeof params.surface === 'boolean') {
108
+ console.warn('surface options is deprecated, headerType instead in screen');
98
109
  if (params.surface) {
99
110
  options = {
100
111
  ...options,
101
- headerTintColor: theme.colors.text.default,
112
+ headerTintColor: Colors.black_17,
102
113
  headerBackground: () => (
103
114
  <HeaderBackground image={null} useSurface={true} />
104
115
  ),
@@ -112,7 +123,13 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
112
123
  }
113
124
  }
114
125
 
126
+ /**
127
+ * custom title
128
+ */
115
129
  if (params.customTitle) {
130
+ console.warn(
131
+ 'customTitle options is deprecated, please used headerTitle instead'
132
+ );
116
133
  options = {
117
134
  ...options,
118
135
  headerTitleAlign: 'left',
@@ -122,12 +139,37 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
122
139
  };
123
140
  }
124
141
 
125
- if (params.toolkitParams) {
142
+ /**
143
+ * header right
144
+ */
145
+ if (params.headerRight) {
146
+ let headerRight: any = (props: any) => {
147
+ return (
148
+ <HeaderRight
149
+ {...props}
150
+ {...params.headerRight}
151
+ onLayout={(e: LayoutChangeEvent) => {
152
+ navigation?.onHeaderRightChange?.(e.nativeEvent.layout.width);
153
+ }}
154
+ />
155
+ );
156
+ };
157
+ if (typeof params.headerRight === 'function') {
158
+ headerRight = (props: any) => {
159
+ return (
160
+ <HeaderRight
161
+ {...props}
162
+ onLayout={(e: LayoutChangeEvent) => {
163
+ navigation?.onHeaderRightChange?.(e.nativeEvent.layout.width);
164
+ }}>
165
+ {params.headerRight(props)}
166
+ </HeaderRight>
167
+ );
168
+ };
169
+ }
126
170
  options = {
127
171
  ...options,
128
- headerRight: (props: any) => {
129
- return <HeaderToolkitAction {...params.toolkitParams} {...props} />;
130
- },
172
+ headerRight,
131
173
  };
132
174
  }
133
175
 
@@ -503,4 +503,4 @@
503
503
  "zalopay_icon": {
504
504
  "uri": "https://static.momocdn.net/app/img/kits/icon_bank/zalopay_icon.png"
505
505
  }
506
- }
506
+ }