@momo-kits/foundation 0.81.43 → 0.88.1-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.
@@ -3,29 +3,45 @@ import {Platform} from 'react-native';
3
3
  import {BottomTabProps, NavigationScreenProps} from './types';
4
4
  import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
5
5
  import {createStackNavigator} from '@react-navigation/stack';
6
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
7
+ import {NavigationContainer} from '@react-navigation/native';
6
8
  import {Icon} from '../Icon';
7
9
  import {Text} from '../Text';
8
10
  import {ApplicationContext} from './index';
9
11
  import {getStackOptions} from './utils';
10
12
  import StackScreen from './StackScreen';
11
- import {useSafeAreaInsets} from 'react-native-safe-area-context';
12
13
 
13
14
  const Tab = createBottomTabNavigator();
14
15
  const Stack = createStackNavigator();
15
16
 
16
17
  const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
18
+ if (route.params?.nested) {
19
+ return (
20
+ <Stack.Navigator>
21
+ <Stack.Screen
22
+ name="Stack"
23
+ component={StackScreen}
24
+ initialParams={{screen: route.params?.screen}}
25
+ options={{...getStackOptions(), ...route.params?.options}}
26
+ />
27
+ </Stack.Navigator>
28
+ );
29
+ }
17
30
  return (
18
- <Stack.Navigator>
19
- <Stack.Screen
20
- name="Stack"
21
- component={StackScreen}
22
- initialParams={{screen: route.params?.screen}}
23
- options={{...getStackOptions(), ...route.params?.options}}
24
- />
25
- </Stack.Navigator>
31
+ <NavigationContainer independent={true}>
32
+ <Stack.Navigator>
33
+ <Stack.Screen
34
+ name="Stack"
35
+ component={StackScreen}
36
+ initialParams={{screen: route.params?.screen}}
37
+ options={{...getStackOptions(), ...route.params?.options}}
38
+ />
39
+ </Stack.Navigator>
40
+ </NavigationContainer>
26
41
  );
27
42
  };
28
43
  const BottomTab: React.FC<BottomTabProps> = ({
44
+ nested,
29
45
  tabs,
30
46
  listeners,
31
47
  navigation,
@@ -61,14 +77,16 @@ const BottomTab: React.FC<BottomTabProps> = ({
61
77
  key={item.name}
62
78
  name={item.name}
63
79
  component={TabScreen}
64
- initialParams={item}
80
+ initialParams={{...item, nested}}
65
81
  listeners={listeners}
66
82
  options={{
67
83
  tabBarLabel: ({color, focused}) => {
68
84
  return (
69
85
  <Text
70
86
  numberOfLines={1}
71
- typography={focused ? 'label_xs' : 'description_xs'}
87
+ typography={
88
+ focused ? 'label_xs_medium' : 'description_xs_regular'
89
+ }
72
90
  color={color}>
73
91
  {item.label}
74
92
  </Text>
@@ -22,7 +22,6 @@ import {
22
22
  HeaderAnimatedProps,
23
23
  HeaderBackgroundProps,
24
24
  HeaderBackProps,
25
- HeaderToolkitProps,
26
25
  NavigationButtonProps,
27
26
  TitleCustomProps,
28
27
  } from './types';
@@ -31,74 +30,6 @@ import {Icon} from '../Icon';
31
30
  import {PopupNotify} from '../Popup';
32
31
  import {Badge, BadgeDot} from '../Badge';
33
32
 
34
- const styles = StyleSheet.create({
35
- navigationButton: {
36
- height: 28,
37
- width: 28,
38
- borderRadius: 14,
39
- justifyContent: 'center',
40
- alignItems: 'center',
41
- },
42
- headerBackground: {
43
- width: '100%',
44
- height: undefined,
45
- position: 'absolute',
46
- aspectRatio: 375 / 154,
47
- },
48
- headerTitleContainer: {
49
- alignItems: 'center',
50
- justifyContent: 'center',
51
- width: '100%',
52
- },
53
- circle: {width: 36, height: 36, borderRadius: 18},
54
- square: {width: 36, height: 36, borderRadius: Radius.XS},
55
- dotAvatar: {
56
- position: 'absolute',
57
- width: 12,
58
- height: 12,
59
- borderRadius: 6,
60
- bottom: 0,
61
- right: 0,
62
- borderWidth: 1,
63
- borderColor: Colors.black_01,
64
- },
65
- headerButton: {paddingHorizontal: 4},
66
- headerRightButton: {
67
- flexDirection: 'row',
68
- justifyContent: 'center',
69
- alignItems: 'center',
70
- paddingRight: Spacing.S,
71
- },
72
- toolkitContainer: {
73
- marginLeft: Spacing.S,
74
- padding: Spacing.XS,
75
- height: 28,
76
- borderRadius: 14,
77
- borderColor: '#00000066',
78
- justifyContent: 'center',
79
- alignItems: 'center',
80
- flexDirection: 'row',
81
- },
82
- divider: {
83
- width: 1,
84
- height: 12,
85
- marginHorizontal: 4,
86
- },
87
- headerLeft: {
88
- marginLeft: 12,
89
- },
90
- title: {
91
- fontSize: scaleSize(15),
92
- lineHeight: scaleSize(22),
93
- fontWeight: 'bold',
94
- },
95
- badge: {
96
- position: 'absolute',
97
- top: -8,
98
- right: -8,
99
- },
100
- });
101
-
102
33
  const NavigationButton: React.FC<NavigationButtonProps> = ({
103
34
  icon,
104
35
  tintColor,
@@ -118,26 +49,35 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
118
49
  };
119
50
  }
120
51
 
52
+ const isNumber = (label: any) => {
53
+ const numberRegex = /^\d+$/;
54
+ return numberRegex.test(String(label));
55
+ };
56
+
121
57
  const renderBadge = useCallback(() => {
122
- if (!badgeValue && !badgeType) return null;
123
58
  if (badgeType === 'dot') {
124
- return <BadgeDot size="small" style={styles.badge} />;
59
+ return <BadgeDot size="small" style={styles.badgeDot} />;
60
+ }
61
+
62
+ if (isNumber(badgeValue)) {
63
+ return <Badge label={badgeValue} style={styles.badge} />;
125
64
  }
126
- return <Badge label={badgeValue} style={styles.badge} />;
127
65
  }, [badgeType, badgeValue]);
128
66
 
129
67
  return (
130
- <TouchableOpacity
131
- accessibilityLabel={`NavigationButton/${accessibilityLabel}`}
132
- style={[styles.navigationButton, buttonStyle]}
133
- onPress={onPress}>
134
- <Icon
135
- source={icon}
136
- color={tintColor ?? theme.colors.text.default}
137
- size={20}
138
- />
68
+ <View style={{width: scaleSize(28)}}>
69
+ <TouchableOpacity
70
+ accessibilityLabel={`NavigationButton/${accessibilityLabel}`}
71
+ style={[styles.navigationButton, buttonStyle]}
72
+ onPress={onPress}>
73
+ <Icon
74
+ source={icon}
75
+ color={tintColor ?? theme.colors.text.default}
76
+ size={20}
77
+ />
78
+ </TouchableOpacity>
139
79
  {renderBadge()}
140
- </TouchableOpacity>
80
+ </View>
141
81
  );
142
82
  };
143
83
 
@@ -304,10 +244,10 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
304
244
  )}
305
245
  </View>
306
246
  <View style={[Styles.flex, {paddingHorizontal: 8}]}>
307
- <Text typography="title_xs" color={tintColor}>
247
+ <Text typography="header_default_bold" color={tintColor}>
308
248
  {title}
309
249
  </Text>
310
- <Text typography="description_s" color={tintColor}>
250
+ <Text typography="description_default_regular" color={tintColor}>
311
251
  {subTitle}
312
252
  </Text>
313
253
  </View>
@@ -347,10 +287,14 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
347
287
  return <View style={styles.headerRightButton}>{renderAction()}</View>;
348
288
  };
349
289
 
350
- const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
290
+ const HeaderToolkitAction: React.FC<any> = ({
291
+ tintColor,
292
+ pinnedTool,
293
+ preventBack,
294
+ }) => {
351
295
  const {theme, navigator} = useContext(ApplicationContext);
352
- const [toolConfig, setToolConfig] = useState<HeaderToolkitProps>();
353
- const {appCode, hidden, type, onAction} = toolConfig ?? {};
296
+ const [toolConfig, setToolConfig] = useState<any>();
297
+ const {onAction} = toolConfig ?? {};
354
298
 
355
299
  let backgroundColor;
356
300
  if (tintColor != Colors.black_01) {
@@ -361,95 +305,78 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
361
305
  if (navigator?.toolkitConfig) {
362
306
  setToolConfig(navigator?.toolkitConfig);
363
307
  } else {
364
- navigator?.requestApi('getToolkit', [undefined], (result: boolean) => {
365
- if (result) {
366
- navigator?.requestApi(
367
- 'getToolkitConfig',
368
- [undefined],
369
- (config: any) => {
370
- navigator.toolkitConfig = {
371
- ...config?.utilityToolConfig,
372
- appCode: config?.appCode,
373
- };
374
- setToolConfig(navigator?.toolkitConfig);
375
- },
376
- );
377
- }
378
- });
308
+ getToolkitConfig();
379
309
  }
380
310
  }, []);
381
311
 
382
- useEffect(() => {
383
- let addFavorite: any;
384
- let removeFavorite: any;
385
- if (appCode) {
386
- const addSchema = `observerToolkit_addFavorite_${appCode}`;
387
- const removeSchema = `observerToolkit_removeFavorite_${appCode}`;
388
- addFavorite = navigator?.requestApi(
389
- 'observer',
390
- [addSchema],
391
- (data: any) => {
392
- if (data?.status) {
393
- setToolConfig({
394
- ...(toolConfig as HeaderToolkitProps),
395
- hidden: true,
396
- });
397
- }
398
- },
399
- );
400
- addFavorite = navigator?.requestApi(
401
- 'observer',
402
- [removeSchema],
403
- (data: any) => {
404
- if (data?.status) {
405
- setToolConfig({
406
- ...(toolConfig as HeaderToolkitProps),
407
- hidden: false,
408
- });
409
- }
410
- },
411
- );
412
- }
413
-
414
- return () => {
415
- addFavorite?.();
416
- removeFavorite?.();
417
- };
418
- }, [appCode]);
419
-
420
- const onUtilityTool = () => {
421
- onAction?.('onUtilityTool');
422
- navigator?.requestApi(type, undefined, undefined);
312
+ const getToolkitConfig = () => {
313
+ navigator?.requestApi('getToolsConfig', [undefined], (config: any) => {
314
+ navigator.toolkitConfig = config;
315
+ setToolConfig(navigator?.toolkitConfig);
316
+ });
423
317
  };
424
318
 
425
319
  const onMore = () => {
426
320
  onAction?.('onMore');
427
- navigator?.requestApi('showToolkit', [toolConfig], undefined);
321
+ navigator?.requestApi(
322
+ 'showTools',
323
+ [undefined],
324
+ (res: {item: {action?: string; key: string}}) => {
325
+ const {item} = res;
326
+ navigator?.toolkitCallback?.(item);
327
+ getToolkitConfig();
328
+ },
329
+ );
428
330
  };
429
331
 
430
332
  const onClose = () => {
431
- onAction?.('onClose');
432
- navigator?.requestApi('dismiss', undefined, undefined);
333
+ if (preventBack) {
334
+ navigator?.showModal({
335
+ screen: () => (
336
+ <PopupNotify
337
+ {...preventBack}
338
+ primary={{
339
+ title: preventBack.primary.title,
340
+ onPress: () => {
341
+ preventBack?.primary.onPress();
342
+ navigator?.requestApi('dismiss', undefined, undefined);
343
+ },
344
+ }}
345
+ />
346
+ ),
347
+ });
348
+ } else {
349
+ navigator?.requestApi('dismiss', undefined, undefined);
350
+ }
433
351
  };
434
352
 
435
- const renderUtilityTool = () => {
436
- if (hidden === false) {
353
+ const renderPinnedTool = () => {
354
+ const pinKey = pinnedTool?.key || toolConfig?.pinnedTool?.key;
355
+ const pinTool = toolConfig?.tools?.find((i: any) => i.key === pinKey);
356
+ const {badgeValue, badgeType} = pinnedTool ?? {};
357
+
358
+ if (pinTool)
437
359
  return (
438
360
  <NavigationButton
439
361
  accessibilityLabel={'UtilityTool'}
440
- icon={type as string}
362
+ icon={pinTool.icon as string}
441
363
  tintColor={tintColor}
442
- onPress={onUtilityTool}
364
+ badgeValue={badgeValue}
365
+ badgeType={badgeType}
366
+ onPress={() => {
367
+ navigator?.requestApi('onToolAction', [pinTool?.key], () => {
368
+ getToolkitConfig();
369
+ });
370
+ navigator?.toolkitCallback?.(pinTool.key);
371
+ }}
443
372
  />
444
373
  );
445
- }
446
- return null;
447
374
  };
448
375
 
449
376
  if (toolConfig) {
450
377
  return (
451
378
  <View style={styles.headerRightButton}>
452
- {renderUtilityTool()}
379
+ {renderPinnedTool()}
453
380
  <View
454
381
  style={[
455
382
  styles.toolkitContainer,
@@ -521,6 +448,79 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
521
448
  );
522
449
  };
523
450
 
451
+ const styles = StyleSheet.create({
452
+ navigationButton: {
453
+ height: 28,
454
+ width: 28,
455
+ borderRadius: 14,
456
+ justifyContent: 'center',
457
+ alignItems: 'center',
458
+ },
459
+ headerBackground: {
460
+ width: '100%',
461
+ height: undefined,
462
+ position: 'absolute',
463
+ aspectRatio: 375 / 154,
464
+ },
465
+ headerTitleContainer: {
466
+ alignItems: 'center',
467
+ justifyContent: 'center',
468
+ width: '100%',
469
+ },
470
+ circle: {width: 36, height: 36, borderRadius: 18},
471
+ square: {width: 36, height: 36, borderRadius: Radius.XS},
472
+ dotAvatar: {
473
+ position: 'absolute',
474
+ width: 12,
475
+ height: 12,
476
+ borderRadius: 6,
477
+ bottom: 0,
478
+ right: 0,
479
+ borderWidth: 1,
480
+ borderColor: Colors.black_01,
481
+ },
482
+ headerButton: {paddingHorizontal: 4},
483
+ headerRightButton: {
484
+ flexDirection: 'row',
485
+ justifyContent: 'center',
486
+ alignItems: 'center',
487
+ paddingRight: Spacing.S,
488
+ },
489
+ toolkitContainer: {
490
+ marginLeft: Spacing.S,
491
+ padding: Spacing.XS,
492
+ height: 28,
493
+ borderRadius: 14,
494
+ borderColor: '#00000066',
495
+ justifyContent: 'center',
496
+ alignItems: 'center',
497
+ flexDirection: 'row',
498
+ },
499
+ divider: {
500
+ width: 1,
501
+ height: 12,
502
+ marginHorizontal: 4,
503
+ },
504
+ headerLeft: {
505
+ marginLeft: 12,
506
+ },
507
+ title: {
508
+ fontSize: scaleSize(15),
509
+ lineHeight: scaleSize(22),
510
+ fontWeight: 'bold',
511
+ },
512
+ badge: {
513
+ position: 'absolute',
514
+ top: -Spacing.S,
515
+ right: -6,
516
+ },
517
+ badgeDot: {
518
+ position: 'absolute',
519
+ top: -Spacing.XS,
520
+ right: -Spacing.XS,
521
+ },
522
+ });
523
+
524
524
  export {
525
525
  NavigationButton,
526
526
  HeaderTitle,
@@ -6,7 +6,7 @@ import {
6
6
  NavigationContainerRef,
7
7
  } from '@react-navigation/native';
8
8
  import {createStackNavigator} from '@react-navigation/stack';
9
- import {DeviceEventEmitter, NativeModules} from 'react-native';
9
+ import {Alert, DeviceEventEmitter, NativeModules} from 'react-native';
10
10
  import StackScreen from './StackScreen';
11
11
  import ModalScreen from './ModalScreen';
12
12
  import Navigator from './Navigator';
@@ -13,6 +13,7 @@ class Navigator {
13
13
  maxApi?: any;
14
14
  trackingInfo?: TrackingInfo;
15
15
  dismissData?: any;
16
+ toolkitCallback?: (item: any) => void;
16
17
 
17
18
  constructor(navigation: any) {
18
19
  this.ref = navigation;
@@ -121,6 +122,12 @@ class Navigator {
121
122
  this.maxApi[func]?.(...args, callback);
122
123
  }
123
124
  };
125
+
126
+ setToolkitCallback = (
127
+ callback: (item: {key: string; action: string}) => void,
128
+ ) => {
129
+ this.toolkitCallback = callback;
130
+ };
124
131
  }
125
132
 
126
133
  export default Navigator;
@@ -5,6 +5,10 @@ import {ApplicationContext} from './index';
5
5
  import {GridSystem} from '../Layout';
6
6
  import {useHeaderHeight} from '@react-navigation/stack';
7
7
 
8
+ const {
9
+ ScreenContext,
10
+ } = require('react-native/Libraries/Components/ScreenContext');
11
+
8
12
  const StackScreen: React.FC<ScreenParams> = props => {
9
13
  const {screen: Component, options}: ScreenParams = props.route.params;
10
14
  const {theme, showGrid, navigator} = useContext(ApplicationContext);
@@ -64,10 +68,16 @@ const StackScreen: React.FC<ScreenParams> = props => {
64
68
  }, []);
65
69
 
66
70
  return (
67
- <>
71
+ <ScreenContext.Provider
72
+ value={{
73
+ app_id: navigator?.trackingInfo?.appId,
74
+ screen_name: Component.name,
75
+ feature_code: navigator?.trackingInfo?.code,
76
+ autoTracking: navigator?.maxApi?.autoTracking,
77
+ }}>
68
78
  <Component heightHeader={heightHeader} {...params} />
69
79
  {showGrid && <GridSystem />}
70
- </>
80
+ </ScreenContext.Provider>
71
81
  );
72
82
  };
73
83
 
@@ -128,8 +128,14 @@ export type NavigationButtonProps = {
128
128
  useBorder?: boolean;
129
129
  onPress: () => void;
130
130
  accessibilityLabel?: string;
131
- badgeType?: 'dot' | 'number' | 'string';
132
- badgeValue?: number | string;
131
+ badgeType?: 'dot' | 'number';
132
+ badgeValue?: number;
133
+ };
134
+
135
+ export type PinnedToolType = {
136
+ key: string;
137
+ badgeValue?: number;
138
+ badgeType?: 'number' | 'dot';
133
139
  };
134
140
 
135
141
  export interface NavigationOptions extends StackNavigationOptions {
@@ -138,6 +144,7 @@ export interface NavigationOptions extends StackNavigationOptions {
138
144
  surface?: boolean;
139
145
  hiddenBack?: boolean;
140
146
  customTitle?: TitleCustomProps;
147
+ pinnedTool?: PinnedToolType;
141
148
  }
142
149
 
143
150
  export interface HeaderBackProps extends NavigationButtonProps {
@@ -166,9 +173,7 @@ export type TitleCustomProps = {
166
173
  export type HeaderToolkitProps = {
167
174
  [key: string]: any;
168
175
  appCode: string;
169
- hidden: boolean;
170
- type: string;
171
- onAction?: (action: string) => void;
176
+ configs: any[];
172
177
  };
173
178
 
174
179
  export type HeaderAnimatedProps = {
@@ -188,6 +193,7 @@ export type BottomTabItemProps = {
188
193
  };
189
194
 
190
195
  export type BottomTabProps = {
196
+ nested?: boolean;
191
197
  tabs: BottomTabItemProps[];
192
198
  initialRouteName?: string;
193
199
  navigation: Navigation;
@@ -201,3 +207,9 @@ export type AnimatedHeader = {
201
207
  type: 'default' | 'surface';
202
208
  component?: (props?: any) => React.ReactElement;
203
209
  };
210
+
211
+ export type ScreenInfo = {
212
+ app_id: string;
213
+ feature_code: string;
214
+ screen_name: string;
215
+ };
@@ -126,6 +126,21 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
126
126
  };
127
127
  }
128
128
 
129
+ if (params.pinnedTool) {
130
+ options = {
131
+ ...options,
132
+ headerRight: (props: any) => {
133
+ return (
134
+ <HeaderToolkitAction
135
+ preventBack={params.preventBack}
136
+ pinnedTool={params.pinnedTool}
137
+ {...props}
138
+ />
139
+ );
140
+ },
141
+ };
142
+ }
143
+
129
144
  return {
130
145
  ...params,
131
146
  ...options,
package/Badge/Badge.tsx CHANGED
@@ -46,7 +46,7 @@ const Badge: FC<BadgeProps> = ({label = 'Label', style, backgroundColor}) => {
46
46
 
47
47
  return (
48
48
  <View style={[style, styles.badge, {backgroundColor: badgeColor}]}>
49
- <Text color={Colors.black_01} typography={'action_xxs'}>
49
+ <Text color={Colors.black_01} typography={'action_xs_bold'}>
50
50
  {formatTitle()}
51
51
  </Text>
52
52
  </View>
@@ -54,7 +54,7 @@ const BadgeRibbon: FC<BadgeRibbonProps> = ({
54
54
  },
55
55
  ]}
56
56
  color={Colors.black_01}
57
- typography={'label_xs'}>
57
+ typography={'label_xs_medium'}>
58
58
  {label}
59
59
  </Text>
60
60
  </View>
@@ -87,7 +87,7 @@ const BadgeRibbon: FC<BadgeRibbonProps> = ({
87
87
  },
88
88
  ]}
89
89
  color={Colors.black_01}
90
- typography={'label_xs'}>
90
+ typography={'label_xs_medium'}>
91
91
  {label}
92
92
  </Text>
93
93
  </View>
package/Badge/styles.ts CHANGED
@@ -4,13 +4,16 @@ import {scaleSize} from '../Text';
4
4
 
5
5
  export default StyleSheet.create({
6
6
  badge: {
7
+ paddingHorizontal: Spacing.XS,
7
8
  borderRadius: Radius.M,
8
9
  justifyContent: 'center',
10
+ alignItems: 'center',
9
11
  height: scaleSize(16),
12
+ minWidth: scaleSize(16),
10
13
  flexDirection: 'row',
14
+ borderWidth: 1,
11
15
  borderColor: Colors.black_01,
12
- paddingHorizontal: Spacing.XS,
13
- alignItems: 'center',
16
+ alignSelf: 'baseline',
14
17
  },
15
18
  dot: {
16
19
  width: 16,