@momo-kits/foundation 0.92.21-beta.2 → 0.92.21-beta.3

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.
@@ -1,9 +1,8 @@
1
1
  import React, {
2
- FC,
2
+ Fragment,
3
3
  useCallback,
4
4
  useContext,
5
5
  useEffect,
6
- useRef,
7
6
  useState,
8
7
  } from 'react';
9
8
  import {
@@ -84,6 +83,11 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
84
83
 
85
84
  const HeaderTitle: React.FC<any> = props => {
86
85
  const {theme} = useContext(ApplicationContext);
86
+ const opacity = props.animatedValue?.interpolate({
87
+ inputRange: [0, 200],
88
+ outputRange: [0, 1],
89
+ extrapolate: 'clamp',
90
+ });
87
91
 
88
92
  return (
89
93
  <Animated.Text
@@ -91,11 +95,7 @@ const HeaderTitle: React.FC<any> = props => {
91
95
  accessibilityLabel={'title_navigation_header'}
92
96
  style={[
93
97
  styles.title,
94
- {
95
- fontFamily: `${theme.font}-Bold`,
96
- color: props.tintColor,
97
- opacity: props.titleOpacity,
98
- },
98
+ {fontFamily: `${theme.font}-Bold`, opacity, color: props.tintColor},
99
99
  ]}
100
100
  />
101
101
  );
@@ -113,7 +113,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
113
113
  useEffect(() => {
114
114
  const backHandler = BackHandler.addEventListener(
115
115
  'hardwareBackPress',
116
- goBackSafe
116
+ goBackSafe,
117
117
  );
118
118
 
119
119
  return () => backHandler.remove();
@@ -263,40 +263,35 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
263
263
  return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
264
264
  };
265
265
 
266
- const HeaderRight: FC<any> = ({type, ...props}) => {
267
- let buttons = props?.buttons || [];
268
- if (!type) {
269
- return <View />;
270
- }
266
+ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
267
+ const validateType = (child: React.ReactElement) => {
268
+ const valid = child?.type === NavigationButton || child?.type === Fragment;
269
+ if (__DEV__ && !valid) {
270
+ console.warn(
271
+ 'HeaderRightAction contains element type of NavigationButton, Please check again.',
272
+ );
273
+ }
274
+ return child;
275
+ };
271
276
 
272
- if (type === 'iconButton') {
273
- if (buttons?.length > 3) {
274
- buttons = buttons.slice(0, 3);
277
+ const renderAction = () => {
278
+ if (Array.isArray(children)) {
279
+ return children.map((child, index) => {
280
+ return (
281
+ <View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
282
+ {React.cloneElement(validateType(child), {...restProps})}
283
+ </View>
284
+ );
285
+ });
275
286
  }
287
+
276
288
  return (
277
- <View style={styles.headerRightButton}>
278
- {buttons?.map?.(
279
- ({icon, onPress}: NavigationButtonProps, index: number) => {
280
- return (
281
- <View
282
- key={`HeaderRightAction ${index}`}
283
- style={{
284
- marginLeft: index !== 0 ? Spacing.S : 0,
285
- }}>
286
- <NavigationButton
287
- icon={icon}
288
- onPress={onPress}
289
- tintColor={props?.tintColor}
290
- />
291
- </View>
292
- );
293
- }
294
- )}
289
+ <View style={styles.headerButton}>
290
+ {React.cloneElement(validateType(children), {...restProps})}
295
291
  </View>
296
292
  );
297
- }
298
-
299
- return <HeaderToolkitAction {...props} />;
293
+ };
294
+ return <View style={styles.headerRightButton}>{renderAction()}</View>;
300
295
  };
301
296
 
302
297
  const HeaderToolkitAction: React.FC<any> = ({
@@ -332,7 +327,7 @@ const HeaderToolkitAction: React.FC<any> = ({
332
327
  (config: any) => {
333
328
  navigator.toolkitConfig = config;
334
329
  setToolConfig(navigator?.toolkitConfig);
335
- }
330
+ },
336
331
  );
337
332
  };
338
333
 
@@ -345,7 +340,7 @@ const HeaderToolkitAction: React.FC<any> = ({
345
340
  const {item} = res;
346
341
  navigator?.toolkitCallback?.(item);
347
342
  getToolkitConfig();
348
- }
343
+ },
349
344
  );
350
345
  };
351
346
 
@@ -362,7 +357,7 @@ const HeaderToolkitAction: React.FC<any> = ({
362
357
  navigator?.maxApi?.dispatchFunction?.(
363
358
  'dismiss',
364
359
  undefined,
365
- undefined
360
+ undefined,
366
361
  );
367
362
  },
368
363
  }}
@@ -393,7 +388,7 @@ const HeaderToolkitAction: React.FC<any> = ({
393
388
  [pinTool?.key],
394
389
  () => {
395
390
  getToolkitConfig();
396
- }
391
+ },
397
392
  );
398
393
  navigator?.toolkitCallback?.(pinTool.key);
399
394
  }}
@@ -410,7 +405,6 @@ const HeaderToolkitAction: React.FC<any> = ({
410
405
  {
411
406
  backgroundColor: backgroundColor ?? '#00000066',
412
407
  borderWidth: backgroundColor ? 0.5 : 0,
413
- marginLeft: renderPinnedTool() ? Spacing.S : 0,
414
408
  },
415
409
  ]}>
416
410
  <TouchableOpacity
@@ -476,42 +470,6 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
476
470
  );
477
471
  };
478
472
 
479
- const ExtendBackground: FC<{
480
- headerBackground: string;
481
- animatedValue: Animated.Value;
482
- heightHeader: number;
483
- }> = ({headerBackground, animatedValue, heightHeader}) => {
484
- const heightAnimated = useRef(new Animated.Value(0));
485
- useEffect(() => {
486
- const listener = animatedValue.addListener(({value}) => {
487
- heightAnimated.current.setValue(value);
488
- });
489
- return () => {
490
- animatedValue?.removeListener(listener);
491
- };
492
- }, []);
493
-
494
- return (
495
- <>
496
- <Image
497
- source={{
498
- uri: headerBackground,
499
- }}
500
- style={styles.extendedHeader}
501
- />
502
- <Animated.View
503
- style={{
504
- height: heightAnimated.current.interpolate({
505
- inputRange: [0, 100],
506
- outputRange: [heightHeader, heightHeader - 52],
507
- extrapolate: 'clamp',
508
- }),
509
- }}
510
- />
511
- </>
512
- );
513
- };
514
-
515
473
  const styles = StyleSheet.create({
516
474
  navigationButton: {
517
475
  height: 28,
@@ -551,6 +509,7 @@ const styles = StyleSheet.create({
551
509
  paddingRight: Spacing.M,
552
510
  },
553
511
  toolkitContainer: {
512
+ marginLeft: Spacing.S,
554
513
  padding: Spacing.XS,
555
514
  height: 28,
556
515
  borderRadius: 14,
@@ -582,12 +541,6 @@ const styles = StyleSheet.create({
582
541
  top: -Spacing.XS,
583
542
  right: -Spacing.XS,
584
543
  },
585
- extendedHeader: {
586
- aspectRatio: 1.75,
587
- position: 'absolute',
588
- width: '100%',
589
- height: 210,
590
- },
591
544
  });
592
545
 
593
546
  export {
@@ -595,9 +548,8 @@ export {
595
548
  HeaderTitle,
596
549
  HeaderLeft,
597
550
  HeaderBackground,
551
+ HeaderRightAction,
598
552
  HeaderToolkitAction,
599
553
  HeaderCustom,
600
554
  HeaderAnimated,
601
- HeaderRight,
602
- ExtendBackground,
603
555
  };
@@ -1,6 +1,9 @@
1
+ import React from 'react';
1
2
  import {NavigationProp} from '@react-navigation/native';
2
3
  import {NavigationOptions, Theme} from './types';
4
+ import {HeaderRightAction} from './index';
3
5
  import {getOptions} from './utils';
6
+ import {HeaderToolkitAction} from './Components';
4
7
 
5
8
  class Navigation {
6
9
  instance: NavigationProp<any>;
@@ -16,6 +19,16 @@ class Navigation {
16
19
  * @param params
17
20
  */
18
21
  private filterParams = (params: NavigationOptions) => {
22
+ if (params.headerRight) {
23
+ const headerRight = params.headerRight?.({}) as React.ReactElement;
24
+ const type = headerRight?.type;
25
+ if (type !== HeaderRightAction && type !== HeaderToolkitAction) {
26
+ console.warn(
27
+ 'headerRight contains element type of HeaderRightAction | HeaderToolkitAction, Please check again.',
28
+ );
29
+ }
30
+ }
31
+
19
32
  if (params.headerLeft) {
20
33
  console.warn('headerLeft not allow override render by design system!');
21
34
  delete params.headerLeft;
@@ -1,92 +1,11 @@
1
1
  import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
- import {useHeaderHeight} from '@react-navigation/stack';
3
- import {InteractionManager, Linking, View} from 'react-native';
4
2
  import {ScreenParams} from './types';
5
3
  import Navigation from './Navigation';
6
4
  import {ApplicationContext, MiniAppContext, ScreenContext} from './index';
7
5
  import {GridSystem} from '../Layout';
8
- import {Text} from '../Text';
9
- import {Colors, Radius, Spacing} from '../Consts';
10
-
11
- /**
12
- * Empty screen for unvalidated screen name
13
- * @constructor
14
- */
15
- const EmptyScreen: React.FC = () => {
16
- return (
17
- <View
18
- style={{
19
- backgroundColor: Colors.black_01,
20
- padding: Spacing.M,
21
- borderRadius: Radius.M,
22
- }}>
23
- <Text typography={'header_m_bold'}>Unvalidated screen name</Text>
24
- <Text
25
- typography={'description_default_regular'}
26
- style={{paddingVertical: Spacing.S}}>
27
- Your screen has not been rendered because Platform has not detected the
28
- screen name. Please migrate to support this feature.
29
- </Text>
30
- <Text typography={'header_default'} style={{width: '100%'}}>
31
- Possible fixes:
32
- </Text>
33
- <View style={{marginLeft: Spacing.S}}>
34
- <Text typography={'body_default_regular'}>1. Off webpack config</Text>
35
- <Text typography={'body_default_regular'}>
36
- 2. Screen name refactoring
37
- </Text>
38
- <View style={{marginLeft: Spacing.S}}>
39
- <Text
40
- typography={'description_default_regular'}
41
- style={{marginBottom: Spacing.S}}>
42
- - Với các screen push/import dạng arrow function ={'>'} đổi thành
43
- named function
44
- </Text>
45
- <Text
46
- typography={'description_default_regular'}
47
- style={{marginBottom: Spacing.S}}>
48
- - Với các screen import dạng High Order Component ={'>'} rename
49
- generic function thành named function
50
- </Text>
51
- <Text
52
- typography={'description_default_regular'}
53
- style={{marginBottom: Spacing.S}}>
54
- - Với Tab Navigator, Platform sẽ lấy Tab Container làm screen name.
55
- Trong trường hợp miniapp muốn track riêng action cho từng tab, tham
56
- khảo theo docs
57
- </Text>
58
- </View>
59
- </View>
60
- <Text typography={'header_s_semibold'}>More information: </Text>
61
- <Text
62
- typography={'body_default_regular'}
63
- color={Colors.blue_01}
64
- onPress={() => {
65
- Linking.openURL(
66
- 'https://gitlab.mservice.com.vn/momo-platform/mini-app/-/tree/vn.momo.uikits/dev/app'
67
- );
68
- }}>
69
- Mini App: vn.momo.uikits/dev
70
- </Text>
71
- <Text
72
- typography={'body_default_regular'}
73
- color={Colors.blue_01}
74
- onPress={() => {
75
- Linking.openURL(
76
- 'https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing'
77
- );
78
- }}>
79
- https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing
80
- </Text>
81
- </View>
82
- );
83
- };
6
+ import {useHeaderHeight} from '@react-navigation/stack';
7
+ import {Alert, InteractionManager} from 'react-native';
84
8
 
85
- /**
86
- * container for stack screen
87
- * @param props
88
- * @constructor
89
- */
90
9
  const StackScreen: React.FC<ScreenParams> = props => {
91
10
  const {theme, showGrid, navigator} = useContext(ApplicationContext);
92
11
  const startTime = useRef(Date.now());
@@ -131,10 +50,8 @@ const StackScreen: React.FC<ScreenParams> = props => {
131
50
  * tracking for screen
132
51
  */
133
52
  useEffect(() => {
134
- if (['Invalid', 'screen'].includes(screenName) && context.enableAutoId) {
135
- setTimeout(() => {
136
- navigator?.showModal({screen: EmptyScreen});
137
- }, 300);
53
+ if (__DEV__ && (!screenName || screenName == 'Invalid')) {
54
+ Alert.alert('Design system', `Unvalidated screen name "${screenName}" !`);
138
55
  }
139
56
 
140
57
  navigator?.maxApi?.of?.({screenName});
@@ -144,29 +144,19 @@ export type RuntimeToolType = {
144
144
  key: string;
145
145
  };
146
146
 
147
- export interface NavigationOptions
148
- extends Omit<StackNavigationOptions, 'headerRight'> {
147
+ export interface NavigationOptions extends StackNavigationOptions {
149
148
  preventBack?: PopupNotifyProps;
150
149
  onPressLeftHeader?: () => void;
151
150
  surface?: boolean;
152
151
  hiddenBack?: boolean;
153
152
  customTitle?: TitleCustomProps;
154
- headerRight?: HeaderRightToolkit | HeaderRightActions | Element;
153
+ toolkitParams?: {
154
+ pinnedTool?: PinnedToolType;
155
+ runtimeTools?: RuntimeToolType[];
156
+ preventClose?: PopupNotifyProps;
157
+ };
155
158
  }
156
159
 
157
- export type HeaderRightToolkit = {
158
- type?: 'toolkit';
159
- pinnedTool?: PinnedToolType;
160
- runtimeTools?: RuntimeToolType[];
161
- preventClose?: PopupNotifyProps;
162
- useMore?: boolean;
163
- };
164
-
165
- export type HeaderRightActions = {
166
- type?: 'iconButton';
167
- buttons: NavigationButtonProps[];
168
- };
169
-
170
160
  export interface HeaderBackProps extends NavigationButtonProps {
171
161
  preventBack?: PopupNotifyProps;
172
162
  onPressLeftHeader?: () => void;
@@ -122,6 +122,15 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
122
122
  };
123
123
  }
124
124
 
125
+ if (params.toolkitParams) {
126
+ options = {
127
+ ...options,
128
+ headerRight: (props: any) => {
129
+ return <HeaderToolkitAction {...params.toolkitParams} {...props} />;
130
+ },
131
+ };
132
+ }
133
+
125
134
  return {
126
135
  ...params,
127
136
  ...options,
package/Button/index.tsx CHANGED
@@ -297,6 +297,7 @@ const Button: FC<ButtonProps> = ({
297
297
  };
298
298
 
299
299
  const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
300
+
300
301
  return (
301
302
  <ComponentContext.Provider
302
303
  value={{
@@ -44,7 +44,7 @@ const InputMoney = forwardRef(
44
44
  value: _value,
45
45
  ...props
46
46
  }: InputMoneyProps,
47
- ref
47
+ ref,
48
48
  ) => {
49
49
  const {theme} = useContext(ApplicationContext);
50
50
  const [focused, setFocused] = useState(false);
@@ -63,7 +63,7 @@ const InputMoney = forwardRef(
63
63
  };
64
64
 
65
65
  const [value, setValue] = useState(
66
- defaultValue ? validateText(defaultValue) : ''
66
+ defaultValue ? validateText(defaultValue) : '',
67
67
  );
68
68
 
69
69
  const onClearText = () => {
@@ -198,7 +198,7 @@ const InputMoney = forwardRef(
198
198
  </View>
199
199
  </ComponentContext.Provider>
200
200
  );
201
- }
201
+ },
202
202
  );
203
203
 
204
204
  export default InputMoney;
@@ -41,7 +41,7 @@ const OTPCaret: FC<CaretProps> = ({index, length}) => {
41
41
  duration: DURATION,
42
42
  useNativeDriver: true,
43
43
  }),
44
- ])
44
+ ]),
45
45
  ).start();
46
46
  }, []);
47
47
  const spacingStyle = !isNaN(Number(length)) &&
@@ -81,7 +81,7 @@ const InputOTP = forwardRef(
81
81
  hintText,
82
82
  ...props
83
83
  }: InputOTPProps,
84
- ref
84
+ ref,
85
85
  ) => {
86
86
  const MAX_LENGTH = 10;
87
87
  const [value, setValue] = useState('');
@@ -143,7 +143,7 @@ const InputOTP = forwardRef(
143
143
  {value[i] || '-'}
144
144
  </Text>
145
145
  )}
146
- </View>
146
+ </View>,
147
147
  );
148
148
  }
149
149
  return TextInputs;
@@ -248,7 +248,7 @@ const InputOTP = forwardRef(
248
248
  </TouchableOpacity>
249
249
  </ComponentContext.Provider>
250
250
  );
251
- }
251
+ },
252
252
  );
253
253
 
254
254
  export default InputOTP;