@momo-kits/foundation 0.92.7-rc.21 → 0.92.7-rc.22
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.
- package/Application/BottomSheet.tsx +216 -0
- package/Application/BottomTab/BottomTabBar.tsx +62 -223
- package/Application/BottomTab/index.tsx +15 -11
- package/Application/Components.tsx +291 -45
- package/Application/Localize.ts +44 -0
- package/Application/ModalScreen.tsx +11 -181
- package/Application/Navigation.ts +4 -18
- package/Application/NavigationContainer.tsx +10 -28
- package/Application/Navigator.ts +14 -16
- package/Application/StackScreen.tsx +222 -42
- package/Application/index.ts +5 -3
- package/Application/types.ts +47 -29
- package/Application/utils.tsx +61 -19
- package/Assets/icon_bank.json +1 -1
- package/Badge/BadgeDotAnimation.tsx +95 -0
- package/Badge/index.tsx +2 -1
- package/Badge/styles.ts +50 -6
- package/Button/index.tsx +7 -8
- package/Icon/index.tsx +1 -1
- package/Icon/types.ts +1 -2
- package/Image/index.tsx +0 -1
- package/Input/Input.tsx +51 -17
- package/Input/InputDropDown.tsx +42 -45
- package/Input/InputMoney.tsx +65 -6
- package/Input/InputOTP.tsx +14 -13
- package/Input/InputSearch.tsx +259 -146
- package/Input/InputTextArea.tsx +0 -1
- package/Input/TextTyping.tsx +113 -0
- package/Input/common.tsx +29 -10
- package/Input/index.tsx +84 -89
- package/Input/styles.ts +44 -7
- package/Input/utils.ts +1 -1
- package/Layout/Card.tsx +4 -3
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/GridSystem.tsx +1 -1
- package/Layout/ItemList.tsx +3 -2
- package/Layout/Screen.tsx +188 -102
- package/Layout/Section.tsx +4 -3
- package/Layout/styles.ts +0 -6
- package/Layout/types.ts +1 -1
- package/Layout/utils.ts +2 -2
- package/Loader/index.tsx +2 -0
- package/Pagination/PaginationScroll.tsx +2 -2
- package/Pagination/styles.ts +1 -1
- package/Popup/PopupNotify.tsx +7 -7
- package/Popup/PopupPromotion.tsx +1 -1
- package/Popup/types.ts +1 -1
- package/Tag/index.tsx +9 -2
- package/Tag/styles.ts +3 -2
- package/Tag/types.ts +12 -0
- package/Title/index.tsx +20 -7
- package/Title/styles.ts +4 -4
- package/code-scanner.js +141 -124
- package/index.ts +7 -0
- package/package.json +5 -4
- package/publish.sh +16 -21
- package/tsconfig.json +1 -1
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import React, {
|
|
2
|
-
|
|
2
|
+
Ref,
|
|
3
3
|
useCallback,
|
|
4
4
|
useContext,
|
|
5
5
|
useEffect,
|
|
6
|
+
useRef,
|
|
6
7
|
useState,
|
|
7
8
|
} from 'react';
|
|
8
9
|
import {
|
|
10
|
+
Alert,
|
|
9
11
|
Animated,
|
|
10
12
|
BackHandler,
|
|
11
13
|
DeviceEventEmitter,
|
|
14
|
+
Dimensions,
|
|
12
15
|
StatusBar,
|
|
13
16
|
StyleSheet,
|
|
14
17
|
TouchableOpacity,
|
|
@@ -29,7 +32,18 @@ import {scaleSize, Text} from '../Text';
|
|
|
29
32
|
import {Icon} from '../Icon';
|
|
30
33
|
import {PopupNotify} from '../Popup';
|
|
31
34
|
import {Badge, BadgeDot} from '../Badge';
|
|
35
|
+
import {HeaderType} from '../Layout/types';
|
|
36
|
+
import Navigation from './Navigation';
|
|
37
|
+
import {InputRef, InputSearch, InputSearchProps} from '../Input';
|
|
38
|
+
import {BadgeDotAnimation} from '../Badge';
|
|
32
39
|
|
|
40
|
+
const SCREEN_PADDING = 12;
|
|
41
|
+
const BACK_WIDTH = 28;
|
|
42
|
+
const {width: screenWidth} = Dimensions.get('window');
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* default navigation button used header nav
|
|
46
|
+
*/
|
|
33
47
|
const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
34
48
|
icon,
|
|
35
49
|
tintColor,
|
|
@@ -41,7 +55,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
41
55
|
}) => {
|
|
42
56
|
const {theme} = useContext(ApplicationContext);
|
|
43
57
|
let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
|
|
44
|
-
if (tintColor
|
|
58
|
+
if (tintColor !== Colors.black_01) {
|
|
45
59
|
buttonStyle = {
|
|
46
60
|
backgroundColor: 'transparent',
|
|
47
61
|
borderColor: '#00000066',
|
|
@@ -58,6 +72,11 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
58
72
|
if (badgeType === 'dot') {
|
|
59
73
|
return <BadgeDot size="small" style={styles.badgeDot} />;
|
|
60
74
|
}
|
|
75
|
+
if (badgeType === 'dot-animation') {
|
|
76
|
+
return (
|
|
77
|
+
<BadgeDotAnimation size="small" style={styles.badgeDotAnimation} />
|
|
78
|
+
);
|
|
79
|
+
}
|
|
61
80
|
|
|
62
81
|
if (isNumber(badgeValue)) {
|
|
63
82
|
return <Badge label={badgeValue} style={styles.badge} />;
|
|
@@ -65,7 +84,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
65
84
|
}, [badgeType, badgeValue]);
|
|
66
85
|
|
|
67
86
|
return (
|
|
68
|
-
<View style={{width:
|
|
87
|
+
<View style={{width: 28}}>
|
|
69
88
|
<TouchableOpacity
|
|
70
89
|
accessibilityLabel={accessibilityLabel}
|
|
71
90
|
style={[styles.navigationButton, buttonStyle]}
|
|
@@ -81,13 +100,18 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
81
100
|
);
|
|
82
101
|
};
|
|
83
102
|
|
|
103
|
+
/**
|
|
104
|
+
* default header title used for nav
|
|
105
|
+
*/
|
|
84
106
|
const HeaderTitle: React.FC<any> = props => {
|
|
85
107
|
const {theme} = useContext(ApplicationContext);
|
|
86
|
-
const opacity = props.animatedValue?.interpolate(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
const opacity = props.animatedValue?.interpolate(
|
|
109
|
+
props.interpolate ?? {
|
|
110
|
+
inputRange: [0, 200],
|
|
111
|
+
outputRange: [0, 1],
|
|
112
|
+
extrapolate: 'clamp',
|
|
113
|
+
}
|
|
114
|
+
);
|
|
91
115
|
|
|
92
116
|
return (
|
|
93
117
|
<Animated.Text
|
|
@@ -101,6 +125,9 @@ const HeaderTitle: React.FC<any> = props => {
|
|
|
101
125
|
);
|
|
102
126
|
};
|
|
103
127
|
|
|
128
|
+
/**
|
|
129
|
+
* default header left used for nav
|
|
130
|
+
*/
|
|
104
131
|
const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
105
132
|
tintColor,
|
|
106
133
|
preventBack,
|
|
@@ -113,7 +140,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
113
140
|
useEffect(() => {
|
|
114
141
|
const backHandler = BackHandler.addEventListener(
|
|
115
142
|
'hardwareBackPress',
|
|
116
|
-
goBackSafe
|
|
143
|
+
goBackSafe
|
|
117
144
|
);
|
|
118
145
|
|
|
119
146
|
return () => backHandler.remove();
|
|
@@ -168,6 +195,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
168
195
|
}
|
|
169
196
|
return true;
|
|
170
197
|
};
|
|
198
|
+
|
|
171
199
|
return (
|
|
172
200
|
<View style={styles.headerLeft}>
|
|
173
201
|
<NavigationButton
|
|
@@ -181,6 +209,9 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
181
209
|
);
|
|
182
210
|
};
|
|
183
211
|
|
|
212
|
+
/**
|
|
213
|
+
* header background for default
|
|
214
|
+
*/
|
|
184
215
|
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
185
216
|
image,
|
|
186
217
|
animatedValue,
|
|
@@ -229,6 +260,10 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
229
260
|
);
|
|
230
261
|
};
|
|
231
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Header custom with image, title, subtitle
|
|
265
|
+
* @constructor
|
|
266
|
+
*/
|
|
232
267
|
const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
233
268
|
title,
|
|
234
269
|
subTitle,
|
|
@@ -238,7 +273,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
238
273
|
tintColor,
|
|
239
274
|
dotColor,
|
|
240
275
|
}) => {
|
|
241
|
-
const avatarStyle = imageShape
|
|
276
|
+
const avatarStyle = imageShape === 'circle' ? styles.circle : styles.square;
|
|
242
277
|
const header = (
|
|
243
278
|
<View style={Styles.row}>
|
|
244
279
|
<View>
|
|
@@ -263,37 +298,42 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
263
298
|
return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
|
|
264
299
|
};
|
|
265
300
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
301
|
+
/**
|
|
302
|
+
* main component for header right
|
|
303
|
+
*/
|
|
304
|
+
const HeaderRight: React.FC<any> = ({type, children, onLayout, ...props}) => {
|
|
305
|
+
if (type === 'icon') {
|
|
306
|
+
let buttons = props?.buttons || [];
|
|
307
|
+
if (buttons?.length > 3) {
|
|
308
|
+
buttons = buttons.slice(0, 3);
|
|
273
309
|
}
|
|
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
|
-
|
|
288
310
|
return (
|
|
289
|
-
<View style={styles.
|
|
290
|
-
{
|
|
311
|
+
<View style={styles.headerRightButton} onLayout={onLayout}>
|
|
312
|
+
{buttons?.map?.((item: NavigationButtonProps, index: number) => {
|
|
313
|
+
return (
|
|
314
|
+
<View
|
|
315
|
+
key={`HeaderRightAction ${index}`}
|
|
316
|
+
style={{
|
|
317
|
+
marginLeft: index !== 0 ? Spacing.S : 0,
|
|
318
|
+
}}>
|
|
319
|
+
<NavigationButton {...item} tintColor={props?.tintColor} />
|
|
320
|
+
</View>
|
|
321
|
+
);
|
|
322
|
+
})}
|
|
291
323
|
</View>
|
|
292
324
|
);
|
|
293
|
-
}
|
|
294
|
-
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<View style={styles.headerRightButton} onLayout={onLayout}>
|
|
329
|
+
{children ?? <HeaderToolkitAction {...props} />}
|
|
330
|
+
</View>
|
|
331
|
+
);
|
|
295
332
|
};
|
|
296
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Header toolkit action
|
|
336
|
+
*/
|
|
297
337
|
const HeaderToolkitAction: React.FC<any> = ({
|
|
298
338
|
tintColor,
|
|
299
339
|
pinnedTool,
|
|
@@ -306,7 +346,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
306
346
|
const {onAction} = toolConfig ?? {};
|
|
307
347
|
|
|
308
348
|
let backgroundColor;
|
|
309
|
-
if (tintColor
|
|
349
|
+
if (tintColor !== Colors.black_01) {
|
|
310
350
|
backgroundColor = 'transparent';
|
|
311
351
|
}
|
|
312
352
|
|
|
@@ -327,7 +367,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
327
367
|
(config: any) => {
|
|
328
368
|
navigator.toolkitConfig = config;
|
|
329
369
|
setToolConfig(navigator?.toolkitConfig);
|
|
330
|
-
}
|
|
370
|
+
}
|
|
331
371
|
);
|
|
332
372
|
};
|
|
333
373
|
|
|
@@ -338,9 +378,9 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
338
378
|
{runtimeTools},
|
|
339
379
|
(res: {item: {action?: string; key: string}}) => {
|
|
340
380
|
const {item} = res;
|
|
341
|
-
navigator?.toolkitCallback?.(item);
|
|
381
|
+
navigator?.toolkitCallback?.(item.key);
|
|
342
382
|
getToolkitConfig();
|
|
343
|
-
}
|
|
383
|
+
}
|
|
344
384
|
);
|
|
345
385
|
};
|
|
346
386
|
|
|
@@ -357,7 +397,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
357
397
|
navigator?.maxApi?.dispatchFunction?.(
|
|
358
398
|
'dismiss',
|
|
359
399
|
undefined,
|
|
360
|
-
undefined
|
|
400
|
+
undefined
|
|
361
401
|
);
|
|
362
402
|
},
|
|
363
403
|
}}
|
|
@@ -385,10 +425,10 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
385
425
|
onPress={() => {
|
|
386
426
|
navigator?.maxApi?.dispatchFunction?.(
|
|
387
427
|
'onToolAction',
|
|
388
|
-
|
|
428
|
+
{item: pinTool},
|
|
389
429
|
() => {
|
|
390
430
|
getToolkitConfig();
|
|
391
|
-
}
|
|
431
|
+
}
|
|
392
432
|
);
|
|
393
433
|
navigator?.toolkitCallback?.(pinTool.key);
|
|
394
434
|
}}
|
|
@@ -397,7 +437,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
397
437
|
};
|
|
398
438
|
if (toolConfig) {
|
|
399
439
|
return (
|
|
400
|
-
<View style={
|
|
440
|
+
<View style={Styles.row}>
|
|
401
441
|
{renderPinnedTool()}
|
|
402
442
|
<View
|
|
403
443
|
style={[
|
|
@@ -405,6 +445,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
405
445
|
{
|
|
406
446
|
backgroundColor: backgroundColor ?? '#00000066',
|
|
407
447
|
borderWidth: backgroundColor ? 0.5 : 0,
|
|
448
|
+
marginLeft: renderPinnedTool() ? Spacing.S : 0,
|
|
408
449
|
},
|
|
409
450
|
]}>
|
|
410
451
|
<TouchableOpacity
|
|
@@ -430,6 +471,9 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
430
471
|
return <View />;
|
|
431
472
|
};
|
|
432
473
|
|
|
474
|
+
/**
|
|
475
|
+
* default header banner for header animated
|
|
476
|
+
*/
|
|
433
477
|
const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
434
478
|
animatedValue,
|
|
435
479
|
image,
|
|
@@ -470,6 +514,191 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
|
470
514
|
);
|
|
471
515
|
};
|
|
472
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Header extended with background image
|
|
519
|
+
* @constructor
|
|
520
|
+
*/
|
|
521
|
+
const HeaderExtendHeader: React.FC<{
|
|
522
|
+
headerType?: HeaderType;
|
|
523
|
+
animatedValue: Animated.Value;
|
|
524
|
+
heightHeader: number;
|
|
525
|
+
inputSearchProps?: InputSearchProps;
|
|
526
|
+
inputSearchRef?: Ref<InputRef>;
|
|
527
|
+
navigation?: Navigation;
|
|
528
|
+
}> = ({
|
|
529
|
+
headerType = 'default',
|
|
530
|
+
animatedValue,
|
|
531
|
+
heightHeader,
|
|
532
|
+
inputSearchProps,
|
|
533
|
+
inputSearchRef,
|
|
534
|
+
navigation,
|
|
535
|
+
}) => {
|
|
536
|
+
const {theme} = useContext(ApplicationContext);
|
|
537
|
+
const [rightSpace, setRightSpace] = useState(0);
|
|
538
|
+
const animated = useRef(new Animated.Value(0));
|
|
539
|
+
|
|
540
|
+
useEffect(() => {
|
|
541
|
+
const listener = animatedValue.addListener(({value}) => {
|
|
542
|
+
animated.current.setValue(value);
|
|
543
|
+
});
|
|
544
|
+
return () => {
|
|
545
|
+
animatedValue?.removeListener(listener);
|
|
546
|
+
};
|
|
547
|
+
}, []);
|
|
548
|
+
|
|
549
|
+
const height = animated.current.interpolate({
|
|
550
|
+
inputRange: [0, 100],
|
|
551
|
+
outputRange: [heightHeader + 52, heightHeader],
|
|
552
|
+
extrapolate: 'clamp',
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const translateX = animated.current.interpolate({
|
|
556
|
+
inputRange: [0, 100],
|
|
557
|
+
outputRange: [SCREEN_PADDING, BACK_WIDTH + SCREEN_PADDING * 2],
|
|
558
|
+
extrapolate: 'clamp',
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
if (navigation) {
|
|
562
|
+
navigation.onHeaderRightChange = (width: number) => {
|
|
563
|
+
setRightSpace(width);
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const renderInputView = (hasColorBG: boolean = false) => {
|
|
568
|
+
return (
|
|
569
|
+
<Animated.View
|
|
570
|
+
style={{
|
|
571
|
+
justifyContent: 'flex-end',
|
|
572
|
+
height,
|
|
573
|
+
}}>
|
|
574
|
+
<Animated.View
|
|
575
|
+
style={{
|
|
576
|
+
transform: [{translateX}],
|
|
577
|
+
marginVertical: Spacing.S,
|
|
578
|
+
width: animated.current.interpolate({
|
|
579
|
+
inputRange: [0, 100],
|
|
580
|
+
outputRange: [
|
|
581
|
+
screenWidth - SCREEN_PADDING * 2,
|
|
582
|
+
screenWidth - SCREEN_PADDING * 3 - BACK_WIDTH - rightSpace,
|
|
583
|
+
],
|
|
584
|
+
extrapolate: 'clamp',
|
|
585
|
+
}),
|
|
586
|
+
}}>
|
|
587
|
+
<InputSearch
|
|
588
|
+
{...inputSearchProps}
|
|
589
|
+
ref={inputSearchRef}
|
|
590
|
+
hasColorBG={hasColorBG}
|
|
591
|
+
showButtonText={false}
|
|
592
|
+
/>
|
|
593
|
+
</Animated.View>
|
|
594
|
+
</Animated.View>
|
|
595
|
+
);
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
if (inputSearchProps) {
|
|
599
|
+
if (headerType === 'surface') {
|
|
600
|
+
return (
|
|
601
|
+
<>
|
|
602
|
+
<Animated.View
|
|
603
|
+
style={[
|
|
604
|
+
styles.headerBox,
|
|
605
|
+
{
|
|
606
|
+
backgroundColor: theme.colors.background.surface,
|
|
607
|
+
borderBottomWidth: 1,
|
|
608
|
+
borderColor: theme.colors.border.default,
|
|
609
|
+
height,
|
|
610
|
+
},
|
|
611
|
+
]}
|
|
612
|
+
/>
|
|
613
|
+
{renderInputView(true)}
|
|
614
|
+
</>
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (headerType === 'extended') {
|
|
619
|
+
return (
|
|
620
|
+
<>
|
|
621
|
+
<Animated.View
|
|
622
|
+
style={[
|
|
623
|
+
styles.headerBox,
|
|
624
|
+
{
|
|
625
|
+
height,
|
|
626
|
+
},
|
|
627
|
+
]}>
|
|
628
|
+
<Image
|
|
629
|
+
source={{
|
|
630
|
+
uri: theme.assets?.headerBackground,
|
|
631
|
+
}}
|
|
632
|
+
style={styles.headerBackground}
|
|
633
|
+
/>
|
|
634
|
+
</Animated.View>
|
|
635
|
+
{renderInputView()}
|
|
636
|
+
</>
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return (
|
|
641
|
+
<>
|
|
642
|
+
<View style={[styles.headerBox, {height: heightHeader}]}>
|
|
643
|
+
<Image
|
|
644
|
+
source={{
|
|
645
|
+
uri: theme.assets?.headerBackground,
|
|
646
|
+
}}
|
|
647
|
+
style={styles.headerBackground}
|
|
648
|
+
/>
|
|
649
|
+
</View>
|
|
650
|
+
{renderInputView()}
|
|
651
|
+
</>
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (headerType === 'extended') {
|
|
656
|
+
return (
|
|
657
|
+
<View style={{minHeight: heightHeader}}>
|
|
658
|
+
<Image
|
|
659
|
+
source={{
|
|
660
|
+
uri: theme.assets?.headerBackground,
|
|
661
|
+
}}
|
|
662
|
+
style={styles.extendedHeader}
|
|
663
|
+
/>
|
|
664
|
+
</View>
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return <View />;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
|
|
672
|
+
if (__DEV__) {
|
|
673
|
+
Alert.alert(
|
|
674
|
+
'HeaderRightAction',
|
|
675
|
+
'This component is deprecated and will removed 10/2024, please use new type headerRight specs instead v0.92.34'
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
const validateType = (child: React.ReactElement) => {
|
|
679
|
+
return child;
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
const renderAction = () => {
|
|
683
|
+
if (Array.isArray(children)) {
|
|
684
|
+
return children.map((child, index) => {
|
|
685
|
+
return (
|
|
686
|
+
<View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
|
|
687
|
+
{React.cloneElement(validateType(child), {...restProps})}
|
|
688
|
+
</View>
|
|
689
|
+
);
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return (
|
|
694
|
+
<View style={styles.headerButton}>
|
|
695
|
+
{React.cloneElement(validateType(children), {...restProps})}
|
|
696
|
+
</View>
|
|
697
|
+
);
|
|
698
|
+
};
|
|
699
|
+
return <View style={styles.headerRightButton}>{renderAction()}</View>;
|
|
700
|
+
};
|
|
701
|
+
|
|
473
702
|
const styles = StyleSheet.create({
|
|
474
703
|
navigationButton: {
|
|
475
704
|
height: 28,
|
|
@@ -509,7 +738,6 @@ const styles = StyleSheet.create({
|
|
|
509
738
|
paddingRight: Spacing.M,
|
|
510
739
|
},
|
|
511
740
|
toolkitContainer: {
|
|
512
|
-
marginLeft: Spacing.S,
|
|
513
741
|
padding: Spacing.XS,
|
|
514
742
|
height: 28,
|
|
515
743
|
borderRadius: 14,
|
|
@@ -541,6 +769,22 @@ const styles = StyleSheet.create({
|
|
|
541
769
|
top: -Spacing.XS,
|
|
542
770
|
right: -Spacing.XS,
|
|
543
771
|
},
|
|
772
|
+
badgeDotAnimation: {
|
|
773
|
+
position: 'absolute',
|
|
774
|
+
top: -Spacing.XS,
|
|
775
|
+
right: -Spacing.XS,
|
|
776
|
+
},
|
|
777
|
+
extendedHeader: {
|
|
778
|
+
aspectRatio: 1.75,
|
|
779
|
+
position: 'absolute',
|
|
780
|
+
width: '100%',
|
|
781
|
+
height: 210,
|
|
782
|
+
},
|
|
783
|
+
headerBox: {
|
|
784
|
+
width: '100%',
|
|
785
|
+
position: 'absolute',
|
|
786
|
+
overflow: 'hidden',
|
|
787
|
+
},
|
|
544
788
|
});
|
|
545
789
|
|
|
546
790
|
export {
|
|
@@ -548,8 +792,10 @@ export {
|
|
|
548
792
|
HeaderTitle,
|
|
549
793
|
HeaderLeft,
|
|
550
794
|
HeaderBackground,
|
|
551
|
-
HeaderRightAction,
|
|
552
795
|
HeaderToolkitAction,
|
|
553
796
|
HeaderCustom,
|
|
554
797
|
HeaderAnimated,
|
|
798
|
+
HeaderRight,
|
|
799
|
+
HeaderExtendHeader,
|
|
800
|
+
HeaderRightAction,
|
|
555
801
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {NativeModules} from 'react-native';
|
|
2
|
+
import {LocalizationObject} from './types';
|
|
3
|
+
import defaultLanguage from '../Assets/language.json';
|
|
4
|
+
|
|
5
|
+
class Localize {
|
|
6
|
+
private assets: LocalizationObject;
|
|
7
|
+
private currentLanguage: 'en' | 'vi';
|
|
8
|
+
|
|
9
|
+
constructor(assets: LocalizationObject) {
|
|
10
|
+
this.assets = {
|
|
11
|
+
vi: {...assets?.vi, ...defaultLanguage.vi},
|
|
12
|
+
en: {...assets?.en, ...defaultLanguage.en},
|
|
13
|
+
};
|
|
14
|
+
this.currentLanguage = 'vi';
|
|
15
|
+
if (NativeModules?.RNResource?.language === 'en') {
|
|
16
|
+
this.currentLanguage = 'en';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get getCurrentLanguage() {
|
|
21
|
+
return this.currentLanguage;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get getAssets() {
|
|
25
|
+
return this.assets;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
translate(key: string) {
|
|
29
|
+
return this.assets[this.currentLanguage]?.[key] || key;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
translateData(data: {vi: string; en: string}) {
|
|
33
|
+
return data[this.currentLanguage] || JSON.stringify(data);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
addTranslations(translations: LocalizationObject) {
|
|
37
|
+
this.assets = {
|
|
38
|
+
vi: {...translations?.vi, ...this.assets.vi},
|
|
39
|
+
en: {...translations?.en, ...this.assets.en},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default Localize;
|