@momo-kits/foundation 0.92.23 → 0.92.24

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.
@@ -89,14 +89,16 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
89
89
  return;
90
90
  }
91
91
  setTimeout(() => {
92
- navigator?.pop();
93
92
  callback?.();
94
- }, 300);
93
+ }, 350);
94
+
95
95
  Animated.timing(pan, {
96
96
  toValue: {x: 0, y: heightDevice},
97
97
  useNativeDriver: false,
98
- duration: 200,
99
- }).start();
98
+ duration: 100,
99
+ }).start(() => {
100
+ navigator?.pop();
101
+ });
100
102
  };
101
103
 
102
104
  /**
@@ -125,7 +125,7 @@ export default function BottomTabBar({
125
125
  );
126
126
  });
127
127
  },
128
- [JSON.stringify(routes), state, descriptors, focusedTab],
128
+ [JSON.stringify(routes), state, descriptors, focusedTab]
129
129
  );
130
130
 
131
131
  /**
@@ -153,7 +153,7 @@ export default function BottomTabBar({
153
153
  </View>
154
154
  <View
155
155
  style={{
156
- top: -6,
156
+ top: -4,
157
157
  backgroundColor: activeTintColor ?? theme.colors.primary,
158
158
  borderRadius: Radius.XL,
159
159
  paddingHorizontal: 6,
@@ -17,9 +17,10 @@ const Tab = createBottomTabNavigator();
17
17
  const Stack = createStackNavigator();
18
18
 
19
19
  const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
20
+ const {theme} = useContext(ApplicationContext);
20
21
  let options = {};
21
22
  if (route.params?.options) {
22
- options = getOptions(route.params?.options);
23
+ options = getOptions(route.params?.options, theme);
23
24
  }
24
25
 
25
26
  if (route.params?.nested) {
@@ -100,7 +101,7 @@ const BottomTab: React.FC<BottomTabProps> = ({
100
101
  name={item.name}
101
102
  component={TabScreen}
102
103
  initialParams={{...item, nested}}
103
- listeners={listeners}
104
+ listeners={item.listeners ?? listeners}
104
105
  options={{
105
106
  tabBarLabel: ({color, focused}) => {
106
107
  return (
@@ -1,8 +1,8 @@
1
1
  import React, {
2
+ Fragment,
2
3
  useCallback,
3
4
  useContext,
4
5
  useEffect,
5
- useRef,
6
6
  useState,
7
7
  } from 'react';
8
8
  import {
@@ -30,9 +30,6 @@ import {Icon} from '../Icon';
30
30
  import {PopupNotify} from '../Popup';
31
31
  import {Badge, BadgeDot} from '../Badge';
32
32
 
33
- /**
34
- * default navigation button used header nav
35
- */
36
33
  const NavigationButton: React.FC<NavigationButtonProps> = ({
37
34
  icon,
38
35
  tintColor,
@@ -84,9 +81,6 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
84
81
  );
85
82
  };
86
83
 
87
- /**
88
- * default header title used for nav
89
- */
90
84
  const HeaderTitle: React.FC<any> = props => {
91
85
  const {theme} = useContext(ApplicationContext);
92
86
  const opacity = props.animatedValue?.interpolate({
@@ -107,9 +101,6 @@ const HeaderTitle: React.FC<any> = props => {
107
101
  );
108
102
  };
109
103
 
110
- /**
111
- * default header left used for nav
112
- */
113
104
  const HeaderLeft: React.FC<HeaderBackProps> = ({
114
105
  tintColor,
115
106
  preventBack,
@@ -122,7 +113,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
122
113
  useEffect(() => {
123
114
  const backHandler = BackHandler.addEventListener(
124
115
  'hardwareBackPress',
125
- goBackSafe
116
+ goBackSafe,
126
117
  );
127
118
 
128
119
  return () => backHandler.remove();
@@ -177,7 +168,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
177
168
  }
178
169
  return true;
179
170
  };
180
-
181
171
  return (
182
172
  <View style={styles.headerLeft}>
183
173
  <NavigationButton
@@ -191,9 +181,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
191
181
  );
192
182
  };
193
183
 
194
- /**
195
- * header background for default
196
- */
197
184
  const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
198
185
  image,
199
186
  animatedValue,
@@ -242,10 +229,6 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
242
229
  );
243
230
  };
244
231
 
245
- /**
246
- * Header custom with image, title, subtitle
247
- * @constructor
248
- */
249
232
  const HeaderCustom: React.FC<TitleCustomProps> = ({
250
233
  title,
251
234
  subTitle,
@@ -280,42 +263,37 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
280
263
  return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
281
264
  };
282
265
 
283
- /**
284
- * main component for header right
285
- */
286
- const HeaderRight: React.FC<any> = ({type, children, onLayout, ...props}) => {
287
- if (type === 'icon') {
288
- let buttons = props?.buttons || [];
289
- if (buttons?.length > 3) {
290
- buttons = buttons.slice(0, 3);
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
+ };
276
+
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
+ });
291
286
  }
287
+
292
288
  return (
293
- <View style={styles.headerRightButton} onLayout={onLayout}>
294
- {buttons?.map?.((item: NavigationButtonProps, index: number) => {
295
- return (
296
- <View
297
- key={`HeaderRightAction ${index}`}
298
- style={{
299
- marginLeft: index !== 0 ? Spacing.S : 0,
300
- }}>
301
- <NavigationButton {...item} tintColor={props?.tintColor} />
302
- </View>
303
- );
304
- })}
289
+ <View style={styles.headerButton}>
290
+ {React.cloneElement(validateType(children), {...restProps})}
305
291
  </View>
306
292
  );
307
- }
308
-
309
- return (
310
- <View style={styles.headerRightButton} onLayout={onLayout}>
311
- {children ?? <HeaderToolkitAction {...props} />}
312
- </View>
313
- );
293
+ };
294
+ return <View style={styles.headerRightButton}>{renderAction()}</View>;
314
295
  };
315
296
 
316
- /**
317
- * Header toolkit action
318
- */
319
297
  const HeaderToolkitAction: React.FC<any> = ({
320
298
  tintColor,
321
299
  pinnedTool,
@@ -349,7 +327,7 @@ const HeaderToolkitAction: React.FC<any> = ({
349
327
  (config: any) => {
350
328
  navigator.toolkitConfig = config;
351
329
  setToolConfig(navigator?.toolkitConfig);
352
- }
330
+ },
353
331
  );
354
332
  };
355
333
 
@@ -362,7 +340,7 @@ const HeaderToolkitAction: React.FC<any> = ({
362
340
  const {item} = res;
363
341
  navigator?.toolkitCallback?.(item);
364
342
  getToolkitConfig();
365
- }
343
+ },
366
344
  );
367
345
  };
368
346
 
@@ -379,7 +357,7 @@ const HeaderToolkitAction: React.FC<any> = ({
379
357
  navigator?.maxApi?.dispatchFunction?.(
380
358
  'dismiss',
381
359
  undefined,
382
- undefined
360
+ undefined,
383
361
  );
384
362
  },
385
363
  }}
@@ -410,7 +388,7 @@ const HeaderToolkitAction: React.FC<any> = ({
410
388
  [pinTool?.key],
411
389
  () => {
412
390
  getToolkitConfig();
413
- }
391
+ },
414
392
  );
415
393
  navigator?.toolkitCallback?.(pinTool.key);
416
394
  }}
@@ -419,7 +397,7 @@ const HeaderToolkitAction: React.FC<any> = ({
419
397
  };
420
398
  if (toolConfig) {
421
399
  return (
422
- <View style={Styles.row}>
400
+ <View style={styles.headerRightButton}>
423
401
  {renderPinnedTool()}
424
402
  <View
425
403
  style={[
@@ -427,7 +405,6 @@ const HeaderToolkitAction: React.FC<any> = ({
427
405
  {
428
406
  backgroundColor: backgroundColor ?? '#00000066',
429
407
  borderWidth: backgroundColor ? 0.5 : 0,
430
- marginLeft: renderPinnedTool() ? Spacing.S : 0,
431
408
  },
432
409
  ]}>
433
410
  <TouchableOpacity
@@ -453,9 +430,6 @@ const HeaderToolkitAction: React.FC<any> = ({
453
430
  return <View />;
454
431
  };
455
432
 
456
- /**
457
- * default header banner for header animated
458
- */
459
433
  const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
460
434
  animatedValue,
461
435
  image,
@@ -496,47 +470,6 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
496
470
  );
497
471
  };
498
472
 
499
- /**
500
- * Header extended with background image
501
- * @constructor
502
- */
503
- const HeaderExtendBackground: React.FC<{
504
- headerBackground: string;
505
- animatedValue: Animated.Value;
506
- heightHeader: number;
507
- }> = ({headerBackground, animatedValue, heightHeader}) => {
508
- const heightAnimated = useRef(new Animated.Value(0));
509
-
510
- useEffect(() => {
511
- const listener = animatedValue.addListener(({value}) => {
512
- heightAnimated.current.setValue(value);
513
- });
514
- return () => {
515
- animatedValue?.removeListener(listener);
516
- };
517
- }, []);
518
-
519
- return (
520
- <>
521
- <Image
522
- source={{
523
- uri: headerBackground,
524
- }}
525
- style={styles.extendedHeader}
526
- />
527
- <Animated.View
528
- style={{
529
- height: heightAnimated.current.interpolate({
530
- inputRange: [0, 100],
531
- outputRange: [heightHeader, heightHeader - 52],
532
- extrapolate: 'clamp',
533
- }),
534
- }}
535
- />
536
- </>
537
- );
538
- };
539
-
540
473
  const styles = StyleSheet.create({
541
474
  navigationButton: {
542
475
  height: 28,
@@ -576,6 +509,7 @@ const styles = StyleSheet.create({
576
509
  paddingRight: Spacing.M,
577
510
  },
578
511
  toolkitContainer: {
512
+ marginLeft: Spacing.S,
579
513
  padding: Spacing.XS,
580
514
  height: 28,
581
515
  borderRadius: 14,
@@ -607,12 +541,6 @@ const styles = StyleSheet.create({
607
541
  top: -Spacing.XS,
608
542
  right: -Spacing.XS,
609
543
  },
610
- extendedHeader: {
611
- aspectRatio: 1.75,
612
- position: 'absolute',
613
- width: '100%',
614
- height: 210,
615
- },
616
544
  });
617
545
 
618
546
  export {
@@ -620,9 +548,8 @@ export {
620
548
  HeaderTitle,
621
549
  HeaderLeft,
622
550
  HeaderBackground,
551
+ HeaderRightAction,
623
552
  HeaderToolkitAction,
624
553
  HeaderCustom,
625
554
  HeaderAnimated,
626
- HeaderRight,
627
- HeaderExtendBackground,
628
555
  };
@@ -21,10 +21,10 @@ const ModalScreen: React.FC<any> = props => {
21
21
  };
22
22
 
23
23
  const Modal: React.FC<ModalParams> = props => {
24
- const {navigator} = useContext(ApplicationContext);
24
+ const {theme, navigator} = useContext(ApplicationContext);
25
25
  const {screen, barrierDismissible} = props.route.params;
26
26
  const Component = useRef(screen).current;
27
- const navigation = new Navigation(props.navigation);
27
+ const navigation = new Navigation(props.navigation, theme);
28
28
  const params = {
29
29
  ...props.route.params,
30
30
  navigation,
@@ -1,13 +1,17 @@
1
+ import React from 'react';
1
2
  import {NavigationProp} from '@react-navigation/native';
2
- import {NavigationOptions} from './types';
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>;
7
- rightHeaderWidth?: number;
10
+ readonly theme: Theme;
8
11
 
9
- constructor(instance: any) {
12
+ constructor(instance: any, theme: Theme) {
10
13
  this.instance = instance;
14
+ this.theme = theme;
11
15
  }
12
16
 
13
17
  /**
@@ -15,6 +19,16 @@ class Navigation {
15
19
  * @param params
16
20
  */
17
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
+
18
32
  if (params.headerLeft) {
19
33
  console.warn('headerLeft not allow override render by design system!');
20
34
  delete params.headerLeft;
@@ -28,7 +42,7 @@ class Navigation {
28
42
  * @param params
29
43
  */
30
44
  setOptions = (params: NavigationOptions) => {
31
- params = getOptions(this.filterParams(params), this);
45
+ params = getOptions(this.filterParams(params), this.theme);
32
46
  this.instance.setOptions(params);
33
47
  };
34
48
  }
@@ -88,7 +88,7 @@ const EmptyScreen: React.FC = () => {
88
88
  * @constructor
89
89
  */
90
90
  const StackScreen: React.FC<ScreenParams> = props => {
91
- const {showGrid, navigator} = useContext(ApplicationContext);
91
+ const {theme, showGrid, navigator} = useContext(ApplicationContext);
92
92
  const startTime = useRef(Date.now());
93
93
  const endTime = useRef(Date.now());
94
94
  const timeLoad = useRef(0);
@@ -104,7 +104,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
104
104
  const context = useContext<any>(MiniAppContext);
105
105
 
106
106
  const {screen: Component, options, initialParams} = props.route.params;
107
- const navigation = new Navigation(props.navigation);
107
+ const navigation = new Navigation(props.navigation, theme);
108
108
  const heightHeader = useHeaderHeight();
109
109
 
110
110
  const data = {
@@ -5,6 +5,7 @@ import {
5
5
  HeaderAnimated,
6
6
  HeaderBackground,
7
7
  HeaderCustom,
8
+ HeaderRightAction,
8
9
  HeaderTitle,
9
10
  NavigationButton,
10
11
  } from './Components';
@@ -30,6 +31,7 @@ export {
30
31
  NavigationButton,
31
32
  HeaderTitle,
32
33
  HeaderBackground,
34
+ HeaderRightAction,
33
35
  HeaderCustom,
34
36
  HeaderAnimated,
35
37
  };
@@ -145,29 +145,19 @@ export type RuntimeToolType = {
145
145
  key: string;
146
146
  };
147
147
 
148
- export interface NavigationOptions
149
- extends Omit<StackNavigationOptions, 'headerRight'> {
148
+ export interface NavigationOptions extends StackNavigationOptions {
150
149
  preventBack?: PopupNotifyProps;
151
150
  onPressLeftHeader?: () => void;
152
151
  surface?: boolean;
153
152
  hiddenBack?: boolean;
154
153
  customTitle?: TitleCustomProps;
155
- headerRight?: HeaderRightToolkit | HeaderRightActions | any;
154
+ toolkitParams?: {
155
+ pinnedTool?: PinnedToolType;
156
+ runtimeTools?: RuntimeToolType[];
157
+ preventClose?: PopupNotifyProps;
158
+ };
156
159
  }
157
160
 
158
- export type HeaderRightToolkit = {
159
- type?: 'toolkit';
160
- pinnedTool?: PinnedToolType;
161
- runtimeTools?: RuntimeToolType[];
162
- preventClose?: PopupNotifyProps;
163
- useMore?: boolean;
164
- };
165
-
166
- export type HeaderRightActions = {
167
- type?: 'icon';
168
- buttons: NavigationButtonProps[];
169
- };
170
-
171
161
  export interface HeaderBackProps extends NavigationButtonProps {
172
162
  preventBack?: PopupNotifyProps;
173
163
  onPressLeftHeader?: () => void;
@@ -7,13 +7,11 @@ import {
7
7
  HeaderBackground,
8
8
  HeaderCustom,
9
9
  HeaderLeft,
10
- HeaderRight,
11
10
  HeaderTitle,
11
+ HeaderToolkitAction,
12
12
  } from './Components';
13
- import {NavigationOptions} from './types';
13
+ import {NavigationOptions, Theme} from './types';
14
14
  import {Colors} from '../Consts';
15
- import Navigation from './Navigation';
16
- import {LayoutChangeEvent} from 'react-native';
17
15
 
18
16
  /**
19
17
  * default options for stack screen
@@ -24,7 +22,7 @@ const getStackOptions = (): StackNavigationOptions => {
24
22
  headerTitle: HeaderTitle,
25
23
  headerBackground: (props: any) => <HeaderBackground {...props} />,
26
24
  headerLeft: (props: any) => <HeaderLeft {...props} />,
27
- headerRight: (props: any) => <HeaderRight {...props} />,
25
+ headerRight: (props: any) => <HeaderToolkitAction {...props} />,
28
26
  headerTintColor: Colors.black_01,
29
27
  };
30
28
  };
@@ -74,42 +72,33 @@ const getModalOptions = (): StackNavigationOptions => {
74
72
  /**
75
73
  * build react-navigation options
76
74
  */
77
- const getOptions = (params: NavigationOptions, navigation?: Navigation) => {
75
+ const getOptions = (params: NavigationOptions, theme: Theme) => {
78
76
  let options = {};
79
77
 
80
- /**
81
- * left header factory
82
- */
83
78
  if (
84
79
  typeof params.onPressLeftHeader === 'function' ||
85
80
  params.preventBack !== undefined ||
86
81
  typeof params.hiddenBack === 'boolean'
87
82
  ) {
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
- }
98
83
  options = {
99
84
  ...options,
100
- headerLeft,
85
+ headerLeft: params.hiddenBack
86
+ ? null
87
+ : (props: any) => (
88
+ <HeaderLeft
89
+ {...props}
90
+ preventBack={params.preventBack}
91
+ onPressLeftHeader={params.onPressLeftHeader}
92
+ />
93
+ ),
101
94
  };
102
95
  }
103
96
 
104
- /**
105
- * surface header style
106
- */
107
97
  if (typeof params.surface === 'boolean') {
108
- console.warn('surface options is deprecated, headerType instead in screen');
109
98
  if (params.surface) {
110
99
  options = {
111
100
  ...options,
112
- headerTintColor: Colors.black_17,
101
+ headerTintColor: theme.colors.text.default,
113
102
  headerBackground: () => (
114
103
  <HeaderBackground image={null} useSurface={true} />
115
104
  ),
@@ -123,13 +112,7 @@ const getOptions = (params: NavigationOptions, navigation?: Navigation) => {
123
112
  }
124
113
  }
125
114
 
126
- /**
127
- * custom title
128
- */
129
115
  if (params.customTitle) {
130
- console.warn(
131
- 'customTitle options is deprecated, please used headerTitle instead'
132
- );
133
116
  options = {
134
117
  ...options,
135
118
  headerTitleAlign: 'left',
@@ -139,41 +122,12 @@ const getOptions = (params: NavigationOptions, navigation?: Navigation) => {
139
122
  };
140
123
  }
141
124
 
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
- if (navigation) {
153
- navigation.rightHeaderWidth = e.nativeEvent.layout.width;
154
- }
155
- }}
156
- />
157
- );
158
- };
159
- if (typeof params.headerRight === 'function') {
160
- headerRight = (props: any) => {
161
- return (
162
- <HeaderRight
163
- {...props}
164
- onLayout={(e: LayoutChangeEvent) => {
165
- if (navigation) {
166
- navigation.rightHeaderWidth = e.nativeEvent.layout.width;
167
- }
168
- }}>
169
- {params.headerRight(props)}
170
- </HeaderRight>
171
- );
172
- };
173
- }
125
+ if (params.toolkitParams) {
174
126
  options = {
175
127
  ...options,
176
- headerRight,
128
+ headerRight: (props: any) => {
129
+ return <HeaderToolkitAction {...params.toolkitParams} {...props} />;
130
+ },
177
131
  };
178
132
  }
179
133
 
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={{
package/Icon/types.ts CHANGED
@@ -16,7 +16,6 @@ export type IconProps = {
16
16
 
17
17
  /**
18
18
  * Optional. Represents the color of the icon.
19
- * It can be any valid color in @momo-kits/foundation.
20
19
  */
21
20
  color?: string | null;
22
21
 
@@ -4,7 +4,7 @@ import {ApplicationContext, ComponentContext} from '../Application';
4
4
  import {Styles} from '../Consts';
5
5
  import {Icon} from '../Icon';
6
6
  import {Loader} from '../Loader';
7
- import {ErrorView, FloatingView, getSizeStyle} from './common';
7
+ import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
8
8
  import {InputDropDownProps} from './index';
9
9
  import styles from './styles';
10
10
 
@@ -61,7 +61,7 @@ const InputDropDown = ({
61
61
  styles.inputWrapper,
62
62
  {backgroundColor: theme.colors.background.surface},
63
63
  getSizeStyle(size),
64
- // getBorderColor(theme, false, errorMessage, disabled),
64
+ getBorderColor(theme, false, errorMessage, disabled),
65
65
  ]}>
66
66
  <FloatingView
67
67
  floatingValue={floatingValue}
@@ -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;