@momo-kits/foundation 0.89.5 → 0.89.6-rc.2
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 +278 -0
- package/Application/{BottomTab.tsx → BottomTab/index.tsx} +42 -18
- package/Application/Components.tsx +350 -86
- package/Application/Localize.ts +44 -0
- package/Application/ModalScreen.tsx +14 -185
- package/Application/Navigation.ts +5 -19
- package/Application/NavigationContainer.tsx +62 -72
- package/Application/Navigator.ts +53 -35
- package/Application/StackScreen.tsx +289 -32
- package/Application/index.ts +13 -15
- package/Application/types.ts +64 -35
- package/Application/utils.tsx +76 -30
- package/Assets/icon_bank.json +1 -1
- package/Badge/Badge.tsx +1 -1
- package/Badge/BadgeDotAnimation.tsx +95 -0
- package/Badge/index.tsx +2 -1
- package/Badge/styles.ts +50 -6
- package/Button/index.tsx +44 -26
- package/CheckBox/index.tsx +37 -26
- package/CheckBox/types.ts +5 -3
- package/Consts/colors+spacing+radius.ts +14 -0
- package/Icon/index.tsx +9 -8
- package/Icon/types.ts +2 -2
- package/IconButton/index.tsx +24 -14
- package/Image/index.tsx +23 -8
- package/Image/types.ts +2 -0
- package/Input/Input.tsx +116 -26
- package/Input/InputDropDown.tsx +66 -51
- package/Input/InputMoney.tsx +106 -15
- package/Input/InputOTP.tsx +49 -26
- package/Input/InputSearch.tsx +252 -99
- package/Input/InputTextArea.tsx +26 -6
- package/Input/TextTyping.tsx +113 -0
- package/Input/common.tsx +48 -22
- package/Input/index.tsx +112 -77
- package/Input/styles.ts +48 -11
- package/Input/utils.ts +1 -1
- package/Layout/Card.tsx +4 -3
- package/Layout/FloatingButton.tsx +168 -0
- package/Layout/GridSystem.tsx +1 -1
- package/Layout/ItemList.tsx +3 -2
- package/Layout/Screen.tsx +242 -121
- package/Layout/Section.tsx +4 -3
- package/Layout/styles.ts +11 -13
- package/Layout/types.ts +1 -1
- package/Layout/utils.ts +4 -4
- package/Loader/index.tsx +2 -0
- package/Pagination/PaginationScroll.tsx +2 -2
- package/Pagination/styles.ts +1 -1
- package/Popup/PopupNotify.tsx +56 -45
- package/Popup/PopupPromotion.tsx +5 -7
- package/Popup/types.ts +1 -7
- package/Radio/index.tsx +35 -20
- package/Radio/types.ts +5 -3
- package/Switch/index.tsx +32 -18
- package/Switch/types.ts +5 -3
- package/Tag/index.tsx +9 -2
- package/Tag/styles.ts +3 -2
- package/Tag/types.ts +12 -0
- package/Text/index.tsx +24 -5
- package/Text/styles.ts +8 -8
- package/Text/types.ts +19 -1
- package/Title/index.tsx +170 -103
- package/Title/styles.ts +36 -9
- package/Title/types.ts +16 -48
- package/code-scanner.js +125 -16
- package/index.ts +7 -0
- package/migrate_typo.js +56 -0
- package/package.json +11 -10
- package/publish.sh +16 -21
- package/tsconfig.json +1 -1
- package/verify.js +37 -40
|
@@ -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';
|
|
32
|
-
|
|
35
|
+
import {HeaderType} from '../Layout/types';
|
|
36
|
+
import Navigation from './Navigation';
|
|
37
|
+
import {InputRef, InputSearch, InputSearchProps} from '../Input';
|
|
38
|
+
import {BadgeDotAnimation} from '../Badge';
|
|
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,
|
|
@@ -37,10 +51,11 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
37
51
|
useBorder = true,
|
|
38
52
|
badgeType,
|
|
39
53
|
badgeValue,
|
|
54
|
+
accessibilityLabel = '',
|
|
40
55
|
}) => {
|
|
41
56
|
const {theme} = useContext(ApplicationContext);
|
|
42
57
|
let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
|
|
43
|
-
if (tintColor
|
|
58
|
+
if (tintColor !== Colors.black_01) {
|
|
44
59
|
buttonStyle = {
|
|
45
60
|
backgroundColor: 'transparent',
|
|
46
61
|
borderColor: '#00000066',
|
|
@@ -57,6 +72,11 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
57
72
|
if (badgeType === 'dot') {
|
|
58
73
|
return <BadgeDot size="small" style={styles.badgeDot} />;
|
|
59
74
|
}
|
|
75
|
+
if (badgeType === 'dot-animation') {
|
|
76
|
+
return (
|
|
77
|
+
<BadgeDotAnimation size="small" style={styles.badgeDotAnimation} />
|
|
78
|
+
);
|
|
79
|
+
}
|
|
60
80
|
|
|
61
81
|
if (isNumber(badgeValue)) {
|
|
62
82
|
return <Badge label={badgeValue} style={styles.badge} />;
|
|
@@ -64,8 +84,9 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
64
84
|
}, [badgeType, badgeValue]);
|
|
65
85
|
|
|
66
86
|
return (
|
|
67
|
-
<View style={{width:
|
|
87
|
+
<View style={{width: 28}}>
|
|
68
88
|
<TouchableOpacity
|
|
89
|
+
accessibilityLabel={accessibilityLabel}
|
|
69
90
|
style={[styles.navigationButton, buttonStyle]}
|
|
70
91
|
onPress={onPress}>
|
|
71
92
|
<Icon
|
|
@@ -79,17 +100,23 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
79
100
|
);
|
|
80
101
|
};
|
|
81
102
|
|
|
103
|
+
/**
|
|
104
|
+
* default header title used for nav
|
|
105
|
+
*/
|
|
82
106
|
const HeaderTitle: React.FC<any> = props => {
|
|
83
107
|
const {theme} = useContext(ApplicationContext);
|
|
84
|
-
const opacity = props.animatedValue?.interpolate(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
const opacity = props.animatedValue?.interpolate(
|
|
109
|
+
props.interpolate ?? {
|
|
110
|
+
inputRange: [0, 200],
|
|
111
|
+
outputRange: [0, 1],
|
|
112
|
+
extrapolate: 'clamp',
|
|
113
|
+
}
|
|
114
|
+
);
|
|
89
115
|
|
|
90
116
|
return (
|
|
91
117
|
<Animated.Text
|
|
92
118
|
{...props}
|
|
119
|
+
accessibilityLabel={'title_navigation_header'}
|
|
93
120
|
style={[
|
|
94
121
|
styles.title,
|
|
95
122
|
{fontFamily: `${theme.font}-Bold`, opacity, color: props.tintColor},
|
|
@@ -98,19 +125,22 @@ const HeaderTitle: React.FC<any> = props => {
|
|
|
98
125
|
);
|
|
99
126
|
};
|
|
100
127
|
|
|
128
|
+
/**
|
|
129
|
+
* default header left used for nav
|
|
130
|
+
*/
|
|
101
131
|
const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
102
132
|
tintColor,
|
|
103
133
|
preventBack,
|
|
104
134
|
onPressLeftHeader,
|
|
105
135
|
useBorder,
|
|
106
136
|
}) => {
|
|
107
|
-
const context = useContext(MiniAppContext);
|
|
137
|
+
const context = useContext<any>(MiniAppContext);
|
|
108
138
|
const {navigator} = useContext(ApplicationContext);
|
|
109
139
|
|
|
110
140
|
useEffect(() => {
|
|
111
141
|
const backHandler = BackHandler.addEventListener(
|
|
112
142
|
'hardwareBackPress',
|
|
113
|
-
goBackSafe
|
|
143
|
+
goBackSafe
|
|
114
144
|
);
|
|
115
145
|
|
|
116
146
|
return () => backHandler.remove();
|
|
@@ -118,20 +148,25 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
118
148
|
|
|
119
149
|
const goBackSafe = () => {
|
|
120
150
|
const goBack = () => {
|
|
121
|
-
const canGoBack = navigator?.ref
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
const canGoBack = navigator?.ref?.current?.canGoBack?.();
|
|
152
|
+
const currentRoute = navigator?.ref?.current?.getCurrentRoute?.();
|
|
153
|
+
const params = {
|
|
154
|
+
appId: context.appId,
|
|
155
|
+
code: context.code,
|
|
156
|
+
screen_name: currentRoute?.params?.screen?.name ?? currentRoute?.name,
|
|
157
|
+
trigger_id: '111154000000000000',
|
|
158
|
+
icon_name: 'back',
|
|
159
|
+
};
|
|
160
|
+
navigator?.maxApi?.showToastDebug?.({
|
|
161
|
+
appId: `auto - ${context.appId}`,
|
|
162
|
+
message: 'service_icon_clicked',
|
|
163
|
+
params,
|
|
164
|
+
});
|
|
165
|
+
navigator?.maxApi?.trackEvent?.('service_icon_clicked', params);
|
|
131
166
|
if (canGoBack) {
|
|
132
|
-
navigator?.ref
|
|
167
|
+
navigator?.ref?.current?.goBack?.();
|
|
133
168
|
} else if (navigator?.maxApi) {
|
|
134
|
-
navigator?.maxApi?.dismiss(navigator
|
|
169
|
+
navigator?.maxApi?.dismiss?.(navigator?.dismissData);
|
|
135
170
|
} else {
|
|
136
171
|
const currentTime = new Date().getTime();
|
|
137
172
|
const requestId = `navigationBackPress#${currentTime}`;
|
|
@@ -164,6 +199,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
164
199
|
return (
|
|
165
200
|
<View style={styles.headerLeft}>
|
|
166
201
|
<NavigationButton
|
|
202
|
+
accessibilityLabel="btn_navigation_back"
|
|
167
203
|
icon="ic_back"
|
|
168
204
|
tintColor={tintColor}
|
|
169
205
|
onPress={goBackSafe}
|
|
@@ -173,17 +209,23 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
|
|
|
173
209
|
);
|
|
174
210
|
};
|
|
175
211
|
|
|
212
|
+
/**
|
|
213
|
+
* header background for default
|
|
214
|
+
*/
|
|
176
215
|
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
177
216
|
image,
|
|
178
|
-
backgroundColor,
|
|
179
217
|
animatedValue,
|
|
180
|
-
|
|
218
|
+
useSurface = false,
|
|
181
219
|
}) => {
|
|
182
220
|
const {theme} = useContext(ApplicationContext);
|
|
183
221
|
let headerImage = theme.assets?.headerBackground;
|
|
222
|
+
let backgroundColor;
|
|
184
223
|
if (image === null) {
|
|
185
224
|
headerImage = undefined;
|
|
186
225
|
}
|
|
226
|
+
if (useSurface) {
|
|
227
|
+
backgroundColor = theme.colors.background.surface;
|
|
228
|
+
}
|
|
187
229
|
const opacity = animatedValue?.interpolate({
|
|
188
230
|
inputRange: [0, 114],
|
|
189
231
|
outputRange: [0, 1],
|
|
@@ -195,9 +237,9 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
195
237
|
style={[
|
|
196
238
|
Styles.flex,
|
|
197
239
|
{
|
|
198
|
-
backgroundColor
|
|
240
|
+
backgroundColor,
|
|
199
241
|
overflow: 'hidden',
|
|
200
|
-
borderBottomWidth:
|
|
242
|
+
borderBottomWidth: useSurface ? 1 : 0,
|
|
201
243
|
borderColor: theme.colors.border.default,
|
|
202
244
|
opacity,
|
|
203
245
|
},
|
|
@@ -218,6 +260,10 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
218
260
|
);
|
|
219
261
|
};
|
|
220
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Header custom with image, title, subtitle
|
|
265
|
+
* @constructor
|
|
266
|
+
*/
|
|
221
267
|
const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
222
268
|
title,
|
|
223
269
|
subTitle,
|
|
@@ -227,7 +273,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
227
273
|
tintColor,
|
|
228
274
|
dotColor,
|
|
229
275
|
}) => {
|
|
230
|
-
const avatarStyle = imageShape
|
|
276
|
+
const avatarStyle = imageShape === 'circle' ? styles.circle : styles.square;
|
|
231
277
|
const header = (
|
|
232
278
|
<View style={Styles.row}>
|
|
233
279
|
<View>
|
|
@@ -237,7 +283,10 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
237
283
|
)}
|
|
238
284
|
</View>
|
|
239
285
|
<View style={[Styles.flex, {paddingHorizontal: 8}]}>
|
|
240
|
-
<Text
|
|
286
|
+
<Text
|
|
287
|
+
accessibilityLabel={'title_navigation_header'}
|
|
288
|
+
typography="header_default_bold"
|
|
289
|
+
color={tintColor}>
|
|
241
290
|
{title}
|
|
242
291
|
</Text>
|
|
243
292
|
<Text typography="description_default_regular" color={tintColor}>
|
|
@@ -249,51 +298,56 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
249
298
|
return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
|
|
250
299
|
};
|
|
251
300
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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);
|
|
259
309
|
}
|
|
260
|
-
return child;
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const renderAction = () => {
|
|
264
|
-
if (Array.isArray(children)) {
|
|
265
|
-
return children.map((child, index) => {
|
|
266
|
-
return (
|
|
267
|
-
<View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
|
|
268
|
-
{React.cloneElement(validateType(child), {...restProps})}
|
|
269
|
-
</View>
|
|
270
|
-
);
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
310
|
return (
|
|
275
|
-
<View style={styles.
|
|
276
|
-
{
|
|
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
|
+
})}
|
|
277
323
|
</View>
|
|
278
324
|
);
|
|
279
|
-
}
|
|
280
|
-
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<View style={styles.headerRightButton} onLayout={onLayout}>
|
|
329
|
+
{children ?? <HeaderToolkitAction {...props} />}
|
|
330
|
+
</View>
|
|
331
|
+
);
|
|
281
332
|
};
|
|
282
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Header toolkit action
|
|
336
|
+
*/
|
|
283
337
|
const HeaderToolkitAction: React.FC<any> = ({
|
|
284
338
|
tintColor,
|
|
285
339
|
pinnedTool,
|
|
286
340
|
runtimeTools = [],
|
|
287
|
-
|
|
341
|
+
preventClose,
|
|
288
342
|
}) => {
|
|
289
|
-
const {
|
|
290
|
-
const miniContext = useContext(MiniAppContext);
|
|
343
|
+
const {navigator} = useContext(ApplicationContext);
|
|
344
|
+
const miniContext = useContext<any>(MiniAppContext);
|
|
291
345
|
const [toolConfig, setToolConfig] = useState<any>();
|
|
292
346
|
const {onAction} = toolConfig ?? {};
|
|
293
347
|
|
|
294
348
|
let backgroundColor;
|
|
295
|
-
if (tintColor
|
|
296
|
-
backgroundColor =
|
|
349
|
+
if (tintColor !== Colors.black_01) {
|
|
350
|
+
backgroundColor = 'transparent';
|
|
297
351
|
}
|
|
298
352
|
|
|
299
353
|
useEffect(() => {
|
|
@@ -313,7 +367,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
313
367
|
(config: any) => {
|
|
314
368
|
navigator.toolkitConfig = config;
|
|
315
369
|
setToolConfig(navigator?.toolkitConfig);
|
|
316
|
-
}
|
|
370
|
+
}
|
|
317
371
|
);
|
|
318
372
|
};
|
|
319
373
|
|
|
@@ -324,26 +378,26 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
324
378
|
{runtimeTools},
|
|
325
379
|
(res: {item: {action?: string; key: string}}) => {
|
|
326
380
|
const {item} = res;
|
|
327
|
-
navigator?.toolkitCallback?.(item);
|
|
381
|
+
navigator?.toolkitCallback?.(item.key);
|
|
328
382
|
getToolkitConfig();
|
|
329
|
-
}
|
|
383
|
+
}
|
|
330
384
|
);
|
|
331
385
|
};
|
|
332
386
|
|
|
333
387
|
const onClose = () => {
|
|
334
|
-
if (
|
|
388
|
+
if (preventClose) {
|
|
335
389
|
navigator?.showModal({
|
|
336
390
|
screen: () => (
|
|
337
391
|
<PopupNotify
|
|
338
|
-
{...
|
|
392
|
+
{...preventClose}
|
|
339
393
|
primary={{
|
|
340
|
-
title:
|
|
394
|
+
title: preventClose.primary.title,
|
|
341
395
|
onPress: () => {
|
|
342
|
-
|
|
396
|
+
preventClose?.primary.onPress();
|
|
343
397
|
navigator?.maxApi?.dispatchFunction?.(
|
|
344
398
|
'dismiss',
|
|
345
399
|
undefined,
|
|
346
|
-
undefined
|
|
400
|
+
undefined
|
|
347
401
|
);
|
|
348
402
|
},
|
|
349
403
|
}}
|
|
@@ -363,6 +417,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
363
417
|
if (pinTool)
|
|
364
418
|
return (
|
|
365
419
|
<NavigationButton
|
|
420
|
+
accessibilityLabel="btn_navigation_pin"
|
|
366
421
|
icon={pinTool.icon as string}
|
|
367
422
|
tintColor={tintColor}
|
|
368
423
|
badgeValue={badgeValue}
|
|
@@ -370,20 +425,19 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
370
425
|
onPress={() => {
|
|
371
426
|
navigator?.maxApi?.dispatchFunction?.(
|
|
372
427
|
'onToolAction',
|
|
373
|
-
|
|
428
|
+
{item: pinTool},
|
|
374
429
|
() => {
|
|
375
430
|
getToolkitConfig();
|
|
376
|
-
}
|
|
431
|
+
}
|
|
377
432
|
);
|
|
378
433
|
navigator?.toolkitCallback?.(pinTool.key);
|
|
379
434
|
}}
|
|
380
435
|
/>
|
|
381
436
|
);
|
|
382
437
|
};
|
|
383
|
-
|
|
384
438
|
if (toolConfig) {
|
|
385
439
|
return (
|
|
386
|
-
<View style={
|
|
440
|
+
<View style={Styles.row}>
|
|
387
441
|
{renderPinnedTool()}
|
|
388
442
|
<View
|
|
389
443
|
style={[
|
|
@@ -391,13 +445,18 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
391
445
|
{
|
|
392
446
|
backgroundColor: backgroundColor ?? '#00000066',
|
|
393
447
|
borderWidth: backgroundColor ? 0.5 : 0,
|
|
448
|
+
marginLeft: renderPinnedTool() ? Spacing.S : 0,
|
|
394
449
|
},
|
|
395
450
|
]}>
|
|
396
|
-
<TouchableOpacity
|
|
451
|
+
<TouchableOpacity
|
|
452
|
+
accessibilityLabel={'btn_navigation_more'}
|
|
453
|
+
onPress={onMore}>
|
|
397
454
|
<Icon color={tintColor} source="navigation_more_horiz" size={20} />
|
|
398
455
|
</TouchableOpacity>
|
|
399
456
|
<View style={[styles.divider, {backgroundColor: tintColor}]} />
|
|
400
|
-
<TouchableOpacity
|
|
457
|
+
<TouchableOpacity
|
|
458
|
+
accessibilityLabel={'btn_navigation_close'}
|
|
459
|
+
onPress={onClose}>
|
|
401
460
|
<Icon
|
|
402
461
|
color={tintColor}
|
|
403
462
|
source="16_navigation_close_circle"
|
|
@@ -412,10 +471,13 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
412
471
|
return <View />;
|
|
413
472
|
};
|
|
414
473
|
|
|
474
|
+
/**
|
|
475
|
+
* default header banner for header animated
|
|
476
|
+
*/
|
|
415
477
|
const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
416
478
|
animatedValue,
|
|
417
479
|
image,
|
|
418
|
-
|
|
480
|
+
children,
|
|
419
481
|
}) => {
|
|
420
482
|
const scale = animatedValue.interpolate({
|
|
421
483
|
inputRange: [-300, 0, 300],
|
|
@@ -434,24 +496,209 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
|
434
496
|
});
|
|
435
497
|
|
|
436
498
|
return (
|
|
437
|
-
<
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
499
|
+
<Animated.View
|
|
500
|
+
style={{
|
|
501
|
+
height: 210,
|
|
502
|
+
opacity: opacity,
|
|
503
|
+
transform: [{scale}, {translateY}],
|
|
504
|
+
}}>
|
|
505
|
+
{children ?? (
|
|
444
506
|
<Image
|
|
445
507
|
source={{
|
|
446
508
|
uri: image,
|
|
447
509
|
}}
|
|
448
510
|
style={{width: '100%', height: '100%'}}
|
|
449
511
|
/>
|
|
450
|
-
|
|
451
|
-
</
|
|
512
|
+
)}
|
|
513
|
+
</Animated.View>
|
|
452
514
|
);
|
|
453
515
|
};
|
|
454
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
|
+
|
|
455
702
|
const styles = StyleSheet.create({
|
|
456
703
|
navigationButton: {
|
|
457
704
|
height: 28,
|
|
@@ -488,10 +735,9 @@ const styles = StyleSheet.create({
|
|
|
488
735
|
flexDirection: 'row',
|
|
489
736
|
justifyContent: 'center',
|
|
490
737
|
alignItems: 'center',
|
|
491
|
-
paddingRight: Spacing.
|
|
738
|
+
paddingRight: Spacing.M,
|
|
492
739
|
},
|
|
493
740
|
toolkitContainer: {
|
|
494
|
-
marginLeft: Spacing.S,
|
|
495
741
|
padding: Spacing.XS,
|
|
496
742
|
height: 28,
|
|
497
743
|
borderRadius: 14,
|
|
@@ -523,6 +769,22 @@ const styles = StyleSheet.create({
|
|
|
523
769
|
top: -Spacing.XS,
|
|
524
770
|
right: -Spacing.XS,
|
|
525
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
|
+
},
|
|
526
788
|
});
|
|
527
789
|
|
|
528
790
|
export {
|
|
@@ -530,8 +792,10 @@ export {
|
|
|
530
792
|
HeaderTitle,
|
|
531
793
|
HeaderLeft,
|
|
532
794
|
HeaderBackground,
|
|
533
|
-
HeaderRightAction,
|
|
534
795
|
HeaderToolkitAction,
|
|
535
796
|
HeaderCustom,
|
|
536
797
|
HeaderAnimated,
|
|
798
|
+
HeaderRight,
|
|
799
|
+
HeaderExtendHeader,
|
|
800
|
+
HeaderRightAction,
|
|
537
801
|
};
|