@momo-kits/foundation 0.81.49 → 0.81.51-beta.0
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 +356 -91
- 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 +154 -48
- package/Application/StackScreen.tsx +289 -32
- package/Application/constants.ts +9 -0
- package/Application/index.ts +13 -15
- package/Application/types.ts +81 -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 +57 -46
- package/Popup/PopupPromotion.tsx +6 -8
- 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 +10 -9
- 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';
|
|
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: any = 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,55 @@ 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
|
-
|
|
259
|
-
|
|
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
|
-
});
|
|
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);
|
|
272
309
|
}
|
|
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
|
-
|
|
287
|
-
preventBack,
|
|
340
|
+
preventClose,
|
|
288
341
|
}) => {
|
|
289
|
-
const {
|
|
290
|
-
const miniContext = useContext(MiniAppContext);
|
|
342
|
+
const {navigator} = useContext(ApplicationContext);
|
|
343
|
+
const miniContext = useContext<any>(MiniAppContext);
|
|
291
344
|
const [toolConfig, setToolConfig] = useState<any>();
|
|
292
345
|
const {onAction} = toolConfig ?? {};
|
|
293
346
|
|
|
294
347
|
let backgroundColor;
|
|
295
|
-
if (tintColor
|
|
296
|
-
backgroundColor =
|
|
348
|
+
if (tintColor !== Colors.black_01) {
|
|
349
|
+
backgroundColor = 'transparent';
|
|
297
350
|
}
|
|
298
351
|
|
|
299
352
|
useEffect(() => {
|
|
@@ -313,37 +366,39 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
313
366
|
(config: any) => {
|
|
314
367
|
navigator.toolkitConfig = config;
|
|
315
368
|
setToolConfig(navigator?.toolkitConfig);
|
|
316
|
-
}
|
|
369
|
+
}
|
|
317
370
|
);
|
|
318
371
|
};
|
|
319
372
|
|
|
320
373
|
const onMore = () => {
|
|
321
374
|
onAction?.('onMore');
|
|
322
375
|
navigator?.maxApi?.dispatchFunction?.(
|
|
323
|
-
'
|
|
324
|
-
{
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
376
|
+
'showToolkit',
|
|
377
|
+
{
|
|
378
|
+
tools: miniContext?.toolkitConfig?.oldTools ?? [
|
|
379
|
+
'addFavorite',
|
|
380
|
+
'addShortcut',
|
|
381
|
+
'share',
|
|
382
|
+
],
|
|
329
383
|
},
|
|
384
|
+
() => {}
|
|
330
385
|
);
|
|
331
386
|
};
|
|
332
387
|
|
|
333
388
|
const onClose = () => {
|
|
334
|
-
if (
|
|
389
|
+
if (preventClose) {
|
|
335
390
|
navigator?.showModal({
|
|
336
391
|
screen: () => (
|
|
337
392
|
<PopupNotify
|
|
338
|
-
{...
|
|
393
|
+
{...preventClose}
|
|
339
394
|
primary={{
|
|
340
|
-
title:
|
|
395
|
+
title: preventClose.primary.title,
|
|
341
396
|
onPress: () => {
|
|
342
|
-
|
|
397
|
+
preventClose?.primary.onPress();
|
|
343
398
|
navigator?.maxApi?.dispatchFunction?.(
|
|
344
399
|
'dismiss',
|
|
345
400
|
undefined,
|
|
346
|
-
undefined
|
|
401
|
+
undefined
|
|
347
402
|
);
|
|
348
403
|
},
|
|
349
404
|
}}
|
|
@@ -363,6 +418,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
363
418
|
if (pinTool)
|
|
364
419
|
return (
|
|
365
420
|
<NavigationButton
|
|
421
|
+
accessibilityLabel="btn_navigation_pin"
|
|
366
422
|
icon={pinTool.icon as string}
|
|
367
423
|
tintColor={tintColor}
|
|
368
424
|
badgeValue={badgeValue}
|
|
@@ -370,20 +426,19 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
370
426
|
onPress={() => {
|
|
371
427
|
navigator?.maxApi?.dispatchFunction?.(
|
|
372
428
|
'onToolAction',
|
|
373
|
-
|
|
429
|
+
{item: pinTool},
|
|
374
430
|
() => {
|
|
375
431
|
getToolkitConfig();
|
|
376
|
-
}
|
|
432
|
+
}
|
|
377
433
|
);
|
|
378
434
|
navigator?.toolkitCallback?.(pinTool.key);
|
|
379
435
|
}}
|
|
380
436
|
/>
|
|
381
437
|
);
|
|
382
438
|
};
|
|
383
|
-
|
|
384
439
|
if (toolConfig) {
|
|
385
440
|
return (
|
|
386
|
-
<View style={
|
|
441
|
+
<View style={Styles.row}>
|
|
387
442
|
{renderPinnedTool()}
|
|
388
443
|
<View
|
|
389
444
|
style={[
|
|
@@ -391,13 +446,18 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
391
446
|
{
|
|
392
447
|
backgroundColor: backgroundColor ?? '#00000066',
|
|
393
448
|
borderWidth: backgroundColor ? 0.5 : 0,
|
|
449
|
+
marginLeft: renderPinnedTool() ? Spacing.S : 0,
|
|
394
450
|
},
|
|
395
451
|
]}>
|
|
396
|
-
<TouchableOpacity
|
|
452
|
+
<TouchableOpacity
|
|
453
|
+
accessibilityLabel={'btn_navigation_more'}
|
|
454
|
+
onPress={onMore}>
|
|
397
455
|
<Icon color={tintColor} source="navigation_more_horiz" size={20} />
|
|
398
456
|
</TouchableOpacity>
|
|
399
457
|
<View style={[styles.divider, {backgroundColor: tintColor}]} />
|
|
400
|
-
<TouchableOpacity
|
|
458
|
+
<TouchableOpacity
|
|
459
|
+
accessibilityLabel={'btn_navigation_close'}
|
|
460
|
+
onPress={onClose}>
|
|
401
461
|
<Icon
|
|
402
462
|
color={tintColor}
|
|
403
463
|
source="16_navigation_close_circle"
|
|
@@ -412,10 +472,13 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
412
472
|
return <View />;
|
|
413
473
|
};
|
|
414
474
|
|
|
475
|
+
/**
|
|
476
|
+
* default header banner for header animated
|
|
477
|
+
*/
|
|
415
478
|
const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
416
479
|
animatedValue,
|
|
417
480
|
image,
|
|
418
|
-
|
|
481
|
+
children,
|
|
419
482
|
}) => {
|
|
420
483
|
const scale = animatedValue.interpolate({
|
|
421
484
|
inputRange: [-300, 0, 300],
|
|
@@ -434,24 +497,209 @@ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
|
|
|
434
497
|
});
|
|
435
498
|
|
|
436
499
|
return (
|
|
437
|
-
<
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
500
|
+
<Animated.View
|
|
501
|
+
style={{
|
|
502
|
+
height: 210,
|
|
503
|
+
opacity: opacity,
|
|
504
|
+
transform: [{scale}, {translateY}],
|
|
505
|
+
}}>
|
|
506
|
+
{children ?? (
|
|
444
507
|
<Image
|
|
445
508
|
source={{
|
|
446
509
|
uri: image,
|
|
447
510
|
}}
|
|
448
511
|
style={{width: '100%', height: '100%'}}
|
|
449
512
|
/>
|
|
450
|
-
|
|
451
|
-
</
|
|
513
|
+
)}
|
|
514
|
+
</Animated.View>
|
|
452
515
|
);
|
|
453
516
|
};
|
|
454
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Header extended with background image
|
|
520
|
+
* @constructor
|
|
521
|
+
*/
|
|
522
|
+
const HeaderExtendHeader: React.FC<{
|
|
523
|
+
headerType?: HeaderType;
|
|
524
|
+
animatedValue: Animated.Value;
|
|
525
|
+
heightHeader: number;
|
|
526
|
+
inputSearchProps?: InputSearchProps;
|
|
527
|
+
inputSearchRef?: Ref<InputRef>;
|
|
528
|
+
navigation?: Navigation;
|
|
529
|
+
}> = ({
|
|
530
|
+
headerType = 'default',
|
|
531
|
+
animatedValue,
|
|
532
|
+
heightHeader,
|
|
533
|
+
inputSearchProps,
|
|
534
|
+
inputSearchRef,
|
|
535
|
+
navigation,
|
|
536
|
+
}) => {
|
|
537
|
+
const {theme} = useContext(ApplicationContext);
|
|
538
|
+
const [rightSpace, setRightSpace] = useState(0);
|
|
539
|
+
const animated = useRef(new Animated.Value(0));
|
|
540
|
+
|
|
541
|
+
useEffect(() => {
|
|
542
|
+
const listener = animatedValue.addListener(({value}) => {
|
|
543
|
+
animated.current.setValue(value);
|
|
544
|
+
});
|
|
545
|
+
return () => {
|
|
546
|
+
animatedValue?.removeListener(listener);
|
|
547
|
+
};
|
|
548
|
+
}, []);
|
|
549
|
+
|
|
550
|
+
const height = animated.current.interpolate({
|
|
551
|
+
inputRange: [0, 100],
|
|
552
|
+
outputRange: [heightHeader + 52, heightHeader],
|
|
553
|
+
extrapolate: 'clamp',
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const translateX = animated.current.interpolate({
|
|
557
|
+
inputRange: [0, 100],
|
|
558
|
+
outputRange: [SCREEN_PADDING, BACK_WIDTH + SCREEN_PADDING * 2],
|
|
559
|
+
extrapolate: 'clamp',
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
if (navigation) {
|
|
563
|
+
navigation.onHeaderRightChange = (width: number) => {
|
|
564
|
+
setRightSpace(width);
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const renderInputView = (hasColorBG: boolean = false) => {
|
|
569
|
+
return (
|
|
570
|
+
<Animated.View
|
|
571
|
+
style={{
|
|
572
|
+
justifyContent: 'flex-end',
|
|
573
|
+
height,
|
|
574
|
+
}}>
|
|
575
|
+
<Animated.View
|
|
576
|
+
style={{
|
|
577
|
+
transform: [{translateX}],
|
|
578
|
+
marginVertical: Spacing.S,
|
|
579
|
+
width: animated.current.interpolate({
|
|
580
|
+
inputRange: [0, 100],
|
|
581
|
+
outputRange: [
|
|
582
|
+
screenWidth - SCREEN_PADDING * 2,
|
|
583
|
+
screenWidth - SCREEN_PADDING * 3 - BACK_WIDTH - rightSpace,
|
|
584
|
+
],
|
|
585
|
+
extrapolate: 'clamp',
|
|
586
|
+
}),
|
|
587
|
+
}}>
|
|
588
|
+
<InputSearch
|
|
589
|
+
{...inputSearchProps}
|
|
590
|
+
ref={inputSearchRef}
|
|
591
|
+
hasColorBG={hasColorBG}
|
|
592
|
+
showButtonText={false}
|
|
593
|
+
/>
|
|
594
|
+
</Animated.View>
|
|
595
|
+
</Animated.View>
|
|
596
|
+
);
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
if (inputSearchProps) {
|
|
600
|
+
if (headerType === 'surface') {
|
|
601
|
+
return (
|
|
602
|
+
<>
|
|
603
|
+
<Animated.View
|
|
604
|
+
style={[
|
|
605
|
+
styles.headerBox,
|
|
606
|
+
{
|
|
607
|
+
backgroundColor: theme.colors.background.surface,
|
|
608
|
+
borderBottomWidth: 1,
|
|
609
|
+
borderColor: theme.colors.border.default,
|
|
610
|
+
height,
|
|
611
|
+
},
|
|
612
|
+
]}
|
|
613
|
+
/>
|
|
614
|
+
{renderInputView(true)}
|
|
615
|
+
</>
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (headerType === 'extended') {
|
|
620
|
+
return (
|
|
621
|
+
<>
|
|
622
|
+
<Animated.View
|
|
623
|
+
style={[
|
|
624
|
+
styles.headerBox,
|
|
625
|
+
{
|
|
626
|
+
height,
|
|
627
|
+
},
|
|
628
|
+
]}>
|
|
629
|
+
<Image
|
|
630
|
+
source={{
|
|
631
|
+
uri: theme.assets?.headerBackground,
|
|
632
|
+
}}
|
|
633
|
+
style={styles.headerBackground}
|
|
634
|
+
/>
|
|
635
|
+
</Animated.View>
|
|
636
|
+
{renderInputView()}
|
|
637
|
+
</>
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return (
|
|
642
|
+
<>
|
|
643
|
+
<View style={[styles.headerBox, {height: heightHeader}]}>
|
|
644
|
+
<Image
|
|
645
|
+
source={{
|
|
646
|
+
uri: theme.assets?.headerBackground,
|
|
647
|
+
}}
|
|
648
|
+
style={styles.headerBackground}
|
|
649
|
+
/>
|
|
650
|
+
</View>
|
|
651
|
+
{renderInputView()}
|
|
652
|
+
</>
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (headerType === 'extended') {
|
|
657
|
+
return (
|
|
658
|
+
<View style={{minHeight: heightHeader}}>
|
|
659
|
+
<Image
|
|
660
|
+
source={{
|
|
661
|
+
uri: theme.assets?.headerBackground,
|
|
662
|
+
}}
|
|
663
|
+
style={styles.extendedHeader}
|
|
664
|
+
/>
|
|
665
|
+
</View>
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return <View />;
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
|
|
673
|
+
if (__DEV__) {
|
|
674
|
+
Alert.alert(
|
|
675
|
+
'HeaderRightAction',
|
|
676
|
+
'This component is deprecated and will removed 10/2024, please use new type headerRight specs instead v0.92.34'
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
const validateType = (child: React.ReactElement) => {
|
|
680
|
+
return child;
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const renderAction = () => {
|
|
684
|
+
if (Array.isArray(children)) {
|
|
685
|
+
return children.map((child, index) => {
|
|
686
|
+
return (
|
|
687
|
+
<View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
|
|
688
|
+
{React.cloneElement(validateType(child), {...restProps})}
|
|
689
|
+
</View>
|
|
690
|
+
);
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return (
|
|
695
|
+
<View style={styles.headerButton}>
|
|
696
|
+
{React.cloneElement(validateType(children), {...restProps})}
|
|
697
|
+
</View>
|
|
698
|
+
);
|
|
699
|
+
};
|
|
700
|
+
return <View style={styles.headerRightButton}>{renderAction()}</View>;
|
|
701
|
+
};
|
|
702
|
+
|
|
455
703
|
const styles = StyleSheet.create({
|
|
456
704
|
navigationButton: {
|
|
457
705
|
height: 28,
|
|
@@ -488,10 +736,9 @@ const styles = StyleSheet.create({
|
|
|
488
736
|
flexDirection: 'row',
|
|
489
737
|
justifyContent: 'center',
|
|
490
738
|
alignItems: 'center',
|
|
491
|
-
paddingRight: Spacing.
|
|
739
|
+
paddingRight: Spacing.M,
|
|
492
740
|
},
|
|
493
741
|
toolkitContainer: {
|
|
494
|
-
marginLeft: Spacing.S,
|
|
495
742
|
padding: Spacing.XS,
|
|
496
743
|
height: 28,
|
|
497
744
|
borderRadius: 14,
|
|
@@ -523,6 +770,22 @@ const styles = StyleSheet.create({
|
|
|
523
770
|
top: -Spacing.XS,
|
|
524
771
|
right: -Spacing.XS,
|
|
525
772
|
},
|
|
773
|
+
badgeDotAnimation: {
|
|
774
|
+
position: 'absolute',
|
|
775
|
+
top: -Spacing.XS,
|
|
776
|
+
right: -Spacing.XS,
|
|
777
|
+
},
|
|
778
|
+
extendedHeader: {
|
|
779
|
+
aspectRatio: 1.75,
|
|
780
|
+
position: 'absolute',
|
|
781
|
+
width: '100%',
|
|
782
|
+
height: 210,
|
|
783
|
+
},
|
|
784
|
+
headerBox: {
|
|
785
|
+
width: '100%',
|
|
786
|
+
position: 'absolute',
|
|
787
|
+
overflow: 'hidden',
|
|
788
|
+
},
|
|
526
789
|
});
|
|
527
790
|
|
|
528
791
|
export {
|
|
@@ -530,8 +793,10 @@ export {
|
|
|
530
793
|
HeaderTitle,
|
|
531
794
|
HeaderLeft,
|
|
532
795
|
HeaderBackground,
|
|
533
|
-
HeaderRightAction,
|
|
534
796
|
HeaderToolkitAction,
|
|
535
797
|
HeaderCustom,
|
|
536
798
|
HeaderAnimated,
|
|
799
|
+
HeaderRight,
|
|
800
|
+
HeaderExtendHeader,
|
|
801
|
+
HeaderRightAction,
|
|
537
802
|
};
|