@momo-kits/foundation 1.0.10 → 1.0.12
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/Image/index.tsx +3 -3
- package/Input/Input.tsx +4 -13
- package/Input/{MoneyInput.tsx → InputMoney.tsx} +16 -34
- package/Input/{SearchInput.tsx → InputSearch.tsx} +5 -8
- package/Input/{TextArea.tsx → InputTextArea.tsx} +6 -5
- package/Input/common.tsx +10 -3
- package/Input/index.tsx +7 -7
- package/Input/styles.ts +1 -1
- package/Input/utils.ts +63 -0
- package/Layout/ScreenContainer.tsx +4 -1
- package/Navigation/BottomTab.tsx +40 -0
- package/Navigation/Components.tsx +1 -12
- package/Navigation/ModalScreen.tsx +5 -1
- package/Navigation/NavigationButton.tsx +5 -0
- package/Navigation/index.ts +2 -0
- package/Navigation/types.ts +15 -2
- package/Popup/PopupPromotion.tsx +42 -26
- package/Popup/types.ts +1 -1
- package/Radio/index.tsx +20 -6
- package/Skeleton/index.tsx +73 -0
- package/Skeleton/types.ts +3 -0
- package/index.ts +2 -2
- package/package.json +1 -1
- package/ContentLoader/index.tsx +0 -67
- package/ContentLoader/types.ts +0 -3
- /package/{ContentLoader → Skeleton}/styles.ts +0 -0
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/Image/index.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
|
|
|
3
3
|
import FastImage from 'react-native-fast-image';
|
|
4
4
|
import styles from './styles';
|
|
5
5
|
import {ApplicationContext} from '../Navigation';
|
|
6
|
-
import {
|
|
6
|
+
import {Skeleton} from '../Skeleton';
|
|
7
7
|
import {Icon} from '../Icon';
|
|
8
8
|
import {Styles} from '../Consts';
|
|
9
9
|
import {FastImagePropsWithoutStyle} from './types';
|
|
@@ -24,12 +24,12 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
24
24
|
const renderContent = () => {
|
|
25
25
|
if (loading || fail) {
|
|
26
26
|
let content = (
|
|
27
|
-
<
|
|
27
|
+
<Skeleton style={[StyleSheet.absoluteFill, styles.image]} />
|
|
28
28
|
);
|
|
29
29
|
if (fail) {
|
|
30
30
|
content = (
|
|
31
31
|
<View style={Styles.flexCenter}>
|
|
32
|
-
<Icon source="
|
|
32
|
+
<Icon source="media_fail" color={theme.colors.text.disable} />
|
|
33
33
|
</View>
|
|
34
34
|
);
|
|
35
35
|
}
|
package/Input/Input.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import {ApplicationContext} from '../Navigation';
|
|
10
10
|
import styles from './styles';
|
|
11
11
|
import {Image} from '../Image';
|
|
12
|
-
import {ErrorView, FloatingView, getBorderColor} from './common';
|
|
12
|
+
import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
|
|
13
13
|
import {InputProps} from './index';
|
|
14
14
|
import {Icon} from '../Icon';
|
|
15
15
|
|
|
@@ -36,17 +36,12 @@ const Input: FC<InputProps> = ({
|
|
|
36
36
|
|
|
37
37
|
const onClearText = () => {
|
|
38
38
|
inputRef?.current?.clear();
|
|
39
|
+
_onChangeText('');
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
const _onChangeText = (text: string) => {
|
|
42
43
|
onChangeText?.(text);
|
|
43
44
|
};
|
|
44
|
-
const getSizeStyle = () => {
|
|
45
|
-
if (size === 'small') {
|
|
46
|
-
return styles.smallContainer;
|
|
47
|
-
}
|
|
48
|
-
return styles.container;
|
|
49
|
-
};
|
|
50
45
|
|
|
51
46
|
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
52
47
|
setFocused(true);
|
|
@@ -73,7 +68,7 @@ const Input: FC<InputProps> = ({
|
|
|
73
68
|
return (
|
|
74
69
|
<View
|
|
75
70
|
style={[
|
|
76
|
-
getSizeStyle(),
|
|
71
|
+
getSizeStyle(size),
|
|
77
72
|
getBorderColor(focused, errorMessage, disabled),
|
|
78
73
|
styles.inputWrapper,
|
|
79
74
|
{backgroundColor: theme.colors.background.surface},
|
|
@@ -118,11 +113,7 @@ const Input: FC<InputProps> = ({
|
|
|
118
113
|
</TouchableOpacity>
|
|
119
114
|
)}
|
|
120
115
|
{icon && (
|
|
121
|
-
<
|
|
122
|
-
tintColor={iconTintColor}
|
|
123
|
-
source={{uri: icon}}
|
|
124
|
-
style={styles.icon}
|
|
125
|
-
/>
|
|
116
|
+
<Icon icon={iconTintColor} source={icon} style={styles.icon} />
|
|
126
117
|
)}
|
|
127
118
|
</View>
|
|
128
119
|
</View>
|
|
@@ -9,15 +9,16 @@ import {
|
|
|
9
9
|
import {ApplicationContext} from '../Navigation';
|
|
10
10
|
import styles from './styles';
|
|
11
11
|
import {Image} from '../Image';
|
|
12
|
-
import {ErrorView, FloatingView, getBorderColor} from './common';
|
|
13
|
-
import {
|
|
12
|
+
import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
|
|
13
|
+
import {InputMoneyProps} from './index';
|
|
14
14
|
import {Icon} from '../Icon';
|
|
15
|
+
import {formatMoneyToNumber, formatNumberToMoney} from './utils';
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const InputMoney: FC<InputMoneyProps> = ({
|
|
17
18
|
onChangeText,
|
|
18
19
|
floatingValue,
|
|
19
20
|
floatingIcon,
|
|
20
|
-
size,
|
|
21
|
+
size = 'small',
|
|
21
22
|
onBlur,
|
|
22
23
|
onFocus,
|
|
23
24
|
errorMessage,
|
|
@@ -30,29 +31,20 @@ const MoneyInput: FC<MoneyInputProps> = ({
|
|
|
30
31
|
}) => {
|
|
31
32
|
const {theme} = useContext(ApplicationContext);
|
|
32
33
|
const [focused, setFocused] = useState(false);
|
|
33
|
-
const [value, setValue] = useState('');
|
|
34
34
|
const inputRef = useRef<any>(null);
|
|
35
|
-
|
|
35
|
+
const [value, setValue] = useState('');
|
|
36
36
|
const onClearText = () => {
|
|
37
37
|
inputRef?.current?.clear();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const formatNumberWithDots = (num: string) => {
|
|
41
|
-
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
|
38
|
+
setValue('');
|
|
39
|
+
onChangeText?.('');
|
|
42
40
|
};
|
|
43
41
|
const _onChangeText = (text: string) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const formattedNumber = formatNumberWithDots(numericValue);
|
|
47
|
-
const formattedValue = `${formattedNumber}đ`;
|
|
48
|
-
onChangeText?.(formattedValue);
|
|
49
|
-
setValue(formattedValue);
|
|
50
|
-
};
|
|
51
|
-
const getSizeStyle = () => {
|
|
52
|
-
if (size === 'small') {
|
|
53
|
-
return styles.smallContainer;
|
|
42
|
+
if (text.length < value.length && value.indexOf(text) === 0) {
|
|
43
|
+
text = value.slice(0, -2) + 'đ';
|
|
54
44
|
}
|
|
55
|
-
|
|
45
|
+
const valueFormat = formatMoneyToNumber(text, 'đ');
|
|
46
|
+
setValue(formatNumberToMoney(valueFormat, 'đ'));
|
|
47
|
+
onChangeText?.(formatMoneyToNumber(text, 'đ').toString());
|
|
56
48
|
};
|
|
57
49
|
|
|
58
50
|
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
@@ -80,7 +72,7 @@ const MoneyInput: FC<MoneyInputProps> = ({
|
|
|
80
72
|
return (
|
|
81
73
|
<View
|
|
82
74
|
style={[
|
|
83
|
-
getSizeStyle(),
|
|
75
|
+
getSizeStyle(size),
|
|
84
76
|
getBorderColor(focused, errorMessage, disabled),
|
|
85
77
|
styles.inputWrapper,
|
|
86
78
|
{backgroundColor: theme.colors.background.surface},
|
|
@@ -124,13 +116,7 @@ const MoneyInput: FC<MoneyInputProps> = ({
|
|
|
124
116
|
/>
|
|
125
117
|
</TouchableOpacity>
|
|
126
118
|
)}
|
|
127
|
-
{icon &&
|
|
128
|
-
<Image
|
|
129
|
-
tintColor={iconTintColor}
|
|
130
|
-
source={{uri: icon}}
|
|
131
|
-
style={styles.icon}
|
|
132
|
-
/>
|
|
133
|
-
)}
|
|
119
|
+
{icon && <Icon color={iconTintColor} source={icon} />}
|
|
134
120
|
</View>
|
|
135
121
|
</View>
|
|
136
122
|
);
|
|
@@ -144,8 +130,4 @@ const MoneyInput: FC<MoneyInputProps> = ({
|
|
|
144
130
|
);
|
|
145
131
|
};
|
|
146
132
|
|
|
147
|
-
|
|
148
|
-
size: 'small',
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
export default MoneyInput;
|
|
133
|
+
export default InputMoney;
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TouchableOpacity,
|
|
7
7
|
View,
|
|
8
8
|
} from 'react-native';
|
|
9
|
-
import {
|
|
9
|
+
import {InputSearchProps} from './index';
|
|
10
10
|
import {getBorderColor} from './common';
|
|
11
11
|
import {ApplicationContext} from '../Navigation';
|
|
12
12
|
import styles from './styles';
|
|
@@ -14,7 +14,7 @@ import {Icon} from '../Icon';
|
|
|
14
14
|
import {Image} from '../Image';
|
|
15
15
|
import {Text} from '../Text';
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const InputSearch: FC<InputSearchProps> = ({
|
|
18
18
|
errorMessage,
|
|
19
19
|
disabled,
|
|
20
20
|
placeholder,
|
|
@@ -47,6 +47,7 @@ const SearchInput: FC<SearchInputProps> = ({
|
|
|
47
47
|
|
|
48
48
|
const onClearText = () => {
|
|
49
49
|
inputRef?.current?.clear();
|
|
50
|
+
_onChangeText('');
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const _onChangeText = (text: string) => {
|
|
@@ -111,11 +112,7 @@ const SearchInput: FC<SearchInputProps> = ({
|
|
|
111
112
|
},
|
|
112
113
|
]}
|
|
113
114
|
/>
|
|
114
|
-
<
|
|
115
|
-
tintColor={iconTintColor}
|
|
116
|
-
source={{uri: icon}}
|
|
117
|
-
style={styles.iconSearchInput}
|
|
118
|
-
/>
|
|
115
|
+
<Icon color={iconTintColor} source={icon} />
|
|
119
116
|
</View>
|
|
120
117
|
)}
|
|
121
118
|
</View>
|
|
@@ -148,4 +145,4 @@ const SearchInput: FC<SearchInputProps> = ({
|
|
|
148
145
|
);
|
|
149
146
|
};
|
|
150
147
|
|
|
151
|
-
export default
|
|
148
|
+
export default InputSearch;
|
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
getBorderColor,
|
|
17
17
|
MAX_LENGTH,
|
|
18
18
|
} from './common';
|
|
19
|
-
import {
|
|
19
|
+
import {InputTextAreaProps} from './index';
|
|
20
20
|
import {Icon} from '../Icon';
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const InputTextArea: FC<InputTextAreaProps> = props => {
|
|
23
23
|
const {theme} = useContext(ApplicationContext);
|
|
24
24
|
const {
|
|
25
25
|
errorMessage,
|
|
@@ -44,6 +44,7 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
44
44
|
|
|
45
45
|
const onClearText = () => {
|
|
46
46
|
inputRef?.current?.clear();
|
|
47
|
+
_onChangeText('');
|
|
47
48
|
};
|
|
48
49
|
|
|
49
50
|
const _onChangeText = (text: string) => {
|
|
@@ -84,7 +85,7 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
84
85
|
<View
|
|
85
86
|
style={[
|
|
86
87
|
getBorderColor(focused, errorMessage, disabled),
|
|
87
|
-
styles.
|
|
88
|
+
styles.textAreaWrapper,
|
|
88
89
|
{
|
|
89
90
|
height: height || DEFAULT_HEIGHT,
|
|
90
91
|
backgroundColor: theme.colors.background.surface,
|
|
@@ -144,8 +145,8 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
144
145
|
);
|
|
145
146
|
};
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
InputTextArea.defaultProps = {
|
|
148
149
|
maxLength: MAX_LENGTH,
|
|
149
150
|
};
|
|
150
151
|
|
|
151
|
-
export default
|
|
152
|
+
export default InputTextArea;
|
package/Input/common.tsx
CHANGED
|
@@ -41,6 +41,12 @@ export const getBorderColor = (
|
|
|
41
41
|
return {borderColor};
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
export const getSizeStyle = (size?: 'small' | 'large') => {
|
|
45
|
+
if (size === 'small') {
|
|
46
|
+
return styles.smallContainer;
|
|
47
|
+
}
|
|
48
|
+
return styles.container;
|
|
49
|
+
};
|
|
44
50
|
export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
|
|
45
51
|
const {theme} = useContext(ApplicationContext);
|
|
46
52
|
const errorColor = theme.colors.error.primary;
|
|
@@ -94,9 +100,10 @@ export const FloatingView: FC<FloatingViewProps> = ({
|
|
|
94
100
|
)}
|
|
95
101
|
</Text>
|
|
96
102
|
{floatingIcon && (
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
source={
|
|
103
|
+
<Icon
|
|
104
|
+
color={floatingIconTintColor}
|
|
105
|
+
source={floatingIcon}
|
|
106
|
+
size={16}
|
|
100
107
|
style={styles.floatingIcon}
|
|
101
108
|
/>
|
|
102
109
|
)}
|
package/Input/index.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Input from './Input';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import InputTextArea from './InputTextArea';
|
|
3
|
+
import InputSearch from './InputSearch';
|
|
4
|
+
import InputMoney from './InputMoney';
|
|
5
5
|
import {TextInputProps} from 'react-native';
|
|
6
6
|
|
|
7
7
|
export interface InputProps extends TextInputProps {
|
|
@@ -23,16 +23,16 @@ type InputPropsWithoutSizeAndIcon = Omit<
|
|
|
23
23
|
type InputPropsWithoutRequiredAndSize = Omit<InputProps, 'required' | 'size'>;
|
|
24
24
|
type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
|
|
25
25
|
|
|
26
|
-
export interface
|
|
26
|
+
export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
|
|
27
27
|
height?: number;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export interface
|
|
30
|
+
export interface InputSearchProps extends InputPropsWithoutRequiredAndSize {
|
|
31
31
|
buttonText?: string;
|
|
32
32
|
showButtonText?: boolean;
|
|
33
33
|
showIcon?: boolean;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export interface
|
|
36
|
+
export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
|
|
37
37
|
|
|
38
|
-
export {Input,
|
|
38
|
+
export {Input, InputTextArea, InputSearch, InputMoney};
|
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',
|
package/Input/utils.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const formatNumberToMoney = (number: number, currency = '') => {
|
|
2
|
+
if (!number || isNaN(number) || Number(number) === 0) {
|
|
3
|
+
return `0${currency}`;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const array = [];
|
|
7
|
+
let result = '';
|
|
8
|
+
let isNegative = false;
|
|
9
|
+
|
|
10
|
+
if (number < 0) {
|
|
11
|
+
isNegative = true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const numberString = Math.abs(number).toString();
|
|
15
|
+
if (numberString.length < 3) {
|
|
16
|
+
return numberString + currency;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let count = 0;
|
|
20
|
+
for (let i = numberString.length - 1; i >= 0; i -= 1) {
|
|
21
|
+
count += 1;
|
|
22
|
+
if (numberString[i] === '.' || numberString[i] === ',') {
|
|
23
|
+
array.push(',');
|
|
24
|
+
count = 0;
|
|
25
|
+
} else {
|
|
26
|
+
array.push(numberString[i]);
|
|
27
|
+
}
|
|
28
|
+
if (count === 3 && i >= 1) {
|
|
29
|
+
array.push('.');
|
|
30
|
+
count = 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (let i = array.length - 1; i >= 0; i -= 1) {
|
|
35
|
+
result += array[i];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isNegative) {
|
|
39
|
+
result = `-${result}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return result + currency;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const formatMoneyToNumber = (money: string, currencyUnit: string) => {
|
|
46
|
+
if (money && money.length > 0) {
|
|
47
|
+
const moneyString = money
|
|
48
|
+
.replace(currencyUnit, '')
|
|
49
|
+
.replace(/,/g, '')
|
|
50
|
+
.replace(/đ/g, '')
|
|
51
|
+
.replace(/\./g, '')
|
|
52
|
+
.replace(/ /g, '');
|
|
53
|
+
const number = Number(moneyString);
|
|
54
|
+
if (isNaN(number)) {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
return number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return Number(money);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export {formatMoneyToNumber, formatNumberToMoney};
|
|
@@ -11,6 +11,7 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
11
11
|
edges,
|
|
12
12
|
enableKeyboardAvoidingView,
|
|
13
13
|
scrollable,
|
|
14
|
+
scrollViewProps,
|
|
14
15
|
}) => {
|
|
15
16
|
let Component: any = View;
|
|
16
17
|
const headerHeight = useHeaderHeight();
|
|
@@ -50,7 +51,9 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
50
51
|
ios: 'padding',
|
|
51
52
|
android: undefined,
|
|
52
53
|
})}>
|
|
53
|
-
<Component style={Styles.flex}>
|
|
54
|
+
<Component {...scrollViewProps} style={Styles.flex}>
|
|
55
|
+
{renderContent()}
|
|
56
|
+
</Component>
|
|
54
57
|
</KeyboardAvoidingView>
|
|
55
58
|
</SafeAreaView>
|
|
56
59
|
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React, {FC} from 'react';
|
|
2
|
+
import {BottomTabProps} from './types';
|
|
3
|
+
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
|
4
|
+
import {Icon} from '../Icon';
|
|
5
|
+
|
|
6
|
+
const Tab = createBottomTabNavigator();
|
|
7
|
+
|
|
8
|
+
const BottomTab: FC<BottomTabProps> = ({tabs}) => {
|
|
9
|
+
return (
|
|
10
|
+
<Tab.Navigator>
|
|
11
|
+
{tabs.map((item, index) => {
|
|
12
|
+
return (
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
<Tab.Screen
|
|
15
|
+
key={`${item.label}-${index}`}
|
|
16
|
+
name={item.label}
|
|
17
|
+
component={item.component}
|
|
18
|
+
options={{
|
|
19
|
+
tabBarLabel: item.label,
|
|
20
|
+
tabBarBadge: item?.badgeLabel,
|
|
21
|
+
tabBarBadgeStyle: {
|
|
22
|
+
borderColor: 'white',
|
|
23
|
+
borderWidth: 2,
|
|
24
|
+
fontSize: 10,
|
|
25
|
+
lineHeight: 14,
|
|
26
|
+
fontWeight: 'bold',
|
|
27
|
+
alignSelf: 'center',
|
|
28
|
+
},
|
|
29
|
+
tabBarIcon: ({color, size}) => (
|
|
30
|
+
<Icon source={item.icon} color={color} size={size} />
|
|
31
|
+
),
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
})}
|
|
36
|
+
</Tab.Navigator>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default BottomTab;
|
|
@@ -88,19 +88,9 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
|
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
-
let backgroundColor;
|
|
92
|
-
if (tintColor != Colors.black_01) {
|
|
93
|
-
backgroundColor = theme.colors.background.surface;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
91
|
return (
|
|
97
92
|
<View style={styles.headerLeft}>
|
|
98
|
-
<NavigationButton
|
|
99
|
-
icon="ic_back"
|
|
100
|
-
tintColor={tintColor}
|
|
101
|
-
backgroundColor={backgroundColor}
|
|
102
|
-
onPress={goBack}
|
|
103
|
-
/>
|
|
93
|
+
<NavigationButton icon="ic_back" tintColor={tintColor} onPress={goBack} />
|
|
104
94
|
</View>
|
|
105
95
|
);
|
|
106
96
|
};
|
|
@@ -206,7 +196,6 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
|
|
|
206
196
|
<NavigationButton
|
|
207
197
|
icon="addFavorite"
|
|
208
198
|
tintColor={tintColor}
|
|
209
|
-
backgroundColor={backgroundColor}
|
|
210
199
|
onPress={() => {}}
|
|
211
200
|
/>
|
|
212
201
|
<View
|
|
@@ -121,7 +121,11 @@ const BottomSheet: React.FC<BottomSheetParams> = ({navigation, route}) => {
|
|
|
121
121
|
<BottomSheetModal
|
|
122
122
|
ref={bottomSheetRef}
|
|
123
123
|
snapPoints={snapPoints}
|
|
124
|
-
onDismiss={
|
|
124
|
+
onDismiss={() => {
|
|
125
|
+
if (mountedRef.current) {
|
|
126
|
+
navigation.pop();
|
|
127
|
+
}
|
|
128
|
+
}}
|
|
125
129
|
handleComponent={null}
|
|
126
130
|
backdropComponent={backdropComponent}>
|
|
127
131
|
<View style={{paddingBottom: bottom}}>
|
|
@@ -3,6 +3,7 @@ import React, {useContext} from 'react';
|
|
|
3
3
|
import {NavigationButtonProps} from './types';
|
|
4
4
|
import {ApplicationContext} from './index';
|
|
5
5
|
import {Icon} from '../Icon';
|
|
6
|
+
import {Colors} from '../Consts';
|
|
6
7
|
|
|
7
8
|
const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
8
9
|
icon,
|
|
@@ -12,6 +13,10 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
12
13
|
useBorder = true,
|
|
13
14
|
}) => {
|
|
14
15
|
const {theme} = useContext(ApplicationContext);
|
|
16
|
+
if (!backgroundColor && tintColor != Colors.black_01) {
|
|
17
|
+
backgroundColor = theme.colors.background.surface;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
return (
|
|
16
21
|
<TouchableOpacity
|
|
17
22
|
style={[
|
package/Navigation/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {NavigationContainer, ApplicationContext} from './NavigationContainer';
|
|
|
2
2
|
import ScreenContainer from '../Layout/ScreenContainer';
|
|
3
3
|
import NavigationButton from './NavigationButton';
|
|
4
4
|
import {HeaderRightAction} from './Components';
|
|
5
|
+
import BottomTab from './BottomTab';
|
|
5
6
|
|
|
6
7
|
export {
|
|
7
8
|
NavigationContainer,
|
|
@@ -9,4 +10,5 @@ export {
|
|
|
9
10
|
ScreenContainer,
|
|
10
11
|
NavigationButton,
|
|
11
12
|
HeaderRightAction,
|
|
13
|
+
BottomTab,
|
|
12
14
|
};
|
package/Navigation/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {ViewProps} from 'react-native';
|
|
2
|
-
import React from 'react';
|
|
1
|
+
import {ScrollViewProps, ViewProps} from 'react-native';
|
|
2
|
+
import React, {ComponentType, ReactElement} from 'react';
|
|
3
3
|
import Navigator from './Navigator';
|
|
4
4
|
|
|
5
5
|
export type Theme = {
|
|
@@ -72,6 +72,7 @@ export interface ScreenContainerProps extends ViewProps {
|
|
|
72
72
|
edges?: any[];
|
|
73
73
|
enableKeyboardAvoidingView?: boolean;
|
|
74
74
|
scrollable: boolean;
|
|
75
|
+
scrollViewProps?: ScrollViewProps;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export type ScreenParams = {
|
|
@@ -121,3 +122,15 @@ export type TitleCustomProps = {
|
|
|
121
122
|
tintColor?: string;
|
|
122
123
|
content?: React.ReactNode;
|
|
123
124
|
};
|
|
125
|
+
|
|
126
|
+
export type BottomTabItemProps = {
|
|
127
|
+
label: string;
|
|
128
|
+
icon: string;
|
|
129
|
+
showDot?: boolean;
|
|
130
|
+
badgeLabel?: string;
|
|
131
|
+
component: ComponentType<any> | undefined;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export type BottomTabProps = {
|
|
135
|
+
tabs: BottomTabItemProps[];
|
|
136
|
+
};
|
package/Popup/PopupPromotion.tsx
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
|
-
import {StyleSheet, View} from 'react-native';
|
|
2
|
+
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 {
|
|
7
|
-
import {
|
|
6
|
+
import {Radius} from '../Consts';
|
|
7
|
+
import {Icon} from '../Icon';
|
|
8
8
|
|
|
9
|
-
const PopupPromotion: React.FC<PopupPromotionProps> = ({image,
|
|
9
|
+
const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
|
|
10
10
|
const {theme, navigator} = useContext(ApplicationContext);
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param callback
|
|
13
|
+
* build close action
|
|
15
14
|
*/
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const buildCloseIcon = () => {
|
|
16
|
+
return (
|
|
17
|
+
<View style={styles.iconCloseContainer}>
|
|
18
|
+
<TouchableOpacity
|
|
19
|
+
onPress={() => {
|
|
20
|
+
navigator?.pop();
|
|
21
|
+
onClose?.();
|
|
22
|
+
}}
|
|
23
|
+
style={[
|
|
24
|
+
styles.iconClose,
|
|
25
|
+
{
|
|
26
|
+
backgroundColor: theme.colors.text.default,
|
|
27
|
+
borderColor: theme.colors.background.surface,
|
|
28
|
+
},
|
|
29
|
+
]}>
|
|
30
|
+
<Icon
|
|
31
|
+
source="navigation_close"
|
|
32
|
+
color={theme.colors.background.surface}
|
|
33
|
+
size={14}
|
|
34
|
+
/>
|
|
35
|
+
</TouchableOpacity>
|
|
36
|
+
</View>
|
|
37
|
+
);
|
|
19
38
|
};
|
|
20
39
|
|
|
21
40
|
return (
|
|
@@ -26,37 +45,34 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({image, primary}) => {
|
|
|
26
45
|
uri: image,
|
|
27
46
|
}}
|
|
28
47
|
/>
|
|
29
|
-
|
|
30
|
-
<Button
|
|
31
|
-
title={primary?.title}
|
|
32
|
-
onPress={() => {
|
|
33
|
-
onAction(primary?.onPress);
|
|
34
|
-
}}
|
|
35
|
-
/>
|
|
36
|
-
</View>
|
|
48
|
+
{buildCloseIcon()}
|
|
37
49
|
</>
|
|
38
50
|
);
|
|
39
51
|
};
|
|
40
52
|
|
|
41
53
|
const styles = StyleSheet.create({
|
|
42
54
|
container: {
|
|
43
|
-
aspectRatio: 0.
|
|
55
|
+
aspectRatio: 0.72,
|
|
44
56
|
},
|
|
45
|
-
|
|
57
|
+
iconCloseContainer: {
|
|
46
58
|
position: 'absolute',
|
|
47
|
-
bottom: 0,
|
|
48
59
|
width: '100%',
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
flexDirection: 'row',
|
|
61
|
+
justifyContent: 'center',
|
|
62
|
+
bottom: -36,
|
|
63
|
+
},
|
|
64
|
+
iconClose: {
|
|
65
|
+
width: 20,
|
|
66
|
+
height: 20,
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
justifyContent: 'center',
|
|
69
|
+
borderRadius: Radius.M,
|
|
70
|
+
borderWidth: 2,
|
|
51
71
|
},
|
|
52
72
|
});
|
|
53
73
|
|
|
54
74
|
PopupPromotion.defaultProps = {
|
|
55
75
|
image: 'https://google.com',
|
|
56
|
-
primary: {
|
|
57
|
-
title: 'Primary',
|
|
58
|
-
onPress: () => {},
|
|
59
|
-
},
|
|
60
76
|
};
|
|
61
77
|
|
|
62
78
|
export default PopupPromotion;
|
package/Popup/types.ts
CHANGED
package/Radio/index.tsx
CHANGED
|
@@ -17,12 +17,24 @@ const Radio: FC<RadioProps> = ({
|
|
|
17
17
|
}) => {
|
|
18
18
|
const {theme} = useContext(ApplicationContext);
|
|
19
19
|
const selected = value === groupValue;
|
|
20
|
-
|
|
21
|
-
let
|
|
20
|
+
let disabledStyle = {};
|
|
21
|
+
let checkBoxStyle = {
|
|
22
|
+
borderWidth: 2,
|
|
23
|
+
borderColor: theme.colors.text.default,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (selected) {
|
|
27
|
+
checkBoxStyle = {
|
|
28
|
+
borderWidth: 6,
|
|
29
|
+
borderColor: theme.colors.primary,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
22
32
|
if (disabled) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
disabledStyle = {
|
|
34
|
+
borderColor: selected
|
|
35
|
+
? theme.colors.background.tonal
|
|
36
|
+
: theme.colors.text.disable,
|
|
37
|
+
};
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
return (
|
|
@@ -39,7 +51,9 @@ const Radio: FC<RadioProps> = ({
|
|
|
39
51
|
<View
|
|
40
52
|
style={[
|
|
41
53
|
styles.radio,
|
|
42
|
-
|
|
54
|
+
checkBoxStyle,
|
|
55
|
+
disabledStyle,
|
|
56
|
+
{marginRight: !!label ? Spacing.XS : 0},
|
|
43
57
|
]}
|
|
44
58
|
/>
|
|
45
59
|
{!!label && <Text typography={'description_default'}>{label}</Text>}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
|
2
|
+
import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
|
|
3
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
4
|
+
import {SkeletonTypes} from './types';
|
|
5
|
+
import {Styles} from '../Consts';
|
|
6
|
+
import styles from './styles';
|
|
7
|
+
import {Colors} from '@momo-kits/foundation';
|
|
8
|
+
|
|
9
|
+
const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
|
|
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;
|
|
15
|
+
|
|
16
|
+
const shimmerColors = [HIGHLIGHT_COLOR1, HIGHLIGHT_COLOR2, HIGHLIGHT_COLOR1];
|
|
17
|
+
const linearTranslate = beginShimmerPosition.interpolate({
|
|
18
|
+
inputRange: [0, 1],
|
|
19
|
+
outputRange: [-width, width],
|
|
20
|
+
});
|
|
21
|
+
const animatedValue = useMemo(() => {
|
|
22
|
+
return Animated.loop(
|
|
23
|
+
Animated.timing(beginShimmerPosition, {
|
|
24
|
+
toValue: 1,
|
|
25
|
+
duration: 1000,
|
|
26
|
+
easing: Easing.linear,
|
|
27
|
+
useNativeDriver: Platform.OS !== 'web',
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
}, [beginShimmerPosition]);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
animatedValue.start();
|
|
34
|
+
return () => {
|
|
35
|
+
animatedValue.stop();
|
|
36
|
+
};
|
|
37
|
+
}, [animatedValue]);
|
|
38
|
+
|
|
39
|
+
const onLayout = (newWidth: number) => {
|
|
40
|
+
if (newWidth !== width) {
|
|
41
|
+
setWidth(newWidth);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return (
|
|
45
|
+
<View style={[styles.container, style]}>
|
|
46
|
+
<View
|
|
47
|
+
onLayout={e => onLayout(e.nativeEvent.layout.width)}
|
|
48
|
+
style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
|
|
49
|
+
<Animated.View
|
|
50
|
+
style={{
|
|
51
|
+
transform: [{translateX: linearTranslate}],
|
|
52
|
+
width: '60%',
|
|
53
|
+
height: '100%',
|
|
54
|
+
}}>
|
|
55
|
+
<LinearGradient
|
|
56
|
+
style={[StyleSheet.absoluteFill]}
|
|
57
|
+
colors={shimmerColors}
|
|
58
|
+
start={{
|
|
59
|
+
x: 0,
|
|
60
|
+
y: 0,
|
|
61
|
+
}}
|
|
62
|
+
end={{
|
|
63
|
+
x: 1,
|
|
64
|
+
y: 0,
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
</Animated.View>
|
|
68
|
+
</View>
|
|
69
|
+
</View>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export {Skeleton};
|
package/index.ts
CHANGED
|
@@ -22,8 +22,8 @@ export * from './Icon/types';
|
|
|
22
22
|
export * from './IconButton';
|
|
23
23
|
export * from './Image';
|
|
24
24
|
export * from './Image/types';
|
|
25
|
-
export * from './
|
|
26
|
-
export * from './
|
|
25
|
+
export * from './Skeleton';
|
|
26
|
+
export * from './Skeleton/types';
|
|
27
27
|
export * from './CheckBox';
|
|
28
28
|
export * from './CheckBox/types';
|
|
29
29
|
export * from './Radio';
|
package/package.json
CHANGED
package/ContentLoader/index.tsx
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import React, {useContext, useEffect, useMemo, useRef} from 'react';
|
|
2
|
-
import {Animated, Platform, useWindowDimensions, View} from 'react-native';
|
|
3
|
-
import LinearGradient from 'react-native-linear-gradient';
|
|
4
|
-
import {ContentLoaderTypes} from './types';
|
|
5
|
-
import {ApplicationContext} from '../Navigation';
|
|
6
|
-
import {Styles} from '../Consts';
|
|
7
|
-
import styles from './styles';
|
|
8
|
-
const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
|
|
9
|
-
const {width} = useWindowDimensions();
|
|
10
|
-
const {theme} = useContext(ApplicationContext);
|
|
11
|
-
const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
|
|
12
|
-
|
|
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];
|
|
19
|
-
const linearTranslate = beginShimmerPosition.interpolate({
|
|
20
|
-
inputRange: [-1, 1],
|
|
21
|
-
outputRange: [0, width],
|
|
22
|
-
});
|
|
23
|
-
const animatedValue = useMemo(() => {
|
|
24
|
-
return Animated.loop(
|
|
25
|
-
Animated.timing(beginShimmerPosition, {
|
|
26
|
-
toValue: 1,
|
|
27
|
-
delay: 0,
|
|
28
|
-
duration: 1000,
|
|
29
|
-
useNativeDriver: Platform.OS !== 'web',
|
|
30
|
-
}),
|
|
31
|
-
);
|
|
32
|
-
}, [beginShimmerPosition]);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
animatedValue.start();
|
|
36
|
-
return () => {
|
|
37
|
-
animatedValue.stop();
|
|
38
|
-
};
|
|
39
|
-
}, [animatedValue]);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<View style={[styles.container, style]}>
|
|
43
|
-
<View style={[Styles.flex, {backgroundColor: shimmerColors[0]}]}>
|
|
44
|
-
<Animated.View
|
|
45
|
-
style={[Styles.flex, {transform: [{translateX: linearTranslate}]}]}>
|
|
46
|
-
<LinearGradient
|
|
47
|
-
colors={shimmerColors}
|
|
48
|
-
style={[Styles.flex, {width: width}]}
|
|
49
|
-
start={{
|
|
50
|
-
x: -1,
|
|
51
|
-
y: 0.5,
|
|
52
|
-
}}
|
|
53
|
-
end={{
|
|
54
|
-
x: 2,
|
|
55
|
-
y: 0.5,
|
|
56
|
-
}}
|
|
57
|
-
locations={location}
|
|
58
|
-
/>
|
|
59
|
-
</Animated.View>
|
|
60
|
-
</View>
|
|
61
|
-
</View>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
ContentLoader.defaultProps = {};
|
|
66
|
-
|
|
67
|
-
export {ContentLoader};
|
package/ContentLoader/types.ts
DELETED
|
File without changes
|