@momo-kits/foundation 1.0.11 → 1.0.13
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/Assets/icon.json +9 -0
- package/Button/index.tsx +3 -10
- package/CheckBox/index.tsx +9 -10
- package/CheckBox/styles.ts +0 -1
- package/Icon/index.tsx +1 -0
- package/Image/index.tsx +7 -3
- package/Input/Input.tsx +1 -5
- package/Input/InputMoney.tsx +1 -7
- package/Input/InputSearch.tsx +20 -16
- package/Input/common.tsx +4 -3
- package/Input/index.tsx +6 -2
- package/Input/styles.ts +1 -3
- package/Layout/ScreenContainer.tsx +12 -2
- package/Navigation/BottomTab.tsx +3 -5
- package/Navigation/Components.tsx +25 -14
- package/Navigation/NavigationButton.tsx +1 -1
- package/Navigation/StackScreen.tsx +2 -1
- package/Navigation/types.ts +6 -3
- package/Navigation/utils.tsx +32 -17
- package/Popup/PopupPromotion.tsx +2 -3
- package/Skeleton/index.tsx +31 -23
- package/package.json +1 -1
package/Assets/icon.json
CHANGED
|
@@ -3934,5 +3934,14 @@
|
|
|
3934
3934
|
},
|
|
3935
3935
|
"ic_error": {
|
|
3936
3936
|
"uri": "https://img.mservice.com.vn/app/img/kits/error_mess_icon.png"
|
|
3937
|
+
},
|
|
3938
|
+
"media_fail": {
|
|
3939
|
+
"uri": "https://static.momocdn.net/app/img/kits/media_fail.png"
|
|
3940
|
+
},
|
|
3941
|
+
"ic_checked": {
|
|
3942
|
+
"uri": "https://img.mservice.com.vn/app/img/kits/checked_ic.png"
|
|
3943
|
+
},
|
|
3944
|
+
"ic_minus": {
|
|
3945
|
+
"uri": "https://img.mservice.com.vn/app/img/kits/minus.png"
|
|
3937
3946
|
}
|
|
3938
3947
|
}
|
package/Button/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import {Typography} from '../Text/types';
|
|
|
11
11
|
import {Colors} from '../Consts';
|
|
12
12
|
import styles from './styles';
|
|
13
13
|
import {Image} from '../Image';
|
|
14
|
+
import {Icon} from '../Icon';
|
|
14
15
|
|
|
15
16
|
export interface ButtonProps extends TouchableOpacityProps {
|
|
16
17
|
type?:
|
|
@@ -179,11 +180,7 @@ const Button: FC<ButtonProps> = ({
|
|
|
179
180
|
styles.leading,
|
|
180
181
|
{width: iconSize, height: iconSize, marginRight},
|
|
181
182
|
]}>
|
|
182
|
-
<
|
|
183
|
-
tintColor={color}
|
|
184
|
-
source={{uri: iconLeft}}
|
|
185
|
-
style={{width: iconSize, height: iconSize}}
|
|
186
|
-
/>
|
|
183
|
+
<Icon color={color} source={iconLeft} size={iconSize} />
|
|
187
184
|
</View>
|
|
188
185
|
);
|
|
189
186
|
}
|
|
@@ -203,11 +200,7 @@ const Button: FC<ButtonProps> = ({
|
|
|
203
200
|
styles.trailing,
|
|
204
201
|
{width: iconSize, height: iconSize, marginLeft},
|
|
205
202
|
]}>
|
|
206
|
-
<
|
|
207
|
-
tintColor={color}
|
|
208
|
-
source={{uri: iconRight}}
|
|
209
|
-
style={{width: iconSize, height: iconSize}}
|
|
210
|
-
/>
|
|
203
|
+
<Icon color={color} source={iconRight} size={iconSize} />
|
|
211
204
|
</View>
|
|
212
205
|
);
|
|
213
206
|
}
|
package/CheckBox/index.tsx
CHANGED
|
@@ -2,13 +2,10 @@ import React, {FC, useContext} from 'react';
|
|
|
2
2
|
import {TouchableOpacity, View} from 'react-native';
|
|
3
3
|
import {CheckBoxProps} from './types';
|
|
4
4
|
import styles from './styles';
|
|
5
|
-
import Image from 'react-native-fast-image';
|
|
6
5
|
import {ApplicationContext} from '../Navigation';
|
|
7
6
|
import {Text} from '../Text';
|
|
7
|
+
import {Icon} from '../Icon';
|
|
8
8
|
|
|
9
|
-
const IC_INDETERMINATED = 'https://img.mservice.com.vn/app/img/kits/minus.png';
|
|
10
|
-
const IC_CHECKED_DEFAULT =
|
|
11
|
-
'https://img.mservice.com.vn/app/img/kits/checked_ic.png';
|
|
12
9
|
const CheckBox: FC<CheckBoxProps> = props => {
|
|
13
10
|
const {theme} = useContext(ApplicationContext);
|
|
14
11
|
const {value, disabled, onChange, style, label, indeterminated} = props;
|
|
@@ -21,11 +18,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
21
18
|
? theme.colors.primary
|
|
22
19
|
: theme.colors.background.surface;
|
|
23
20
|
|
|
24
|
-
let iconSource =
|
|
25
|
-
|
|
26
|
-
if (indeterminated) {
|
|
27
|
-
iconSource = IC_INDETERMINATED;
|
|
28
|
-
}
|
|
21
|
+
let iconSource = indeterminated ? 'ic_minus' : 'ic_checked';
|
|
29
22
|
|
|
30
23
|
if (disabled) {
|
|
31
24
|
borderColor = haveValue
|
|
@@ -47,7 +40,13 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
47
40
|
disabled={disabled}
|
|
48
41
|
style={[style, styles.container]}>
|
|
49
42
|
<View style={[checkboxStyle, styles.checkbox]}>
|
|
50
|
-
|
|
43
|
+
{haveValue && (
|
|
44
|
+
<Icon
|
|
45
|
+
color={theme.colors.background.surface}
|
|
46
|
+
size={20}
|
|
47
|
+
source={iconSource}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
51
50
|
</View>
|
|
52
51
|
<Text typography={'description_default'}>{label}</Text>
|
|
53
52
|
</TouchableOpacity>
|
package/CheckBox/styles.ts
CHANGED
package/Icon/index.tsx
CHANGED
package/Image/index.tsx
CHANGED
|
@@ -10,11 +10,12 @@ import {FastImagePropsWithoutStyle} from './types';
|
|
|
10
10
|
|
|
11
11
|
export interface ImageProps extends FastImagePropsWithoutStyle {
|
|
12
12
|
style?: StyleProp<ViewStyle>;
|
|
13
|
+
loading?: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
16
17
|
const {theme} = useContext(ApplicationContext);
|
|
17
|
-
const [loading, setLoading] = useState(
|
|
18
|
+
const [loading, setLoading] = useState(rest.loading);
|
|
18
19
|
const [fail, setFail] = useState(false);
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -29,7 +30,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
29
30
|
if (fail) {
|
|
30
31
|
content = (
|
|
31
32
|
<View style={Styles.flexCenter}>
|
|
32
|
-
<Icon source="
|
|
33
|
+
<Icon source="media_fail" color={theme.colors.text.disable} />
|
|
33
34
|
</View>
|
|
34
35
|
);
|
|
35
36
|
}
|
|
@@ -54,7 +55,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
54
55
|
style={styles.image}
|
|
55
56
|
onLoad={() => {
|
|
56
57
|
setFail(false);
|
|
57
|
-
setLoading(
|
|
58
|
+
setLoading(rest.loading);
|
|
58
59
|
}}
|
|
59
60
|
onLoadEnd={() => setLoading(false)}
|
|
60
61
|
onError={() => setFail(true)}
|
|
@@ -64,4 +65,7 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
64
65
|
);
|
|
65
66
|
};
|
|
66
67
|
|
|
68
|
+
Image.defaultProps = {
|
|
69
|
+
loading: true,
|
|
70
|
+
};
|
|
67
71
|
export {Image};
|
package/Input/Input.tsx
CHANGED
|
@@ -113,11 +113,7 @@ const Input: FC<InputProps> = ({
|
|
|
113
113
|
</TouchableOpacity>
|
|
114
114
|
)}
|
|
115
115
|
{icon && (
|
|
116
|
-
<
|
|
117
|
-
tintColor={iconTintColor}
|
|
118
|
-
source={{uri: icon}}
|
|
119
|
-
style={styles.icon}
|
|
120
|
-
/>
|
|
116
|
+
<Icon icon={iconTintColor} source={icon} style={styles.icon} />
|
|
121
117
|
)}
|
|
122
118
|
</View>
|
|
123
119
|
</View>
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -116,13 +116,7 @@ const InputMoney: FC<InputMoneyProps> = ({
|
|
|
116
116
|
/>
|
|
117
117
|
</TouchableOpacity>
|
|
118
118
|
)}
|
|
119
|
-
{icon &&
|
|
120
|
-
<Image
|
|
121
|
-
tintColor={iconTintColor}
|
|
122
|
-
source={{uri: icon}}
|
|
123
|
-
style={styles.icon}
|
|
124
|
-
/>
|
|
125
|
-
)}
|
|
119
|
+
{icon && <Icon color={iconTintColor} source={icon} />}
|
|
126
120
|
</View>
|
|
127
121
|
</View>
|
|
128
122
|
);
|
package/Input/InputSearch.tsx
CHANGED
|
@@ -7,16 +7,12 @@ import {
|
|
|
7
7
|
View,
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import {InputSearchProps} from './index';
|
|
10
|
-
import {getBorderColor} from './common';
|
|
11
10
|
import {ApplicationContext} from '../Navigation';
|
|
12
11
|
import styles from './styles';
|
|
13
12
|
import {Icon} from '../Icon';
|
|
14
|
-
import {Image} from '../Image';
|
|
15
13
|
import {Text} from '../Text';
|
|
16
14
|
|
|
17
15
|
const InputSearch: FC<InputSearchProps> = ({
|
|
18
|
-
errorMessage,
|
|
19
|
-
disabled,
|
|
20
16
|
placeholder,
|
|
21
17
|
onFocus,
|
|
22
18
|
onBlur,
|
|
@@ -27,6 +23,7 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
27
23
|
buttonText = 'Hủy',
|
|
28
24
|
showButtonText = true,
|
|
29
25
|
showIcon = true,
|
|
26
|
+
showBorder = true,
|
|
30
27
|
style,
|
|
31
28
|
...props
|
|
32
29
|
}) => {
|
|
@@ -54,20 +51,25 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
54
51
|
onChangeText?.(text);
|
|
55
52
|
};
|
|
56
53
|
|
|
54
|
+
const getBorderColor = () => {
|
|
55
|
+
let borderColor = showBorder
|
|
56
|
+
? theme.colors.border.default
|
|
57
|
+
: theme.colors.background.surface;
|
|
58
|
+
|
|
59
|
+
if (focused) {
|
|
60
|
+
borderColor = theme.colors.primary;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {borderColor};
|
|
64
|
+
};
|
|
65
|
+
|
|
57
66
|
const renderInputView = () => {
|
|
58
|
-
const disabledColor = theme.colors.text.disable;
|
|
59
67
|
let textColor = theme.colors.text.default;
|
|
60
68
|
let placeholderColor = theme.colors.text.hint;
|
|
61
69
|
|
|
62
|
-
if (disabled) {
|
|
63
|
-
textColor = disabledColor;
|
|
64
|
-
placeholderColor = disabledColor;
|
|
65
|
-
iconTintColor = disabledColor;
|
|
66
|
-
}
|
|
67
70
|
return (
|
|
68
71
|
<TextInput
|
|
69
72
|
{...props}
|
|
70
|
-
editable={!disabled}
|
|
71
73
|
textAlignVertical="top"
|
|
72
74
|
ref={inputRef}
|
|
73
75
|
style={[
|
|
@@ -112,9 +114,9 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
112
114
|
},
|
|
113
115
|
]}
|
|
114
116
|
/>
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
source={
|
|
117
|
+
<Icon
|
|
118
|
+
color={iconTintColor}
|
|
119
|
+
source={icon}
|
|
118
120
|
style={styles.iconSearchInput}
|
|
119
121
|
/>
|
|
120
122
|
</View>
|
|
@@ -126,9 +128,11 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
126
128
|
<View style={[style, styles.searchInputContainer]}>
|
|
127
129
|
<View
|
|
128
130
|
style={[
|
|
129
|
-
getBorderColor(
|
|
131
|
+
getBorderColor(),
|
|
130
132
|
styles.searchInputWrapper,
|
|
131
|
-
{
|
|
133
|
+
{
|
|
134
|
+
backgroundColor: theme.colors.background.surface,
|
|
135
|
+
},
|
|
132
136
|
]}>
|
|
133
137
|
<Icon
|
|
134
138
|
source={'navigation_search'}
|
package/Input/common.tsx
CHANGED
|
@@ -100,9 +100,10 @@ export const FloatingView: FC<FloatingViewProps> = ({
|
|
|
100
100
|
)}
|
|
101
101
|
</Text>
|
|
102
102
|
{floatingIcon && (
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
source={
|
|
103
|
+
<Icon
|
|
104
|
+
color={floatingIconTintColor}
|
|
105
|
+
source={floatingIcon}
|
|
106
|
+
size={16}
|
|
106
107
|
style={styles.floatingIcon}
|
|
107
108
|
/>
|
|
108
109
|
)}
|
package/Input/index.tsx
CHANGED
|
@@ -20,17 +20,21 @@ type InputPropsWithoutSizeAndIcon = Omit<
|
|
|
20
20
|
InputProps,
|
|
21
21
|
'size' | 'icon' | 'iconColor'
|
|
22
22
|
>;
|
|
23
|
-
type
|
|
23
|
+
type InputPropsOmitForSearch = Omit<
|
|
24
|
+
InputProps,
|
|
25
|
+
'required' | 'size' | 'errorMessage' | 'disabled'
|
|
26
|
+
>;
|
|
24
27
|
type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
|
|
25
28
|
|
|
26
29
|
export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
|
|
27
30
|
height?: number;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
export interface InputSearchProps extends
|
|
33
|
+
export interface InputSearchProps extends InputPropsOmitForSearch {
|
|
31
34
|
buttonText?: string;
|
|
32
35
|
showButtonText?: boolean;
|
|
33
36
|
showIcon?: boolean;
|
|
37
|
+
showBorder?: boolean;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
|
package/Input/styles.ts
CHANGED
|
@@ -25,7 +25,7 @@ export default StyleSheet.create({
|
|
|
25
25
|
paddingHorizontal: Spacing.S,
|
|
26
26
|
flexDirection: 'row',
|
|
27
27
|
},
|
|
28
|
-
floatingIcon: {
|
|
28
|
+
floatingIcon: {marginLeft: Spacing.XS},
|
|
29
29
|
errorIcon: {marginRight: Spacing.XS},
|
|
30
30
|
errorView: {
|
|
31
31
|
flexDirection: 'row',
|
|
@@ -104,8 +104,6 @@ export default StyleSheet.create({
|
|
|
104
104
|
alignItems: 'center',
|
|
105
105
|
},
|
|
106
106
|
iconSearchInput: {
|
|
107
|
-
width: 24,
|
|
108
|
-
height: 24,
|
|
109
107
|
marginLeft: Spacing.S,
|
|
110
108
|
},
|
|
111
109
|
searchInputContainer: {flexDirection: 'row', alignItems: 'center'},
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {KeyboardAvoidingView, Platform,
|
|
1
|
+
import {Animated, KeyboardAvoidingView, Platform, View} from 'react-native';
|
|
2
2
|
import {useHeaderHeight} from '@react-navigation/stack';
|
|
3
3
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import {ScreenContainerProps} from '../Navigation/types';
|
|
6
6
|
import {Spacing, Styles} from '../Consts';
|
|
7
7
|
import {ScreenSection, validateChildren} from './index';
|
|
8
|
+
import {Image} from '../Image';
|
|
8
9
|
|
|
9
10
|
const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
10
11
|
children,
|
|
@@ -12,11 +13,12 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
12
13
|
enableKeyboardAvoidingView,
|
|
13
14
|
scrollable,
|
|
14
15
|
scrollViewProps,
|
|
16
|
+
headerImage,
|
|
15
17
|
}) => {
|
|
16
18
|
let Component: any = View;
|
|
17
19
|
const headerHeight = useHeaderHeight();
|
|
18
20
|
if (scrollable) {
|
|
19
|
-
Component = ScrollView;
|
|
21
|
+
Component = Animated.ScrollView;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -52,6 +54,14 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
52
54
|
android: undefined,
|
|
53
55
|
})}>
|
|
54
56
|
<Component {...scrollViewProps} style={Styles.flex}>
|
|
57
|
+
{headerImage && (
|
|
58
|
+
<Image
|
|
59
|
+
source={{
|
|
60
|
+
uri: headerImage,
|
|
61
|
+
}}
|
|
62
|
+
style={{width: '100%', height: 300}}
|
|
63
|
+
/>
|
|
64
|
+
)}
|
|
55
65
|
{renderContent()}
|
|
56
66
|
</Component>
|
|
57
67
|
</KeyboardAvoidingView>
|
package/Navigation/BottomTab.tsx
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React, {FC} from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {BottomTabItemProps, BottomTabProps} from './types';
|
|
2
|
+
import {BottomTabProps} from './types';
|
|
4
3
|
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
|
5
|
-
import {Icon} from '
|
|
4
|
+
import {Icon} from '../Icon';
|
|
6
5
|
|
|
7
6
|
const Tab = createBottomTabNavigator();
|
|
8
7
|
|
|
@@ -11,11 +10,10 @@ const BottomTab: FC<BottomTabProps> = ({tabs}) => {
|
|
|
11
10
|
<Tab.Navigator>
|
|
12
11
|
{tabs.map((item, index) => {
|
|
13
12
|
return (
|
|
14
|
-
// @ts-ignore
|
|
15
13
|
<Tab.Screen
|
|
16
14
|
key={`${item.label}-${index}`}
|
|
17
15
|
name={item.label}
|
|
18
|
-
component={item.
|
|
16
|
+
component={item.screen}
|
|
19
17
|
options={{
|
|
20
18
|
tabBarLabel: item.label,
|
|
21
19
|
tabBarBadge: item?.badgeLabel,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
DeviceEventEmitter,
|
|
4
5
|
StatusBar,
|
|
5
6
|
StyleSheet,
|
|
@@ -47,7 +48,6 @@ const styles = StyleSheet.create({
|
|
|
47
48
|
marginLeft: Spacing.S,
|
|
48
49
|
padding: Spacing.XS,
|
|
49
50
|
height: 28,
|
|
50
|
-
borderWidth: 0.5,
|
|
51
51
|
borderRadius: 14,
|
|
52
52
|
borderColor: '#00000066',
|
|
53
53
|
justifyContent: 'center',
|
|
@@ -62,15 +62,19 @@ const styles = StyleSheet.create({
|
|
|
62
62
|
headerLeft: {
|
|
63
63
|
marginLeft: 12,
|
|
64
64
|
},
|
|
65
|
+
title: {fontSize: 15, lineHeight: 22, fontWeight: '600'},
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
const HeaderTitle =
|
|
68
|
+
const HeaderTitle: React.FC<any> = props => {
|
|
69
|
+
const opacity = props.animatedValue?.interpolate({
|
|
70
|
+
inputRange: [0, 200],
|
|
71
|
+
outputRange: [0, 1],
|
|
72
|
+
extrapolate: 'clamp',
|
|
73
|
+
});
|
|
68
74
|
return (
|
|
69
|
-
<Text
|
|
75
|
+
<Animated.Text
|
|
70
76
|
{...props}
|
|
71
|
-
|
|
72
|
-
weight="bold"
|
|
73
|
-
color={props.tintColor}
|
|
77
|
+
style={[styles.title, {opacity, color: props.tintColor}]}
|
|
74
78
|
/>
|
|
75
79
|
);
|
|
76
80
|
};
|
|
@@ -98,19 +102,28 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
|
|
|
98
102
|
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
99
103
|
image,
|
|
100
104
|
backgroundColor,
|
|
105
|
+
animatedValue,
|
|
101
106
|
}) => {
|
|
102
107
|
const {theme} = useContext(ApplicationContext);
|
|
103
108
|
let headerImage = theme.assets?.headerBackground;
|
|
104
109
|
if (image === null) {
|
|
105
110
|
headerImage = undefined;
|
|
106
111
|
}
|
|
112
|
+
const opacity = animatedValue?.interpolate({
|
|
113
|
+
inputRange: [0, 200],
|
|
114
|
+
outputRange: [0, 1],
|
|
115
|
+
extrapolate: 'clamp',
|
|
116
|
+
});
|
|
107
117
|
return (
|
|
108
|
-
<View
|
|
118
|
+
<Animated.View
|
|
109
119
|
style={[
|
|
110
120
|
Styles.flex,
|
|
111
121
|
{
|
|
112
122
|
backgroundColor: backgroundColor ?? theme.colors.background.default,
|
|
113
123
|
overflow: 'hidden',
|
|
124
|
+
borderBottomWidth: headerImage ? 0 : 1,
|
|
125
|
+
borderColor: theme.colors.border.default,
|
|
126
|
+
opacity,
|
|
114
127
|
},
|
|
115
128
|
]}>
|
|
116
129
|
<StatusBar
|
|
@@ -119,7 +132,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
119
132
|
{headerImage && (
|
|
120
133
|
<Image style={styles.headerBackground} source={{uri: headerImage}} />
|
|
121
134
|
)}
|
|
122
|
-
</View>
|
|
135
|
+
</Animated.View>
|
|
123
136
|
);
|
|
124
137
|
};
|
|
125
138
|
|
|
@@ -193,15 +206,13 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
|
|
|
193
206
|
|
|
194
207
|
return (
|
|
195
208
|
<View style={styles.headerRightButton}>
|
|
196
|
-
<NavigationButton
|
|
197
|
-
icon="addFavorite"
|
|
198
|
-
tintColor={tintColor}
|
|
199
|
-
onPress={() => {}}
|
|
200
|
-
/>
|
|
201
209
|
<View
|
|
202
210
|
style={[
|
|
203
211
|
styles.toolkitContainer,
|
|
204
|
-
{
|
|
212
|
+
{
|
|
213
|
+
backgroundColor: backgroundColor ?? '#00000066',
|
|
214
|
+
borderWidth: backgroundColor ? 0.5 : 0,
|
|
215
|
+
},
|
|
205
216
|
]}>
|
|
206
217
|
<TouchableOpacity>
|
|
207
218
|
<Icon color={tintColor} source="navigation_more_horiz" size={20} />
|
|
@@ -23,7 +23,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
23
23
|
styles.container,
|
|
24
24
|
{
|
|
25
25
|
backgroundColor: backgroundColor ?? '#00000066',
|
|
26
|
-
borderWidth: useBorder ? 0.5 : 0,
|
|
26
|
+
borderWidth: useBorder && backgroundColor ? 0.5 : 0,
|
|
27
27
|
},
|
|
28
28
|
]}
|
|
29
29
|
onPress={onPress}>
|
package/Navigation/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {ScrollViewProps, ViewProps} from 'react-native';
|
|
2
|
-
import React
|
|
1
|
+
import {Animated, ScrollViewProps, ViewProps} from 'react-native';
|
|
2
|
+
import React from 'react';
|
|
3
3
|
import Navigator from './Navigator';
|
|
4
4
|
|
|
5
5
|
export type Theme = {
|
|
@@ -73,6 +73,7 @@ export interface ScreenContainerProps extends ViewProps {
|
|
|
73
73
|
enableKeyboardAvoidingView?: boolean;
|
|
74
74
|
scrollable: boolean;
|
|
75
75
|
scrollViewProps?: ScrollViewProps;
|
|
76
|
+
headerImage?: string;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
export type ScreenParams = {
|
|
@@ -107,11 +108,13 @@ export type NavigationOptions = {
|
|
|
107
108
|
headerTitleAlign?: 'left' | 'center';
|
|
108
109
|
customTitle?: TitleCustomProps;
|
|
109
110
|
headerRight?: (props?: any) => React.ReactElement;
|
|
111
|
+
animatedValue?: Animated.Value;
|
|
110
112
|
};
|
|
111
113
|
|
|
112
114
|
export type HeaderBackgroundProps = {
|
|
113
115
|
image?: string | null;
|
|
114
116
|
backgroundColor?: string | null;
|
|
117
|
+
animatedValue?: Animated.Value;
|
|
115
118
|
};
|
|
116
119
|
|
|
117
120
|
export type TitleCustomProps = {
|
|
@@ -128,7 +131,7 @@ export type BottomTabItemProps = {
|
|
|
128
131
|
icon: string;
|
|
129
132
|
showDot?: boolean;
|
|
130
133
|
badgeLabel?: string;
|
|
131
|
-
|
|
134
|
+
screen: React.ComponentType<any>;
|
|
132
135
|
};
|
|
133
136
|
|
|
134
137
|
export type BottomTabProps = {
|
package/Navigation/utils.tsx
CHANGED
|
@@ -73,43 +73,58 @@ const getModalOptions = (): StackNavigationOptions => {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const getOptions = (params: NavigationOptions, theme: Theme) => {
|
|
76
|
-
let
|
|
77
|
-
let
|
|
76
|
+
let backgroundProps = {};
|
|
77
|
+
let titleProps = {};
|
|
78
|
+
let options = {};
|
|
78
79
|
|
|
79
80
|
if (params.surface == true) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<HeaderBackground
|
|
83
|
-
image={null}
|
|
84
|
-
backgroundColor={theme.colors.background.surface}
|
|
85
|
-
/>
|
|
86
|
-
),
|
|
81
|
+
options = {
|
|
82
|
+
...options,
|
|
87
83
|
...getTintColor({
|
|
88
84
|
...theme,
|
|
89
85
|
assets: {...theme.assets, headerBackground: undefined},
|
|
90
86
|
}),
|
|
91
87
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
backgroundProps = {
|
|
89
|
+
...backgroundProps,
|
|
90
|
+
image: null,
|
|
91
|
+
backgroundColor: theme.colors.background.surface,
|
|
96
92
|
};
|
|
93
|
+
} else {
|
|
94
|
+
backgroundProps = {};
|
|
95
|
+
options = {...options, ...getTintColor(theme)};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (params.animatedValue) {
|
|
99
|
+
backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
|
|
100
|
+
titleProps = {...titleProps, animatedValue: params.animatedValue};
|
|
101
|
+
options = {...options, headerTransparent: true};
|
|
102
|
+
} else {
|
|
103
|
+
options = {...options, headerTransparent: false};
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
if (params.customTitle) {
|
|
100
|
-
|
|
107
|
+
options = {
|
|
108
|
+
...options,
|
|
101
109
|
headerTitleAlign: 'left',
|
|
102
110
|
headerTitle: (props: any) => {
|
|
103
111
|
return <HeaderCustom {...params.customTitle} {...props} />;
|
|
104
112
|
},
|
|
105
113
|
};
|
|
106
114
|
} else {
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
options = {
|
|
116
|
+
...options,
|
|
117
|
+
headerTitle: (props: any) => {
|
|
118
|
+
return <HeaderTitle {...titleProps} {...props} />;
|
|
119
|
+
},
|
|
109
120
|
};
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
...params,
|
|
125
|
+
...options,
|
|
126
|
+
headerBackground: () => <HeaderBackground {...backgroundProps} />,
|
|
127
|
+
};
|
|
113
128
|
};
|
|
114
129
|
|
|
115
130
|
export {getStackOptions, getDialogOptions, getModalOptions, getOptions};
|
package/Popup/PopupPromotion.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import {StyleSheet, TouchableOpacity, View} from 'react-native';
|
|
|
3
3
|
import {PopupPromotionProps} from './types';
|
|
4
4
|
import {ApplicationContext} from '../Navigation';
|
|
5
5
|
import {Image} from '../Image';
|
|
6
|
-
import {Radius} from '../Consts';
|
|
6
|
+
import {Radius, Spacing} from '../Consts';
|
|
7
7
|
import {Icon} from '../Icon';
|
|
8
8
|
|
|
9
9
|
const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
|
|
@@ -55,11 +55,10 @@ const styles = StyleSheet.create({
|
|
|
55
55
|
aspectRatio: 0.72,
|
|
56
56
|
},
|
|
57
57
|
iconCloseContainer: {
|
|
58
|
-
position: 'absolute',
|
|
59
58
|
width: '100%',
|
|
60
59
|
flexDirection: 'row',
|
|
61
60
|
justifyContent: 'center',
|
|
62
|
-
|
|
61
|
+
marginTop: Spacing.L,
|
|
63
62
|
},
|
|
64
63
|
iconClose: {
|
|
65
64
|
width: 20,
|
package/Skeleton/index.tsx
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {Animated, Platform,
|
|
1
|
+
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
|
2
|
+
import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
|
|
3
3
|
import LinearGradient from 'react-native-linear-gradient';
|
|
4
4
|
import {SkeletonTypes} from './types';
|
|
5
|
-
import {ApplicationContext} from '../Navigation';
|
|
6
5
|
import {Styles} from '../Consts';
|
|
7
6
|
import styles from './styles';
|
|
7
|
+
import {Colors} from '@momo-kits/foundation';
|
|
8
|
+
|
|
8
9
|
const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const [width, setWidth] = useState(0);
|
|
11
|
+
const PRIMARY_COLOR = Colors.black_05;
|
|
12
|
+
const HIGHLIGHT_COLOR1 = Colors.black_05;
|
|
13
|
+
const HIGHLIGHT_COLOR2 = Colors.black_03;
|
|
14
|
+
const beginShimmerPosition = useRef(new Animated.Value(0)).current;
|
|
12
15
|
|
|
13
|
-
const shimmerColors = [
|
|
14
|
-
theme.colors.text.disable + '40',
|
|
15
|
-
theme.colors.text.disable + '80',
|
|
16
|
-
theme.colors.text.disable,
|
|
17
|
-
];
|
|
18
|
-
const location = [0.3, 0.5, 0.7];
|
|
16
|
+
const shimmerColors = [HIGHLIGHT_COLOR1, HIGHLIGHT_COLOR2, HIGHLIGHT_COLOR1];
|
|
19
17
|
const linearTranslate = beginShimmerPosition.interpolate({
|
|
20
|
-
inputRange: [
|
|
21
|
-
outputRange: [
|
|
18
|
+
inputRange: [0, 1],
|
|
19
|
+
outputRange: [-width, width],
|
|
22
20
|
});
|
|
23
21
|
const animatedValue = useMemo(() => {
|
|
24
22
|
return Animated.loop(
|
|
25
23
|
Animated.timing(beginShimmerPosition, {
|
|
26
24
|
toValue: 1,
|
|
27
|
-
delay: 0,
|
|
28
25
|
duration: 1000,
|
|
26
|
+
easing: Easing.linear,
|
|
29
27
|
useNativeDriver: Platform.OS !== 'web',
|
|
30
28
|
}),
|
|
31
29
|
);
|
|
@@ -38,23 +36,33 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
|
|
|
38
36
|
};
|
|
39
37
|
}, [animatedValue]);
|
|
40
38
|
|
|
39
|
+
const onLayout = (newWidth: number) => {
|
|
40
|
+
if (newWidth !== width) {
|
|
41
|
+
setWidth(newWidth);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
41
44
|
return (
|
|
42
45
|
<View style={[styles.container, style]}>
|
|
43
|
-
<View
|
|
46
|
+
<View
|
|
47
|
+
onLayout={e => onLayout(e.nativeEvent.layout.width)}
|
|
48
|
+
style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
|
|
44
49
|
<Animated.View
|
|
45
|
-
style={
|
|
50
|
+
style={{
|
|
51
|
+
transform: [{translateX: linearTranslate}],
|
|
52
|
+
width: '60%',
|
|
53
|
+
height: '100%',
|
|
54
|
+
}}>
|
|
46
55
|
<LinearGradient
|
|
56
|
+
style={[StyleSheet.absoluteFill]}
|
|
47
57
|
colors={shimmerColors}
|
|
48
|
-
style={[Styles.flex, {width: width}]}
|
|
49
58
|
start={{
|
|
50
|
-
x:
|
|
51
|
-
y: 0
|
|
59
|
+
x: 0,
|
|
60
|
+
y: 0,
|
|
52
61
|
}}
|
|
53
62
|
end={{
|
|
54
|
-
x:
|
|
55
|
-
y: 0
|
|
63
|
+
x: 1,
|
|
64
|
+
y: 0,
|
|
56
65
|
}}
|
|
57
|
-
locations={location}
|
|
58
66
|
/>
|
|
59
67
|
</Animated.View>
|
|
60
68
|
</View>
|