@momo-kits/foundation 1.0.1 → 1.0.4
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/Button/index.tsx +39 -23
- package/CheckBox/index.tsx +11 -7
- package/CheckBox/types.ts +6 -3
- package/Consts/theme.ts +57 -1
- package/ContentLoader/index.tsx +2 -3
- package/Icon/icon.json +3 -0
- package/Icon/index.tsx +9 -4
- package/Icon/types.ts +4 -1
- package/IconButton/index.tsx +24 -4
- package/Image/index.tsx +11 -12
- package/Image/types.ts +1 -3
- package/Input/Input.tsx +160 -0
- package/Input/TextArea.tsx +26 -65
- package/Input/common.tsx +70 -0
- package/Input/index.tsx +23 -197
- package/Input/styles.ts +1 -5
- package/Layout/GridSystem.tsx +1 -1
- package/Layout/ScreenContainer.tsx +5 -19
- package/Layout/ScreenSection.tsx +13 -0
- package/Layout/SectionItem.tsx +3 -0
- package/Layout/utils.ts +14 -0
- package/Navigation/Components.tsx +60 -12
- package/Navigation/ModalScreen.tsx +56 -43
- package/Navigation/Navigation.ts +8 -4
- package/Navigation/NavigationButton.tsx +5 -2
- package/Navigation/NavigationContainer.tsx +25 -58
- package/Navigation/StackScreen.tsx +12 -7
- package/Navigation/types.ts +20 -7
- package/Navigation/utils.tsx +77 -21
- package/Playground/index.tsx +249 -0
- package/Playground/styles.ts +16 -0
- package/Playground/types.ts +16 -0
- package/Popup/PopupNotify.tsx +210 -0
- package/Popup/PopupPromotion.tsx +62 -0
- package/Popup/index.tsx +4 -0
- package/Popup/types.ts +22 -0
- package/Radio/index.tsx +25 -9
- package/Radio/types.ts +5 -2
- package/Switch/index.tsx +8 -6
- package/Switch/types.ts +6 -3
- package/Text/index.tsx +9 -7
- package/Text/styles.ts +3 -3
- package/Text/types.ts +5 -14
- package/index.ts +6 -6
- package/package.json +4 -5
- package/publish.sh +6 -8
- package/ActivityIndicator.tsx +0 -244
- package/Button/types.ts +0 -27
- package/IconButton/types.ts +0 -16
- package/Input/types.ts +0 -23
package/Button/index.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {FC, useContext} from 'react';
|
|
2
2
|
import {
|
|
3
|
-
GestureResponderEvent,
|
|
4
3
|
StyleSheet,
|
|
5
4
|
TouchableOpacity,
|
|
5
|
+
TouchableOpacityProps,
|
|
6
6
|
View,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
import {ApplicationContext} from '../Navigation';
|
|
@@ -10,25 +10,42 @@ import {Text} from '../Text';
|
|
|
10
10
|
import {Typography} from '../Text/types';
|
|
11
11
|
import {Colors} from '../Consts';
|
|
12
12
|
import styles from './styles';
|
|
13
|
-
import {ButtonProps} from './types';
|
|
14
13
|
import {Image} from '../Image';
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
export interface ButtonProps extends TouchableOpacityProps {
|
|
16
|
+
type?:
|
|
17
|
+
| 'primary'
|
|
18
|
+
| 'secondary'
|
|
19
|
+
| 'tonal'
|
|
20
|
+
| 'outline'
|
|
21
|
+
| 'danger'
|
|
22
|
+
| 'text'
|
|
23
|
+
| 'disabled';
|
|
24
|
+
size?: 'large' | 'medium' | 'small';
|
|
25
|
+
full?: boolean;
|
|
26
|
+
iconRight?: string;
|
|
27
|
+
iconLeft?: string;
|
|
28
|
+
title: string;
|
|
29
|
+
useTintColor?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const Button: FC<ButtonProps> = ({
|
|
33
|
+
type,
|
|
34
|
+
size,
|
|
35
|
+
useTintColor,
|
|
36
|
+
full,
|
|
37
|
+
iconRight,
|
|
38
|
+
iconLeft,
|
|
39
|
+
title,
|
|
40
|
+
onPress,
|
|
41
|
+
...rest
|
|
42
|
+
}) => {
|
|
17
43
|
const {theme} = useContext(ApplicationContext);
|
|
18
|
-
const {type, size, useTintColor, full, iconRight, iconLeft, title, onPress} =
|
|
19
|
-
props;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* export size style
|
|
23
|
-
*/
|
|
24
44
|
const getSizeStyle = () => {
|
|
25
45
|
const styleSheet: {[key: string]: any} = styles;
|
|
26
46
|
return styleSheet[size ?? 'small'];
|
|
27
47
|
};
|
|
28
48
|
|
|
29
|
-
/**
|
|
30
|
-
* export type style
|
|
31
|
-
*/
|
|
32
49
|
const getTypeStyle = () => {
|
|
33
50
|
switch (type) {
|
|
34
51
|
case 'disabled':
|
|
@@ -39,13 +56,13 @@ const Button: FC<ButtonProps> = props => {
|
|
|
39
56
|
return {backgroundColor: theme.colors.primary};
|
|
40
57
|
case 'secondary':
|
|
41
58
|
return {
|
|
42
|
-
backgroundColor: theme.colors.background.
|
|
59
|
+
backgroundColor: theme.colors.background.surface,
|
|
43
60
|
borderWidth: 1,
|
|
44
61
|
borderColor: theme.colors.border.default,
|
|
45
62
|
};
|
|
46
63
|
case 'outline':
|
|
47
64
|
return {
|
|
48
|
-
backgroundColor:
|
|
65
|
+
backgroundColor: theme.colors.background.surface,
|
|
49
66
|
borderWidth: 1,
|
|
50
67
|
borderColor: theme.colors.primary,
|
|
51
68
|
};
|
|
@@ -58,9 +75,7 @@ const Button: FC<ButtonProps> = props => {
|
|
|
58
75
|
backgroundColor: theme.colors.error.primary,
|
|
59
76
|
};
|
|
60
77
|
case 'text':
|
|
61
|
-
return {
|
|
62
|
-
backgroundColor: Colors.black_01,
|
|
63
|
-
};
|
|
78
|
+
return {};
|
|
64
79
|
default:
|
|
65
80
|
return {backgroundColor: theme.colors.primary};
|
|
66
81
|
}
|
|
@@ -137,9 +152,9 @@ const Button: FC<ButtonProps> = props => {
|
|
|
137
152
|
};
|
|
138
153
|
|
|
139
154
|
/**
|
|
140
|
-
* render
|
|
155
|
+
* render title
|
|
141
156
|
*/
|
|
142
|
-
const
|
|
157
|
+
const renderTitle = () => {
|
|
143
158
|
const typography = getTypography();
|
|
144
159
|
const color = getTextColor();
|
|
145
160
|
return (
|
|
@@ -204,7 +219,7 @@ const Button: FC<ButtonProps> = props => {
|
|
|
204
219
|
full && {width: '100%'},
|
|
205
220
|
]);
|
|
206
221
|
|
|
207
|
-
const onPressButton = (e:
|
|
222
|
+
const onPressButton = (e: any) => {
|
|
208
223
|
if (type === 'disabled') {
|
|
209
224
|
return () => {};
|
|
210
225
|
}
|
|
@@ -212,14 +227,15 @@ const Button: FC<ButtonProps> = props => {
|
|
|
212
227
|
};
|
|
213
228
|
|
|
214
229
|
const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
|
|
230
|
+
|
|
215
231
|
return (
|
|
216
232
|
<TouchableOpacity
|
|
217
|
-
{...
|
|
233
|
+
{...rest}
|
|
218
234
|
activeOpacity={activeOpacity}
|
|
219
235
|
onPress={onPressButton}
|
|
220
236
|
style={buttonStyle}>
|
|
221
237
|
{renderLeading()}
|
|
222
|
-
{
|
|
238
|
+
{renderTitle()}
|
|
223
239
|
{renderTrailing()}
|
|
224
240
|
</TouchableOpacity>
|
|
225
241
|
);
|
|
@@ -234,4 +250,4 @@ Button.defaultProps = {
|
|
|
234
250
|
useTintColor: true,
|
|
235
251
|
};
|
|
236
252
|
|
|
237
|
-
export
|
|
253
|
+
export {Button};
|
package/CheckBox/index.tsx
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import React, {FC, useContext} from 'react';
|
|
2
2
|
import {TouchableOpacity, View} from 'react-native';
|
|
3
|
-
|
|
4
3
|
import {CheckBoxProps} from './types';
|
|
5
|
-
import {Text} from '@momo-kits/foundation';
|
|
6
4
|
import styles from './styles';
|
|
7
5
|
import Image from 'react-native-fast-image';
|
|
8
6
|
import {ApplicationContext} from '../Navigation';
|
|
9
|
-
import {
|
|
7
|
+
import {Text} from '../Text';
|
|
10
8
|
|
|
11
9
|
const IC_INDETERMINATED = 'https://img.mservice.com.vn/app/img/kits/minus.png';
|
|
12
10
|
const IC_CHECKED_DEFAULT =
|
|
13
11
|
'https://img.mservice.com.vn/app/img/kits/checked_ic.png';
|
|
14
12
|
const CheckBox: FC<CheckBoxProps> = props => {
|
|
15
13
|
const {theme} = useContext(ApplicationContext);
|
|
16
|
-
const {value, disabled, onChange, label, indeterminated} = props;
|
|
14
|
+
const {value, disabled, onChange, style, label, indeterminated} = props;
|
|
17
15
|
|
|
18
16
|
const haveValue = value || indeterminated;
|
|
19
17
|
let borderColor = haveValue
|
|
20
18
|
? theme.colors.primary
|
|
21
19
|
: theme.colors.text.default;
|
|
22
|
-
let backgroundColor = haveValue
|
|
20
|
+
let backgroundColor = haveValue
|
|
21
|
+
? theme.colors.primary
|
|
22
|
+
: theme.colors.background.surface;
|
|
23
23
|
|
|
24
24
|
let iconSource = value ? IC_CHECKED_DEFAULT : undefined;
|
|
25
25
|
|
|
@@ -33,7 +33,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
33
33
|
: theme.colors.border.disable;
|
|
34
34
|
backgroundColor = haveValue
|
|
35
35
|
? theme.colors.background.disable
|
|
36
|
-
:
|
|
36
|
+
: theme.colors.background.surface;
|
|
37
37
|
}
|
|
38
38
|
const checkboxStyle = {borderColor, backgroundColor, borderWidth: 1};
|
|
39
39
|
|
|
@@ -45,7 +45,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
45
45
|
activeOpacity={0.8}
|
|
46
46
|
onPress={onChangeValue}
|
|
47
47
|
disabled={disabled}
|
|
48
|
-
style={styles.container}>
|
|
48
|
+
style={[style, styles.container]}>
|
|
49
49
|
<View style={[checkboxStyle, styles.checkbox]}>
|
|
50
50
|
<Image style={styles.icon} source={{uri: iconSource}} />
|
|
51
51
|
</View>
|
|
@@ -54,4 +54,8 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
54
54
|
);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
+
CheckBox.defaultProps = {
|
|
58
|
+
disabled: false,
|
|
59
|
+
};
|
|
60
|
+
|
|
57
61
|
export {CheckBox};
|
package/CheckBox/types.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import {ViewStyle} from 'react-native';
|
|
2
|
+
|
|
3
|
+
export type CheckBoxProps = {
|
|
2
4
|
value: boolean;
|
|
3
5
|
disabled?: boolean;
|
|
4
6
|
label?: string;
|
|
5
7
|
onChange: (value: boolean) => void;
|
|
6
|
-
indeterminated
|
|
7
|
-
|
|
8
|
+
indeterminated?: boolean;
|
|
9
|
+
style?: ViewStyle;
|
|
10
|
+
};
|
package/Consts/theme.ts
CHANGED
|
@@ -57,9 +57,65 @@ const defaultTheme: Theme = {
|
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
const defaultDarkTheme: Theme = {
|
|
61
|
+
dark: true,
|
|
62
|
+
colors: {
|
|
63
|
+
primary: '#ff79b0',
|
|
64
|
+
secondary: '#ffacdc',
|
|
65
|
+
background: {
|
|
66
|
+
default: '#121212', // Dark background
|
|
67
|
+
surface: '#1e1e1e', // Slightly lighter surface background
|
|
68
|
+
tonal: '#171717', // Tonal background
|
|
69
|
+
pressed: '#1a1a1a', // Pressed state background
|
|
70
|
+
selected: '#1a1a1a', // Selected state background
|
|
71
|
+
disable: '#303030', // Disabled state background
|
|
72
|
+
},
|
|
73
|
+
text: {
|
|
74
|
+
default: '#ffffff', // White text for better contrast
|
|
75
|
+
secondary: '#b0b0b0', // Light gray secondary text
|
|
76
|
+
hint: '#727272', // Hint text color
|
|
77
|
+
disable: '#505050', // Disabled text color
|
|
78
|
+
},
|
|
79
|
+
border: {
|
|
80
|
+
default: '#2a2a2a', // Darker borders
|
|
81
|
+
disable: '#242424', // Disabled state border color
|
|
82
|
+
},
|
|
83
|
+
success: {
|
|
84
|
+
primary: Colors.green_03,
|
|
85
|
+
secondary: Colors.green_07,
|
|
86
|
+
container: Colors.green_08,
|
|
87
|
+
},
|
|
88
|
+
warning: {
|
|
89
|
+
primary: Colors.orange_03,
|
|
90
|
+
secondary: Colors.orange_07,
|
|
91
|
+
container: Colors.orange_08,
|
|
92
|
+
},
|
|
93
|
+
error: {
|
|
94
|
+
primary: Colors.red_03,
|
|
95
|
+
secondary: Colors.red_07,
|
|
96
|
+
container: Colors.red_08,
|
|
97
|
+
},
|
|
98
|
+
highlight: {
|
|
99
|
+
primary: Colors.mint_03,
|
|
100
|
+
secondary: Colors.mint_07,
|
|
101
|
+
container: Colors.mint_08,
|
|
102
|
+
},
|
|
103
|
+
interactive: {
|
|
104
|
+
primary: Colors.blue_03,
|
|
105
|
+
secondary: Colors.blue_07,
|
|
106
|
+
container: Colors.blue_08,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
font: 'SFProText',
|
|
110
|
+
assets: {
|
|
111
|
+
headerBackground:
|
|
112
|
+
'https://static.momocdn.net/app/img/app/img/header-background.png',
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
60
116
|
const defaultContext: Context = {
|
|
61
117
|
theme: defaultTheme,
|
|
62
118
|
navigator: undefined,
|
|
63
119
|
};
|
|
64
120
|
|
|
65
|
-
export {defaultContext, defaultTheme};
|
|
121
|
+
export {defaultContext, defaultTheme, defaultDarkTheme};
|
package/ContentLoader/index.tsx
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import React, {useContext, useEffect, useMemo, useRef} from 'react';
|
|
2
2
|
import {Animated, Platform, useWindowDimensions, View} from 'react-native';
|
|
3
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
3
4
|
import {ContentLoaderTypes} from './types';
|
|
4
5
|
import {ApplicationContext} from '../Navigation';
|
|
5
|
-
import LinearGradient from 'react-native-linear-gradient';
|
|
6
6
|
import {Styles} from '../Consts';
|
|
7
7
|
import styles from './styles';
|
|
8
|
-
const ContentLoader: React.FC<ContentLoaderTypes> =
|
|
8
|
+
const ContentLoader: React.FC<ContentLoaderTypes> = ({style}) => {
|
|
9
9
|
const {width} = useWindowDimensions();
|
|
10
10
|
const {theme} = useContext(ApplicationContext);
|
|
11
11
|
const beginShimmerPosition = useRef(new Animated.Value(-1)).current;
|
|
12
|
-
const {style} = props;
|
|
13
12
|
|
|
14
13
|
const shimmerColors = [
|
|
15
14
|
theme.colors.text.disable + '40',
|
package/Icon/icon.json
CHANGED
package/Icon/index.tsx
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
|
-
import {IconProps, Image, ApplicationContext} from '../index';
|
|
3
2
|
import IconSources from './icon.json';
|
|
3
|
+
import {IconProps} from './types';
|
|
4
|
+
import {ApplicationContext} from '../Navigation';
|
|
5
|
+
import {Image} from '../Image';
|
|
4
6
|
|
|
5
|
-
const Icon: React.FC<IconProps> = ({source, size, color}) => {
|
|
7
|
+
const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
|
|
6
8
|
const {theme} = useContext(ApplicationContext);
|
|
7
9
|
|
|
10
|
+
/**
|
|
11
|
+
* get icon source maps or remote http
|
|
12
|
+
*/
|
|
8
13
|
const getIconSource = (): any => {
|
|
9
14
|
if (source && !source.includes('http')) {
|
|
10
|
-
let icon: {[key: string]:
|
|
15
|
+
let icon: {[key: string]: {uri: string}} = IconSources;
|
|
11
16
|
return icon[source] ?? icon.ic_warning;
|
|
12
17
|
}
|
|
13
18
|
return {uri: source};
|
|
@@ -16,7 +21,7 @@ const Icon: React.FC<IconProps> = ({source, size, color}) => {
|
|
|
16
21
|
return (
|
|
17
22
|
<Image
|
|
18
23
|
source={getIconSource()}
|
|
19
|
-
style={{width: size, height: size}}
|
|
24
|
+
style={[style, {width: size, height: size}]}
|
|
20
25
|
tintColor={color ?? theme.colors.text.default}
|
|
21
26
|
/>
|
|
22
27
|
);
|
package/Icon/types.ts
CHANGED
package/IconButton/index.tsx
CHANGED
|
@@ -3,13 +3,19 @@ import {
|
|
|
3
3
|
GestureResponderEvent,
|
|
4
4
|
StyleSheet,
|
|
5
5
|
TouchableOpacity,
|
|
6
|
+
TouchableOpacityProps,
|
|
6
7
|
} from 'react-native';
|
|
7
|
-
import {IconButtonProps} from './types';
|
|
8
8
|
import {ApplicationContext} from '../Navigation';
|
|
9
9
|
import {Colors} from '../Consts';
|
|
10
10
|
import {Icon} from '../Icon';
|
|
11
11
|
import styles from './styles';
|
|
12
12
|
|
|
13
|
+
export interface IconButtonProps extends TouchableOpacityProps {
|
|
14
|
+
icon: string;
|
|
15
|
+
type?: 'primary' | 'tonal' | 'secondary' | 'danger' | 'outline' | 'disabled';
|
|
16
|
+
size?: 'large' | 'small';
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
const IconButton: React.FC<IconButtonProps> = ({
|
|
14
20
|
type,
|
|
15
21
|
icon,
|
|
@@ -19,12 +25,19 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
19
25
|
}) => {
|
|
20
26
|
const {theme} = useContext(ApplicationContext);
|
|
21
27
|
|
|
28
|
+
/**
|
|
29
|
+
* get size icon button
|
|
30
|
+
*/
|
|
22
31
|
const getSizeStyle = () => {
|
|
23
32
|
if (size === 'small') {
|
|
24
33
|
return styles.small;
|
|
25
34
|
}
|
|
26
35
|
return styles.large;
|
|
27
36
|
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* get style for icon button by type
|
|
40
|
+
*/
|
|
28
41
|
const getTypeStyle = () => {
|
|
29
42
|
switch (type) {
|
|
30
43
|
case 'disabled':
|
|
@@ -35,13 +48,13 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
35
48
|
return {backgroundColor: theme.colors.primary};
|
|
36
49
|
case 'secondary':
|
|
37
50
|
return {
|
|
38
|
-
backgroundColor:
|
|
51
|
+
backgroundColor: theme.colors.background.surface,
|
|
39
52
|
borderWidth: 1,
|
|
40
53
|
borderColor: theme.colors.border.default,
|
|
41
54
|
};
|
|
42
55
|
case 'outline':
|
|
43
56
|
return {
|
|
44
|
-
backgroundColor:
|
|
57
|
+
backgroundColor: theme.colors.background.surface,
|
|
45
58
|
borderWidth: 1,
|
|
46
59
|
borderColor: theme.colors.primary,
|
|
47
60
|
};
|
|
@@ -58,6 +71,9 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
58
71
|
}
|
|
59
72
|
};
|
|
60
73
|
|
|
74
|
+
/**
|
|
75
|
+
* get color for icon
|
|
76
|
+
*/
|
|
61
77
|
const getIconColor = () => {
|
|
62
78
|
switch (type) {
|
|
63
79
|
case 'disabled':
|
|
@@ -77,6 +93,10 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
77
93
|
}
|
|
78
94
|
};
|
|
79
95
|
|
|
96
|
+
/**
|
|
97
|
+
* handle press
|
|
98
|
+
* @param e
|
|
99
|
+
*/
|
|
80
100
|
const onPressButton = (e: GestureResponderEvent) => {
|
|
81
101
|
if (type === 'disabled') {
|
|
82
102
|
return () => {};
|
|
@@ -85,9 +105,9 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
85
105
|
};
|
|
86
106
|
|
|
87
107
|
const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
|
|
88
|
-
|
|
89
108
|
const buttonStyle = StyleSheet.flatten([getTypeStyle(), getSizeStyle()]);
|
|
90
109
|
const iconSize = size === 'small' ? 16 : 24;
|
|
110
|
+
|
|
91
111
|
return (
|
|
92
112
|
<TouchableOpacity
|
|
93
113
|
{...rest}
|
package/Image/index.tsx
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import React, {useContext, useState} from 'react';
|
|
2
|
-
import {StyleSheet, View} from 'react-native';
|
|
2
|
+
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
|
|
3
3
|
import FastImage from 'react-native-fast-image';
|
|
4
|
-
|
|
5
4
|
import styles from './styles';
|
|
6
|
-
import {ImageProps} from './types';
|
|
7
5
|
import {ApplicationContext} from '../Navigation';
|
|
8
6
|
import {ContentLoader} from '../ContentLoader';
|
|
9
7
|
import {Icon} from '../Icon';
|
|
10
8
|
import {Styles} from '../Consts';
|
|
9
|
+
import {FastImagePropsWithoutStyle} from './types';
|
|
10
|
+
|
|
11
|
+
export interface ImageProps extends FastImagePropsWithoutStyle {
|
|
12
|
+
style?: StyleProp<ViewStyle>;
|
|
13
|
+
}
|
|
11
14
|
|
|
12
|
-
const Image: React.FC<ImageProps> =
|
|
15
|
+
const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
13
16
|
const {theme} = useContext(ApplicationContext);
|
|
14
|
-
const {style, placeholder, source} = props;
|
|
15
17
|
const [loading, setLoading] = useState(typeof source === 'object');
|
|
16
18
|
const [fail, setFail] = useState(false);
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
|
-
* render content
|
|
21
|
+
* render content loading | fail | rendered
|
|
20
22
|
* @returns {JSX.Element}
|
|
21
23
|
*/
|
|
22
24
|
const renderContent = () => {
|
|
23
25
|
if (loading || fail) {
|
|
24
|
-
let content =
|
|
26
|
+
let content = (
|
|
25
27
|
<ContentLoader style={[StyleSheet.absoluteFill, styles.image]} />
|
|
26
28
|
);
|
|
27
29
|
if (fail) {
|
|
@@ -47,7 +49,8 @@ const Image: React.FC<ImageProps> = props => {
|
|
|
47
49
|
return (
|
|
48
50
|
<View style={[styles.container, style]}>
|
|
49
51
|
<FastImage
|
|
50
|
-
{...
|
|
52
|
+
{...rest}
|
|
53
|
+
source={source}
|
|
51
54
|
style={styles.image}
|
|
52
55
|
onLoad={() => {
|
|
53
56
|
setFail(false);
|
|
@@ -61,8 +64,4 @@ const Image: React.FC<ImageProps> = props => {
|
|
|
61
64
|
);
|
|
62
65
|
};
|
|
63
66
|
|
|
64
|
-
Image.defaultProps = {
|
|
65
|
-
style: {},
|
|
66
|
-
};
|
|
67
|
-
|
|
68
67
|
export {Image};
|
package/Image/types.ts
CHANGED
package/Input/Input.tsx
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React, {FC, useContext, useRef, useState} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
NativeSyntheticEvent,
|
|
4
|
+
TextInput,
|
|
5
|
+
TextInputFocusEventData,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
View,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import {ApplicationContext} from '../Navigation';
|
|
10
|
+
import styles from './styles';
|
|
11
|
+
import {Text} from '../Text';
|
|
12
|
+
import {Image} from '../Image';
|
|
13
|
+
import {getBorderColor, renderFloatingView} from './common';
|
|
14
|
+
import {InputProps} from './index';
|
|
15
|
+
import {Icon} from '../Icon';
|
|
16
|
+
|
|
17
|
+
const Input: FC<InputProps> = ({
|
|
18
|
+
value,
|
|
19
|
+
onChangeText,
|
|
20
|
+
floatingValue,
|
|
21
|
+
floatingIcon,
|
|
22
|
+
size,
|
|
23
|
+
placeholder,
|
|
24
|
+
onBlur,
|
|
25
|
+
onFocus,
|
|
26
|
+
errorMessage,
|
|
27
|
+
icon,
|
|
28
|
+
disabled,
|
|
29
|
+
floatingIconColor,
|
|
30
|
+
iconColor,
|
|
31
|
+
...props
|
|
32
|
+
}) => {
|
|
33
|
+
const {theme} = useContext(ApplicationContext);
|
|
34
|
+
const [focused, setFocused] = useState(false);
|
|
35
|
+
const inputRef = useRef<any>(null);
|
|
36
|
+
|
|
37
|
+
const onClearText = () => {
|
|
38
|
+
inputRef?.current?.clear();
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const _onChangeText = (text: string) => {
|
|
42
|
+
onChangeText?.(text);
|
|
43
|
+
};
|
|
44
|
+
const getSizeStyle = () => {
|
|
45
|
+
if (size === 'small') {
|
|
46
|
+
return styles.smallContainer;
|
|
47
|
+
}
|
|
48
|
+
return styles.container;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
52
|
+
setFocused(true);
|
|
53
|
+
onFocus?.(e);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
57
|
+
setFocused(false);
|
|
58
|
+
onBlur?.(e);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const renderInputView = () => {
|
|
62
|
+
const disabledColor = theme.colors.text.disable;
|
|
63
|
+
let textColor = theme.colors.text.default;
|
|
64
|
+
let placeholderColor = theme.colors.text.hint;
|
|
65
|
+
let iconTintColor = iconColor;
|
|
66
|
+
|
|
67
|
+
if (disabled) {
|
|
68
|
+
textColor = disabledColor;
|
|
69
|
+
placeholderColor = disabledColor;
|
|
70
|
+
iconTintColor = disabledColor;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<View
|
|
75
|
+
style={[
|
|
76
|
+
getSizeStyle(),
|
|
77
|
+
getBorderColor(focused, errorMessage, disabled),
|
|
78
|
+
styles.inputWrapper,
|
|
79
|
+
]}>
|
|
80
|
+
{renderFloatingView(
|
|
81
|
+
floatingValue,
|
|
82
|
+
floatingIconColor,
|
|
83
|
+
disabled,
|
|
84
|
+
floatingIcon,
|
|
85
|
+
)}
|
|
86
|
+
<View style={styles.inputView}>
|
|
87
|
+
<TextInput
|
|
88
|
+
{...props}
|
|
89
|
+
editable={!disabled}
|
|
90
|
+
textAlignVertical="top"
|
|
91
|
+
ref={inputRef}
|
|
92
|
+
style={[
|
|
93
|
+
styles.input,
|
|
94
|
+
{
|
|
95
|
+
color: textColor,
|
|
96
|
+
},
|
|
97
|
+
]}
|
|
98
|
+
value={value}
|
|
99
|
+
onChangeText={_onChangeText}
|
|
100
|
+
onFocus={_onFocus}
|
|
101
|
+
onBlur={_onBlur}
|
|
102
|
+
placeholder={placeholder}
|
|
103
|
+
selectionColor={theme.colors.primary}
|
|
104
|
+
placeholderTextColor={placeholderColor}
|
|
105
|
+
/>
|
|
106
|
+
</View>
|
|
107
|
+
<View style={styles.iconView}>
|
|
108
|
+
{focused && (
|
|
109
|
+
<TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
|
|
110
|
+
<Icon
|
|
111
|
+
source="24_navigation_close_circle_full"
|
|
112
|
+
size={16}
|
|
113
|
+
color={theme.colors.text.hint}
|
|
114
|
+
/>
|
|
115
|
+
</TouchableOpacity>
|
|
116
|
+
)}
|
|
117
|
+
{icon && (
|
|
118
|
+
<Image
|
|
119
|
+
tintColor={iconTintColor}
|
|
120
|
+
source={{uri: icon}}
|
|
121
|
+
style={styles.icon}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
124
|
+
</View>
|
|
125
|
+
</View>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const renderErrorView = () => {
|
|
130
|
+
if (errorMessage) {
|
|
131
|
+
return (
|
|
132
|
+
<View style={styles.errorView}>
|
|
133
|
+
<View style={styles.errorIcon}>
|
|
134
|
+
<Icon
|
|
135
|
+
source="ic_error"
|
|
136
|
+
size={16}
|
|
137
|
+
color={theme.colors.error.primary}
|
|
138
|
+
/>
|
|
139
|
+
</View>
|
|
140
|
+
<Text color={theme.colors.error.primary} typography={'description_s'}>
|
|
141
|
+
{errorMessage}
|
|
142
|
+
</Text>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<View style={styles.wrapper}>
|
|
150
|
+
{renderInputView()}
|
|
151
|
+
{renderErrorView()}
|
|
152
|
+
</View>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
Input.defaultProps = {
|
|
157
|
+
size: 'large',
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default Input;
|