@momo-kits/foundation 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Assets/header-background.png +0 -0
- package/Button/index.tsx +307 -0
- package/Button/styles.ts +41 -0
- package/Button/types.ts +18 -0
- package/CheckBox/index.js +74 -0
- package/CheckBox/styles.js +3 -0
- package/Consts/colors+spacing+radius.ts +162 -0
- package/Consts/index.ts +76 -0
- package/Consts/styles.ts +137 -0
- package/ContentLoader/index.tsx +71 -0
- package/ContentLoader/styles.ts +5 -0
- package/ContentLoader/types.ts +3 -0
- package/Divider/index.js +43 -0
- package/Divider/styles.js +10 -0
- package/Icon/icon.json +3935 -0
- package/Icon/index.tsx +30 -0
- package/Icon/types.ts +8 -0
- package/IconButton/index.tsx +127 -0
- package/IconButton/types.ts +17 -0
- package/Image/index.tsx +67 -0
- package/Image/styles.ts +13 -0
- package/Image/types.ts +6 -0
- package/Layout/Row.tsx +42 -0
- package/Layout/Screen.tsx +68 -0
- package/Layout/Section.tsx +30 -0
- package/Layout/View.tsx +84 -0
- package/Layout/index.ts +6 -0
- package/Layout/styles.ts +24 -0
- package/Layout/types.ts +39 -0
- package/Layout/utils.ts +37 -0
- package/Navigation/Components.tsx +55 -0
- package/Navigation/ModalScreen.tsx +177 -0
- package/Navigation/Navigation.ts +34 -0
- package/Navigation/NavigationButton.tsx +25 -0
- package/Navigation/NavigationContainer.tsx +74 -0
- package/Navigation/Navigator.ts +45 -0
- package/Navigation/ScreenContainer.tsx +38 -0
- package/Navigation/StackScreen.tsx +19 -0
- package/Navigation/index.ts +10 -0
- package/Navigation/types.ts +87 -0
- package/Navigation/utils.tsx +84 -0
- package/SizedBox/index.js +23 -0
- package/SizedBox/styles.js +7 -0
- package/Text/index.tsx +164 -0
- package/Text/styles.ts +34 -0
- package/Text/types.ts +47 -0
- package/TextInput/index.js +225 -0
- package/TextInput/styles.js +55 -0
- package/index.ts +18 -0
- package/package.json +41 -0
- package/publish.sh +26 -0
package/Icon/index.tsx
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {IconProps, Image, NavigationContext} from '../index';
|
|
3
|
+
import SourceSets from './icon.json';
|
|
4
|
+
|
|
5
|
+
const Icon: React.FC<IconProps> = ({name, source, size, color}) => {
|
|
6
|
+
const {theme} = useContext(NavigationContext);
|
|
7
|
+
|
|
8
|
+
const getIconSource = (): any => {
|
|
9
|
+
if (name) {
|
|
10
|
+
let icon: {[key: string]: object} = SourceSets;
|
|
11
|
+
return icon[name] ?? icon.ic_warning;
|
|
12
|
+
}
|
|
13
|
+
return source;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Image
|
|
18
|
+
source={getIconSource()}
|
|
19
|
+
style={{width: size, height: size}}
|
|
20
|
+
tintColor={color ?? theme.colors.text}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
Icon.defaultProps = {
|
|
26
|
+
name: 'ic_back',
|
|
27
|
+
size: 24,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export {Icon};
|
package/Icon/types.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {StyleSheet, TouchableOpacity, View} from 'react-native';
|
|
3
|
+
import {NavigationContext, Colors, Icon, IconButtonProps} from '../index';
|
|
4
|
+
|
|
5
|
+
const IconButton: React.FC<IconButtonProps> = ({
|
|
6
|
+
style,
|
|
7
|
+
type,
|
|
8
|
+
icon,
|
|
9
|
+
size,
|
|
10
|
+
shape,
|
|
11
|
+
...rest
|
|
12
|
+
}) => {
|
|
13
|
+
const {theme} = useContext(NavigationContext);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* export size style
|
|
17
|
+
*/
|
|
18
|
+
const getSizeStyle = () => {
|
|
19
|
+
switch (size) {
|
|
20
|
+
case 'large':
|
|
21
|
+
return styles.large;
|
|
22
|
+
case 'small':
|
|
23
|
+
return styles.small;
|
|
24
|
+
|
|
25
|
+
default:
|
|
26
|
+
return styles.small;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* export size style
|
|
32
|
+
*/
|
|
33
|
+
const getIconSize = () => {
|
|
34
|
+
switch (size) {
|
|
35
|
+
case 'large':
|
|
36
|
+
return 24;
|
|
37
|
+
case 'small':
|
|
38
|
+
return 16;
|
|
39
|
+
|
|
40
|
+
default:
|
|
41
|
+
return 16;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* export type style
|
|
47
|
+
*/
|
|
48
|
+
const getTypeStyle = () => {
|
|
49
|
+
switch (type) {
|
|
50
|
+
case 'primary':
|
|
51
|
+
return {backgroundColor: theme.colors.primary};
|
|
52
|
+
case 'tonal':
|
|
53
|
+
return {backgroundColor: theme.colors.primary + '33'};
|
|
54
|
+
case 'secondary':
|
|
55
|
+
return {borderColor: theme.colors.border, borderWidth: 1};
|
|
56
|
+
case 'outline':
|
|
57
|
+
return {
|
|
58
|
+
borderWidth: 1,
|
|
59
|
+
borderColor: theme.colors.primary,
|
|
60
|
+
};
|
|
61
|
+
case 'disabled':
|
|
62
|
+
return {backgroundColor: theme.colors.border};
|
|
63
|
+
default:
|
|
64
|
+
return {backgroundColor: theme.colors.primary};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const getIconColor = () => {
|
|
69
|
+
switch (type) {
|
|
70
|
+
case 'primary':
|
|
71
|
+
return Colors.black_01;
|
|
72
|
+
case 'tonal':
|
|
73
|
+
return theme.colors.primary;
|
|
74
|
+
case 'secondary':
|
|
75
|
+
return theme.colors.text;
|
|
76
|
+
case 'outline':
|
|
77
|
+
return theme.colors.primary;
|
|
78
|
+
case 'disabled':
|
|
79
|
+
return theme.colors.text + '4D';
|
|
80
|
+
default:
|
|
81
|
+
return Colors.black_01;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const buttonStyle = StyleSheet.flatten([
|
|
86
|
+
getSizeStyle(),
|
|
87
|
+
getTypeStyle(),
|
|
88
|
+
shape === 'rectangle' && {borderRadius: 8},
|
|
89
|
+
style,
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<TouchableOpacity
|
|
94
|
+
{...rest}
|
|
95
|
+
disabled={type === 'disabled'}
|
|
96
|
+
style={buttonStyle}>
|
|
97
|
+
<Icon name={icon} size={getIconSize()} color={getIconColor()} />
|
|
98
|
+
</TouchableOpacity>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
IconButton.defaultProps = {
|
|
103
|
+
icon: 'close',
|
|
104
|
+
type: 'primary',
|
|
105
|
+
size: 'small',
|
|
106
|
+
shape: 'circle',
|
|
107
|
+
children: <View />,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const styles = StyleSheet.create({
|
|
111
|
+
large: {
|
|
112
|
+
height: 48,
|
|
113
|
+
width: 48,
|
|
114
|
+
borderRadius: 24,
|
|
115
|
+
justifyContent: 'center',
|
|
116
|
+
alignItems: 'center',
|
|
117
|
+
},
|
|
118
|
+
small: {
|
|
119
|
+
height: 36,
|
|
120
|
+
width: 36,
|
|
121
|
+
borderRadius: 18,
|
|
122
|
+
justifyContent: 'center',
|
|
123
|
+
alignItems: 'center',
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export {IconButton};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {TouchableOpacityProps} from 'react-native';
|
|
2
|
+
|
|
3
|
+
export type IconButtonType =
|
|
4
|
+
| 'primary'
|
|
5
|
+
| 'tonal'
|
|
6
|
+
| 'secondary'
|
|
7
|
+
| 'outline'
|
|
8
|
+
| 'disabled';
|
|
9
|
+
export type IconButtonSize = 'large' | 'small';
|
|
10
|
+
export type IconButtonShape = 'circle' | 'rectangle';
|
|
11
|
+
|
|
12
|
+
export interface IconButtonProps extends TouchableOpacityProps {
|
|
13
|
+
icon: string;
|
|
14
|
+
type?: IconButtonType;
|
|
15
|
+
size?: IconButtonSize;
|
|
16
|
+
shape?: IconButtonShape;
|
|
17
|
+
}
|
package/Image/index.tsx
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, {useContext, useState} from 'react';
|
|
2
|
+
import {StyleSheet, View} from 'react-native';
|
|
3
|
+
import FastImage from 'react-native-fast-image';
|
|
4
|
+
import {
|
|
5
|
+
ContentLoader,
|
|
6
|
+
Icon,
|
|
7
|
+
ImageProps,
|
|
8
|
+
NavigationContext,
|
|
9
|
+
Styles,
|
|
10
|
+
Text,
|
|
11
|
+
} from '../index';
|
|
12
|
+
import styles from './styles';
|
|
13
|
+
|
|
14
|
+
const Image: React.FC<ImageProps> = props => {
|
|
15
|
+
const {theme} = useContext(NavigationContext);
|
|
16
|
+
const {style, placeholder, error, source} = props;
|
|
17
|
+
const [loading, setLoading] = useState(typeof source === 'object');
|
|
18
|
+
const [fail, setFail] = useState(false);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* render content
|
|
22
|
+
* @returns {JSX.Element}
|
|
23
|
+
*/
|
|
24
|
+
const renderContent = () => {
|
|
25
|
+
if (loading || fail) {
|
|
26
|
+
let content = placeholder ?? (
|
|
27
|
+
<ContentLoader style={[StyleSheet.absoluteFill, styles.image]} />
|
|
28
|
+
);
|
|
29
|
+
if (fail) {
|
|
30
|
+
content = error ?? (
|
|
31
|
+
<View
|
|
32
|
+
style={[Styles.flexCenter, {backgroundColor: theme.colors.border}]}>
|
|
33
|
+
<Icon name="error-outline" />
|
|
34
|
+
<Text typography="subtitle" style={Styles.textCenter}>
|
|
35
|
+
Can't load image
|
|
36
|
+
</Text>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return (
|
|
41
|
+
<View style={[StyleSheet.absoluteFill, styles.image]}>{content}</View>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<View style={[styles.container, style]}>
|
|
48
|
+
<FastImage
|
|
49
|
+
{...props}
|
|
50
|
+
style={styles.image}
|
|
51
|
+
onLoad={() => {
|
|
52
|
+
setFail(false);
|
|
53
|
+
setLoading(true);
|
|
54
|
+
}}
|
|
55
|
+
onLoadEnd={() => setLoading(false)}
|
|
56
|
+
onError={() => setFail(true)}
|
|
57
|
+
/>
|
|
58
|
+
{renderContent()}
|
|
59
|
+
</View>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
Image.defaultProps = {
|
|
64
|
+
style: {},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export {Image};
|
package/Image/styles.ts
ADDED
package/Image/types.ts
ADDED
package/Layout/Row.tsx
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
import styles from './styles';
|
|
4
|
+
import {MMSectionContext} from './Section';
|
|
5
|
+
import {DEFAULT_SCREEN_PADDING, screenWidth} from './utils';
|
|
6
|
+
|
|
7
|
+
const MMRow: React.FC<any> = props => {
|
|
8
|
+
const haveMargin = useContext(MMSectionContext);
|
|
9
|
+
const rowWidth = haveMargin
|
|
10
|
+
? screenWidth - DEFAULT_SCREEN_PADDING * 4
|
|
11
|
+
: screenWidth - DEFAULT_SCREEN_PADDING * 2;
|
|
12
|
+
|
|
13
|
+
const {children} = props;
|
|
14
|
+
let totalGap = 0;
|
|
15
|
+
return (
|
|
16
|
+
<View
|
|
17
|
+
style={[
|
|
18
|
+
styles.row,
|
|
19
|
+
{
|
|
20
|
+
width: rowWidth,
|
|
21
|
+
},
|
|
22
|
+
]}>
|
|
23
|
+
{React.Children.map(children, (child, index) => {
|
|
24
|
+
let isEndLine = false;
|
|
25
|
+
totalGap += child.props.span;
|
|
26
|
+
if (totalGap >= 12) {
|
|
27
|
+
totalGap = 0;
|
|
28
|
+
isEndLine = true;
|
|
29
|
+
}
|
|
30
|
+
if (totalGap + children[index + 1]?.props?.span > 12) {
|
|
31
|
+
totalGap = 0;
|
|
32
|
+
}
|
|
33
|
+
return React.cloneElement(child, {
|
|
34
|
+
isEndLine: isEndLine,
|
|
35
|
+
isRowChild: true,
|
|
36
|
+
});
|
|
37
|
+
})}
|
|
38
|
+
</View>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default MMRow;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {ScrollView, View} from 'react-native';
|
|
3
|
+
import styles from './styles';
|
|
4
|
+
import {MMScreenProps} from './types';
|
|
5
|
+
import {MMSection} from './index';
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_GUTTER,
|
|
8
|
+
DEFAULT_SCREEN_PADDING,
|
|
9
|
+
screenWidth,
|
|
10
|
+
validateChildren,
|
|
11
|
+
} from './utils';
|
|
12
|
+
|
|
13
|
+
const MMScreen = (props: MMScreenProps) => {
|
|
14
|
+
const {children, scrollable} = props;
|
|
15
|
+
|
|
16
|
+
const parentWidth = screenWidth - DEFAULT_SCREEN_PADDING * 2;
|
|
17
|
+
|
|
18
|
+
const colWidth = (parentWidth - DEFAULT_GUTTER * 11) / 12;
|
|
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
|
+
flexDirection: 'row',
|
|
30
|
+
marginHorizontal: 12,
|
|
31
|
+
}}>
|
|
32
|
+
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((i, ii) => {
|
|
33
|
+
return (
|
|
34
|
+
<View
|
|
35
|
+
pointerEvents="none"
|
|
36
|
+
style={{
|
|
37
|
+
width: colWidth,
|
|
38
|
+
height: '100%',
|
|
39
|
+
opacity: 0.2,
|
|
40
|
+
backgroundColor: '#bae7ff',
|
|
41
|
+
marginRight: ii !== 12 ? DEFAULT_GUTTER : 0,
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
})}
|
|
46
|
+
</View>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (scrollable) {
|
|
51
|
+
return (
|
|
52
|
+
<ScrollView
|
|
53
|
+
showsVerticalScrollIndicator={false}
|
|
54
|
+
style={[styles.screen, {width: screenWidth}]}>
|
|
55
|
+
{validateChildren(children, MMSection)}
|
|
56
|
+
{renderOverlay()}
|
|
57
|
+
</ScrollView>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return (
|
|
61
|
+
<View style={[styles.screen, {width: screenWidth}]}>
|
|
62
|
+
{validateChildren(children, MMSection)}
|
|
63
|
+
{renderOverlay()}
|
|
64
|
+
</View>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default MMScreen;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, {createContext} from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
import styles from './styles';
|
|
4
|
+
import {MMSectionProps} from './types';
|
|
5
|
+
import {MMRow} from './index';
|
|
6
|
+
import {DEFAULT_SCREEN_PADDING, screenWidth, validateChildren} from './utils';
|
|
7
|
+
|
|
8
|
+
export const MMSectionContext = createContext({});
|
|
9
|
+
|
|
10
|
+
const MMSection: React.FC<MMSectionProps> = props => {
|
|
11
|
+
const {haveMargin = false, children} = props;
|
|
12
|
+
return (
|
|
13
|
+
<MMSectionContext.Provider value={haveMargin}>
|
|
14
|
+
<View
|
|
15
|
+
style={[
|
|
16
|
+
styles.section,
|
|
17
|
+
{
|
|
18
|
+
width: haveMargin
|
|
19
|
+
? screenWidth - DEFAULT_SCREEN_PADDING * 2
|
|
20
|
+
: screenWidth,
|
|
21
|
+
marginHorizontal: haveMargin ? DEFAULT_SCREEN_PADDING : 0,
|
|
22
|
+
},
|
|
23
|
+
]}>
|
|
24
|
+
{validateChildren(children, MMRow)}
|
|
25
|
+
</View>
|
|
26
|
+
</MMSectionContext.Provider>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default MMSection;
|
package/Layout/View.tsx
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
import {MMViewProps} from './types';
|
|
4
|
+
import styles from './styles';
|
|
5
|
+
import {MMSectionContext} from './Section';
|
|
6
|
+
import {screenWidth} from './utils';
|
|
7
|
+
import {Colors, Shadow} from '@momo-kits/core';
|
|
8
|
+
|
|
9
|
+
const MMView: React.FC<MMViewProps> = props => {
|
|
10
|
+
const {
|
|
11
|
+
span = 12,
|
|
12
|
+
children,
|
|
13
|
+
isEndLine,
|
|
14
|
+
alignItems,
|
|
15
|
+
justifyContent,
|
|
16
|
+
padding,
|
|
17
|
+
backgroundColor,
|
|
18
|
+
borderRadius,
|
|
19
|
+
direction,
|
|
20
|
+
shadow = 'none',
|
|
21
|
+
isRowChild = false,
|
|
22
|
+
} = props;
|
|
23
|
+
const NUM_OF_SPAN = 12;
|
|
24
|
+
const DEFAULT_SCREEN_PADDING = 12;
|
|
25
|
+
const GUTTER = 12;
|
|
26
|
+
const haveMargin = useContext(MMSectionContext);
|
|
27
|
+
const shadowStyle =
|
|
28
|
+
shadow !== 'none' ? (shadow === 'light' ? Shadow.Light : Shadow.Dark) : {};
|
|
29
|
+
|
|
30
|
+
const parentWidth = haveMargin
|
|
31
|
+
? screenWidth - DEFAULT_SCREEN_PADDING * 4
|
|
32
|
+
: screenWidth - DEFAULT_SCREEN_PADDING * 2;
|
|
33
|
+
|
|
34
|
+
const paddingStyle = {
|
|
35
|
+
paddingTop: padding?.[0] || 0,
|
|
36
|
+
paddingRight: padding?.[1] || 0,
|
|
37
|
+
paddingBottom: padding?.[2] || 0,
|
|
38
|
+
paddingLeft: padding?.[3] || 0,
|
|
39
|
+
};
|
|
40
|
+
const colWidth =
|
|
41
|
+
(span * (parentWidth - GUTTER * (NUM_OF_SPAN - 1))) / NUM_OF_SPAN +
|
|
42
|
+
GUTTER * (span - 1);
|
|
43
|
+
|
|
44
|
+
const renderOverlay = () => {
|
|
45
|
+
return (
|
|
46
|
+
<View
|
|
47
|
+
pointerEvents={'none'}
|
|
48
|
+
style={{
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
top: 0,
|
|
51
|
+
bottom: 0,
|
|
52
|
+
left: 0,
|
|
53
|
+
right: 0,
|
|
54
|
+
borderColor: Colors.pink_08,
|
|
55
|
+
borderWidth: 1,
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<View
|
|
63
|
+
style={[
|
|
64
|
+
styles.col,
|
|
65
|
+
{
|
|
66
|
+
width: colWidth,
|
|
67
|
+
marginRight: isEndLine ? 0 : GUTTER,
|
|
68
|
+
marginBottom: isRowChild ? GUTTER : 0,
|
|
69
|
+
alignItems,
|
|
70
|
+
backgroundColor,
|
|
71
|
+
borderRadius,
|
|
72
|
+
justifyContent,
|
|
73
|
+
flexDirection: direction,
|
|
74
|
+
},
|
|
75
|
+
paddingStyle,
|
|
76
|
+
shadowStyle,
|
|
77
|
+
]}>
|
|
78
|
+
{children}
|
|
79
|
+
{renderOverlay()}
|
|
80
|
+
</View>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default MMView;
|
package/Layout/index.ts
ADDED
package/Layout/styles.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
import {Colors} from '@momo-kits/core';
|
|
3
|
+
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
col: {
|
|
6
|
+
minHeight: 1,
|
|
7
|
+
},
|
|
8
|
+
row: {
|
|
9
|
+
minHeight: 1,
|
|
10
|
+
flexDirection: 'row',
|
|
11
|
+
flexWrap: 'wrap',
|
|
12
|
+
},
|
|
13
|
+
section: {
|
|
14
|
+
paddingHorizontal: 12,
|
|
15
|
+
marginBottom: 12,
|
|
16
|
+
},
|
|
17
|
+
screen: {
|
|
18
|
+
flex: 1,
|
|
19
|
+
backgroundColor: Colors.black_01,
|
|
20
|
+
paddingVertical: 12,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default styles;
|
package/Layout/types.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {ReactElement} from 'react';
|
|
2
|
+
|
|
3
|
+
type SpanNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
|
4
|
+
type ViewAlignItems = 'flex-start' | 'flex-end' | 'center';
|
|
5
|
+
|
|
6
|
+
type ViewJustifyContent =
|
|
7
|
+
| 'flex-start'
|
|
8
|
+
| 'flex-end'
|
|
9
|
+
| 'center'
|
|
10
|
+
| 'space-between'
|
|
11
|
+
| 'space-around'
|
|
12
|
+
| 'space-evenly';
|
|
13
|
+
|
|
14
|
+
type ViewDirection = 'row' | 'column';
|
|
15
|
+
|
|
16
|
+
type ViewShadow = 'none' | 'light' | 'dark';
|
|
17
|
+
export interface MMScreenProps {
|
|
18
|
+
children: ReactElement;
|
|
19
|
+
scrollable: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MMSectionProps {
|
|
23
|
+
haveMargin?: boolean;
|
|
24
|
+
children: ReactElement;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MMViewProps {
|
|
28
|
+
span: SpanNumber;
|
|
29
|
+
children: ReactElement;
|
|
30
|
+
isEndLine?: boolean;
|
|
31
|
+
isRowChild?: boolean;
|
|
32
|
+
alignItems?: ViewAlignItems;
|
|
33
|
+
justifyContent: ViewJustifyContent;
|
|
34
|
+
padding: Array<number>;
|
|
35
|
+
backgroundColor: string;
|
|
36
|
+
borderRadius: number;
|
|
37
|
+
direction: ViewDirection;
|
|
38
|
+
shadow: ViewShadow;
|
|
39
|
+
}
|
package/Layout/utils.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {Dimensions} from 'react-native';
|
|
2
|
+
import {FC, JSXElementConstructor, ReactElement, ReactNode} from 'react';
|
|
3
|
+
import {MMSectionProps} from './types';
|
|
4
|
+
|
|
5
|
+
export const screenWidth = Dimensions.get('window').width;
|
|
6
|
+
|
|
7
|
+
export const DEFAULT_SCREEN_PADDING = 12;
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_GUTTER = 12;
|
|
10
|
+
export const validateChildren = (
|
|
11
|
+
children: ReactElement<any, string | JSXElementConstructor<any>> & ReactNode,
|
|
12
|
+
childrenType:
|
|
13
|
+
| string
|
|
14
|
+
| FC<MMSectionProps>
|
|
15
|
+
| JSXElementConstructor<any>
|
|
16
|
+
| FC<any>,
|
|
17
|
+
) => {
|
|
18
|
+
if (Array.isArray(children)) {
|
|
19
|
+
return children?.map((child: ReactElement) => {
|
|
20
|
+
if (child?.type === childrenType) {
|
|
21
|
+
return child;
|
|
22
|
+
}
|
|
23
|
+
console.error(
|
|
24
|
+
'Wrong children type for this container, please check document.',
|
|
25
|
+
);
|
|
26
|
+
return null;
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
if (children?.type === childrenType) {
|
|
30
|
+
return children;
|
|
31
|
+
}
|
|
32
|
+
console.error(
|
|
33
|
+
'Wrong children type for this container, please check document.',
|
|
34
|
+
);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, {useContext} from 'react';
|
|
2
|
+
import {StatusBar, StyleSheet, View} from 'react-native';
|
|
3
|
+
import {Image, NavigationButton, NavigationContext, Styles} from '../index';
|
|
4
|
+
|
|
5
|
+
const styles = StyleSheet.create({
|
|
6
|
+
headerBackground: {
|
|
7
|
+
width: '100%',
|
|
8
|
+
height: undefined,
|
|
9
|
+
position: 'absolute',
|
|
10
|
+
aspectRatio: 375 / 154,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const HeaderBackground: React.FC<any> = () => {
|
|
15
|
+
const {theme} = useContext(NavigationContext);
|
|
16
|
+
const source: any = theme.assets?.headerBackground;
|
|
17
|
+
return (
|
|
18
|
+
<View
|
|
19
|
+
style={[
|
|
20
|
+
Styles.flex,
|
|
21
|
+
{backgroundColor: theme.colors.background, overflow: 'hidden'},
|
|
22
|
+
]}>
|
|
23
|
+
<StatusBar barStyle="light-content" />
|
|
24
|
+
<Image style={styles.headerBackground} source={source} />
|
|
25
|
+
</View>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
|
|
30
|
+
const validType = (item: any) => {
|
|
31
|
+
if (item.type !== NavigationButton) {
|
|
32
|
+
console.error(
|
|
33
|
+
'element type of NavigationButton, Please migrate to use NavigationButton of kits.',
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const renderAction = () => {
|
|
38
|
+
if (Array.isArray(children)) {
|
|
39
|
+
return children.map((child, index) => {
|
|
40
|
+
validType(child);
|
|
41
|
+
return (
|
|
42
|
+
<React.Fragment key={index}>
|
|
43
|
+
{React.cloneElement(child, {...restProps})}
|
|
44
|
+
</React.Fragment>
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
validType(children);
|
|
50
|
+
return React.cloneElement(children, {...restProps});
|
|
51
|
+
};
|
|
52
|
+
return <View style={Styles.headerRightButton}>{renderAction()}</View>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export {HeaderBackground, HeaderRightAction};
|