@momo-kits/foundation 1.0.12 → 1.0.14
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 +1 -1
- package/CheckBox/index.tsx +2 -1
- package/Icon/index.tsx +2 -0
- package/IconButton/index.tsx +1 -0
- package/Image/index.tsx +17 -4
- package/Input/Input.tsx +2 -5
- package/Input/InputMoney.tsx +1 -1
- package/Input/InputSearch.tsx +25 -15
- package/Input/InputTextArea.tsx +1 -1
- package/Input/index.tsx +6 -2
- package/Input/styles.ts +0 -2
- package/Layout/Card.tsx +87 -0
- package/Layout/GridSystem.tsx +19 -4
- package/Layout/ScreenContainer.tsx +57 -8
- package/Layout/{ScreenSection.tsx → Section.tsx} +51 -25
- package/Layout/index.ts +14 -10
- package/Layout/types.ts +11 -2
- package/Layout/utils.ts +2 -35
- package/Navigation/BottomTab.tsx +1 -2
- package/Navigation/Components.tsx +39 -25
- package/Navigation/ModalScreen.tsx +4 -2
- package/Navigation/NavigationButton.tsx +3 -1
- package/Navigation/NavigationContainer.tsx +2 -3
- package/Navigation/StackScreen.tsx +1 -1
- package/Navigation/types.ts +10 -4
- package/Navigation/utils.tsx +32 -17
- package/Popup/PopupNotify.tsx +1 -0
- package/Popup/PopupPromotion.tsx +4 -5
- package/Radio/index.tsx +1 -0
- package/Skeleton/index.tsx +1 -1
- package/Switch/index.tsx +1 -0
- package/Text/index.tsx +12 -2
- package/package.json +1 -1
- package/Layout/SectionItem.tsx +0 -63
package/Button/index.tsx
CHANGED
|
@@ -10,7 +10,6 @@ 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 {Image} from '../Image';
|
|
14
13
|
import {Icon} from '../Icon';
|
|
15
14
|
|
|
16
15
|
export interface ButtonProps extends TouchableOpacityProps {
|
|
@@ -224,6 +223,7 @@ const Button: FC<ButtonProps> = ({
|
|
|
224
223
|
return (
|
|
225
224
|
<TouchableOpacity
|
|
226
225
|
{...rest}
|
|
226
|
+
accessibilityLabel={`Button/${title}`}
|
|
227
227
|
activeOpacity={activeOpacity}
|
|
228
228
|
onPress={onPressButton}
|
|
229
229
|
style={buttonStyle}>
|
package/CheckBox/index.tsx
CHANGED
|
@@ -35,6 +35,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
35
35
|
};
|
|
36
36
|
return (
|
|
37
37
|
<TouchableOpacity
|
|
38
|
+
accessibilityLabel={`CheckBox/${label}`}
|
|
38
39
|
activeOpacity={0.8}
|
|
39
40
|
onPress={onChangeValue}
|
|
40
41
|
disabled={disabled}
|
|
@@ -48,7 +49,7 @@ const CheckBox: FC<CheckBoxProps> = props => {
|
|
|
48
49
|
/>
|
|
49
50
|
)}
|
|
50
51
|
</View>
|
|
51
|
-
<Text typography={'description_default'}>{label}</Text>
|
|
52
|
+
{!!label && <Text typography={'description_default'}>{label}</Text>}
|
|
52
53
|
</TouchableOpacity>
|
|
53
54
|
);
|
|
54
55
|
};
|
package/Icon/index.tsx
CHANGED
|
@@ -20,6 +20,8 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
|
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
22
|
<Image
|
|
23
|
+
accessibilityLabel={`Icon/${getIconSource()}`}
|
|
24
|
+
loading={false}
|
|
23
25
|
source={getIconSource()}
|
|
24
26
|
style={[style, {width: size, height: size}]}
|
|
25
27
|
tintColor={color ?? theme.colors.text.default}
|
package/IconButton/index.tsx
CHANGED
package/Image/index.tsx
CHANGED
|
@@ -10,11 +10,18 @@ import {FastImagePropsWithoutStyle} from './types';
|
|
|
10
10
|
|
|
11
11
|
export interface ImageProps extends FastImagePropsWithoutStyle {
|
|
12
12
|
style?: StyleProp<ViewStyle>;
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
accessibilityLabel?: string;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
const Image: React.FC<ImageProps> = ({
|
|
17
|
+
const Image: React.FC<ImageProps> = ({
|
|
18
|
+
style,
|
|
19
|
+
source,
|
|
20
|
+
accessibilityLabel,
|
|
21
|
+
...rest
|
|
22
|
+
}) => {
|
|
16
23
|
const {theme} = useContext(ApplicationContext);
|
|
17
|
-
const [loading, setLoading] = useState(
|
|
24
|
+
const [loading, setLoading] = useState(rest.loading);
|
|
18
25
|
const [fail, setFail] = useState(false);
|
|
19
26
|
|
|
20
27
|
/**
|
|
@@ -47,14 +54,16 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
47
54
|
};
|
|
48
55
|
|
|
49
56
|
return (
|
|
50
|
-
<View
|
|
57
|
+
<View
|
|
58
|
+
style={[styles.container, style]}
|
|
59
|
+
accessibilityLabel={`Image/${accessibilityLabel ?? source}`}>
|
|
51
60
|
<FastImage
|
|
52
61
|
{...rest}
|
|
53
62
|
source={source}
|
|
54
63
|
style={styles.image}
|
|
55
64
|
onLoad={() => {
|
|
56
65
|
setFail(false);
|
|
57
|
-
setLoading(
|
|
66
|
+
setLoading(rest.loading);
|
|
58
67
|
}}
|
|
59
68
|
onLoadEnd={() => setLoading(false)}
|
|
60
69
|
onError={() => setFail(true)}
|
|
@@ -64,4 +73,8 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
|
|
|
64
73
|
);
|
|
65
74
|
};
|
|
66
75
|
|
|
76
|
+
Image.defaultProps = {
|
|
77
|
+
loading: true,
|
|
78
|
+
};
|
|
79
|
+
|
|
67
80
|
export {Image};
|
package/Input/Input.tsx
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import {ApplicationContext} from '../Navigation';
|
|
10
10
|
import styles from './styles';
|
|
11
|
-
import {Image} from '../Image';
|
|
12
11
|
import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
|
|
13
12
|
import {InputProps} from './index';
|
|
14
13
|
import {Icon} from '../Icon';
|
|
@@ -112,16 +111,14 @@ const Input: FC<InputProps> = ({
|
|
|
112
111
|
/>
|
|
113
112
|
</TouchableOpacity>
|
|
114
113
|
)}
|
|
115
|
-
{icon &&
|
|
116
|
-
<Icon icon={iconTintColor} source={icon} style={styles.icon} />
|
|
117
|
-
)}
|
|
114
|
+
{icon && <Icon color={iconTintColor} source={icon} size={24} />}
|
|
118
115
|
</View>
|
|
119
116
|
</View>
|
|
120
117
|
);
|
|
121
118
|
};
|
|
122
119
|
|
|
123
120
|
return (
|
|
124
|
-
<View style={styles.wrapper}>
|
|
121
|
+
<View style={styles.wrapper} accessibilityLabel={`Input`}>
|
|
125
122
|
{renderInputView()}
|
|
126
123
|
<ErrorView errorMessage={errorMessage} />
|
|
127
124
|
</View>
|
package/Input/InputMoney.tsx
CHANGED
package/Input/InputSearch.tsx
CHANGED
|
@@ -7,16 +7,12 @@ import {
|
|
|
7
7
|
View,
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import {InputSearchProps} from './index';
|
|
10
|
-
import {getBorderColor} from './common';
|
|
11
10
|
import {ApplicationContext} from '../Navigation';
|
|
12
11
|
import styles from './styles';
|
|
13
12
|
import {Icon} from '../Icon';
|
|
14
|
-
import {Image} from '../Image';
|
|
15
13
|
import {Text} from '../Text';
|
|
16
14
|
|
|
17
15
|
const InputSearch: FC<InputSearchProps> = ({
|
|
18
|
-
errorMessage,
|
|
19
|
-
disabled,
|
|
20
16
|
placeholder,
|
|
21
17
|
onFocus,
|
|
22
18
|
onBlur,
|
|
@@ -27,6 +23,7 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
27
23
|
buttonText = 'Hủy',
|
|
28
24
|
showButtonText = true,
|
|
29
25
|
showIcon = true,
|
|
26
|
+
showBorder = true,
|
|
30
27
|
style,
|
|
31
28
|
...props
|
|
32
29
|
}) => {
|
|
@@ -54,20 +51,25 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
54
51
|
onChangeText?.(text);
|
|
55
52
|
};
|
|
56
53
|
|
|
54
|
+
const getBorderColor = () => {
|
|
55
|
+
let borderColor = showBorder
|
|
56
|
+
? theme.colors.border.default
|
|
57
|
+
: theme.colors.background.surface;
|
|
58
|
+
|
|
59
|
+
if (focused) {
|
|
60
|
+
borderColor = theme.colors.primary;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {borderColor};
|
|
64
|
+
};
|
|
65
|
+
|
|
57
66
|
const renderInputView = () => {
|
|
58
|
-
const disabledColor = theme.colors.text.disable;
|
|
59
67
|
let textColor = theme.colors.text.default;
|
|
60
68
|
let placeholderColor = theme.colors.text.hint;
|
|
61
69
|
|
|
62
|
-
if (disabled) {
|
|
63
|
-
textColor = disabledColor;
|
|
64
|
-
placeholderColor = disabledColor;
|
|
65
|
-
iconTintColor = disabledColor;
|
|
66
|
-
}
|
|
67
70
|
return (
|
|
68
71
|
<TextInput
|
|
69
72
|
{...props}
|
|
70
|
-
editable={!disabled}
|
|
71
73
|
textAlignVertical="top"
|
|
72
74
|
ref={inputRef}
|
|
73
75
|
style={[
|
|
@@ -112,19 +114,27 @@ const InputSearch: FC<InputSearchProps> = ({
|
|
|
112
114
|
},
|
|
113
115
|
]}
|
|
114
116
|
/>
|
|
115
|
-
<Icon
|
|
117
|
+
<Icon
|
|
118
|
+
color={iconTintColor}
|
|
119
|
+
source={icon}
|
|
120
|
+
style={styles.iconSearchInput}
|
|
121
|
+
/>
|
|
116
122
|
</View>
|
|
117
123
|
)}
|
|
118
124
|
</View>
|
|
119
125
|
);
|
|
120
126
|
};
|
|
121
127
|
return (
|
|
122
|
-
<View
|
|
128
|
+
<View
|
|
129
|
+
style={[style, styles.searchInputContainer]}
|
|
130
|
+
accessibilityLabel={`InputSearch`}>
|
|
123
131
|
<View
|
|
124
132
|
style={[
|
|
125
|
-
getBorderColor(
|
|
133
|
+
getBorderColor(),
|
|
126
134
|
styles.searchInputWrapper,
|
|
127
|
-
{
|
|
135
|
+
{
|
|
136
|
+
backgroundColor: theme.colors.background.surface,
|
|
137
|
+
},
|
|
128
138
|
]}>
|
|
129
139
|
<Icon
|
|
130
140
|
source={'navigation_search'}
|
package/Input/InputTextArea.tsx
CHANGED
|
@@ -138,7 +138,7 @@ const InputTextArea: FC<InputTextAreaProps> = props => {
|
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
return (
|
|
141
|
-
<View style={styles.wrapper}>
|
|
141
|
+
<View style={styles.wrapper} accessibilityLabel={`InputTextArea`}>
|
|
142
142
|
{renderInputView()}
|
|
143
143
|
<ErrorView errorMessage={errorMessage} />
|
|
144
144
|
</View>
|
package/Input/index.tsx
CHANGED
|
@@ -20,17 +20,21 @@ type InputPropsWithoutSizeAndIcon = Omit<
|
|
|
20
20
|
InputProps,
|
|
21
21
|
'size' | 'icon' | 'iconColor'
|
|
22
22
|
>;
|
|
23
|
-
type
|
|
23
|
+
type InputPropsOmitForSearch = Omit<
|
|
24
|
+
InputProps,
|
|
25
|
+
'required' | 'size' | 'errorMessage' | 'disabled'
|
|
26
|
+
>;
|
|
24
27
|
type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
|
|
25
28
|
|
|
26
29
|
export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
|
|
27
30
|
height?: number;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
export interface InputSearchProps extends
|
|
33
|
+
export interface InputSearchProps extends InputPropsOmitForSearch {
|
|
31
34
|
buttonText?: string;
|
|
32
35
|
showButtonText?: boolean;
|
|
33
36
|
showIcon?: boolean;
|
|
37
|
+
showBorder?: boolean;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
|
package/Input/styles.ts
CHANGED
package/Layout/Card.tsx
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
|
|
4
|
+
import {CardProps, GridContextProps} from './types';
|
|
5
|
+
import {GridContext} from './index';
|
|
6
|
+
|
|
7
|
+
const Card: React.FC<CardProps> = ({
|
|
8
|
+
widthSpan = 12,
|
|
9
|
+
heightSpan,
|
|
10
|
+
usePadding,
|
|
11
|
+
children,
|
|
12
|
+
style,
|
|
13
|
+
}) => {
|
|
14
|
+
const grid = useContext(GridContext);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* render overlay view only dev mode
|
|
18
|
+
*/
|
|
19
|
+
const renderOverlay = () => {
|
|
20
|
+
return (
|
|
21
|
+
<View
|
|
22
|
+
pointerEvents={'none'}
|
|
23
|
+
style={{
|
|
24
|
+
position: 'absolute',
|
|
25
|
+
top: 0,
|
|
26
|
+
bottom: 0,
|
|
27
|
+
left: 0,
|
|
28
|
+
right: 0,
|
|
29
|
+
borderColor: 'red',
|
|
30
|
+
borderWidth: 1,
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const styles: any = style ?? {};
|
|
37
|
+
|
|
38
|
+
const numberOfColumns = 12;
|
|
39
|
+
const gutterSize = 8;
|
|
40
|
+
let margin = 0;
|
|
41
|
+
if (usePadding) {
|
|
42
|
+
margin = 12;
|
|
43
|
+
}
|
|
44
|
+
const widthSection = grid.getSizeSpan(widthSpan) - margin * 2;
|
|
45
|
+
const totalGutterSize = gutterSize * (numberOfColumns - 1);
|
|
46
|
+
const sizePerSpan = (widthSection - totalGutterSize) / numberOfColumns;
|
|
47
|
+
const gridContext: GridContextProps = {
|
|
48
|
+
numberOfColumns,
|
|
49
|
+
gutterSize,
|
|
50
|
+
margin,
|
|
51
|
+
sizePerSpan,
|
|
52
|
+
getSizeSpan: span => {
|
|
53
|
+
return span * sizePerSpan + (span - 1) * gutterSize;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View
|
|
59
|
+
accessibilityLabel={`Card`}
|
|
60
|
+
style={{
|
|
61
|
+
...styles,
|
|
62
|
+
width: grid.getSizeSpan(widthSpan),
|
|
63
|
+
height: heightSpan ? grid.getSizeSpan(heightSpan) : undefined,
|
|
64
|
+
paddingHorizontal: margin,
|
|
65
|
+
overflow: 'hidden',
|
|
66
|
+
margin: undefined,
|
|
67
|
+
marginTop: undefined,
|
|
68
|
+
marginBottom: undefined,
|
|
69
|
+
marginLeft: undefined,
|
|
70
|
+
marginRight: undefined,
|
|
71
|
+
}}>
|
|
72
|
+
<GridContext.Provider value={gridContext}>
|
|
73
|
+
{children}
|
|
74
|
+
</GridContext.Provider>
|
|
75
|
+
{__DEV__ && renderOverlay()}
|
|
76
|
+
</View>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
Card.defaultProps = {
|
|
81
|
+
widthSpan: 12,
|
|
82
|
+
usePadding: false,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
Card.displayName = 'Card';
|
|
86
|
+
|
|
87
|
+
export default Card;
|
package/Layout/GridSystem.tsx
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
2
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
3
|
-
import {StyleSheet, View} from 'react-native';
|
|
3
|
+
import {Dimensions, StyleSheet, View} from 'react-native';
|
|
4
4
|
import {ApplicationContext} from '../Navigation';
|
|
5
|
-
import {useGridSystem} from './index';
|
|
6
5
|
import {Colors, Spacing} from '../Consts';
|
|
6
|
+
import {GridContextProps} from './types';
|
|
7
7
|
|
|
8
8
|
const GridSystem: React.FC = () => {
|
|
9
9
|
const {theme} = useContext(ApplicationContext);
|
|
10
|
-
const
|
|
10
|
+
const numberOfColumns = 12;
|
|
11
|
+
const gutterSize = 12;
|
|
12
|
+
const margin = 12;
|
|
13
|
+
const widthSection = Dimensions.get('window').width - margin * 2;
|
|
14
|
+
const totalGutterSize = gutterSize * (numberOfColumns - 1);
|
|
15
|
+
const sizePerSpan = (widthSection - totalGutterSize) / numberOfColumns;
|
|
16
|
+
|
|
17
|
+
const grid: GridContextProps = {
|
|
18
|
+
numberOfColumns,
|
|
19
|
+
gutterSize,
|
|
20
|
+
margin,
|
|
21
|
+
sizePerSpan,
|
|
22
|
+
getSizeSpan: span => {
|
|
23
|
+
return span * sizePerSpan + (span - 1) * gutterSize;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
11
26
|
const insets = useSafeAreaInsets();
|
|
12
27
|
|
|
13
28
|
const list = [];
|
|
@@ -24,7 +39,7 @@ const GridSystem: React.FC = () => {
|
|
|
24
39
|
insets,
|
|
25
40
|
{
|
|
26
41
|
borderColor: theme.colors.error.primary,
|
|
27
|
-
marginHorizontal: grid.
|
|
42
|
+
marginHorizontal: grid.margin,
|
|
28
43
|
},
|
|
29
44
|
]}>
|
|
30
45
|
{list.map((i, index) => {
|
|
@@ -1,36 +1,60 @@
|
|
|
1
|
-
import {KeyboardAvoidingView, Platform,
|
|
1
|
+
import {Animated, KeyboardAvoidingView, Platform, View} from 'react-native';
|
|
2
2
|
import {useHeaderHeight} from '@react-navigation/stack';
|
|
3
3
|
import {SafeAreaView} from 'react-native-safe-area-context';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import {ScreenContainerProps} from '../Navigation/types';
|
|
6
6
|
import {Spacing, Styles} from '../Consts';
|
|
7
|
-
import {
|
|
7
|
+
import {Section, validateChildren} from './index';
|
|
8
8
|
|
|
9
9
|
const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
10
10
|
children,
|
|
11
11
|
edges,
|
|
12
12
|
enableKeyboardAvoidingView,
|
|
13
13
|
scrollable,
|
|
14
|
+
scrollY,
|
|
15
|
+
headerBackground,
|
|
14
16
|
scrollViewProps,
|
|
17
|
+
footerComponent: Footer,
|
|
15
18
|
}) => {
|
|
19
|
+
let marginHeader = 0;
|
|
20
|
+
let handleScroll;
|
|
21
|
+
let imageAnimatedStyle = {};
|
|
16
22
|
let Component: any = View;
|
|
17
23
|
const headerHeight = useHeaderHeight();
|
|
18
24
|
if (scrollable) {
|
|
19
|
-
Component = ScrollView;
|
|
25
|
+
Component = Animated.ScrollView;
|
|
26
|
+
}
|
|
27
|
+
if (scrollY) {
|
|
28
|
+
marginHeader = useHeaderHeight();
|
|
29
|
+
imageAnimatedStyle = {
|
|
30
|
+
transform: [
|
|
31
|
+
{
|
|
32
|
+
scale: scrollY.interpolate?.({
|
|
33
|
+
inputRange: [-300, -110, 100],
|
|
34
|
+
outputRange: [1.75, 1, 1],
|
|
35
|
+
extrapolate: 'clamp',
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
handleScroll = Animated.event(
|
|
41
|
+
[{nativeEvent: {contentOffset: {y: scrollY}}}],
|
|
42
|
+
{useNativeDriver: true},
|
|
43
|
+
);
|
|
20
44
|
}
|
|
21
45
|
|
|
22
46
|
/**
|
|
23
47
|
* build content for screen
|
|
24
48
|
*/
|
|
25
49
|
const renderContent = () => {
|
|
26
|
-
const results = validateChildren(children,
|
|
50
|
+
const results = validateChildren(children, Section);
|
|
27
51
|
if (Array.isArray(results)) {
|
|
28
52
|
return results.map((item, index) => {
|
|
29
53
|
return (
|
|
30
54
|
<View
|
|
31
|
-
key={`
|
|
55
|
+
key={`Section${index}`}
|
|
32
56
|
style={{
|
|
33
|
-
|
|
57
|
+
marginTop: item.props?.useMargin ? Spacing.M : 0,
|
|
34
58
|
flex: item.props?.expanded ? 1 : undefined,
|
|
35
59
|
}}>
|
|
36
60
|
{item}
|
|
@@ -42,7 +66,28 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
42
66
|
};
|
|
43
67
|
|
|
44
68
|
return (
|
|
45
|
-
<SafeAreaView
|
|
69
|
+
<SafeAreaView
|
|
70
|
+
style={Styles.flex}
|
|
71
|
+
edges={edges}
|
|
72
|
+
accessibilityLabel={`ScreenContainer`}>
|
|
73
|
+
<View
|
|
74
|
+
style={{
|
|
75
|
+
position: 'absolute',
|
|
76
|
+
height: 300,
|
|
77
|
+
width: '100%',
|
|
78
|
+
}}>
|
|
79
|
+
{headerBackground && (
|
|
80
|
+
<Animated.Image
|
|
81
|
+
source={{
|
|
82
|
+
uri: headerBackground,
|
|
83
|
+
}}
|
|
84
|
+
style={{
|
|
85
|
+
aspectRatio: 1.3,
|
|
86
|
+
...imageAnimatedStyle,
|
|
87
|
+
}}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
</View>
|
|
46
91
|
<KeyboardAvoidingView
|
|
47
92
|
style={Styles.flex}
|
|
48
93
|
keyboardVerticalOffset={headerHeight}
|
|
@@ -51,9 +96,13 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
|
|
|
51
96
|
ios: 'padding',
|
|
52
97
|
android: undefined,
|
|
53
98
|
})}>
|
|
54
|
-
<Component
|
|
99
|
+
<Component
|
|
100
|
+
{...scrollViewProps}
|
|
101
|
+
onScroll={handleScroll}
|
|
102
|
+
style={[Styles.flex, {marginTop: marginHeader}]}>
|
|
55
103
|
{renderContent()}
|
|
56
104
|
</Component>
|
|
105
|
+
{Footer && <Section>{Footer}</Section>}
|
|
57
106
|
</KeyboardAvoidingView>
|
|
58
107
|
</SafeAreaView>
|
|
59
108
|
);
|
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {View} from 'react-native';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
2
|
+
import {Dimensions, View} from 'react-native';
|
|
3
|
+
import {validateChildren} from './utils';
|
|
4
|
+
import Card from './Card';
|
|
5
|
+
import {GridContextProps, SectionProps} from './types';
|
|
6
|
+
import {GridContext} from './index';
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
8
|
+
const Section: React.FC<SectionProps> = ({children, useMargin = true}) => {
|
|
9
|
+
const numberOfColumns = 12;
|
|
10
|
+
const gutterSize = 12;
|
|
11
|
+
let margin = 0;
|
|
12
|
+
if (useMargin) {
|
|
13
|
+
margin = 12;
|
|
14
|
+
}
|
|
15
|
+
let widthSection = Dimensions.get('window').width;
|
|
16
|
+
if (useMargin) widthSection = widthSection - margin * 2;
|
|
17
|
+
const totalGutterSize = gutterSize * (numberOfColumns - 1);
|
|
18
|
+
const sizePerSpan = (widthSection - totalGutterSize) / numberOfColumns;
|
|
19
|
+
|
|
20
|
+
const gridContext: GridContextProps = {
|
|
21
|
+
numberOfColumns,
|
|
22
|
+
gutterSize,
|
|
23
|
+
margin,
|
|
24
|
+
sizePerSpan,
|
|
25
|
+
getSizeSpan: span => {
|
|
26
|
+
return span * sizePerSpan + (span - 1) * gutterSize;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
9
29
|
|
|
10
30
|
/**
|
|
11
31
|
* render overlay only dev mode
|
|
@@ -40,17 +60,17 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
|
40
60
|
) => {
|
|
41
61
|
return (
|
|
42
62
|
<View
|
|
43
|
-
key={`
|
|
63
|
+
key={`Card${cursor}`}
|
|
44
64
|
style={{
|
|
45
65
|
flexDirection: 'row',
|
|
46
|
-
marginBottom: endRow ? 0 :
|
|
66
|
+
marginBottom: endRow ? 0 : gridContext.gutterSize,
|
|
47
67
|
}}>
|
|
48
68
|
{rows.map((i: React.ReactElement, index: number) => {
|
|
49
69
|
return (
|
|
50
|
-
<View
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
<View key={`Card${cursor}${index}`} style={{flexDirection: 'row'}}>
|
|
71
|
+
{index != 0 && (
|
|
72
|
+
<View style={{width: gridContext.gutterSize}}></View>
|
|
73
|
+
)}
|
|
54
74
|
{i}
|
|
55
75
|
</View>
|
|
56
76
|
);
|
|
@@ -79,7 +99,7 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
|
79
99
|
return previousValue + currentValue;
|
|
80
100
|
});
|
|
81
101
|
|
|
82
|
-
if (totalSpan <=
|
|
102
|
+
if (totalSpan <= gridContext.numberOfColumns) {
|
|
83
103
|
rows.push(item);
|
|
84
104
|
} else {
|
|
85
105
|
cursor += 1;
|
|
@@ -99,19 +119,25 @@ const ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
|
|
|
99
119
|
};
|
|
100
120
|
|
|
101
121
|
return (
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
122
|
+
<GridContext.Provider value={gridContext}>
|
|
123
|
+
<View
|
|
124
|
+
accessibilityLabel={`Section`}
|
|
125
|
+
style={{
|
|
126
|
+
width: gridContext.getSizeSpan(12),
|
|
127
|
+
marginHorizontal: gridContext.margin,
|
|
128
|
+
flexDirection: 'row',
|
|
129
|
+
flexWrap: 'wrap',
|
|
130
|
+
}}>
|
|
131
|
+
{renderView(validateChildren(children, Card))}
|
|
132
|
+
{__DEV__ && renderOverlay()}
|
|
133
|
+
</View>
|
|
134
|
+
</GridContext.Provider>
|
|
112
135
|
);
|
|
113
136
|
};
|
|
114
137
|
|
|
115
|
-
|
|
138
|
+
Section.displayName = 'Section';
|
|
116
139
|
|
|
117
|
-
|
|
140
|
+
Section.defaultProps = {
|
|
141
|
+
useMargin: true,
|
|
142
|
+
};
|
|
143
|
+
export default Section;
|
package/Layout/index.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import Card from './Card';
|
|
2
|
+
import Section from './Section';
|
|
3
3
|
import GridSystem from './GridSystem';
|
|
4
|
-
import {
|
|
4
|
+
import {validateChildren} from './utils';
|
|
5
|
+
import {createContext} from 'react';
|
|
6
|
+
import {GridContextProps} from './types';
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
8
|
+
const GridContext = createContext<GridContextProps>({
|
|
9
|
+
numberOfColumns: 12,
|
|
10
|
+
gutterSize: 12,
|
|
11
|
+
margin: 12,
|
|
12
|
+
sizePerSpan: 0,
|
|
13
|
+
getSizeSpan: span => 0,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export {GridContext, Card, Section, GridSystem, validateChildren};
|
package/Layout/types.ts
CHANGED
|
@@ -2,11 +2,20 @@ import {ViewProps} from 'react-native';
|
|
|
2
2
|
|
|
3
3
|
type SpanNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export type GridContextProps = {
|
|
6
|
+
numberOfColumns: number;
|
|
7
|
+
gutterSize: number;
|
|
8
|
+
margin?: number;
|
|
9
|
+
sizePerSpan: number;
|
|
10
|
+
getSizeSpan: (span: number) => number;
|
|
11
|
+
};
|
|
12
|
+
export interface SectionProps extends ViewProps {
|
|
6
13
|
expanded?: boolean;
|
|
14
|
+
useMargin?: boolean;
|
|
7
15
|
}
|
|
8
16
|
|
|
9
|
-
export interface
|
|
17
|
+
export interface CardProps extends ViewProps {
|
|
10
18
|
widthSpan: SpanNumber;
|
|
11
19
|
heightSpan?: SpanNumber;
|
|
20
|
+
usePadding?: boolean;
|
|
12
21
|
}
|
package/Layout/utils.ts
CHANGED
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
import {Alert
|
|
1
|
+
import {Alert} from 'react-native';
|
|
2
2
|
import React, {ReactElement} from 'react';
|
|
3
|
-
import {GutterSize, NumberOfColumns, ScreenPadding} from '../Consts';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* hook component for use grid system
|
|
7
|
-
* @param useMargin
|
|
8
|
-
*/
|
|
9
|
-
const useGridSystem = (useMargin: boolean = true) => {
|
|
10
|
-
const isDevMode = false;
|
|
11
|
-
const gutterSize = GutterSize;
|
|
12
|
-
const screenPadding = useMargin ? ScreenPadding : 0;
|
|
13
|
-
const numberOfColumns = NumberOfColumns;
|
|
14
|
-
const widthDevice = Dimensions.get('window').width;
|
|
15
|
-
const parentWidth = widthDevice - screenPadding * 2;
|
|
16
|
-
const totalGutterSize = gutterSize * (numberOfColumns - 1);
|
|
17
|
-
const sizePerSpan = (parentWidth - totalGutterSize) / numberOfColumns;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* get size of element with number span
|
|
21
|
-
* @param span
|
|
22
|
-
*/
|
|
23
|
-
const getSizeSpan = (span: number = numberOfColumns): number => {
|
|
24
|
-
return span * sizePerSpan + (span - 1) * gutterSize;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
isDevMode,
|
|
29
|
-
gutterSize,
|
|
30
|
-
screenPadding,
|
|
31
|
-
numberOfColumns,
|
|
32
|
-
sizePerSpan,
|
|
33
|
-
getSizeSpan,
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
3
|
|
|
37
4
|
/**
|
|
38
5
|
* validate children type
|
|
@@ -80,4 +47,4 @@ const validateChildren = (
|
|
|
80
47
|
return results;
|
|
81
48
|
};
|
|
82
49
|
|
|
83
|
-
export {
|
|
50
|
+
export {validateChildren};
|
package/Navigation/BottomTab.tsx
CHANGED
|
@@ -10,11 +10,10 @@ const BottomTab: FC<BottomTabProps> = ({tabs}) => {
|
|
|
10
10
|
<Tab.Navigator>
|
|
11
11
|
{tabs.map((item, index) => {
|
|
12
12
|
return (
|
|
13
|
-
// @ts-ignore
|
|
14
13
|
<Tab.Screen
|
|
15
14
|
key={`${item.label}-${index}`}
|
|
16
15
|
name={item.label}
|
|
17
|
-
component={item.
|
|
16
|
+
component={item.screen}
|
|
18
17
|
options={{
|
|
19
18
|
tabBarLabel: item.label,
|
|
20
19
|
tabBarBadge: item?.badgeLabel,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
DeviceEventEmitter,
|
|
4
5
|
StatusBar,
|
|
5
6
|
StyleSheet,
|
|
@@ -10,7 +11,6 @@ import {ApplicationContext, NavigationButton} from './index';
|
|
|
10
11
|
import {Colors, Spacing, Styles} from '../Consts';
|
|
11
12
|
import {Image} from '../Image';
|
|
12
13
|
import {HeaderBackgroundProps, TitleCustomProps} from './types';
|
|
13
|
-
import {useGridSystem} from '../Layout';
|
|
14
14
|
import {Text} from '../Text';
|
|
15
15
|
import {Icon} from '../Icon';
|
|
16
16
|
|
|
@@ -24,6 +24,7 @@ const styles = StyleSheet.create({
|
|
|
24
24
|
headerTitleContainer: {
|
|
25
25
|
alignItems: 'center',
|
|
26
26
|
justifyContent: 'center',
|
|
27
|
+
width: '100%',
|
|
27
28
|
},
|
|
28
29
|
avatar: {width: 36, height: 36, borderRadius: 18},
|
|
29
30
|
dotAvatar: {
|
|
@@ -47,7 +48,6 @@ const styles = StyleSheet.create({
|
|
|
47
48
|
marginLeft: Spacing.S,
|
|
48
49
|
padding: Spacing.XS,
|
|
49
50
|
height: 28,
|
|
50
|
-
borderWidth: 0.5,
|
|
51
51
|
borderRadius: 14,
|
|
52
52
|
borderColor: '#00000066',
|
|
53
53
|
justifyContent: 'center',
|
|
@@ -62,15 +62,20 @@ const styles = StyleSheet.create({
|
|
|
62
62
|
headerLeft: {
|
|
63
63
|
marginLeft: 12,
|
|
64
64
|
},
|
|
65
|
+
title: {fontSize: 15, lineHeight: 22, fontWeight: '600'},
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
const HeaderTitle =
|
|
68
|
+
const HeaderTitle: React.FC<any> = props => {
|
|
69
|
+
const opacity = props.animatedValue?.interpolate({
|
|
70
|
+
inputRange: [0, 200],
|
|
71
|
+
outputRange: [0, 1],
|
|
72
|
+
extrapolate: 'clamp',
|
|
73
|
+
});
|
|
68
74
|
return (
|
|
69
|
-
<Text
|
|
75
|
+
<Animated.Text
|
|
70
76
|
{...props}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
color={props.tintColor}
|
|
77
|
+
accessibilityLabel={`HeaderTitle/${props.children}`}
|
|
78
|
+
style={[styles.title, {opacity, color: props.tintColor}]}
|
|
74
79
|
/>
|
|
75
80
|
);
|
|
76
81
|
};
|
|
@@ -90,7 +95,12 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
|
|
|
90
95
|
|
|
91
96
|
return (
|
|
92
97
|
<View style={styles.headerLeft}>
|
|
93
|
-
<NavigationButton
|
|
98
|
+
<NavigationButton
|
|
99
|
+
icon="ic_back"
|
|
100
|
+
tintColor={tintColor}
|
|
101
|
+
onPress={goBack}
|
|
102
|
+
accessibilityLabel={'Back'}
|
|
103
|
+
/>
|
|
94
104
|
</View>
|
|
95
105
|
);
|
|
96
106
|
};
|
|
@@ -98,19 +108,31 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
|
|
|
98
108
|
const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
99
109
|
image,
|
|
100
110
|
backgroundColor,
|
|
111
|
+
animatedValue,
|
|
101
112
|
}) => {
|
|
102
113
|
const {theme} = useContext(ApplicationContext);
|
|
103
114
|
let headerImage = theme.assets?.headerBackground;
|
|
115
|
+
let borderBottomWidth = 0;
|
|
104
116
|
if (image === null) {
|
|
117
|
+
borderBottomWidth = 1;
|
|
105
118
|
headerImage = undefined;
|
|
106
119
|
}
|
|
120
|
+
const opacity = animatedValue?.interpolate({
|
|
121
|
+
inputRange: [0, 200],
|
|
122
|
+
outputRange: [0, 1],
|
|
123
|
+
extrapolate: 'clamp',
|
|
124
|
+
});
|
|
125
|
+
|
|
107
126
|
return (
|
|
108
|
-
<View
|
|
127
|
+
<Animated.View
|
|
109
128
|
style={[
|
|
110
129
|
Styles.flex,
|
|
111
130
|
{
|
|
112
131
|
backgroundColor: backgroundColor ?? theme.colors.background.default,
|
|
113
132
|
overflow: 'hidden',
|
|
133
|
+
borderBottomWidth: borderBottomWidth,
|
|
134
|
+
borderColor: theme.colors.border.default,
|
|
135
|
+
opacity,
|
|
114
136
|
},
|
|
115
137
|
]}>
|
|
116
138
|
<StatusBar
|
|
@@ -119,7 +141,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
119
141
|
{headerImage && (
|
|
120
142
|
<Image style={styles.headerBackground} source={{uri: headerImage}} />
|
|
121
143
|
)}
|
|
122
|
-
</View>
|
|
144
|
+
</Animated.View>
|
|
123
145
|
);
|
|
124
146
|
};
|
|
125
147
|
|
|
@@ -131,8 +153,6 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
131
153
|
tintColor,
|
|
132
154
|
dotColor,
|
|
133
155
|
}) => {
|
|
134
|
-
const {getSizeSpan} = useGridSystem();
|
|
135
|
-
|
|
136
156
|
const header = (
|
|
137
157
|
<View style={Styles.row}>
|
|
138
158
|
<View>
|
|
@@ -151,11 +171,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
|
|
|
151
171
|
</View>
|
|
152
172
|
</View>
|
|
153
173
|
);
|
|
154
|
-
return
|
|
155
|
-
<View style={[styles.headerTitleContainer, {width: getSizeSpan(10)}]}>
|
|
156
|
-
{content ?? header}
|
|
157
|
-
</View>
|
|
158
|
-
);
|
|
174
|
+
return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
|
|
159
175
|
};
|
|
160
176
|
|
|
161
177
|
const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
|
|
@@ -193,21 +209,19 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
|
|
|
193
209
|
|
|
194
210
|
return (
|
|
195
211
|
<View style={styles.headerRightButton}>
|
|
196
|
-
<NavigationButton
|
|
197
|
-
icon="addFavorite"
|
|
198
|
-
tintColor={tintColor}
|
|
199
|
-
onPress={() => {}}
|
|
200
|
-
/>
|
|
201
212
|
<View
|
|
202
213
|
style={[
|
|
203
214
|
styles.toolkitContainer,
|
|
204
|
-
{
|
|
215
|
+
{
|
|
216
|
+
backgroundColor: backgroundColor ?? '#00000066',
|
|
217
|
+
borderWidth: backgroundColor ? 0.5 : 0,
|
|
218
|
+
},
|
|
205
219
|
]}>
|
|
206
|
-
<TouchableOpacity>
|
|
220
|
+
<TouchableOpacity accessibilityLabel={'Toolkit/More'}>
|
|
207
221
|
<Icon color={tintColor} source="navigation_more_horiz" size={20} />
|
|
208
222
|
</TouchableOpacity>
|
|
209
223
|
<View style={[styles.divider, {backgroundColor: tintColor}]} />
|
|
210
|
-
<TouchableOpacity>
|
|
224
|
+
<TouchableOpacity accessibilityLabel={'Toolkit/Close'}>
|
|
211
225
|
<Icon
|
|
212
226
|
color={tintColor}
|
|
213
227
|
source="16_navigation_close_circle"
|
|
@@ -63,7 +63,7 @@ const Modal: React.FC<ModalParams> = ({navigation, route}) => {
|
|
|
63
63
|
style={styles.modalSpaceVertical}
|
|
64
64
|
onPress={() => onDismiss()}
|
|
65
65
|
/>
|
|
66
|
-
<View style={styles.modalContent}>
|
|
66
|
+
<View style={styles.modalContent} accessibilityLabel={'Modal'}>
|
|
67
67
|
<Component {...params} />
|
|
68
68
|
</View>
|
|
69
69
|
<Pressable
|
|
@@ -128,7 +128,9 @@ const BottomSheet: React.FC<BottomSheetParams> = ({navigation, route}) => {
|
|
|
128
128
|
}}
|
|
129
129
|
handleComponent={null}
|
|
130
130
|
backdropComponent={backdropComponent}>
|
|
131
|
-
<View
|
|
131
|
+
<View
|
|
132
|
+
style={{paddingBottom: bottom}}
|
|
133
|
+
accessibilityLabel={'BottomSheet'}>
|
|
132
134
|
<View style={[styles.sheetContainer, {backgroundColor}]}>
|
|
133
135
|
<View style={styles.indicatorContainer}>
|
|
134
136
|
<View
|
|
@@ -11,6 +11,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
11
11
|
onPress,
|
|
12
12
|
backgroundColor,
|
|
13
13
|
useBorder = true,
|
|
14
|
+
accessibilityLabel,
|
|
14
15
|
}) => {
|
|
15
16
|
const {theme} = useContext(ApplicationContext);
|
|
16
17
|
if (!backgroundColor && tintColor != Colors.black_01) {
|
|
@@ -19,11 +20,12 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
|
|
|
19
20
|
|
|
20
21
|
return (
|
|
21
22
|
<TouchableOpacity
|
|
23
|
+
accessibilityLabel={`NavigationButton/${accessibilityLabel}`}
|
|
22
24
|
style={[
|
|
23
25
|
styles.container,
|
|
24
26
|
{
|
|
25
27
|
backgroundColor: backgroundColor ?? '#00000066',
|
|
26
|
-
borderWidth: useBorder ? 0.5 : 0,
|
|
28
|
+
borderWidth: useBorder && backgroundColor ? 0.5 : 0,
|
|
27
29
|
},
|
|
28
30
|
]}
|
|
29
31
|
onPress={onPress}>
|
|
@@ -10,7 +10,7 @@ import StackScreen from './StackScreen';
|
|
|
10
10
|
import ModalScreen from './ModalScreen';
|
|
11
11
|
import Navigator from './Navigator';
|
|
12
12
|
import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
|
|
13
|
-
import {GridSystem
|
|
13
|
+
import {GridSystem} from '../Layout';
|
|
14
14
|
import {defaultContext} from '../Consts';
|
|
15
15
|
import {NavigationContainerProps} from './types';
|
|
16
16
|
|
|
@@ -22,7 +22,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
22
22
|
theme,
|
|
23
23
|
options,
|
|
24
24
|
}) => {
|
|
25
|
-
const grid = useGridSystem();
|
|
26
25
|
const navigationRef = React.useRef<NavigationContainerRef>(null);
|
|
27
26
|
const navigator = useRef(new Navigator(navigationRef));
|
|
28
27
|
|
|
@@ -75,7 +74,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
75
74
|
</ReactNavigationContainer>
|
|
76
75
|
</ApplicationContext.Provider>
|
|
77
76
|
</BottomSheetModalProvider>
|
|
78
|
-
{
|
|
77
|
+
{__DEV__ && <GridSystem />}
|
|
79
78
|
</SafeAreaProvider>
|
|
80
79
|
);
|
|
81
80
|
};
|
package/Navigation/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {ScrollViewProps, ViewProps} from 'react-native';
|
|
2
|
-
import React
|
|
1
|
+
import {Animated, ScrollViewProps, ViewProps} from 'react-native';
|
|
2
|
+
import React from 'react';
|
|
3
3
|
import Navigator from './Navigator';
|
|
4
4
|
|
|
5
5
|
export type Theme = {
|
|
@@ -71,8 +71,11 @@ export type NavigationContainerProps = {
|
|
|
71
71
|
export interface ScreenContainerProps extends ViewProps {
|
|
72
72
|
edges?: any[];
|
|
73
73
|
enableKeyboardAvoidingView?: boolean;
|
|
74
|
-
|
|
74
|
+
headerBackground?: string;
|
|
75
|
+
scrollable?: boolean;
|
|
76
|
+
scrollY?: Animated.Value;
|
|
75
77
|
scrollViewProps?: ScrollViewProps;
|
|
78
|
+
footerComponent?: React.ElementType;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
export type ScreenParams = {
|
|
@@ -99,6 +102,7 @@ export type NavigationButtonProps = {
|
|
|
99
102
|
backgroundColor?: string;
|
|
100
103
|
useBorder?: boolean;
|
|
101
104
|
onPress: () => void;
|
|
105
|
+
accessibilityLabel?: string;
|
|
102
106
|
};
|
|
103
107
|
|
|
104
108
|
export type NavigationOptions = {
|
|
@@ -107,11 +111,13 @@ export type NavigationOptions = {
|
|
|
107
111
|
headerTitleAlign?: 'left' | 'center';
|
|
108
112
|
customTitle?: TitleCustomProps;
|
|
109
113
|
headerRight?: (props?: any) => React.ReactElement;
|
|
114
|
+
animatedValue?: Animated.Value;
|
|
110
115
|
};
|
|
111
116
|
|
|
112
117
|
export type HeaderBackgroundProps = {
|
|
113
118
|
image?: string | null;
|
|
114
119
|
backgroundColor?: string | null;
|
|
120
|
+
animatedValue?: Animated.Value;
|
|
115
121
|
};
|
|
116
122
|
|
|
117
123
|
export type TitleCustomProps = {
|
|
@@ -128,7 +134,7 @@ export type BottomTabItemProps = {
|
|
|
128
134
|
icon: string;
|
|
129
135
|
showDot?: boolean;
|
|
130
136
|
badgeLabel?: string;
|
|
131
|
-
|
|
137
|
+
screen: React.ComponentType<any>;
|
|
132
138
|
};
|
|
133
139
|
|
|
134
140
|
export type BottomTabProps = {
|
package/Navigation/utils.tsx
CHANGED
|
@@ -73,43 +73,58 @@ const getModalOptions = (): StackNavigationOptions => {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const getOptions = (params: NavigationOptions, theme: Theme) => {
|
|
76
|
-
let
|
|
77
|
-
let
|
|
76
|
+
let backgroundProps = {};
|
|
77
|
+
let titleProps = {};
|
|
78
|
+
let options = {};
|
|
78
79
|
|
|
79
80
|
if (params.surface == true) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<HeaderBackground
|
|
83
|
-
image={null}
|
|
84
|
-
backgroundColor={theme.colors.background.surface}
|
|
85
|
-
/>
|
|
86
|
-
),
|
|
81
|
+
options = {
|
|
82
|
+
...options,
|
|
87
83
|
...getTintColor({
|
|
88
84
|
...theme,
|
|
89
85
|
assets: {...theme.assets, headerBackground: undefined},
|
|
90
86
|
}),
|
|
91
87
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
backgroundProps = {
|
|
89
|
+
...backgroundProps,
|
|
90
|
+
image: null,
|
|
91
|
+
backgroundColor: theme.colors.background.surface,
|
|
96
92
|
};
|
|
93
|
+
} else {
|
|
94
|
+
backgroundProps = {};
|
|
95
|
+
options = {...options, ...getTintColor(theme)};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (params.animatedValue) {
|
|
99
|
+
backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
|
|
100
|
+
titleProps = {...titleProps, animatedValue: params.animatedValue};
|
|
101
|
+
options = {...options, headerTransparent: true};
|
|
102
|
+
} else {
|
|
103
|
+
options = {...options, headerTransparent: false};
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
if (params.customTitle) {
|
|
100
|
-
|
|
107
|
+
options = {
|
|
108
|
+
...options,
|
|
101
109
|
headerTitleAlign: 'left',
|
|
102
110
|
headerTitle: (props: any) => {
|
|
103
111
|
return <HeaderCustom {...params.customTitle} {...props} />;
|
|
104
112
|
},
|
|
105
113
|
};
|
|
106
114
|
} else {
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
options = {
|
|
116
|
+
...options,
|
|
117
|
+
headerTitle: (props: any) => {
|
|
118
|
+
return <HeaderTitle {...titleProps} {...props} />;
|
|
119
|
+
},
|
|
109
120
|
};
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
...params,
|
|
125
|
+
...options,
|
|
126
|
+
headerBackground: () => <HeaderBackground {...backgroundProps} />,
|
|
127
|
+
};
|
|
113
128
|
};
|
|
114
129
|
|
|
115
130
|
export {getStackOptions, getDialogOptions, getModalOptions, getOptions};
|
package/Popup/PopupNotify.tsx
CHANGED
package/Popup/PopupPromotion.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import {StyleSheet, TouchableOpacity, View} from 'react-native';
|
|
|
3
3
|
import {PopupPromotionProps} from './types';
|
|
4
4
|
import {ApplicationContext} from '../Navigation';
|
|
5
5
|
import {Image} from '../Image';
|
|
6
|
-
import {Radius} from '../Consts';
|
|
6
|
+
import {Radius, Spacing} from '../Consts';
|
|
7
7
|
import {Icon} from '../Icon';
|
|
8
8
|
|
|
9
9
|
const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
|
|
@@ -38,7 +38,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
|
|
41
|
+
<View accessibilityLabel={'PopupPromotion'}>
|
|
42
42
|
<Image
|
|
43
43
|
style={styles.container}
|
|
44
44
|
source={{
|
|
@@ -46,7 +46,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({image, onClose}) => {
|
|
|
46
46
|
}}
|
|
47
47
|
/>
|
|
48
48
|
{buildCloseIcon()}
|
|
49
|
-
|
|
49
|
+
</View>
|
|
50
50
|
);
|
|
51
51
|
};
|
|
52
52
|
|
|
@@ -55,11 +55,10 @@ const styles = StyleSheet.create({
|
|
|
55
55
|
aspectRatio: 0.72,
|
|
56
56
|
},
|
|
57
57
|
iconCloseContainer: {
|
|
58
|
-
position: 'absolute',
|
|
59
58
|
width: '100%',
|
|
60
59
|
flexDirection: 'row',
|
|
61
60
|
justifyContent: 'center',
|
|
62
|
-
|
|
61
|
+
marginTop: Spacing.L,
|
|
63
62
|
},
|
|
64
63
|
iconClose: {
|
|
65
64
|
width: 20,
|
package/Radio/index.tsx
CHANGED
package/Skeleton/index.tsx
CHANGED
|
@@ -42,7 +42,7 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
return (
|
|
45
|
-
<View style={[styles.container, style]}>
|
|
45
|
+
<View style={[styles.container, style]} accessibilityLabel={'Skeleton'}>
|
|
46
46
|
<View
|
|
47
47
|
onLayout={e => onLayout(e.nativeEvent.layout.width)}
|
|
48
48
|
style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
|
package/Switch/index.tsx
CHANGED
package/Text/index.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import {Text as RNText, TextProps as RNTextProps} from 'react-native';
|
|
|
3
3
|
import styles from './styles';
|
|
4
4
|
import {Typography, TypographyWeight} from './types';
|
|
5
5
|
import {ApplicationContext} from '../Navigation';
|
|
6
|
+
import {GridContext} from '../Layout';
|
|
6
7
|
|
|
7
8
|
const SFProText: TypographyWeight = {
|
|
8
9
|
100: 'Thin',
|
|
@@ -40,6 +41,7 @@ const FontStyle: {[key: string]: string} = {
|
|
|
40
41
|
export interface TextProps extends RNTextProps {
|
|
41
42
|
typography: Typography;
|
|
42
43
|
color?: string;
|
|
44
|
+
widthSpan?: number;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const Text: React.FC<TextProps> = ({
|
|
@@ -47,8 +49,10 @@ const Text: React.FC<TextProps> = ({
|
|
|
47
49
|
color,
|
|
48
50
|
children,
|
|
49
51
|
style,
|
|
52
|
+
widthSpan,
|
|
50
53
|
...rest
|
|
51
54
|
}) => {
|
|
55
|
+
const grid = useContext(GridContext);
|
|
52
56
|
const {theme} = useContext(ApplicationContext);
|
|
53
57
|
|
|
54
58
|
const getTypoStyle = (typo: Typography) => {
|
|
@@ -83,11 +87,17 @@ const Text: React.FC<TextProps> = ({
|
|
|
83
87
|
};
|
|
84
88
|
|
|
85
89
|
const textStyle = getTypoStyle(typography);
|
|
86
|
-
|
|
90
|
+
const spanStyle = widthSpan ? {width: grid.getSizeSpan(widthSpan)} : {};
|
|
87
91
|
return (
|
|
88
92
|
<RNText
|
|
89
93
|
{...rest}
|
|
90
|
-
|
|
94
|
+
accessibilityLabel={`Text/${children}`}
|
|
95
|
+
style={[
|
|
96
|
+
style,
|
|
97
|
+
textStyle,
|
|
98
|
+
spanStyle,
|
|
99
|
+
{color: color ?? theme.colors.text.default},
|
|
100
|
+
]}>
|
|
91
101
|
{children ?? ''}
|
|
92
102
|
</RNText>
|
|
93
103
|
);
|
package/package.json
CHANGED
package/Layout/SectionItem.tsx
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import React, {useContext} from 'react';
|
|
2
|
-
import {View} from 'react-native';
|
|
3
|
-
import {useGridSystem} from './index';
|
|
4
|
-
import {SectionItemProps} from './types';
|
|
5
|
-
import {ApplicationContext} from '../Navigation';
|
|
6
|
-
|
|
7
|
-
const SectionItem: React.FC<SectionItemProps> = ({
|
|
8
|
-
widthSpan = 12,
|
|
9
|
-
heightSpan,
|
|
10
|
-
children,
|
|
11
|
-
style,
|
|
12
|
-
}) => {
|
|
13
|
-
const {theme} = useContext(ApplicationContext);
|
|
14
|
-
const grid = useGridSystem();
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* render overlay view only dev mode
|
|
18
|
-
*/
|
|
19
|
-
const renderOverlay = () => {
|
|
20
|
-
return (
|
|
21
|
-
<View
|
|
22
|
-
pointerEvents={'none'}
|
|
23
|
-
style={{
|
|
24
|
-
position: 'absolute',
|
|
25
|
-
top: 0,
|
|
26
|
-
bottom: 0,
|
|
27
|
-
left: 0,
|
|
28
|
-
right: 0,
|
|
29
|
-
borderColor: 'red',
|
|
30
|
-
borderWidth: 1,
|
|
31
|
-
}}
|
|
32
|
-
/>
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const styles: any = style ?? {};
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<View
|
|
40
|
-
style={{
|
|
41
|
-
...styles,
|
|
42
|
-
width: grid.getSizeSpan(widthSpan),
|
|
43
|
-
height: heightSpan ? grid.getSizeSpan(heightSpan) : undefined,
|
|
44
|
-
overflow: 'hidden',
|
|
45
|
-
margin: undefined,
|
|
46
|
-
marginTop: undefined,
|
|
47
|
-
marginBottom: undefined,
|
|
48
|
-
marginLeft: undefined,
|
|
49
|
-
marginRight: undefined,
|
|
50
|
-
}}>
|
|
51
|
-
{children}
|
|
52
|
-
{grid.isDevMode && renderOverlay()}
|
|
53
|
-
</View>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
SectionItem.defaultProps = {
|
|
58
|
-
widthSpan: 12,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
SectionItem.displayName = 'SectionItem';
|
|
62
|
-
|
|
63
|
-
export default SectionItem;
|