@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/Input/TextArea.tsx
CHANGED
|
@@ -7,18 +7,15 @@ import {
|
|
|
7
7
|
View,
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import styles from './styles';
|
|
10
|
-
import {Image} from '../Image';
|
|
11
10
|
import {Text} from '../Text';
|
|
12
|
-
import {TextAreaProps} from './types';
|
|
13
11
|
import {ApplicationContext} from '../Navigation';
|
|
14
|
-
import {
|
|
12
|
+
import {getBorderColor, renderFloatingView} from './common';
|
|
13
|
+
import {TextAreaProps} from './index';
|
|
14
|
+
import {Icon} from '../Icon';
|
|
15
15
|
|
|
16
|
-
const errorMessageIcon =
|
|
17
|
-
'https://img.mservice.com.vn/app/img/kits/error_mess_icon.png';
|
|
18
|
-
const ic_clear =
|
|
19
|
-
'https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/24_navigation_close_circle_full.png';
|
|
20
16
|
const DEFAULT_HEIGHT = 112;
|
|
21
17
|
const MAX_LENGTH = 300;
|
|
18
|
+
|
|
22
19
|
const TextArea: FC<TextAreaProps> = props => {
|
|
23
20
|
const {theme} = useContext(ApplicationContext);
|
|
24
21
|
const {
|
|
@@ -59,56 +56,6 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
59
56
|
setFocused(false);
|
|
60
57
|
onBlur?.(e);
|
|
61
58
|
};
|
|
62
|
-
const getBorderColor = () => {
|
|
63
|
-
let borderColor = theme.colors.border.default;
|
|
64
|
-
|
|
65
|
-
if (focused) {
|
|
66
|
-
borderColor = theme.colors.primary;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!!errorMessage) {
|
|
70
|
-
borderColor = theme.colors.error.primary;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (disabled) {
|
|
74
|
-
borderColor = theme.colors.border.disable;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return {borderColor};
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const renderFloatingView = () => {
|
|
81
|
-
if (floatingValue) {
|
|
82
|
-
let floatingTextColor = theme.colors.text.hint;
|
|
83
|
-
let floatingIconTintColor = floatingIconColor;
|
|
84
|
-
if (disabled) {
|
|
85
|
-
floatingTextColor = theme.colors.text.disable;
|
|
86
|
-
floatingIconTintColor = theme.colors.text.disable;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<View
|
|
91
|
-
style={[
|
|
92
|
-
styles.floatingView,
|
|
93
|
-
{
|
|
94
|
-
backgroundColor: Colors.black_01,
|
|
95
|
-
zIndex: 10,
|
|
96
|
-
},
|
|
97
|
-
]}>
|
|
98
|
-
<Text color={floatingTextColor} typography={'label_s'}>
|
|
99
|
-
{floatingValue}
|
|
100
|
-
</Text>
|
|
101
|
-
{floatingIcon && (
|
|
102
|
-
<Image
|
|
103
|
-
tintColor={floatingIconTintColor}
|
|
104
|
-
source={{uri: floatingIcon}}
|
|
105
|
-
style={styles.floatingIcon}
|
|
106
|
-
/>
|
|
107
|
-
)}
|
|
108
|
-
</View>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
59
|
|
|
113
60
|
const renderCountingView = () => {
|
|
114
61
|
return (
|
|
@@ -132,11 +79,19 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
132
79
|
return (
|
|
133
80
|
<View
|
|
134
81
|
style={[
|
|
135
|
-
getBorderColor(),
|
|
82
|
+
getBorderColor(focused, errorMessage, disabled),
|
|
136
83
|
styles.textAreaWrapper,
|
|
137
|
-
{
|
|
84
|
+
{
|
|
85
|
+
height: height || DEFAULT_HEIGHT,
|
|
86
|
+
backgroundColor: theme.colors.background.surface,
|
|
87
|
+
},
|
|
138
88
|
]}>
|
|
139
|
-
{renderFloatingView(
|
|
89
|
+
{renderFloatingView(
|
|
90
|
+
floatingValue,
|
|
91
|
+
floatingIconColor,
|
|
92
|
+
disabled,
|
|
93
|
+
floatingIcon,
|
|
94
|
+
)}
|
|
140
95
|
<View style={styles.rowArea}>
|
|
141
96
|
<View style={styles.textAreaView}>
|
|
142
97
|
<TextInput
|
|
@@ -162,10 +117,10 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
162
117
|
</View>
|
|
163
118
|
{focused && (
|
|
164
119
|
<TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
120
|
+
<Icon
|
|
121
|
+
source="24_navigation_close_circle_full"
|
|
122
|
+
size={16}
|
|
123
|
+
color={theme.colors.text.hint}
|
|
169
124
|
/>
|
|
170
125
|
</TouchableOpacity>
|
|
171
126
|
)}
|
|
@@ -179,7 +134,13 @@ const TextArea: FC<TextAreaProps> = props => {
|
|
|
179
134
|
if (errorMessage) {
|
|
180
135
|
return (
|
|
181
136
|
<View style={styles.errorView}>
|
|
182
|
-
<
|
|
137
|
+
<View style={styles.errorIcon}>
|
|
138
|
+
<Icon
|
|
139
|
+
source="ic_error"
|
|
140
|
+
size={16}
|
|
141
|
+
color={theme.colors.error.primary}
|
|
142
|
+
/>
|
|
143
|
+
</View>
|
|
183
144
|
<Text color={theme.colors.error.primary} typography={'description_s'}>
|
|
184
145
|
{errorMessage}
|
|
185
146
|
</Text>
|
package/Input/common.tsx
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {View} from 'react-native';
|
|
2
|
+
import styles from './styles';
|
|
3
|
+
import {Text} from '../Text';
|
|
4
|
+
import {Image} from '../Image';
|
|
5
|
+
import React, {useContext} from 'react';
|
|
6
|
+
import {ApplicationContext} from '../Navigation';
|
|
7
|
+
|
|
8
|
+
export const getBorderColor = (
|
|
9
|
+
focused: boolean,
|
|
10
|
+
errorMessage?: string,
|
|
11
|
+
disabled?: boolean,
|
|
12
|
+
) => {
|
|
13
|
+
const {theme} = useContext(ApplicationContext);
|
|
14
|
+
|
|
15
|
+
let borderColor = theme.colors.border.default;
|
|
16
|
+
|
|
17
|
+
if (focused) {
|
|
18
|
+
borderColor = theme.colors.primary;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!!errorMessage) {
|
|
22
|
+
borderColor = theme.colors.error.primary;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (disabled) {
|
|
26
|
+
borderColor = theme.colors.border.disable;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {borderColor};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const renderFloatingView = (
|
|
33
|
+
floatingValue?: string,
|
|
34
|
+
floatingIconColor?: string,
|
|
35
|
+
disabled?: boolean,
|
|
36
|
+
floatingIcon?: string,
|
|
37
|
+
) => {
|
|
38
|
+
const {theme} = useContext(ApplicationContext);
|
|
39
|
+
|
|
40
|
+
if (floatingValue) {
|
|
41
|
+
let floatingTextColor = theme.colors.text.hint;
|
|
42
|
+
let floatingIconTintColor = floatingIconColor;
|
|
43
|
+
if (disabled) {
|
|
44
|
+
floatingTextColor = theme.colors.text.disable;
|
|
45
|
+
floatingIconTintColor = theme.colors.text.disable;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<View
|
|
50
|
+
style={[
|
|
51
|
+
styles.floatingView,
|
|
52
|
+
{
|
|
53
|
+
backgroundColor: theme.colors.background.surface,
|
|
54
|
+
zIndex: 10,
|
|
55
|
+
},
|
|
56
|
+
]}>
|
|
57
|
+
<Text color={floatingTextColor} typography={'label_s'}>
|
|
58
|
+
{floatingValue}
|
|
59
|
+
</Text>
|
|
60
|
+
{floatingIcon && (
|
|
61
|
+
<Image
|
|
62
|
+
tintColor={floatingIconTintColor}
|
|
63
|
+
source={{uri: floatingIcon}}
|
|
64
|
+
style={styles.floatingIcon}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</View>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
};
|
package/Input/index.tsx
CHANGED
|
@@ -1,200 +1,26 @@
|
|
|
1
|
-
import
|
|
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 {InputProps} from './types';
|
|
1
|
+
import Input from './Input';
|
|
12
2
|
import TextArea from './TextArea';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
import {TextInputProps} from 'react-native';
|
|
4
|
+
|
|
5
|
+
export interface InputProps extends TextInputProps {
|
|
6
|
+
size?: 'small' | 'large';
|
|
7
|
+
floatingValue?: string;
|
|
8
|
+
floatingIcon?: string;
|
|
9
|
+
errorMessage?: string;
|
|
10
|
+
icon?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
floatingIconColor?: string;
|
|
13
|
+
iconColor?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface TextAreaProps extends TextInputProps {
|
|
17
|
+
errorMessage: string;
|
|
18
|
+
floatingValue: string;
|
|
19
|
+
floatingIcon: string;
|
|
20
|
+
disabled: boolean;
|
|
21
|
+
floatingIconColor: string;
|
|
22
|
+
placeholder: string;
|
|
23
|
+
height: number;
|
|
24
|
+
}
|
|
16
25
|
|
|
17
|
-
const errorMessageIcon =
|
|
18
|
-
'https://img.mservice.com.vn/app/img/kits/error_mess_icon.png';
|
|
19
|
-
const ic_clear =
|
|
20
|
-
'https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/24_navigation_close_circle_full.png';
|
|
21
|
-
const MAX_LENGTH = 100;
|
|
22
|
-
const Input: FC<InputProps> = props => {
|
|
23
|
-
const {theme} = useContext(ApplicationContext);
|
|
24
|
-
const {
|
|
25
|
-
value,
|
|
26
|
-
onChangeText,
|
|
27
|
-
floatingValue,
|
|
28
|
-
floatingIcon,
|
|
29
|
-
size,
|
|
30
|
-
placeholder,
|
|
31
|
-
onBlur,
|
|
32
|
-
onFocus,
|
|
33
|
-
errorMessage,
|
|
34
|
-
icon,
|
|
35
|
-
disabled,
|
|
36
|
-
floatingIconColor,
|
|
37
|
-
iconColor,
|
|
38
|
-
} = props;
|
|
39
|
-
|
|
40
|
-
const [focused, setFocused] = useState(false);
|
|
41
|
-
const inputRef = useRef(null);
|
|
42
|
-
|
|
43
|
-
const onClearText = () => {
|
|
44
|
-
inputRef?.current?.clear();
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const _onChangeText = (text: string) => {
|
|
48
|
-
onChangeText?.(text);
|
|
49
|
-
};
|
|
50
|
-
const getSizeStyle = () => {
|
|
51
|
-
if (size === 'small') {
|
|
52
|
-
return styles.smallContainer;
|
|
53
|
-
}
|
|
54
|
-
return styles.container;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const getBorderColor = () => {
|
|
58
|
-
let borderColor = theme.colors.border.default;
|
|
59
|
-
|
|
60
|
-
if (focused) {
|
|
61
|
-
borderColor = theme.colors.primary;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!!errorMessage) {
|
|
65
|
-
borderColor = theme.colors.error.primary;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (disabled) {
|
|
69
|
-
borderColor = theme.colors.border.disable;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return {borderColor};
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
76
|
-
setFocused(true);
|
|
77
|
-
onFocus?.(e);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
81
|
-
setFocused(false);
|
|
82
|
-
onBlur?.(e);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const renderFloatingView = () => {
|
|
86
|
-
if (floatingValue) {
|
|
87
|
-
let floatingTextColor = theme.colors.text.hint;
|
|
88
|
-
let floatingIconTintColor = floatingIconColor;
|
|
89
|
-
if (disabled) {
|
|
90
|
-
floatingTextColor = theme.colors.text.disable;
|
|
91
|
-
floatingIconTintColor = theme.colors.text.disable;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<View
|
|
96
|
-
style={[
|
|
97
|
-
styles.floatingView,
|
|
98
|
-
{
|
|
99
|
-
backgroundColor: Colors.black_01,
|
|
100
|
-
zIndex: 10,
|
|
101
|
-
},
|
|
102
|
-
]}>
|
|
103
|
-
<Text color={floatingTextColor} typography={'label_s'}>
|
|
104
|
-
{floatingValue}
|
|
105
|
-
</Text>
|
|
106
|
-
{floatingIcon && (
|
|
107
|
-
<Image
|
|
108
|
-
tintColor={floatingIconTintColor}
|
|
109
|
-
source={{uri: floatingIcon}}
|
|
110
|
-
style={styles.floatingIcon}
|
|
111
|
-
/>
|
|
112
|
-
)}
|
|
113
|
-
</View>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const renderInputView = () => {
|
|
119
|
-
const disabledColor = theme.colors.text.disable;
|
|
120
|
-
let textColor = theme.colors.text.default;
|
|
121
|
-
let placeholderColor = theme.colors.text.hint;
|
|
122
|
-
let iconTintColor = iconColor;
|
|
123
|
-
|
|
124
|
-
if (disabled) {
|
|
125
|
-
textColor = disabledColor;
|
|
126
|
-
placeholderColor = disabledColor;
|
|
127
|
-
iconTintColor = disabledColor;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<View style={[getSizeStyle(), getBorderColor(), styles.inputWrapper]}>
|
|
132
|
-
{renderFloatingView()}
|
|
133
|
-
<View style={styles.inputView}>
|
|
134
|
-
<TextInput
|
|
135
|
-
editable={!disabled}
|
|
136
|
-
textAlignVertical="top"
|
|
137
|
-
ref={inputRef}
|
|
138
|
-
style={[
|
|
139
|
-
styles.input,
|
|
140
|
-
{
|
|
141
|
-
color: textColor,
|
|
142
|
-
},
|
|
143
|
-
]}
|
|
144
|
-
value={value}
|
|
145
|
-
onChangeText={_onChangeText}
|
|
146
|
-
onFocus={_onFocus}
|
|
147
|
-
onBlur={_onBlur}
|
|
148
|
-
placeholder={placeholder}
|
|
149
|
-
selectionColor={theme.colors.primary}
|
|
150
|
-
placeholderTextColor={placeholderColor}
|
|
151
|
-
/>
|
|
152
|
-
</View>
|
|
153
|
-
<View style={styles.iconView}>
|
|
154
|
-
{focused && (
|
|
155
|
-
<TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
|
|
156
|
-
<Image
|
|
157
|
-
tintColor={theme.colors.text.hint}
|
|
158
|
-
source={{uri: ic_clear}}
|
|
159
|
-
style={styles.iconClose}
|
|
160
|
-
/>
|
|
161
|
-
</TouchableOpacity>
|
|
162
|
-
)}
|
|
163
|
-
{icon && (
|
|
164
|
-
<Image
|
|
165
|
-
tintColor={iconTintColor}
|
|
166
|
-
source={{uri: icon}}
|
|
167
|
-
style={styles.icon}
|
|
168
|
-
/>
|
|
169
|
-
)}
|
|
170
|
-
</View>
|
|
171
|
-
</View>
|
|
172
|
-
);
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const renderErrorView = () => {
|
|
176
|
-
if (errorMessage) {
|
|
177
|
-
return (
|
|
178
|
-
<View style={styles.errorView}>
|
|
179
|
-
<Image style={styles.errorIcon} source={{uri: errorMessageIcon}} />
|
|
180
|
-
<Text color={theme.colors.error.primary} typography={'description_s'}>
|
|
181
|
-
{errorMessage}
|
|
182
|
-
</Text>
|
|
183
|
-
</View>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
return (
|
|
189
|
-
<View style={styles.wrapper}>
|
|
190
|
-
{renderInputView()}
|
|
191
|
-
{renderErrorView()}
|
|
192
|
-
</View>
|
|
193
|
-
);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
Input.defaultProps = {
|
|
197
|
-
size: 'large',
|
|
198
|
-
maxLength: MAX_LENGTH,
|
|
199
|
-
};
|
|
200
26
|
export {Input, TextArea};
|
package/Input/styles.ts
CHANGED
|
@@ -29,7 +29,7 @@ export default StyleSheet.create({
|
|
|
29
29
|
flexDirection: 'row',
|
|
30
30
|
},
|
|
31
31
|
floatingIcon: {width: 16, height: 16, marginLeft: Spacing.XS},
|
|
32
|
-
errorIcon: {
|
|
32
|
+
errorIcon: {marginRight: Spacing.XS},
|
|
33
33
|
errorView: {
|
|
34
34
|
flexDirection: 'row',
|
|
35
35
|
alignItems: 'center',
|
|
@@ -38,10 +38,6 @@ export default StyleSheet.create({
|
|
|
38
38
|
justifyContent: 'space-between',
|
|
39
39
|
flex: 1,
|
|
40
40
|
},
|
|
41
|
-
iconClose: {
|
|
42
|
-
width: 16,
|
|
43
|
-
height: 16,
|
|
44
|
-
},
|
|
45
41
|
iconView: {
|
|
46
42
|
flexDirection: 'row',
|
|
47
43
|
alignItems: 'center',
|
package/Layout/GridSystem.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {ApplicationContext} from '../Navigation';
|
|
|
5
5
|
import {useGridSystem} from './index';
|
|
6
6
|
import {Colors, Spacing} from '../Consts';
|
|
7
7
|
|
|
8
|
-
const GridSystem: React.FC
|
|
8
|
+
const GridSystem: React.FC = () => {
|
|
9
9
|
const {theme} = useContext(ApplicationContext);
|
|
10
10
|
const grid = useGridSystem();
|
|
11
11
|
const insets = useSafeAreaInsets();
|
|
@@ -1,33 +1,26 @@
|
|
|
1
1
|
import {KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native';
|
|
2
2
|
import {useHeaderHeight} from '@react-navigation/stack';
|
|
3
3
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
|
4
|
-
import React
|
|
4
|
+
import React from 'react';
|
|
5
5
|
import {ScreenContainerProps} from '../Navigation/types';
|
|
6
|
-
import {ApplicationContext} from '../Navigation';
|
|
7
6
|
import {Spacing, Styles} from '../Consts';
|
|
8
7
|
import {ScreenSection, validateChildren} from './index';
|
|
9
8
|
|
|
10
9
|
const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
11
10
|
children,
|
|
12
|
-
navigation,
|
|
13
|
-
options,
|
|
14
11
|
edges,
|
|
15
12
|
enableKeyboardAvoidingView,
|
|
16
13
|
scrollable,
|
|
17
14
|
}) => {
|
|
18
15
|
let Component: any = View;
|
|
19
|
-
const {theme} = useContext(ApplicationContext);
|
|
20
16
|
const headerHeight = useHeaderHeight();
|
|
21
17
|
if (scrollable) {
|
|
22
18
|
Component = ScrollView;
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
}, [navigation, options]);
|
|
30
|
-
|
|
21
|
+
/**
|
|
22
|
+
* build content for screen
|
|
23
|
+
*/
|
|
31
24
|
const renderContent = () => {
|
|
32
25
|
const results = validateChildren(children, ScreenSection);
|
|
33
26
|
if (Array.isArray(results)) {
|
|
@@ -48,14 +41,7 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
48
41
|
};
|
|
49
42
|
|
|
50
43
|
return (
|
|
51
|
-
<SafeAreaView
|
|
52
|
-
style={[
|
|
53
|
-
Styles.flex,
|
|
54
|
-
{
|
|
55
|
-
backgroundColor: theme.colors.background.default,
|
|
56
|
-
},
|
|
57
|
-
]}
|
|
58
|
-
edges={edges}>
|
|
44
|
+
<SafeAreaView style={Styles.flex} edges={edges}>
|
|
59
45
|
<KeyboardAvoidingView
|
|
60
46
|
style={Styles.flex}
|
|
61
47
|
keyboardVerticalOffset={headerHeight}
|
package/Layout/ScreenSection.tsx
CHANGED
|
@@ -7,6 +7,9 @@ import {ScreenSectionProps} from './types';
|
|
|
7
7
|
const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
8
8
|
const grid = useGridSystem();
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* render overlay only dev mode
|
|
12
|
+
*/
|
|
10
13
|
const renderOverlay = () => {
|
|
11
14
|
return (
|
|
12
15
|
<View
|
|
@@ -24,6 +27,12 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
|
24
27
|
);
|
|
25
28
|
};
|
|
26
29
|
|
|
30
|
+
/**
|
|
31
|
+
* build a row view in side session
|
|
32
|
+
* @param rows
|
|
33
|
+
* @param cursor
|
|
34
|
+
* @param endRow
|
|
35
|
+
*/
|
|
27
36
|
const addRowView = (
|
|
28
37
|
rows: any[],
|
|
29
38
|
cursor: number = 0,
|
|
@@ -50,6 +59,10 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
|
50
59
|
);
|
|
51
60
|
};
|
|
52
61
|
|
|
62
|
+
/**
|
|
63
|
+
* render children content for session
|
|
64
|
+
* @param children
|
|
65
|
+
*/
|
|
53
66
|
const renderView = (
|
|
54
67
|
children: any,
|
|
55
68
|
): React.ReactElement | React.ReactElement[] => {
|
package/Layout/SectionItem.tsx
CHANGED
package/Layout/utils.ts
CHANGED
|
@@ -2,6 +2,10 @@ import {Alert, Dimensions} from 'react-native';
|
|
|
2
2
|
import React, {ReactElement} from 'react';
|
|
3
3
|
import {GutterSize, NumberOfColumns, ScreenPadding} from '../Consts';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* hook component for use grid system
|
|
7
|
+
* @param useMargin
|
|
8
|
+
*/
|
|
5
9
|
const useGridSystem = (useMargin: boolean = true) => {
|
|
6
10
|
const isDevMode = false;
|
|
7
11
|
const gutterSize = GutterSize;
|
|
@@ -12,6 +16,10 @@ const useGridSystem = (useMargin: boolean = true) => {
|
|
|
12
16
|
const totalGutterSize = gutterSize * (numberOfColumns - 1);
|
|
13
17
|
const sizePerSpan = (parentWidth - totalGutterSize) / numberOfColumns;
|
|
14
18
|
|
|
19
|
+
/**
|
|
20
|
+
* get size of element with number span
|
|
21
|
+
* @param span
|
|
22
|
+
*/
|
|
15
23
|
const getSizeSpan = (span: number = numberOfColumns): number => {
|
|
16
24
|
return span * sizePerSpan + (span - 1) * gutterSize;
|
|
17
25
|
};
|
|
@@ -25,6 +33,12 @@ const useGridSystem = (useMargin: boolean = true) => {
|
|
|
25
33
|
getSizeSpan,
|
|
26
34
|
};
|
|
27
35
|
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* validate children type
|
|
39
|
+
* @param children
|
|
40
|
+
* @param childrenType
|
|
41
|
+
*/
|
|
28
42
|
const validateChildren = (
|
|
29
43
|
children:
|
|
30
44
|
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
2
|
import {StatusBar, StyleSheet, View} from 'react-native';
|
|
3
3
|
import {ApplicationContext, NavigationButton} from './index';
|
|
4
|
-
import {Styles} from '../Consts';
|
|
4
|
+
import {Colors, Styles} from '../Consts';
|
|
5
5
|
import {Image} from '../Image';
|
|
6
|
+
import {HeaderBackgroundProps, TitleCustomProps} from './types';
|
|
7
|
+
import {useGridSystem} from '../Layout';
|
|
8
|
+
import {Text} from '../Text';
|
|
6
9
|
|
|
7
10
|
const styles = StyleSheet.create({
|
|
8
11
|
headerBackground: {
|
|
@@ -11,9 +14,24 @@ const styles = StyleSheet.create({
|
|
|
11
14
|
position: 'absolute',
|
|
12
15
|
aspectRatio: 375 / 154,
|
|
13
16
|
},
|
|
17
|
+
headerTitleContainer: {
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
justifyContent: 'center',
|
|
20
|
+
},
|
|
21
|
+
avatar: {width: 36, height: 36, borderRadius: 18},
|
|
22
|
+
dotAvatar: {
|
|
23
|
+
position: 'absolute',
|
|
24
|
+
width: 12,
|
|
25
|
+
height: 12,
|
|
26
|
+
borderRadius: 6,
|
|
27
|
+
bottom: 0,
|
|
28
|
+
right: 0,
|
|
29
|
+
borderWidth: 1,
|
|
30
|
+
borderColor: Colors.black_01,
|
|
31
|
+
},
|
|
14
32
|
});
|
|
15
33
|
|
|
16
|
-
const HeaderBackground = () => {
|
|
34
|
+
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({image}) => {
|
|
17
35
|
const {theme} = useContext(ApplicationContext);
|
|
18
36
|
return (
|
|
19
37
|
<View
|
|
@@ -21,15 +39,45 @@ const HeaderBackground = () => {
|
|
|
21
39
|
Styles.flex,
|
|
22
40
|
{backgroundColor: theme.colors.background.surface, overflow: 'hidden'},
|
|
23
41
|
]}>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
<StatusBar
|
|
43
|
+
barStyle={image || theme.dark ? 'light-content' : 'dark-content'}
|
|
44
|
+
/>
|
|
45
|
+
{image && <Image style={styles.headerBackground} source={{uri: image}} />}
|
|
46
|
+
</View>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
51
|
+
title,
|
|
52
|
+
subTitle,
|
|
53
|
+
image,
|
|
54
|
+
content,
|
|
55
|
+
tintColor,
|
|
56
|
+
dotColor,
|
|
57
|
+
}) => {
|
|
58
|
+
const {getSizeSpan} = useGridSystem();
|
|
59
|
+
|
|
60
|
+
const header = (
|
|
61
|
+
<View style={Styles.row}>
|
|
62
|
+
<View>
|
|
63
|
+
<Image source={{uri: image}} style={styles.avatar} />
|
|
64
|
+
{dotColor && (
|
|
65
|
+
<View style={[styles.dotAvatar, {backgroundColor: dotColor}]} />
|
|
66
|
+
)}
|
|
67
|
+
</View>
|
|
68
|
+
<View style={[Styles.flex, Styles.paddingHorizontal8]}>
|
|
69
|
+
<Text typography="title_xs" color={tintColor}>
|
|
70
|
+
{title}
|
|
71
|
+
</Text>
|
|
72
|
+
<Text typography="description_s" color={tintColor}>
|
|
73
|
+
{subTitle}
|
|
74
|
+
</Text>
|
|
75
|
+
</View>
|
|
76
|
+
</View>
|
|
77
|
+
);
|
|
78
|
+
return (
|
|
79
|
+
<View style={[styles.headerTitleContainer, {width: getSizeSpan(10)}]}>
|
|
80
|
+
{content ?? header}
|
|
33
81
|
</View>
|
|
34
82
|
);
|
|
35
83
|
};
|
|
@@ -60,4 +108,4 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
|
|
|
60
108
|
return <View style={Styles.headerRightButton}>{renderAction()}</View>;
|
|
61
109
|
};
|
|
62
110
|
|
|
63
|
-
export {HeaderBackground, HeaderRightAction};
|
|
111
|
+
export {HeaderBackground, HeaderRightAction, HeaderCustom};
|