@momo-kits/foundation 1.0.0 → 1.0.1
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/ActivityIndicator.tsx +244 -0
- package/Button/index.tsx +94 -164
- package/Button/types.ts +12 -3
- package/CheckBox/index.tsx +57 -0
- package/CheckBox/styles.ts +14 -0
- package/CheckBox/types.ts +7 -0
- package/Consts/colors+spacing+radius.ts +6 -4
- package/Consts/index.ts +4 -73
- package/Consts/styles.ts +1 -1
- package/Consts/theme.ts +65 -0
- package/ContentLoader/index.tsx +8 -11
- package/Icon/index.tsx +11 -11
- package/Icon/types.ts +1 -4
- package/IconButton/index.tsx +52 -72
- package/IconButton/styles.ts +19 -0
- package/IconButton/types.ts +1 -2
- package/Image/index.tsx +19 -18
- package/Image/types.ts +0 -1
- package/Input/TextArea.tsx +202 -0
- package/Input/index.tsx +200 -0
- package/Input/styles.ts +92 -0
- package/Input/types.ts +23 -0
- package/Layout/GridSystem.tsx +109 -0
- package/Layout/ScreenContainer.tsx +78 -0
- package/Layout/ScreenSection.tsx +104 -0
- package/Layout/SectionItem.tsx +60 -0
- package/Layout/index.ts +11 -5
- package/Layout/types.ts +6 -33
- package/Layout/utils.ts +55 -23
- package/Navigation/Components.tsx +16 -8
- package/Navigation/ModalScreen.tsx +35 -25
- package/Navigation/Navigation.ts +2 -2
- package/Navigation/NavigationButton.tsx +5 -3
- package/Navigation/NavigationContainer.tsx +59 -17
- package/Navigation/StackScreen.tsx +8 -2
- package/Navigation/index.ts +5 -3
- package/Navigation/types.ts +53 -36
- package/Navigation/utils.tsx +20 -18
- package/Radio/index.tsx +34 -0
- package/Radio/styles.ts +11 -0
- package/Radio/types.ts +7 -0
- package/Switch/index.tsx +37 -0
- package/Switch/styles.ts +23 -0
- package/Switch/types.ts +5 -0
- package/Text/index.tsx +36 -120
- package/Text/styles.ts +24 -23
- package/Text/types.ts +2 -0
- package/index.ts +18 -1
- package/package.json +1 -1
- package/publish.sh +8 -6
- package/CheckBox/index.js +0 -74
- package/CheckBox/styles.js +0 -3
- package/Layout/Row.tsx +0 -42
- package/Layout/Screen.tsx +0 -68
- package/Layout/Section.tsx +0 -30
- package/Layout/View.tsx +0 -84
- package/Layout/styles.ts +0 -24
- package/Navigation/ScreenContainer.tsx +0 -38
- package/SizedBox/index.js +0 -23
- package/SizedBox/styles.js +0 -7
- package/TextInput/index.js +0 -225
- package/TextInput/styles.js +0 -55
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Animated,
|
|
4
|
+
Easing,
|
|
5
|
+
Platform,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
View,
|
|
9
|
+
ViewStyle,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
|
|
12
|
+
export type Props = React.ComponentPropsWithRef<typeof View> & {
|
|
13
|
+
/**
|
|
14
|
+
* Whether to show the indicator or hide it.
|
|
15
|
+
*/
|
|
16
|
+
animating?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The color of the spinner.
|
|
19
|
+
*/
|
|
20
|
+
color?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Size of the indicator.
|
|
23
|
+
*/
|
|
24
|
+
size?: 'small' | 'large' | number;
|
|
25
|
+
/**
|
|
26
|
+
* Whether the indicator should hide when not animating.
|
|
27
|
+
*/
|
|
28
|
+
hidesWhenStopped?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Style for position indicator.
|
|
31
|
+
*/
|
|
32
|
+
style?: StyleProp<ViewStyle>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const DURATION = 2400;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Activity indicator is used to present progress of some activity in the app.
|
|
39
|
+
* It can be used as a drop-in for the ActivityIndicator shipped with React Native.
|
|
40
|
+
*
|
|
41
|
+
* ## Usage
|
|
42
|
+
* ```js
|
|
43
|
+
* import * as React from 'react';
|
|
44
|
+
* import { ActivityIndicator, MD2Colors } from 'react-native-paper';
|
|
45
|
+
*
|
|
46
|
+
* const MyComponent = () => (
|
|
47
|
+
* <ActivityIndicator animating={true} color={MD2Colors.red800} />
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* export default MyComponent;
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
const ActivityIndicator = ({
|
|
54
|
+
animating = true,
|
|
55
|
+
color: indicatorColor,
|
|
56
|
+
hidesWhenStopped = true,
|
|
57
|
+
size: indicatorSize = 'small',
|
|
58
|
+
style,
|
|
59
|
+
...rest
|
|
60
|
+
}: Props) => {
|
|
61
|
+
const { current: timer } = React.useRef<Animated.Value>(
|
|
62
|
+
new Animated.Value(0)
|
|
63
|
+
);
|
|
64
|
+
const { current: fade } = React.useRef<Animated.Value>(
|
|
65
|
+
new Animated.Value(!animating && hidesWhenStopped ? 0 : 1)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const rotation = React.useRef<Animated.CompositeAnimation | undefined>(
|
|
69
|
+
undefined
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const startRotation = React.useCallback(() => {
|
|
73
|
+
// Show indicator
|
|
74
|
+
Animated.timing(fade, {
|
|
75
|
+
duration: 200,
|
|
76
|
+
toValue: 1,
|
|
77
|
+
isInteraction: false,
|
|
78
|
+
useNativeDriver: true,
|
|
79
|
+
}).start();
|
|
80
|
+
|
|
81
|
+
// Circular animation in loop
|
|
82
|
+
if (rotation.current) {
|
|
83
|
+
timer.setValue(0);
|
|
84
|
+
// $FlowFixMe
|
|
85
|
+
Animated.loop(rotation.current).start();
|
|
86
|
+
}
|
|
87
|
+
}, [fade, timer]);
|
|
88
|
+
|
|
89
|
+
const stopRotation = () => {
|
|
90
|
+
if (rotation.current) {
|
|
91
|
+
rotation.current.stop();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
React.useEffect(() => {
|
|
96
|
+
if (rotation.current === undefined) {
|
|
97
|
+
// Circular animation in loop
|
|
98
|
+
rotation.current = Animated.timing(timer, {
|
|
99
|
+
duration: DURATION,
|
|
100
|
+
easing: Easing.linear,
|
|
101
|
+
// Animated.loop does not work if useNativeDriver is true on web
|
|
102
|
+
useNativeDriver: Platform.OS !== 'web',
|
|
103
|
+
toValue: 1,
|
|
104
|
+
isInteraction: false,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (animating) {
|
|
109
|
+
startRotation();
|
|
110
|
+
} else if (hidesWhenStopped) {
|
|
111
|
+
// Hide indicator first and then stop rotation
|
|
112
|
+
Animated.timing(fade, {
|
|
113
|
+
duration: 200,
|
|
114
|
+
toValue: 0,
|
|
115
|
+
useNativeDriver: true,
|
|
116
|
+
isInteraction: false,
|
|
117
|
+
}).start(stopRotation);
|
|
118
|
+
} else {
|
|
119
|
+
stopRotation();
|
|
120
|
+
}
|
|
121
|
+
}, [animating, fade, hidesWhenStopped, startRotation, timer]);
|
|
122
|
+
|
|
123
|
+
const color = indicatorColor || 'red';
|
|
124
|
+
const size =
|
|
125
|
+
typeof indicatorSize === 'string'
|
|
126
|
+
? indicatorSize === 'small'
|
|
127
|
+
? 24
|
|
128
|
+
: 48
|
|
129
|
+
: indicatorSize
|
|
130
|
+
? indicatorSize
|
|
131
|
+
: 24;
|
|
132
|
+
|
|
133
|
+
const frames = (60 * DURATION) / 1000;
|
|
134
|
+
const easing = Easing.bezier(0.4, 0.0, 0.7, 1.0);
|
|
135
|
+
const containerStyle = {
|
|
136
|
+
width: size,
|
|
137
|
+
height: size / 2,
|
|
138
|
+
overflow: 'hidden' as const,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<View
|
|
143
|
+
style={[styles.container, style]}
|
|
144
|
+
{...rest}
|
|
145
|
+
accessible
|
|
146
|
+
accessibilityRole="progressbar"
|
|
147
|
+
accessibilityState={{ busy: animating }}
|
|
148
|
+
>
|
|
149
|
+
<Animated.View
|
|
150
|
+
style={[{ width: size, height: size, opacity: fade }]}
|
|
151
|
+
collapsable={false}
|
|
152
|
+
>
|
|
153
|
+
{[0, 1].map((index) => {
|
|
154
|
+
// Thanks to https://github.com/n4kz/react-native-indicators for the great work
|
|
155
|
+
const inputRange = Array.from(
|
|
156
|
+
new Array(frames),
|
|
157
|
+
(_, frameIndex) => frameIndex / (frames - 1)
|
|
158
|
+
);
|
|
159
|
+
const outputRange = Array.from(new Array(frames), (_, frameIndex) => {
|
|
160
|
+
let progress = (2 * frameIndex) / (frames - 1);
|
|
161
|
+
const rotation = index ? +(360 - 15) : -(180 - 15);
|
|
162
|
+
|
|
163
|
+
if (progress > 1.0) {
|
|
164
|
+
progress = 2.0 - progress;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const direction = index ? -1 : +1;
|
|
168
|
+
|
|
169
|
+
return `${direction * (180 - 30) * easing(progress) + rotation}deg`;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const layerStyle = {
|
|
173
|
+
width: size,
|
|
174
|
+
height: size,
|
|
175
|
+
transform: [
|
|
176
|
+
{
|
|
177
|
+
rotate: timer.interpolate({
|
|
178
|
+
inputRange: [0, 1],
|
|
179
|
+
outputRange: [`${0 + 30 + 15}deg`, `${2 * 360 + 30 + 15}deg`],
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const viewportStyle = {
|
|
186
|
+
width: size,
|
|
187
|
+
height: size,
|
|
188
|
+
transform: [
|
|
189
|
+
{
|
|
190
|
+
translateY: index ? -size / 2 : 0,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
rotate: timer.interpolate({ inputRange, outputRange }),
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const offsetStyle = index ? { top: size / 2 } : null;
|
|
199
|
+
|
|
200
|
+
const lineStyle = {
|
|
201
|
+
width: size,
|
|
202
|
+
height: size,
|
|
203
|
+
borderColor: color,
|
|
204
|
+
borderWidth: size / 10,
|
|
205
|
+
borderRadius: size / 2,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<Animated.View key={index} style={[styles.layer]}>
|
|
210
|
+
<Animated.View style={layerStyle}>
|
|
211
|
+
<Animated.View
|
|
212
|
+
style={[containerStyle, offsetStyle]}
|
|
213
|
+
collapsable={false}
|
|
214
|
+
>
|
|
215
|
+
<Animated.View style={viewportStyle}>
|
|
216
|
+
<Animated.View style={containerStyle} collapsable={false}>
|
|
217
|
+
<Animated.View style={lineStyle} />
|
|
218
|
+
</Animated.View>
|
|
219
|
+
</Animated.View>
|
|
220
|
+
</Animated.View>
|
|
221
|
+
</Animated.View>
|
|
222
|
+
</Animated.View>
|
|
223
|
+
);
|
|
224
|
+
})}
|
|
225
|
+
</Animated.View>
|
|
226
|
+
</View>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const styles = StyleSheet.create({
|
|
231
|
+
container: {
|
|
232
|
+
justifyContent: 'center',
|
|
233
|
+
alignItems: 'center',
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
layer: {
|
|
237
|
+
...StyleSheet.absoluteFillObject,
|
|
238
|
+
|
|
239
|
+
justifyContent: 'center',
|
|
240
|
+
alignItems: 'center',
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
export default ActivityIndicator;
|
package/Button/index.tsx
CHANGED
|
@@ -1,98 +1,71 @@
|
|
|
1
|
-
import React, {useContext} from 'react';
|
|
1
|
+
import React, {FC, useContext} from 'react';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
GestureResponderEvent,
|
|
4
4
|
StyleSheet,
|
|
5
5
|
TouchableOpacity,
|
|
6
6
|
View,
|
|
7
7
|
} from 'react-native';
|
|
8
|
-
import {
|
|
8
|
+
import {ApplicationContext} from '../Navigation';
|
|
9
|
+
import {Text} from '../Text';
|
|
10
|
+
import {Typography} from '../Text/types';
|
|
11
|
+
import {Colors} from '../Consts';
|
|
9
12
|
import styles from './styles';
|
|
13
|
+
import {ButtonProps} from './types';
|
|
14
|
+
import {Image} from '../Image';
|
|
10
15
|
|
|
11
|
-
const
|
|
12
|
-
const {theme} = useContext(
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
textStyle,
|
|
16
|
-
type,
|
|
17
|
-
size,
|
|
18
|
-
full,
|
|
19
|
-
disabled,
|
|
20
|
-
leading,
|
|
21
|
-
trailing,
|
|
22
|
-
loading,
|
|
23
|
-
children,
|
|
24
|
-
} = props;
|
|
16
|
+
const Button: FC<ButtonProps> = props => {
|
|
17
|
+
const {theme} = useContext(ApplicationContext);
|
|
18
|
+
const {type, size, useTintColor, full, iconRight, iconLeft, title, onPress} =
|
|
19
|
+
props;
|
|
25
20
|
|
|
26
21
|
/**
|
|
27
22
|
* export size style
|
|
28
23
|
*/
|
|
29
24
|
const getSizeStyle = () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return styles.large;
|
|
33
|
-
case 'medium':
|
|
34
|
-
return styles.medium;
|
|
35
|
-
case 'small':
|
|
36
|
-
return styles.small;
|
|
37
|
-
|
|
38
|
-
default:
|
|
39
|
-
return styles.large;
|
|
40
|
-
}
|
|
25
|
+
const styleSheet: {[key: string]: any} = styles;
|
|
26
|
+
return styleSheet[size ?? 'small'];
|
|
41
27
|
};
|
|
42
28
|
|
|
43
29
|
/**
|
|
44
30
|
* export type style
|
|
45
31
|
*/
|
|
46
32
|
const getTypeStyle = () => {
|
|
47
|
-
if (disabled) {
|
|
48
|
-
return {
|
|
49
|
-
backgroundColor: theme.colors.border,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
33
|
switch (type) {
|
|
34
|
+
case 'disabled':
|
|
35
|
+
return {
|
|
36
|
+
backgroundColor: theme.colors.background.disable,
|
|
37
|
+
};
|
|
53
38
|
case 'primary':
|
|
54
39
|
return {backgroundColor: theme.colors.primary};
|
|
55
40
|
case 'secondary':
|
|
56
41
|
return {
|
|
57
|
-
backgroundColor: theme.colors.
|
|
42
|
+
backgroundColor: theme.colors.background.disable,
|
|
58
43
|
borderWidth: 1,
|
|
59
|
-
borderColor: theme.colors.border,
|
|
44
|
+
borderColor: theme.colors.border.default,
|
|
60
45
|
};
|
|
61
46
|
case 'outline':
|
|
62
47
|
return {
|
|
63
|
-
backgroundColor:
|
|
48
|
+
backgroundColor: Colors.black_01,
|
|
64
49
|
borderWidth: 1,
|
|
65
50
|
borderColor: theme.colors.primary,
|
|
66
51
|
};
|
|
52
|
+
case 'tonal':
|
|
53
|
+
return {
|
|
54
|
+
backgroundColor: theme.colors.background.tonal,
|
|
55
|
+
};
|
|
56
|
+
case 'danger':
|
|
57
|
+
return {
|
|
58
|
+
backgroundColor: theme.colors.error.primary,
|
|
59
|
+
};
|
|
67
60
|
case 'text':
|
|
68
|
-
return {
|
|
69
|
-
|
|
61
|
+
return {
|
|
62
|
+
backgroundColor: Colors.black_01,
|
|
63
|
+
};
|
|
70
64
|
default:
|
|
71
65
|
return {backgroundColor: theme.colors.primary};
|
|
72
66
|
}
|
|
73
67
|
};
|
|
74
68
|
|
|
75
|
-
/**
|
|
76
|
-
* export loading color
|
|
77
|
-
*/
|
|
78
|
-
const getLoadingColor = () => {
|
|
79
|
-
if (disabled) {
|
|
80
|
-
return theme.colors.textSecondary;
|
|
81
|
-
}
|
|
82
|
-
switch (type) {
|
|
83
|
-
case 'primary':
|
|
84
|
-
return Colors.black_01;
|
|
85
|
-
case 'secondary':
|
|
86
|
-
return theme.colors.text;
|
|
87
|
-
case 'outline':
|
|
88
|
-
return theme.colors.primary;
|
|
89
|
-
case 'text':
|
|
90
|
-
return theme.colors.primary;
|
|
91
|
-
default:
|
|
92
|
-
return theme.colors.primary;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
69
|
/**
|
|
97
70
|
* export icon size
|
|
98
71
|
*/
|
|
@@ -128,109 +101,74 @@ const Index = props => {
|
|
|
128
101
|
/**
|
|
129
102
|
* export typography style
|
|
130
103
|
*/
|
|
131
|
-
const getTypography = () => {
|
|
104
|
+
const getTypography = (): Typography => {
|
|
132
105
|
switch (size) {
|
|
133
106
|
case 'large':
|
|
134
|
-
return '
|
|
107
|
+
return 'action_default';
|
|
135
108
|
case 'medium':
|
|
136
|
-
return '
|
|
109
|
+
return 'action_s';
|
|
137
110
|
case 'small':
|
|
138
|
-
return '
|
|
111
|
+
return 'action_xs';
|
|
139
112
|
|
|
140
113
|
default:
|
|
141
|
-
return '
|
|
114
|
+
return 'action_default';
|
|
142
115
|
}
|
|
143
116
|
};
|
|
144
117
|
|
|
145
|
-
|
|
146
|
-
* render Text
|
|
147
|
-
*/
|
|
148
|
-
const renderText = () => {
|
|
149
|
-
const typography = getTypography();
|
|
150
|
-
if (disabled) {
|
|
151
|
-
return (
|
|
152
|
-
<Text
|
|
153
|
-
typography={typography}
|
|
154
|
-
weight="bold"
|
|
155
|
-
type="secondary"
|
|
156
|
-
numberOfLines={1}
|
|
157
|
-
style={textStyle}>
|
|
158
|
-
{children}
|
|
159
|
-
</Text>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
118
|
+
const getTextColor = (): string => {
|
|
162
119
|
switch (type) {
|
|
120
|
+
case 'disabled':
|
|
121
|
+
return theme.colors.text.disable;
|
|
163
122
|
case 'primary':
|
|
164
|
-
return
|
|
165
|
-
<Text
|
|
166
|
-
typography={typography}
|
|
167
|
-
weight="bold"
|
|
168
|
-
color="white"
|
|
169
|
-
numberOfLines={1}
|
|
170
|
-
style={textStyle}>
|
|
171
|
-
{children}
|
|
172
|
-
</Text>
|
|
173
|
-
);
|
|
123
|
+
return Colors.black_01;
|
|
174
124
|
case 'secondary':
|
|
175
|
-
return
|
|
176
|
-
<Text
|
|
177
|
-
typography={typography}
|
|
178
|
-
weight="bold"
|
|
179
|
-
numberOfLines={1}
|
|
180
|
-
style={textStyle}>
|
|
181
|
-
{children}
|
|
182
|
-
</Text>
|
|
183
|
-
);
|
|
125
|
+
return theme.colors.text.default;
|
|
184
126
|
case 'outline':
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
numberOfLines={1}
|
|
191
|
-
style={textStyle}>
|
|
192
|
-
{children}
|
|
193
|
-
</Text>
|
|
194
|
-
);
|
|
127
|
+
return theme.colors.primary;
|
|
128
|
+
case 'tonal':
|
|
129
|
+
return theme.colors.primary;
|
|
130
|
+
case 'danger':
|
|
131
|
+
return Colors.black_01;
|
|
195
132
|
case 'text':
|
|
196
|
-
return
|
|
197
|
-
<Text
|
|
198
|
-
typography={typography}
|
|
199
|
-
type="secondary"
|
|
200
|
-
weight="bold"
|
|
201
|
-
numberOfLines={1}
|
|
202
|
-
style={textStyle}>
|
|
203
|
-
{children}
|
|
204
|
-
</Text>
|
|
205
|
-
);
|
|
206
|
-
|
|
133
|
+
return theme.colors.primary;
|
|
207
134
|
default:
|
|
208
|
-
return
|
|
209
|
-
<Text
|
|
210
|
-
typography={typography}
|
|
211
|
-
weight="bold"
|
|
212
|
-
numberOfLines={1}
|
|
213
|
-
style={textStyle}>
|
|
214
|
-
{children}
|
|
215
|
-
</Text>
|
|
216
|
-
);
|
|
135
|
+
return Colors.black_01;
|
|
217
136
|
}
|
|
218
137
|
};
|
|
219
138
|
|
|
139
|
+
/**
|
|
140
|
+
* render Text
|
|
141
|
+
*/
|
|
142
|
+
const renderText = () => {
|
|
143
|
+
const typography = getTypography();
|
|
144
|
+
const color = getTextColor();
|
|
145
|
+
return (
|
|
146
|
+
<Text typography={typography} color={color} numberOfLines={1}>
|
|
147
|
+
{title}
|
|
148
|
+
</Text>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
220
152
|
/**
|
|
221
153
|
* render leading
|
|
222
154
|
*/
|
|
223
155
|
const renderLeading = () => {
|
|
224
|
-
if (
|
|
156
|
+
if (iconLeft) {
|
|
225
157
|
const iconSize = getIconSize();
|
|
226
158
|
const marginRight = getIconSpace();
|
|
159
|
+
const color = useTintColor ? getTextColor() : undefined;
|
|
160
|
+
|
|
227
161
|
return (
|
|
228
162
|
<View
|
|
229
163
|
style={[
|
|
230
164
|
styles.leading,
|
|
231
165
|
{width: iconSize, height: iconSize, marginRight},
|
|
232
166
|
]}>
|
|
233
|
-
|
|
167
|
+
<Image
|
|
168
|
+
tintColor={color}
|
|
169
|
+
source={{uri: iconLeft}}
|
|
170
|
+
style={{width: iconSize, height: iconSize}}
|
|
171
|
+
/>
|
|
234
172
|
</View>
|
|
235
173
|
);
|
|
236
174
|
}
|
|
@@ -241,16 +179,8 @@ const Index = props => {
|
|
|
241
179
|
*/
|
|
242
180
|
const renderTrailing = () => {
|
|
243
181
|
const marginLeft = getIconSpace();
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
<View style={[styles.trailing, {marginLeft}]}>
|
|
247
|
-
<View style={Styles.flexCenter}>
|
|
248
|
-
<ActivityIndicator color={getLoadingColor()} />
|
|
249
|
-
</View>
|
|
250
|
-
</View>
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
if (trailing) {
|
|
182
|
+
const color = useTintColor ? getTextColor() : undefined;
|
|
183
|
+
if (iconRight) {
|
|
254
184
|
const iconSize = getIconSize();
|
|
255
185
|
return (
|
|
256
186
|
<View
|
|
@@ -258,7 +188,11 @@ const Index = props => {
|
|
|
258
188
|
styles.trailing,
|
|
259
189
|
{width: iconSize, height: iconSize, marginLeft},
|
|
260
190
|
]}>
|
|
261
|
-
|
|
191
|
+
<Image
|
|
192
|
+
tintColor={color}
|
|
193
|
+
source={{uri: iconRight}}
|
|
194
|
+
style={{width: iconSize, height: iconSize}}
|
|
195
|
+
/>
|
|
262
196
|
</View>
|
|
263
197
|
);
|
|
264
198
|
}
|
|
@@ -268,11 +202,22 @@ const Index = props => {
|
|
|
268
202
|
getSizeStyle(),
|
|
269
203
|
getTypeStyle(),
|
|
270
204
|
full && {width: '100%'},
|
|
271
|
-
style,
|
|
272
205
|
]);
|
|
273
206
|
|
|
207
|
+
const onPressButton = (e: GestureResponderEvent) => {
|
|
208
|
+
if (type === 'disabled') {
|
|
209
|
+
return () => {};
|
|
210
|
+
}
|
|
211
|
+
onPress?.(e);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
|
|
274
215
|
return (
|
|
275
|
-
<TouchableOpacity
|
|
216
|
+
<TouchableOpacity
|
|
217
|
+
{...props}
|
|
218
|
+
activeOpacity={activeOpacity}
|
|
219
|
+
onPress={onPressButton}
|
|
220
|
+
style={buttonStyle}>
|
|
276
221
|
{renderLeading()}
|
|
277
222
|
{renderText()}
|
|
278
223
|
{renderTrailing()}
|
|
@@ -280,28 +225,13 @@ const Index = props => {
|
|
|
280
225
|
);
|
|
281
226
|
};
|
|
282
227
|
|
|
283
|
-
|
|
284
|
-
// textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
285
|
-
// type: PropTypes.oneOf(['primary', 'secondary','' ,'outline', 'text']),
|
|
286
|
-
// size: PropTypes.oneOf(['large', 'medium', 'small']),
|
|
287
|
-
// full: PropTypes.bool,
|
|
288
|
-
// disabled: PropTypes.bool,
|
|
289
|
-
// leading: PropTypes.element,
|
|
290
|
-
// trailing: PropTypes.element,
|
|
291
|
-
// loading: PropTypes.bool,
|
|
292
|
-
// children: PropTypes.string,
|
|
293
|
-
// };
|
|
294
|
-
|
|
295
|
-
Index.defaultProps = {
|
|
296
|
-
textStyle: {},
|
|
228
|
+
Button.defaultProps = {
|
|
297
229
|
type: 'primary',
|
|
298
230
|
size: 'large',
|
|
299
231
|
full: true,
|
|
300
232
|
disabled: false,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
loading: false,
|
|
304
|
-
children: 'Button',
|
|
233
|
+
title: 'Button',
|
|
234
|
+
useTintColor: true,
|
|
305
235
|
};
|
|
306
236
|
|
|
307
|
-
export default
|
|
237
|
+
export default Button;
|
package/Button/types.ts
CHANGED
|
@@ -8,11 +8,20 @@ export type ButtonType =
|
|
|
8
8
|
| 'secondary'
|
|
9
9
|
| 'tonal'
|
|
10
10
|
| 'outline'
|
|
11
|
-
| '
|
|
12
|
-
| 'text'
|
|
11
|
+
| 'danger'
|
|
12
|
+
| 'text'
|
|
13
|
+
| 'disabled';
|
|
13
14
|
|
|
14
15
|
export type ButtonSize = 'large' | 'medium' | 'small';
|
|
15
16
|
|
|
16
17
|
export interface ButtonProps
|
|
17
18
|
extends TouchableOpacityProps,
|
|
18
|
-
TouchableNativeFeedbackProps {
|
|
19
|
+
TouchableNativeFeedbackProps {
|
|
20
|
+
type?: ButtonType;
|
|
21
|
+
size?: ButtonSize;
|
|
22
|
+
full?: boolean;
|
|
23
|
+
iconRight?: string;
|
|
24
|
+
iconLeft?: string;
|
|
25
|
+
title: string;
|
|
26
|
+
useTintColor?: boolean;
|
|
27
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, {FC, useContext} from 'react';
|
|
2
|
+
import {TouchableOpacity, View} from 'react-native';
|
|
3
|
+
|
|
4
|
+
import {CheckBoxProps} from './types';
|
|
5
|
+
import {Text} from '@momo-kits/foundation';
|
|
6
|
+
import styles from './styles';
|
|
7
|
+
import Image from 'react-native-fast-image';
|
|
8
|
+
import {ApplicationContext} from '../Navigation';
|
|
9
|
+
import {Colors} from '../Consts';
|
|
10
|
+
|
|
11
|
+
const IC_INDETERMINATED = 'https://img.mservice.com.vn/app/img/kits/minus.png';
|
|
12
|
+
const IC_CHECKED_DEFAULT =
|
|
13
|
+
'https://img.mservice.com.vn/app/img/kits/checked_ic.png';
|
|
14
|
+
const CheckBox: FC<CheckBoxProps> = props => {
|
|
15
|
+
const {theme} = useContext(ApplicationContext);
|
|
16
|
+
const {value, disabled, onChange, label, indeterminated} = props;
|
|
17
|
+
|
|
18
|
+
const haveValue = value || indeterminated;
|
|
19
|
+
let borderColor = haveValue
|
|
20
|
+
? theme.colors.primary
|
|
21
|
+
: theme.colors.text.default;
|
|
22
|
+
let backgroundColor = haveValue ? theme.colors.primary : Colors.black_01;
|
|
23
|
+
|
|
24
|
+
let iconSource = value ? IC_CHECKED_DEFAULT : undefined;
|
|
25
|
+
|
|
26
|
+
if (indeterminated) {
|
|
27
|
+
iconSource = IC_INDETERMINATED;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (disabled) {
|
|
31
|
+
borderColor = haveValue
|
|
32
|
+
? theme.colors.background.disable
|
|
33
|
+
: theme.colors.border.disable;
|
|
34
|
+
backgroundColor = haveValue
|
|
35
|
+
? theme.colors.background.disable
|
|
36
|
+
: Colors.black_01;
|
|
37
|
+
}
|
|
38
|
+
const checkboxStyle = {borderColor, backgroundColor, borderWidth: 1};
|
|
39
|
+
|
|
40
|
+
const onChangeValue = () => {
|
|
41
|
+
onChange?.(!value);
|
|
42
|
+
};
|
|
43
|
+
return (
|
|
44
|
+
<TouchableOpacity
|
|
45
|
+
activeOpacity={0.8}
|
|
46
|
+
onPress={onChangeValue}
|
|
47
|
+
disabled={disabled}
|
|
48
|
+
style={styles.container}>
|
|
49
|
+
<View style={[checkboxStyle, styles.checkbox]}>
|
|
50
|
+
<Image style={styles.icon} source={{uri: iconSource}} />
|
|
51
|
+
</View>
|
|
52
|
+
<Text typography={'description_default'}>{label}</Text>
|
|
53
|
+
</TouchableOpacity>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export {CheckBox};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
import {Radius, Spacing} from '../Consts';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
checkbox: {
|
|
6
|
+
width: 24,
|
|
7
|
+
height: 24,
|
|
8
|
+
borderRadius: Radius.XS,
|
|
9
|
+
borderWidth: 2,
|
|
10
|
+
marginRight: Spacing.S,
|
|
11
|
+
},
|
|
12
|
+
container: {flexDirection: 'row'},
|
|
13
|
+
icon: {width: 20, height: 20},
|
|
14
|
+
});
|