@momo-kits/foundation 0.76.1-beta.2 → 0.77.1-optimize.10

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