@momo-kits/foundation 0.81.1-beta.6 → 0.81.1-optimize.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.
Files changed (67) hide show
  1. package/Application/BottomTab.tsx +76 -23
  2. package/Application/Components.tsx +243 -198
  3. package/Application/ModalScreen.tsx +20 -65
  4. package/Application/Navigation.ts +15 -4
  5. package/Application/NavigationContainer.tsx +20 -20
  6. package/Application/Navigator.ts +61 -28
  7. package/Application/StackScreen.tsx +41 -23
  8. package/Application/index.ts +16 -6
  9. package/Application/types.ts +34 -19
  10. package/Application/utils.tsx +26 -0
  11. package/Assets/icon.json +83 -5
  12. package/Assets/icon_bank.json +506 -0
  13. package/Assets/language.json +3 -1
  14. package/Badge/Badge.tsx +56 -0
  15. package/Badge/BadgeDot.tsx +11 -0
  16. package/Badge/BadgeRibbon.tsx +125 -0
  17. package/Badge/Shape.tsx +29 -0
  18. package/Badge/index.tsx +7 -0
  19. package/Badge/styles.ts +58 -0
  20. package/Badge/types.ts +63 -0
  21. package/Button/index.tsx +26 -9
  22. package/Button/styles.ts +19 -0
  23. package/CheckBox/index.tsx +1 -2
  24. package/Consts/colors+spacing+radius.ts +3 -3
  25. package/Icon/index.tsx +7 -3
  26. package/Icon/types.ts +3 -3
  27. package/IconButton/index.tsx +0 -1
  28. package/Image/index.tsx +39 -49
  29. package/Image/styles.ts +1 -9
  30. package/Image/types.ts +3 -1
  31. package/Input/Input.tsx +37 -16
  32. package/Input/InputDropDown.tsx +5 -14
  33. package/Input/InputMoney.tsx +28 -11
  34. package/Input/InputOTP.tsx +169 -145
  35. package/Input/InputSearch.tsx +9 -13
  36. package/Input/InputTextArea.tsx +6 -12
  37. package/Input/common.tsx +5 -3
  38. package/Input/index.tsx +15 -9
  39. package/Input/styles.ts +1 -4
  40. package/Layout/Card.tsx +20 -11
  41. package/Layout/GridSystem.tsx +1 -2
  42. package/Layout/Item.tsx +0 -1
  43. package/Layout/ItemList.tsx +39 -40
  44. package/Layout/ItemSectionList.tsx +39 -0
  45. package/Layout/Screen.tsx +96 -45
  46. package/Layout/Section.tsx +17 -19
  47. package/Layout/index.ts +2 -1
  48. package/Layout/styles.ts +16 -15
  49. package/Layout/types.ts +2 -5
  50. package/Pagination/PaginationNumber.tsx +1 -1
  51. package/Pagination/PaginationScroll.tsx +0 -1
  52. package/Popup/PopupNotify.tsx +71 -14
  53. package/Popup/PopupPromotion.tsx +43 -6
  54. package/Popup/types.ts +12 -3
  55. package/Radio/index.tsx +1 -2
  56. package/Skeleton/index.tsx +1 -1
  57. package/Switch/index.tsx +0 -1
  58. package/Tag/index.tsx +2 -4
  59. package/Text/index.tsx +3 -2
  60. package/Text/styles.ts +38 -0
  61. package/Text/types.ts +25 -13
  62. package/Title/index.tsx +82 -38
  63. package/Title/styles.ts +16 -10
  64. package/Title/types.ts +2 -1
  65. package/index.ts +2 -0
  66. package/package.json +6 -6
  67. package/verify.js +15 -0
@@ -1,4 +1,10 @@
1
- import React, {Fragment, useContext, useEffect, useState} from 'react';
1
+ import React, {
2
+ Fragment,
3
+ useCallback,
4
+ useContext,
5
+ useEffect,
6
+ useState,
7
+ } from 'react';
2
8
  import {
3
9
  Animated,
4
10
  BackHandler,
@@ -7,123 +13,73 @@ import {
7
13
  StyleSheet,
8
14
  TouchableOpacity,
9
15
  View,
16
+ ViewStyle,
10
17
  } from 'react-native';
11
- import {ApplicationContext} from './index';
18
+ import {ApplicationContext, MiniAppContext} from './index';
12
19
  import {Colors, Radius, Spacing, Styles} from '../Consts';
13
20
  import {Image} from '../Image';
14
21
  import {
15
22
  HeaderAnimatedProps,
16
23
  HeaderBackgroundProps,
17
24
  HeaderBackProps,
18
- HeaderToolkitProps,
19
25
  NavigationButtonProps,
20
26
  TitleCustomProps,
21
27
  } from './types';
22
28
  import {scaleSize, Text} from '../Text';
23
29
  import {Icon} from '../Icon';
24
30
  import {PopupNotify} from '../Popup';
25
-
26
- const TRIGGER_ID = "'111154000000000000";
27
-
28
- const styles = StyleSheet.create({
29
- navigationButton: {
30
- height: 28,
31
- width: 28,
32
- borderRadius: 14,
33
- borderColor: '#00000066',
34
- justifyContent: 'center',
35
- alignItems: 'center',
36
- },
37
- headerBackground: {
38
- width: '100%',
39
- height: undefined,
40
- position: 'absolute',
41
- aspectRatio: 375 / 154,
42
- },
43
- headerTitleContainer: {
44
- alignItems: 'center',
45
- justifyContent: 'center',
46
- width: '100%',
47
- },
48
- circle: {width: 36, height: 36, borderRadius: 18},
49
- square: {width: 36, height: 36, borderRadius: Radius.XS},
50
- dotAvatar: {
51
- position: 'absolute',
52
- width: 12,
53
- height: 12,
54
- borderRadius: 6,
55
- bottom: 0,
56
- right: 0,
57
- borderWidth: 1,
58
- borderColor: Colors.black_01,
59
- },
60
- headerButton: {paddingHorizontal: 4},
61
- headerRightButton: {
62
- flexDirection: 'row',
63
- overflow: 'hidden',
64
- justifyContent: 'center',
65
- alignItems: 'center',
66
- paddingRight: Spacing.S,
67
- },
68
- toolkitContainer: {
69
- marginLeft: Spacing.S,
70
- padding: Spacing.XS,
71
- height: 28,
72
- borderRadius: 14,
73
- borderColor: '#00000066',
74
- justifyContent: 'center',
75
- alignItems: 'center',
76
- flexDirection: 'row',
77
- },
78
- divider: {
79
- width: 1,
80
- height: 12,
81
- marginHorizontal: 4,
82
- },
83
- headerLeft: {
84
- marginLeft: 12,
85
- },
86
- title: {
87
- fontSize: scaleSize(15),
88
- lineHeight: scaleSize(22),
89
- fontWeight: 'bold',
90
- },
91
- });
31
+ import {Badge, BadgeDot} from '../Badge';
92
32
 
93
33
  const NavigationButton: React.FC<NavigationButtonProps> = ({
94
34
  icon,
95
35
  tintColor,
96
36
  onPress,
97
- backgroundColor,
98
37
  useBorder = true,
99
- accessibilityLabel,
38
+ badgeType,
39
+ badgeValue,
100
40
  }) => {
101
41
  const {theme} = useContext(ApplicationContext);
102
- if (!backgroundColor && tintColor != Colors.black_01) {
103
- backgroundColor = theme.colors.background.surface;
42
+ let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
43
+ if (tintColor != Colors.black_01) {
44
+ buttonStyle = {
45
+ backgroundColor: 'transparent',
46
+ borderColor: '#00000066',
47
+ borderWidth: useBorder ? 0.5 : 0,
48
+ };
104
49
  }
105
50
 
51
+ const isNumber = (label: any) => {
52
+ const numberRegex = /^\d+$/;
53
+ return numberRegex.test(String(label));
54
+ };
55
+
56
+ const renderBadge = useCallback(() => {
57
+ if (badgeType === 'dot') {
58
+ return <BadgeDot size="small" style={styles.badgeDot} />;
59
+ }
60
+
61
+ if (isNumber(badgeValue)) {
62
+ return <Badge label={badgeValue} style={styles.badge} />;
63
+ }
64
+ }, [badgeType, badgeValue]);
65
+
106
66
  return (
107
- <TouchableOpacity
108
- accessibilityLabel={`NavigationButton/${accessibilityLabel}`}
109
- style={[
110
- styles.navigationButton,
111
- {
112
- backgroundColor: backgroundColor ?? '#00000066',
113
- borderWidth: useBorder && backgroundColor ? 0.5 : 0,
114
- },
115
- ]}
116
- onPress={onPress}>
117
- <Icon
118
- source={icon}
119
- color={tintColor ?? theme.colors.text.default}
120
- size={20}
121
- />
122
- </TouchableOpacity>
67
+ <View style={{width: scaleSize(28)}}>
68
+ <TouchableOpacity
69
+ style={[styles.navigationButton, buttonStyle]}
70
+ onPress={onPress}>
71
+ <Icon
72
+ source={icon}
73
+ color={tintColor ?? theme.colors.text.default}
74
+ size={20}
75
+ />
76
+ </TouchableOpacity>
77
+ {renderBadge()}
78
+ </View>
123
79
  );
124
80
  };
125
81
 
126
- const HeaderTitle: React.FC<any> = ({accessibilityLabel = '', ...props}) => {
82
+ const HeaderTitle: React.FC<any> = props => {
127
83
  const {theme} = useContext(ApplicationContext);
128
84
  const opacity = props.animatedValue?.interpolate({
129
85
  inputRange: [0, 200],
@@ -134,7 +90,6 @@ const HeaderTitle: React.FC<any> = ({accessibilityLabel = '', ...props}) => {
134
90
  return (
135
91
  <Animated.Text
136
92
  {...props}
137
- accessibilityLabel={`HeaderTitle/${accessibilityLabel}${props.children}`}
138
93
  style={[
139
94
  styles.title,
140
95
  {fontFamily: `${theme.font}-Bold`, opacity, color: props.tintColor},
@@ -148,58 +103,61 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
148
103
  preventBack,
149
104
  onPressLeftHeader,
150
105
  useBorder,
151
- backgroundColor,
152
- accessibilityLabel = '',
153
106
  }) => {
154
- const {navigator, appInfo} = useContext(ApplicationContext);
155
- const screen_name = navigator?.ref?.current?.getCurrentRoute().name;
107
+ const context = useContext(MiniAppContext);
108
+ const {navigator} = useContext(ApplicationContext);
156
109
 
157
110
  useEffect(() => {
158
111
  const backHandler = BackHandler.addEventListener(
159
112
  'hardwareBackPress',
160
- goBack,
113
+ goBackSafe,
161
114
  );
162
115
 
163
116
  return () => backHandler.remove();
164
117
  }, []);
165
118
 
166
- const goBack = () => {
167
- const canGoBack = navigator?.ref.current?.canGoBack();
168
-
169
- if (appInfo) {
170
- navigator?.maxApi?.trackEvent('service_icon_clicked', {
171
- ...appInfo,
172
- screen_name,
173
- trigger_id: TRIGGER_ID,
174
- icon_name: 'back',
175
- });
176
- }
177
-
178
- if (canGoBack) {
179
- if (preventBack) {
180
- navigator?.showModal({
181
- screen: () => (
182
- <PopupNotify
183
- {...preventBack}
184
- primary={{
185
- title: preventBack.primary.title,
186
- onPress: () => {
187
- preventBack?.primary.onPress();
188
- navigator?.ref.current?.goBack();
189
- },
190
- }}
191
- />
192
- ),
119
+ const goBackSafe = () => {
120
+ const goBack = () => {
121
+ const canGoBack = navigator?.ref.current?.canGoBack();
122
+ if (!canGoBack) {
123
+ const currentRoute = navigator?.ref?.current.getCurrentRoute();
124
+ navigator?.maxApi?.trackEvent?.('service_icon_clicked', {
125
+ ...context,
126
+ screen_name: currentRoute?.params?.screen?.name ?? currentRoute?.name,
127
+ trigger_id: '111154000000000000',
128
+ icon_name: 'back',
193
129
  });
194
- } else {
130
+ }
131
+ if (canGoBack) {
195
132
  navigator?.ref.current?.goBack();
133
+ } else if (navigator?.maxApi) {
134
+ navigator?.maxApi?.dismiss(navigator.dismissData);
135
+ } else {
136
+ const currentTime = new Date().getTime();
137
+ const requestId = `navigationBackPress#${currentTime}`;
138
+ DeviceEventEmitter.emit('dismiss', {requestId});
196
139
  }
140
+ onPressLeftHeader?.();
141
+ };
142
+
143
+ if (preventBack) {
144
+ navigator?.showModal({
145
+ screen: () => (
146
+ <PopupNotify
147
+ {...preventBack}
148
+ primary={{
149
+ title: preventBack.primary.title,
150
+ onPress: () => {
151
+ preventBack?.primary.onPress();
152
+ goBack();
153
+ },
154
+ }}
155
+ />
156
+ ),
157
+ });
197
158
  } else {
198
- const currentTime = new Date().getTime();
199
- const requestId = `navigationBackPress#${currentTime}`;
200
- DeviceEventEmitter.emit('dismiss', {requestId});
159
+ goBack();
201
160
  }
202
- onPressLeftHeader?.();
203
161
  return true;
204
162
  };
205
163
 
@@ -208,10 +166,8 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
208
166
  <NavigationButton
209
167
  icon="ic_back"
210
168
  tintColor={tintColor}
211
- onPress={goBack}
212
- accessibilityLabel={`${accessibilityLabel}Back`}
169
+ onPress={goBackSafe}
213
170
  useBorder={useBorder}
214
- backgroundColor={backgroundColor}
215
171
  />
216
172
  </View>
217
173
  );
@@ -248,6 +204,8 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
248
204
  ]}>
249
205
  <StatusBar
250
206
  barStyle={headerImage || theme.dark ? 'light-content' : 'dark-content'}
207
+ translucent={true}
208
+ backgroundColor={'transparent'}
251
209
  />
252
210
  {!!headerImage && (
253
211
  <Image
@@ -279,10 +237,10 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
279
237
  )}
280
238
  </View>
281
239
  <View style={[Styles.flex, {paddingHorizontal: 8}]}>
282
- <Text typography="title_xs" color={tintColor}>
240
+ <Text typography="header_default_bold" color={tintColor}>
283
241
  {title}
284
242
  </Text>
285
- <Text typography="description_s" color={tintColor}>
243
+ <Text typography="description_default_regular" color={tintColor}>
286
244
  {subTitle}
287
245
  </Text>
288
246
  </View>
@@ -322,10 +280,16 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
322
280
  return <View style={styles.headerRightButton}>{renderAction()}</View>;
323
281
  };
324
282
 
325
- const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
283
+ const HeaderToolkitAction: React.FC<any> = ({
284
+ tintColor,
285
+ pinnedTool,
286
+ runtimeTools = [],
287
+ preventBack,
288
+ }) => {
326
289
  const {theme, navigator} = useContext(ApplicationContext);
327
- const [toolConfig, setToolConfig] = useState<HeaderToolkitProps>();
328
- const {appCode, hidden, type, onAction} = toolConfig ?? {};
290
+ const miniContext = useContext(MiniAppContext);
291
+ const [toolConfig, setToolConfig] = useState<any>();
292
+ const {onAction} = toolConfig ?? {};
329
293
 
330
294
  let backgroundColor;
331
295
  if (tintColor != Colors.black_01) {
@@ -333,82 +297,94 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
333
297
  }
334
298
 
335
299
  useEffect(() => {
336
- navigator?.getToolkit().then((toolConfig: any) => {
337
- setToolConfig(toolConfig);
338
- });
339
- }, []);
340
-
341
- useEffect(() => {
342
- let addFavorite: any;
343
- let removeFavorite: any;
344
- if (appCode) {
345
- const addSchema = `observerToolkit_addFavorite_${appCode}`;
346
- const removeSchema = `observerToolkit_removeFavorite_${appCode}`;
347
- addFavorite = navigator?.requestApi(
348
- 'observer',
349
- [addSchema],
350
- (data: any) => {
351
- if (data?.status) {
352
- setToolConfig({
353
- ...(toolConfig as HeaderToolkitProps),
354
- hidden: true,
355
- });
356
- }
357
- },
358
- );
359
- addFavorite = navigator?.requestApi(
360
- 'observer',
361
- [removeSchema],
362
- (data: any) => {
363
- if (data?.status) {
364
- setToolConfig({
365
- ...(toolConfig as HeaderToolkitProps),
366
- hidden: false,
367
- });
368
- }
369
- },
370
- );
300
+ if (miniContext?.toolkitConfig?.hidden === false) {
301
+ if (navigator?.toolkitConfig) {
302
+ setToolConfig(navigator?.toolkitConfig);
303
+ } else {
304
+ getToolkitConfig();
305
+ }
371
306
  }
307
+ }, []);
372
308
 
373
- return () => {
374
- addFavorite?.();
375
- removeFavorite?.();
376
- };
377
- }, [appCode]);
378
-
379
- const onUtilityTool = () => {
380
- onAction?.('onUtilityTool');
381
- navigator?.requestApi(type, undefined, undefined);
309
+ const getToolkitConfig = () => {
310
+ navigator?.maxApi?.dispatchFunction?.(
311
+ 'getToolsConfig',
312
+ [undefined],
313
+ (config: any) => {
314
+ navigator.toolkitConfig = config;
315
+ setToolConfig(navigator?.toolkitConfig);
316
+ },
317
+ );
382
318
  };
383
319
 
384
320
  const onMore = () => {
385
321
  onAction?.('onMore');
386
- navigator?.requestApi('showToolkit', [toolConfig], undefined);
322
+ navigator?.maxApi?.dispatchFunction?.(
323
+ 'showTools',
324
+ {runtimeTools},
325
+ (res: {item: {action?: string; key: string}}) => {
326
+ const {item} = res;
327
+ navigator?.toolkitCallback?.(item);
328
+ getToolkitConfig();
329
+ },
330
+ );
387
331
  };
388
332
 
389
333
  const onClose = () => {
390
- onAction?.('onClose');
391
- navigator?.requestApi('dismiss', undefined, undefined);
334
+ if (preventBack) {
335
+ navigator?.showModal({
336
+ screen: () => (
337
+ <PopupNotify
338
+ {...preventBack}
339
+ primary={{
340
+ title: preventBack.primary.title,
341
+ onPress: () => {
342
+ preventBack?.primary.onPress();
343
+ navigator?.maxApi?.dispatchFunction?.(
344
+ 'dismiss',
345
+ undefined,
346
+ undefined,
347
+ );
348
+ },
349
+ }}
350
+ />
351
+ ),
352
+ });
353
+ } else {
354
+ navigator?.maxApi?.dispatchFunction?.('dismiss', undefined, undefined);
355
+ }
392
356
  };
393
357
 
394
- const renderUtilityTool = () => {
395
- if (hidden === false) {
358
+ const renderPinnedTool = () => {
359
+ const pinKey = pinnedTool?.key || toolConfig?.pinnedTool?.key;
360
+ const pinTool = toolConfig?.tools?.find((i: any) => i.key === pinKey);
361
+ const {badgeValue, badgeType} = pinnedTool ?? {};
362
+
363
+ if (pinTool)
396
364
  return (
397
365
  <NavigationButton
398
- accessibilityLabel={'UtilityTool'}
399
- icon={type as string}
366
+ icon={pinTool.icon as string}
400
367
  tintColor={tintColor}
401
- onPress={onUtilityTool}
368
+ badgeValue={badgeValue}
369
+ badgeType={badgeType}
370
+ onPress={() => {
371
+ navigator?.maxApi?.dispatchFunction?.(
372
+ 'onToolAction',
373
+ [pinTool?.key],
374
+ () => {
375
+ getToolkitConfig();
376
+ },
377
+ );
378
+ navigator?.toolkitCallback?.(pinTool.key);
379
+ }}
402
380
  />
403
381
  );
404
- }
405
- return null;
406
382
  };
407
383
 
408
384
  if (toolConfig) {
409
385
  return (
410
386
  <View style={styles.headerRightButton}>
411
- {renderUtilityTool()}
387
+ {renderPinnedTool()}
412
388
  <View
413
389
  style={[
414
390
  styles.toolkitContainer,
@@ -417,15 +393,11 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
417
393
  borderWidth: backgroundColor ? 0.5 : 0,
418
394
  },
419
395
  ]}>
420
- <TouchableOpacity
421
- accessibilityLabel={'Toolkit/More'}
422
- onPress={onMore}>
396
+ <TouchableOpacity onPress={onMore}>
423
397
  <Icon color={tintColor} source="navigation_more_horiz" size={20} />
424
398
  </TouchableOpacity>
425
399
  <View style={[styles.divider, {backgroundColor: tintColor}]} />
426
- <TouchableOpacity
427
- accessibilityLabel={`Toolkit/Close`}
428
- onPress={onClose}>
400
+ <TouchableOpacity onPress={onClose}>
429
401
  <Icon
430
402
  color={tintColor}
431
403
  source="16_navigation_close_circle"
@@ -480,6 +452,79 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
480
452
  );
481
453
  };
482
454
 
455
+ const styles = StyleSheet.create({
456
+ navigationButton: {
457
+ height: 28,
458
+ width: 28,
459
+ borderRadius: 14,
460
+ justifyContent: 'center',
461
+ alignItems: 'center',
462
+ },
463
+ headerBackground: {
464
+ width: '100%',
465
+ height: undefined,
466
+ position: 'absolute',
467
+ aspectRatio: 375 / 154,
468
+ },
469
+ headerTitleContainer: {
470
+ alignItems: 'center',
471
+ justifyContent: 'center',
472
+ width: '100%',
473
+ },
474
+ circle: {width: 36, height: 36, borderRadius: 18},
475
+ square: {width: 36, height: 36, borderRadius: Radius.XS},
476
+ dotAvatar: {
477
+ position: 'absolute',
478
+ width: 12,
479
+ height: 12,
480
+ borderRadius: 6,
481
+ bottom: 0,
482
+ right: 0,
483
+ borderWidth: 1,
484
+ borderColor: Colors.black_01,
485
+ },
486
+ headerButton: {paddingHorizontal: 4},
487
+ headerRightButton: {
488
+ flexDirection: 'row',
489
+ justifyContent: 'center',
490
+ alignItems: 'center',
491
+ paddingRight: Spacing.S,
492
+ },
493
+ toolkitContainer: {
494
+ marginLeft: Spacing.S,
495
+ padding: Spacing.XS,
496
+ height: 28,
497
+ borderRadius: 14,
498
+ borderColor: '#00000066',
499
+ justifyContent: 'center',
500
+ alignItems: 'center',
501
+ flexDirection: 'row',
502
+ },
503
+ divider: {
504
+ width: 1,
505
+ height: 12,
506
+ marginHorizontal: 4,
507
+ },
508
+ headerLeft: {
509
+ marginLeft: 12,
510
+ },
511
+ title: {
512
+ fontSize: scaleSize(15),
513
+ lineHeight: scaleSize(22),
514
+ fontWeight: 'bold',
515
+ },
516
+ badge: {
517
+ position: 'absolute',
518
+ top: -Spacing.S,
519
+ right: -6,
520
+ },
521
+ badgeDot: {
522
+ position: 'absolute',
523
+ top: -Spacing.XS,
524
+ right: -Spacing.XS,
525
+ },
526
+ });
527
+
483
528
  export {
484
529
  NavigationButton,
485
530
  HeaderTitle,