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