@momo-kits/foundation 1.0.13 → 1.0.15

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 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}>
@@ -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,7 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
20
20
 
21
21
  return (
22
22
  <Image
23
+ accessibilityLabel={`Icon/${getIconSource()}`}
23
24
  loading={false}
24
25
  source={getIconSource()}
25
26
  style={[style, {width: size, height: size}]}
@@ -111,6 +111,7 @@ const IconButton: React.FC<IconButtonProps> = ({
111
111
  return (
112
112
  <TouchableOpacity
113
113
  {...rest}
114
+ accessibilityLabel={`IconButton/${icon}`}
114
115
  activeOpacity={activeOpacity}
115
116
  onPress={onPressButton}
116
117
  style={buttonStyle}>
package/Image/index.tsx CHANGED
@@ -11,9 +11,15 @@ import {FastImagePropsWithoutStyle} from './types';
11
11
  export interface ImageProps extends FastImagePropsWithoutStyle {
12
12
  style?: StyleProp<ViewStyle>;
13
13
  loading?: boolean;
14
+ accessibilityLabel?: string;
14
15
  }
15
16
 
16
- const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
17
+ const Image: React.FC<ImageProps> = ({
18
+ style,
19
+ source,
20
+ accessibilityLabel,
21
+ ...rest
22
+ }) => {
17
23
  const {theme} = useContext(ApplicationContext);
18
24
  const [loading, setLoading] = useState(rest.loading);
19
25
  const [fail, setFail] = useState(false);
@@ -48,7 +54,9 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
48
54
  };
49
55
 
50
56
  return (
51
- <View style={[styles.container, style]}>
57
+ <View
58
+ style={[styles.container, style]}
59
+ accessibilityLabel={`Image/${accessibilityLabel ?? source}`}>
52
60
  <FastImage
53
61
  {...rest}
54
62
  source={source}
@@ -68,4 +76,5 @@ const Image: React.FC<ImageProps> = ({style, source, ...rest}) => {
68
76
  Image.defaultProps = {
69
77
  loading: true,
70
78
  };
79
+
71
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>
@@ -123,7 +123,7 @@ const InputMoney: FC<InputMoneyProps> = ({
123
123
  };
124
124
 
125
125
  return (
126
- <View style={styles.wrapper}>
126
+ <View style={styles.wrapper} accessibilityLabel={`InputMoney`}>
127
127
  {renderInputView()}
128
128
  <ErrorView errorMessage={errorMessage} />
129
129
  </View>
@@ -22,7 +22,6 @@ const InputSearch: FC<InputSearchProps> = ({
22
22
  icon,
23
23
  buttonText = 'Hủy',
24
24
  showButtonText = true,
25
- showIcon = true,
26
25
  showBorder = true,
27
26
  style,
28
27
  ...props
@@ -104,7 +103,7 @@ const InputSearch: FC<InputSearchProps> = ({
104
103
  />
105
104
  </TouchableOpacity>
106
105
  )}
107
- {showIcon && icon && (
106
+ {icon || (
108
107
  <View style={{flexDirection: 'row'}}>
109
108
  <View
110
109
  style={[
@@ -116,7 +115,7 @@ const InputSearch: FC<InputSearchProps> = ({
116
115
  />
117
116
  <Icon
118
117
  color={iconTintColor}
119
- source={icon}
118
+ source={icon as string}
120
119
  style={styles.iconSearchInput}
121
120
  />
122
121
  </View>
@@ -125,7 +124,9 @@ const InputSearch: FC<InputSearchProps> = ({
125
124
  );
126
125
  };
127
126
  return (
128
- <View style={[style, styles.searchInputContainer]}>
127
+ <View
128
+ style={[style, styles.searchInputContainer]}
129
+ accessibilityLabel={`InputSearch`}>
129
130
  <View
130
131
  style={[
131
132
  getBorderColor(),
@@ -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/common.tsx CHANGED
@@ -1,7 +1,6 @@
1
1
  import {View} from 'react-native';
2
2
  import styles from './styles';
3
3
  import {Text} from '../Text';
4
- import {Image} from '../Image';
5
4
  import React, {FC, useContext} from 'react';
6
5
  import {ApplicationContext} from '../Navigation';
7
6
  import {Icon} from '../Icon';
@@ -99,10 +98,10 @@ export const FloatingView: FC<FloatingViewProps> = ({
99
98
  </Text>
100
99
  )}
101
100
  </Text>
102
- {floatingIcon && (
101
+ {floatingIcon || (
103
102
  <Icon
104
103
  color={floatingIconTintColor}
105
- source={floatingIcon}
104
+ source={floatingIcon as string}
106
105
  size={16}
107
106
  style={styles.floatingIcon}
108
107
  />
package/Input/index.tsx CHANGED
@@ -33,7 +33,6 @@ export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
33
33
  export interface InputSearchProps extends InputPropsOmitForSearch {
34
34
  buttonText?: string;
35
35
  showButtonText?: boolean;
36
- showIcon?: boolean;
37
36
  showBorder?: boolean;
38
37
  }
39
38
 
@@ -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;
@@ -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 grid = useGridSystem();
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.screenPadding,
42
+ marginHorizontal: grid.margin,
28
43
  },
29
44
  ]}>
30
45
  {list.map((i, index) => {
@@ -4,35 +4,57 @@ 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 {ScreenSection, validateChildren} from './index';
8
- import {Image} from '../Image';
7
+ import {Section, validateChildren} from './index';
9
8
 
10
9
  const ScreenContainer: React.FC<ScreenContainerProps> = ({
11
10
  children,
12
11
  edges,
13
12
  enableKeyboardAvoidingView,
14
13
  scrollable,
14
+ scrollY,
15
+ headerBackground,
15
16
  scrollViewProps,
16
- headerImage,
17
+ footerComponent: Footer,
17
18
  }) => {
19
+ let marginHeader = 0;
20
+ let handleScroll;
21
+ let imageAnimatedStyle = {};
18
22
  let Component: any = View;
19
23
  const headerHeight = useHeaderHeight();
20
24
  if (scrollable) {
21
25
  Component = Animated.ScrollView;
22
26
  }
27
+ if (scrollY) {
28
+ marginHeader = useHeaderHeight();
29
+ imageAnimatedStyle = {
30
+ transform: [
31
+ {
32
+ scale: scrollY.interpolate?.({
33
+ inputRange: [-300, 0, 1],
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
+ );
44
+ }
23
45
 
24
46
  /**
25
47
  * build content for screen
26
48
  */
27
49
  const renderContent = () => {
28
- const results = validateChildren(children, ScreenSection);
50
+ const results = validateChildren(children, Section);
29
51
  if (Array.isArray(results)) {
30
52
  return results.map((item, index) => {
31
53
  return (
32
54
  <View
33
- key={`ScreenSection${index}`}
55
+ key={`Section${index}`}
34
56
  style={{
35
- paddingTop: index != 0 ? 12 : Spacing.S,
57
+ marginTop: item.props?.useMargin ? Spacing.M : 0,
36
58
  flex: item.props?.expanded ? 1 : undefined,
37
59
  }}>
38
60
  {item}
@@ -44,7 +66,28 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
44
66
  };
45
67
 
46
68
  return (
47
- <SafeAreaView style={Styles.flex} edges={edges}>
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>
48
91
  <KeyboardAvoidingView
49
92
  style={Styles.flex}
50
93
  keyboardVerticalOffset={headerHeight}
@@ -53,17 +96,13 @@ const ScreenContainer: React.FC<ScreenContainerProps> = ({
53
96
  ios: 'padding',
54
97
  android: undefined,
55
98
  })}>
56
- <Component {...scrollViewProps} style={Styles.flex}>
57
- {headerImage && (
58
- <Image
59
- source={{
60
- uri: headerImage,
61
- }}
62
- style={{width: '100%', height: 300}}
63
- />
64
- )}
99
+ <Component
100
+ {...scrollViewProps}
101
+ onScroll={handleScroll}
102
+ style={[Styles.flex, {marginTop: marginHeader}]}>
65
103
  {renderContent()}
66
104
  </Component>
105
+ {Footer && <Section>{Footer}</Section>}
67
106
  </KeyboardAvoidingView>
68
107
  </SafeAreaView>
69
108
  );
@@ -1,11 +1,31 @@
1
1
  import React from 'react';
2
- import {View} from 'react-native';
3
- import {useGridSystem, validateChildren} from './utils';
4
- import SectionItem from './SectionItem';
5
- import {ScreenSectionProps} from './types';
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 ScreenSection: React.FC<ScreenSectionProps> = ({children}) => {
8
- const grid = useGridSystem();
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={`SectionItem${cursor}`}
63
+ key={`Card${cursor}`}
44
64
  style={{
45
65
  flexDirection: 'row',
46
- marginBottom: endRow ? 0 : grid.gutterSize,
66
+ marginBottom: endRow ? 0 : gridContext.gutterSize,
47
67
  }}>
48
68
  {rows.map((i: React.ReactElement, index: number) => {
49
69
  return (
50
- <View
51
- key={`SectionItem${cursor}${index}`}
52
- style={{flexDirection: 'row'}}>
53
- {index != 0 && <View style={{width: grid.gutterSize}}></View>}
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 <= grid.numberOfColumns) {
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
- <View
103
- style={{
104
- width: grid.getSizeSpan(),
105
- marginHorizontal: grid.screenPadding,
106
- flexDirection: 'row',
107
- flexWrap: 'wrap',
108
- }}>
109
- {renderView(validateChildren(children, SectionItem))}
110
- {grid.isDevMode && renderOverlay()}
111
- </View>
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
- ScreenSection.displayName = 'ScreenSection';
138
+ Section.displayName = 'Section';
116
139
 
117
- export default ScreenSection;
140
+ Section.defaultProps = {
141
+ useMargin: true,
142
+ };
143
+ export default Section;
package/Layout/index.ts CHANGED
@@ -1,12 +1,16 @@
1
- import SectionItem from './SectionItem';
2
- import ScreenSection from './ScreenSection';
1
+ import Card from './Card';
2
+ import Section from './Section';
3
3
  import GridSystem from './GridSystem';
4
- import {useGridSystem, validateChildren} from './utils';
4
+ import {validateChildren} from './utils';
5
+ import {createContext} from 'react';
6
+ import {GridContextProps} from './types';
5
7
 
6
- export {
7
- SectionItem,
8
- ScreenSection,
9
- GridSystem,
10
- useGridSystem,
11
- validateChildren,
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 interface ScreenSectionProps extends ViewProps {
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 SectionItemProps extends ViewProps {
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, Dimensions} from 'react-native';
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 {useGridSystem, validateChildren};
50
+ export {validateChildren};
@@ -8,10 +8,9 @@ import {
8
8
  View,
9
9
  } from 'react-native';
10
10
  import {ApplicationContext, NavigationButton} from './index';
11
- import {Colors, Spacing, Styles} from '../Consts';
11
+ import {Colors, Radius, Spacing, Styles} from '../Consts';
12
12
  import {Image} from '../Image';
13
13
  import {HeaderBackgroundProps, TitleCustomProps} from './types';
14
- import {useGridSystem} from '../Layout';
15
14
  import {Text} from '../Text';
16
15
  import {Icon} from '../Icon';
17
16
 
@@ -25,8 +24,10 @@ const styles = StyleSheet.create({
25
24
  headerTitleContainer: {
26
25
  alignItems: 'center',
27
26
  justifyContent: 'center',
27
+ width: '100%',
28
28
  },
29
- avatar: {width: 36, height: 36, borderRadius: 18},
29
+ circle: {width: 36, height: 36, borderRadius: 18},
30
+ square: {width: 36, height: 36, borderRadius: Radius.XS},
30
31
  dotAvatar: {
31
32
  position: 'absolute',
32
33
  width: 12,
@@ -74,6 +75,7 @@ const HeaderTitle: React.FC<any> = props => {
74
75
  return (
75
76
  <Animated.Text
76
77
  {...props}
78
+ accessibilityLabel={`HeaderTitle/${props.children}`}
77
79
  style={[styles.title, {opacity, color: props.tintColor}]}
78
80
  />
79
81
  );
@@ -94,7 +96,12 @@ const HeaderLeft: React.FC<any> = ({tintColor}) => {
94
96
 
95
97
  return (
96
98
  <View style={styles.headerLeft}>
97
- <NavigationButton icon="ic_back" tintColor={tintColor} onPress={goBack} />
99
+ <NavigationButton
100
+ icon="ic_back"
101
+ tintColor={tintColor}
102
+ onPress={goBack}
103
+ accessibilityLabel={'Back'}
104
+ />
98
105
  </View>
99
106
  );
100
107
  };
@@ -106,7 +113,9 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
106
113
  }) => {
107
114
  const {theme} = useContext(ApplicationContext);
108
115
  let headerImage = theme.assets?.headerBackground;
116
+ let borderBottomWidth = 0;
109
117
  if (image === null) {
118
+ borderBottomWidth = 1;
110
119
  headerImage = undefined;
111
120
  }
112
121
  const opacity = animatedValue?.interpolate({
@@ -114,6 +123,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
114
123
  outputRange: [0, 1],
115
124
  extrapolate: 'clamp',
116
125
  });
126
+
117
127
  return (
118
128
  <Animated.View
119
129
  style={[
@@ -121,7 +131,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
121
131
  {
122
132
  backgroundColor: backgroundColor ?? theme.colors.background.default,
123
133
  overflow: 'hidden',
124
- borderBottomWidth: headerImage ? 0 : 1,
134
+ borderBottomWidth: borderBottomWidth,
125
135
  borderColor: theme.colors.border.default,
126
136
  opacity,
127
137
  },
@@ -129,7 +139,7 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
129
139
  <StatusBar
130
140
  barStyle={headerImage || theme.dark ? 'light-content' : 'dark-content'}
131
141
  />
132
- {headerImage && (
142
+ {headerImage || (
133
143
  <Image style={styles.headerBackground} source={{uri: headerImage}} />
134
144
  )}
135
145
  </Animated.View>
@@ -140,17 +150,17 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
140
150
  title,
141
151
  subTitle,
142
152
  image,
153
+ imageShape = 'circle',
143
154
  content,
144
155
  tintColor,
145
156
  dotColor,
146
157
  }) => {
147
- const {getSizeSpan} = useGridSystem();
148
-
158
+ const avatarStyle = imageShape == 'circle' ? styles.square : styles.square;
149
159
  const header = (
150
160
  <View style={Styles.row}>
151
161
  <View>
152
- <Image source={{uri: image}} style={styles.avatar} />
153
- {dotColor && (
162
+ <Image source={{uri: image}} style={avatarStyle} />
163
+ {dotColor || (
154
164
  <View style={[styles.dotAvatar, {backgroundColor: dotColor}]} />
155
165
  )}
156
166
  </View>
@@ -164,11 +174,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
164
174
  </View>
165
175
  </View>
166
176
  );
167
- return (
168
- <View style={[styles.headerTitleContainer, {width: getSizeSpan(10)}]}>
169
- {content ?? header}
170
- </View>
171
- );
177
+ return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
172
178
  };
173
179
 
174
180
  const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
@@ -214,11 +220,11 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
214
220
  borderWidth: backgroundColor ? 0.5 : 0,
215
221
  },
216
222
  ]}>
217
- <TouchableOpacity>
223
+ <TouchableOpacity accessibilityLabel={'Toolkit/More'}>
218
224
  <Icon color={tintColor} source="navigation_more_horiz" size={20} />
219
225
  </TouchableOpacity>
220
226
  <View style={[styles.divider, {backgroundColor: tintColor}]} />
221
- <TouchableOpacity>
227
+ <TouchableOpacity accessibilityLabel={'Toolkit/Close'}>
222
228
  <Icon
223
229
  color={tintColor}
224
230
  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 style={{paddingBottom: bottom}}>
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,6 +20,7 @@ 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
  {
@@ -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, useGridSystem} from '../Layout';
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
- {grid.isDevMode && <GridSystem />}
77
+ {__DEV__ && <GridSystem />}
79
78
  </SafeAreaProvider>
80
79
  );
81
80
  };
@@ -24,7 +24,6 @@ const StackScreen: React.FC<any> = props => {
24
24
  }
25
25
  }, [options]);
26
26
 
27
- console.log(params);
28
27
  return <Component {...params} />;
29
28
  };
30
29
 
@@ -71,9 +71,11 @@ export type NavigationContainerProps = {
71
71
  export interface ScreenContainerProps extends ViewProps {
72
72
  edges?: any[];
73
73
  enableKeyboardAvoidingView?: boolean;
74
- scrollable: boolean;
74
+ headerBackground?: string;
75
+ scrollable?: boolean;
76
+ scrollY?: Animated.Value;
75
77
  scrollViewProps?: ScrollViewProps;
76
- headerImage?: string;
78
+ footerComponent?: React.ElementType;
77
79
  }
78
80
 
79
81
  export type ScreenParams = {
@@ -100,6 +102,7 @@ export type NavigationButtonProps = {
100
102
  backgroundColor?: string;
101
103
  useBorder?: boolean;
102
104
  onPress: () => void;
105
+ accessibilityLabel?: string;
103
106
  };
104
107
 
105
108
  export type NavigationOptions = {
@@ -121,6 +124,7 @@ export type TitleCustomProps = {
121
124
  title?: string;
122
125
  subTitle?: string;
123
126
  image?: string;
127
+ imageShape?: 'circle' | 'square';
124
128
  dotColor?: string;
125
129
  tintColor?: string;
126
130
  content?: React.ReactNode;
@@ -36,11 +36,11 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
36
36
  const renderRow = () => {
37
37
  return (
38
38
  <View style={Styles.row}>
39
- {secondary?.title && (
39
+ {secondary?.title || (
40
40
  <>
41
41
  <View style={Styles.flex}>
42
42
  <Button
43
- title={secondary.title}
43
+ title={secondary?.title as string}
44
44
  type="text"
45
45
  size="medium"
46
46
  onPress={() => {
@@ -73,11 +73,11 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
73
73
  onAction(primary.onPress);
74
74
  }}
75
75
  />
76
- {secondary?.title && (
76
+ {secondary?.title || (
77
77
  <>
78
78
  <View style={styles.buttonSpace} />
79
79
  <Button
80
- title={secondary.title}
80
+ title={secondary?.title as string}
81
81
  type="text"
82
82
  size="medium"
83
83
  onPress={() => {
@@ -132,6 +132,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
132
132
 
133
133
  return (
134
134
  <View
135
+ accessibilityLabel={'PopupNotify'}
135
136
  style={[
136
137
  styles.container,
137
138
  {backgroundColor: theme.colors.background.surface},
@@ -146,7 +147,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
146
147
  {description}
147
148
  </Text>
148
149
  </View>
149
- {information && (
150
+ {information || (
150
151
  <View style={styles.information}>
151
152
  <Text
152
153
  typography={'description_xs'}
@@ -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
 
package/Radio/index.tsx CHANGED
@@ -39,6 +39,7 @@ const Radio: FC<RadioProps> = ({
39
39
 
40
40
  return (
41
41
  <TouchableOpacity
42
+ accessibilityLabel={`Radio/${label}`}
42
43
  onPress={onChange}
43
44
  disabled={disabled}
44
45
  style={[
@@ -2,9 +2,8 @@ import React, {useEffect, useMemo, useRef, useState} from 'react';
2
2
  import {Animated, Easing, Platform, StyleSheet, View} from 'react-native';
3
3
  import LinearGradient from 'react-native-linear-gradient';
4
4
  import {SkeletonTypes} from './types';
5
- import {Styles} from '../Consts';
5
+ import {Colors, Styles} from '../Consts';
6
6
  import styles from './styles';
7
- import {Colors} from '@momo-kits/foundation';
8
7
 
9
8
  const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
10
9
  const [width, setWidth] = useState(0);
@@ -42,7 +41,7 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
42
41
  }
43
42
  };
44
43
  return (
45
- <View style={[styles.container, style]}>
44
+ <View style={[styles.container, style]} accessibilityLabel={'Skeleton'}>
46
45
  <View
47
46
  onLayout={e => onLayout(e.nativeEvent.layout.width)}
48
47
  style={[Styles.flex, {backgroundColor: PRIMARY_COLOR}]}>
package/Switch/index.tsx CHANGED
@@ -18,6 +18,7 @@ const Switch: FC<SwitchProps> = props => {
18
18
 
19
19
  return (
20
20
  <TouchableOpacity
21
+ accessibilityLabel={'Switch'}
21
22
  disabled={disabled}
22
23
  onPress={() => onChange?.(!value)}
23
24
  style={[
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
- style={[style, textStyle, {color: color ?? theme.colors.text.default}]}>
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {
@@ -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;