@momo-kits/foundation 0.92.21-beta.9 → 0.92.21-rc.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.
@@ -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) {
@@ -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 {
@@ -29,14 +29,7 @@ import {scaleSize, Text} from '../Text';
29
29
  import {Icon} from '../Icon';
30
30
  import {PopupNotify} from '../Popup';
31
31
  import {Badge, BadgeDot} from '../Badge';
32
- import {HeaderType} from '../Layout/types';
33
- import Navigation from './Navigation';
34
- import {InputSearchProps} from '../Input';
35
- import AnimatedInputSearch from '../Layout/AnimatedInputSearch';
36
32
 
37
- /**
38
- * default navigation button used header nav
39
- */
40
33
  const NavigationButton: React.FC<NavigationButtonProps> = ({
41
34
  icon,
42
35
  tintColor,
@@ -88,18 +81,13 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
88
81
  );
89
82
  };
90
83
 
91
- /**
92
- * default header title used for nav
93
- */
94
84
  const HeaderTitle: React.FC<any> = props => {
95
85
  const {theme} = useContext(ApplicationContext);
96
- const opacity = props.animatedValue?.interpolate(
97
- props.interpolate ?? {
98
- inputRange: [0, 200],
99
- outputRange: [0, 1],
100
- extrapolate: 'clamp',
101
- }
102
- );
86
+ const opacity = props.animatedValue?.interpolate({
87
+ inputRange: [0, 200],
88
+ outputRange: [0, 1],
89
+ extrapolate: 'clamp',
90
+ });
103
91
 
104
92
  return (
105
93
  <Animated.Text
@@ -113,9 +101,6 @@ const HeaderTitle: React.FC<any> = props => {
113
101
  );
114
102
  };
115
103
 
116
- /**
117
- * default header left used for nav
118
- */
119
104
  const HeaderLeft: React.FC<HeaderBackProps> = ({
120
105
  tintColor,
121
106
  preventBack,
@@ -128,7 +113,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
128
113
  useEffect(() => {
129
114
  const backHandler = BackHandler.addEventListener(
130
115
  'hardwareBackPress',
131
- goBackSafe
116
+ goBackSafe,
132
117
  );
133
118
 
134
119
  return () => backHandler.remove();
@@ -183,7 +168,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
183
168
  }
184
169
  return true;
185
170
  };
186
-
187
171
  return (
188
172
  <View style={styles.headerLeft}>
189
173
  <NavigationButton
@@ -197,9 +181,6 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
197
181
  );
198
182
  };
199
183
 
200
- /**
201
- * header background for default
202
- */
203
184
  const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
204
185
  image,
205
186
  animatedValue,
@@ -248,10 +229,6 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
248
229
  );
249
230
  };
250
231
 
251
- /**
252
- * Header custom with image, title, subtitle
253
- * @constructor
254
- */
255
232
  const HeaderCustom: React.FC<TitleCustomProps> = ({
256
233
  title,
257
234
  subTitle,
@@ -286,42 +263,37 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
286
263
  return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
287
264
  };
288
265
 
289
- /**
290
- * main component for header right
291
- */
292
- const HeaderRight: React.FC<any> = ({type, children, onLayout, ...props}) => {
293
- if (type === 'icon') {
294
- let buttons = props?.buttons || [];
295
- if (buttons?.length > 3) {
296
- 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
+ );
297
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
+ });
286
+ }
287
+
298
288
  return (
299
- <View style={styles.headerRightButton} onLayout={onLayout}>
300
- {buttons?.map?.((item: NavigationButtonProps, index: number) => {
301
- return (
302
- <View
303
- key={`HeaderRightAction ${index}`}
304
- style={{
305
- marginLeft: index !== 0 ? Spacing.S : 0,
306
- }}>
307
- <NavigationButton {...item} tintColor={props?.tintColor} />
308
- </View>
309
- );
310
- })}
289
+ <View style={styles.headerButton}>
290
+ {React.cloneElement(validateType(children), {...restProps})}
311
291
  </View>
312
292
  );
313
- }
314
-
315
- return (
316
- <View style={styles.headerRightButton} onLayout={onLayout}>
317
- {children ?? <HeaderToolkitAction {...props} />}
318
- </View>
319
- );
293
+ };
294
+ return <View style={styles.headerRightButton}>{renderAction()}</View>;
320
295
  };
321
296
 
322
- /**
323
- * Header toolkit action
324
- */
325
297
  const HeaderToolkitAction: React.FC<any> = ({
326
298
  tintColor,
327
299
  pinnedTool,
@@ -355,7 +327,7 @@ const HeaderToolkitAction: React.FC<any> = ({
355
327
  (config: any) => {
356
328
  navigator.toolkitConfig = config;
357
329
  setToolConfig(navigator?.toolkitConfig);
358
- }
330
+ },
359
331
  );
360
332
  };
361
333
 
@@ -368,7 +340,7 @@ const HeaderToolkitAction: React.FC<any> = ({
368
340
  const {item} = res;
369
341
  navigator?.toolkitCallback?.(item);
370
342
  getToolkitConfig();
371
- }
343
+ },
372
344
  );
373
345
  };
374
346
 
@@ -385,7 +357,7 @@ const HeaderToolkitAction: React.FC<any> = ({
385
357
  navigator?.maxApi?.dispatchFunction?.(
386
358
  'dismiss',
387
359
  undefined,
388
- undefined
360
+ undefined,
389
361
  );
390
362
  },
391
363
  }}
@@ -416,7 +388,7 @@ const HeaderToolkitAction: React.FC<any> = ({
416
388
  [pinTool?.key],
417
389
  () => {
418
390
  getToolkitConfig();
419
- }
391
+ },
420
392
  );
421
393
  navigator?.toolkitCallback?.(pinTool.key);
422
394
  }}
@@ -425,7 +397,7 @@ const HeaderToolkitAction: React.FC<any> = ({
425
397
  };
426
398
  if (toolConfig) {
427
399
  return (
428
- <View style={Styles.row}>
400
+ <View style={styles.headerRightButton}>
429
401
  {renderPinnedTool()}
430
402
  <View
431
403
  style={[
@@ -433,7 +405,6 @@ const HeaderToolkitAction: React.FC<any> = ({
433
405
  {
434
406
  backgroundColor: backgroundColor ?? '#00000066',
435
407
  borderWidth: backgroundColor ? 0.5 : 0,
436
- marginLeft: renderPinnedTool() ? Spacing.S : 0,
437
408
  },
438
409
  ]}>
439
410
  <TouchableOpacity
@@ -459,9 +430,6 @@ const HeaderToolkitAction: React.FC<any> = ({
459
430
  return <View />;
460
431
  };
461
432
 
462
- /**
463
- * default header banner for header animated
464
- */
465
433
  const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
466
434
  animatedValue,
467
435
  image,
@@ -502,152 +470,6 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
502
470
  );
503
471
  };
504
472
 
505
- /**
506
- * Header extended with background image
507
- * @constructor
508
- */
509
- const HeaderExtendHeader: React.FC<{
510
- headerType?: HeaderType;
511
- animatedValue: Animated.Value;
512
- heightHeader: number;
513
- inputSearchProps?: InputSearchProps;
514
- navigation?: Navigation;
515
- }> = ({
516
- headerType = 'default',
517
- animatedValue,
518
- heightHeader,
519
- inputSearchProps,
520
- navigation,
521
- }) => {
522
- const {theme} = useContext(ApplicationContext);
523
-
524
- const heightAnimated = useRef(new Animated.Value(0));
525
-
526
- useEffect(() => {
527
- const listener = animatedValue.addListener(({value}) => {
528
- heightAnimated.current.setValue(value);
529
- });
530
- return () => {
531
- animatedValue?.removeListener(listener);
532
- };
533
- }, []);
534
-
535
- if (inputSearchProps) {
536
- if (headerType === 'surface') {
537
- return (
538
- <View
539
- style={{
540
- backgroundColor: theme.colors.background.surface,
541
- borderBottomWidth: 1,
542
- borderColor: theme.colors.border.default,
543
- }}>
544
- <Animated.View
545
- style={{
546
- justifyContent: 'flex-end',
547
- height: heightAnimated.current.interpolate({
548
- inputRange: [0, 100],
549
- outputRange: [heightHeader + 52, heightHeader],
550
- extrapolate: 'clamp',
551
- }),
552
- }}>
553
- <AnimatedInputSearch
554
- animatedValue={animatedValue}
555
- navigation={navigation}
556
- {...inputSearchProps}
557
- hasColorBG={true}
558
- />
559
- </Animated.View>
560
- </View>
561
- );
562
- }
563
-
564
- if (headerType === 'extended') {
565
- return (
566
- <>
567
- <Animated.View
568
- style={[
569
- styles.headerBox,
570
- {
571
- height: heightAnimated.current.interpolate({
572
- inputRange: [0, 100],
573
- outputRange: [heightHeader + 52, heightHeader],
574
- extrapolate: 'clamp',
575
- }),
576
- },
577
- ]}>
578
- <Image
579
- source={{
580
- uri: theme.assets?.headerBackground,
581
- }}
582
- style={styles.headerBackground}
583
- />
584
- </Animated.View>
585
-
586
- <Animated.View
587
- style={{
588
- justifyContent: 'flex-end',
589
- height: heightAnimated.current.interpolate({
590
- inputRange: [0, 100],
591
- outputRange: [heightHeader + 52, heightHeader],
592
- extrapolate: 'clamp',
593
- }),
594
- }}>
595
- <AnimatedInputSearch
596
- animatedValue={animatedValue}
597
- navigation={navigation}
598
- {...inputSearchProps}
599
- />
600
- </Animated.View>
601
- </>
602
- );
603
- }
604
-
605
- return (
606
- <>
607
- <View style={[styles.headerBox, {height: heightHeader}]}>
608
- <Image
609
- source={{
610
- uri: theme.assets?.headerBackground,
611
- }}
612
- style={styles.headerBackground}
613
- />
614
- </View>
615
-
616
- <Animated.View
617
- style={{
618
- justifyContent: 'flex-end',
619
- height: heightAnimated.current.interpolate({
620
- inputRange: [0, 100],
621
- outputRange: [heightHeader + 52, heightHeader],
622
- extrapolate: 'clamp',
623
- }),
624
- }}>
625
- <AnimatedInputSearch
626
- animatedValue={animatedValue}
627
- navigation={navigation}
628
- {...inputSearchProps}
629
- />
630
- </Animated.View>
631
- </>
632
- );
633
- }
634
-
635
- if (headerType === 'extended') {
636
- return (
637
- <View style={{minHeight: heightHeader}}>
638
- <Image
639
- source={{
640
- uri: theme.assets?.headerBackground,
641
- }}
642
- style={styles.extendedHeader}
643
- />
644
- </View>
645
- );
646
- }
647
-
648
- return <View />;
649
- };
650
-
651
473
  const styles = StyleSheet.create({
652
474
  navigationButton: {
653
475
  height: 28,
@@ -687,6 +509,7 @@ const styles = StyleSheet.create({
687
509
  paddingRight: Spacing.M,
688
510
  },
689
511
  toolkitContainer: {
512
+ marginLeft: Spacing.S,
690
513
  padding: Spacing.XS,
691
514
  height: 28,
692
515
  borderRadius: 14,
@@ -718,17 +541,6 @@ const styles = StyleSheet.create({
718
541
  top: -Spacing.XS,
719
542
  right: -Spacing.XS,
720
543
  },
721
- extendedHeader: {
722
- aspectRatio: 1.75,
723
- position: 'absolute',
724
- width: '100%',
725
- height: 210,
726
- },
727
- headerBox: {
728
- width: '100%',
729
- position: 'absolute',
730
- overflow: 'hidden',
731
- },
732
544
  });
733
545
 
734
546
  export {
@@ -736,9 +548,8 @@ export {
736
548
  HeaderTitle,
737
549
  HeaderLeft,
738
550
  HeaderBackground,
551
+ HeaderRightAction,
739
552
  HeaderToolkitAction,
740
553
  HeaderCustom,
741
554
  HeaderAnimated,
742
- HeaderRight,
743
- HeaderExtendHeader,
744
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={{