@momo-kits/foundation 0.75.1-beta.8 → 0.76.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/{Navigation → Application}/BottomTab.tsx +19 -6
  2. package/{Navigation → Application}/Components.tsx +24 -15
  3. package/{Navigation → Application}/ModalScreen.tsx +17 -13
  4. package/{Navigation → Application}/Navigation.ts +5 -5
  5. package/{Navigation → Application}/NavigationContainer.tsx +3 -3
  6. package/{Navigation → Application}/StackScreen.tsx +7 -7
  7. package/{Navigation → Application}/index.ts +7 -3
  8. package/{Navigation → Application}/types.ts +23 -5
  9. package/{Navigation → Application}/utils.tsx +4 -6
  10. package/Assets/icon.json +6 -0
  11. package/Button/index.tsx +1 -1
  12. package/CheckBox/index.tsx +1 -1
  13. package/Consts/theme.ts +1 -1
  14. package/Divider/index.tsx +1 -1
  15. package/Icon/index.tsx +2 -2
  16. package/IconButton/index.tsx +1 -1
  17. package/Image/index.tsx +4 -2
  18. package/Input/Input.tsx +2 -1
  19. package/Input/InputMoney.tsx +2 -1
  20. package/Input/InputSearch.tsx +4 -2
  21. package/Input/InputTextArea.tsx +20 -19
  22. package/Input/common.tsx +1 -1
  23. package/Input/index.tsx +2 -0
  24. package/Layout/Card.tsx +108 -54
  25. package/Layout/GridSystem.tsx +4 -2
  26. package/Layout/Item.tsx +60 -0
  27. package/Layout/Screen.tsx +188 -0
  28. package/Layout/Section.tsx +12 -9
  29. package/Layout/index.ts +2 -1
  30. package/Layout/types.ts +7 -7
  31. package/Layout/utils.ts +46 -16
  32. package/Pagination/Dot.tsx +1 -1
  33. package/Pagination/PaginationDot.tsx +1 -1
  34. package/Pagination/PaginationNumber.tsx +1 -2
  35. package/Pagination/PaginationScroll.tsx +2 -1
  36. package/Pagination/PaginationWhiteDot.tsx +1 -1
  37. package/Popup/PopupNotify.tsx +1 -1
  38. package/Popup/PopupPromotion.tsx +1 -1
  39. package/Radio/index.tsx +1 -1
  40. package/Switch/index.tsx +1 -1
  41. package/Tag/index.tsx +3 -1
  42. package/Text/index.tsx +5 -4
  43. package/Text/utils.ts +14 -0
  44. package/index.ts +9 -2
  45. package/package.json +40 -40
  46. package/publish.sh +2 -5
  47. package/Layout/ScreenContainer.tsx +0 -122
  48. package/Navigation/Observer.ts +0 -79
  49. /package/{Navigation → Application}/NavigationButton.tsx +0 -0
  50. /package/{Navigation → Application}/Navigator.ts +0 -0
@@ -8,7 +8,6 @@ import {
8
8
  } from 'react-native';
9
9
  import styles from './styles';
10
10
  import {Text} from '../Text';
11
- import {ApplicationContext} from '../Navigation';
12
11
  import {
13
12
  DEFAULT_HEIGHT,
14
13
  ErrorView,
@@ -18,26 +17,26 @@ import {
18
17
  } from './common';
19
18
  import {InputTextAreaProps} from './index';
20
19
  import {Icon} from '../Icon';
20
+ import {ApplicationContext} from '../Application';
21
21
 
22
- const InputTextArea: FC<InputTextAreaProps> = props => {
22
+ const InputTextArea: FC<InputTextAreaProps> = ({
23
+ errorMessage,
24
+ onChangeText,
25
+ floatingIconColor,
26
+ floatingIcon,
27
+ floatingValue,
28
+ onFocus,
29
+ onBlur,
30
+ disabled,
31
+ value,
32
+ defaultValue,
33
+ height,
34
+ placeholder,
35
+ maxLength,
36
+ required,
37
+ ...props
38
+ }) => {
23
39
  const {theme} = useContext(ApplicationContext);
24
- const {
25
- errorMessage,
26
- onChangeText,
27
- floatingIconColor,
28
- floatingIcon,
29
- floatingValue,
30
- onFocus,
31
- onBlur,
32
- disabled,
33
- value,
34
- defaultValue,
35
- height,
36
- placeholder,
37
- maxLength,
38
- required,
39
- } = props;
40
-
41
40
  const [focused, setFocused] = useState(false);
42
41
  const [inputValue, setInputValue] = useState(defaultValue ?? '');
43
42
  const inputRef = useRef<any>(null);
@@ -101,6 +100,8 @@ const InputTextArea: FC<InputTextAreaProps> = props => {
101
100
  <View style={styles.rowArea}>
102
101
  <View style={styles.textAreaView}>
103
102
  <TextInput
103
+ {...props}
104
+ accessibilityLabel={`TextInput`}
104
105
  ref={inputRef}
105
106
  editable={!disabled}
106
107
  textAlignVertical="top"
package/Input/common.tsx CHANGED
@@ -2,7 +2,7 @@ import {View} from 'react-native';
2
2
  import styles from './styles';
3
3
  import {Text} from '../Text';
4
4
  import React, {FC, useContext} from 'react';
5
- import {ApplicationContext} from '../Navigation';
5
+ import {ApplicationContext} from '../Application';
6
6
  import {Icon} from '../Icon';
7
7
  import {Styles} from '../Consts';
8
8
 
package/Input/index.tsx CHANGED
@@ -89,6 +89,8 @@ export interface InputSearchProps extends InputPropsOmitForSearch {
89
89
  * Defaults to `true` if not provided.
90
90
  */
91
91
  showBorder?: boolean;
92
+
93
+ onPressButtonText?: () => void;
92
94
  }
93
95
 
94
96
  export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
package/Layout/Card.tsx CHANGED
@@ -1,21 +1,32 @@
1
- import React, {useContext} from 'react';
2
- import {View} from 'react-native';
3
-
1
+ import React from 'react';
2
+ import {Dimensions, View} from 'react-native';
3
+ import {useGridSystem, validateChildren} from './utils';
4
4
  import {CardProps, GridContextProps} from './types';
5
5
  import {GridContext} from './index';
6
6
  import {GRIDVIEW} from '../Consts';
7
+ import Item from './Item';
8
+
9
+ const Card: React.FC<CardProps> = ({children, style}) => {
10
+ const {numberOfColumns} = useGridSystem();
7
11
 
8
- const Card: React.FC<CardProps> = ({
9
- widthSpan = 12,
10
- heightSpan,
11
- usePadding,
12
- children,
13
- style,
14
- }) => {
15
- const grid = useContext(GridContext);
12
+ const gutterSize = 8;
13
+ const margin = 12;
14
+
15
+ const widthSection = Dimensions.get('window').width - margin * 2;
16
+ const totalGutterSize = gutterSize * (numberOfColumns - 1);
17
+ const sizePerSpan = (widthSection - totalGutterSize - 24) / numberOfColumns;
16
18
 
19
+ const gridContext: GridContextProps = {
20
+ numberOfColumns,
21
+ gutterSize,
22
+ margin,
23
+ sizePerSpan,
24
+ getSizeSpan: span => {
25
+ return span * sizePerSpan + (span - 1) * gutterSize;
26
+ },
27
+ };
17
28
  /**
18
- * render overlay view only dev mode
29
+ * render overlay only dev mode
19
30
  */
20
31
  const renderOverlay = () => {
21
32
  return (
@@ -34,55 +45,98 @@ const Card: React.FC<CardProps> = ({
34
45
  );
35
46
  };
36
47
 
37
- const styles: any = style ?? {};
48
+ /**
49
+ * build a row view in side session
50
+ * @param rows
51
+ * @param cursor
52
+ * @param endRow
53
+ */
54
+ const addRowView = (
55
+ rows: any[],
56
+ cursor: number = 0,
57
+ endRow: boolean = false,
58
+ ) => {
59
+ return (
60
+ <View
61
+ key={`Item${cursor}`}
62
+ style={{
63
+ flexDirection: 'row',
64
+ marginBottom: endRow ? 0 : gridContext.gutterSize,
65
+ }}>
66
+ {rows.map((i: React.ReactElement, index: number) => {
67
+ return (
68
+ <View key={`Item${cursor}${index}`} style={{flexDirection: 'row'}}>
69
+ {index != 0 && (
70
+ <View style={{width: gridContext.gutterSize}}></View>
71
+ )}
72
+ {i}
73
+ </View>
74
+ );
75
+ })}
76
+ </View>
77
+ );
78
+ };
79
+
80
+ /**
81
+ * render children content for card
82
+ * @param children
83
+ */
84
+ const renderView = (
85
+ children: any,
86
+ ): React.ReactElement | React.ReactElement[] => {
87
+ const element: React.ReactElement | React.ReactElement[] = [];
88
+ if (Array.isArray(children)) {
89
+ let cursor = 0;
90
+ let rows: any[] = [];
91
+ for (let i = 0; i < children.length; ++i) {
92
+ const item = children[i];
93
+ const totalSpan = rows
94
+ .concat([item])
95
+ .map(i => i.props?.widthSpan)
96
+ .reduce((previousValue, currentValue) => {
97
+ return previousValue + currentValue;
98
+ });
38
99
 
39
- const numberOfColumns = 12;
40
- const gutterSize = 8;
41
- let margin = 0;
42
- if (usePadding) {
43
- margin = 12;
44
- }
45
- const widthSection = grid.getSizeSpan(widthSpan) - margin * 2;
46
- const totalGutterSize = gutterSize * (numberOfColumns - 1);
47
- const sizePerSpan = (widthSection - totalGutterSize) / numberOfColumns;
48
- const gridContext: GridContextProps = {
49
- numberOfColumns,
50
- gutterSize,
51
- margin,
52
- sizePerSpan,
53
- getSizeSpan: span => {
54
- return span * sizePerSpan + (span - 1) * gutterSize;
55
- },
100
+ if (totalSpan <= gridContext.numberOfColumns) {
101
+ rows.push(item);
102
+ } else {
103
+ cursor += 1;
104
+ element.push(addRowView(rows, cursor));
105
+ rows = [item];
106
+ }
107
+
108
+ if (i == children.length - 1) {
109
+ cursor += 1;
110
+ element.push(addRowView(rows, cursor, true));
111
+ }
112
+ }
113
+ } else {
114
+ element.push(children);
115
+ }
116
+ return element;
56
117
  };
57
118
 
58
119
  return (
59
- <View
60
- accessibilityLabel={`Card`}
61
- style={{
62
- ...styles,
63
- width: grid.getSizeSpan(widthSpan),
64
- height: heightSpan ? grid.getSizeSpan(heightSpan) : undefined,
65
- paddingHorizontal: margin,
66
- overflow: 'hidden',
67
- margin: undefined,
68
- marginTop: undefined,
69
- marginBottom: undefined,
70
- marginLeft: undefined,
71
- marginRight: undefined,
72
- }}>
73
- <GridContext.Provider value={gridContext}>
74
- {children}
75
- </GridContext.Provider>
76
- {GRIDVIEW && renderOverlay()}
77
- </View>
120
+ <GridContext.Provider value={gridContext}>
121
+ <View
122
+ accessibilityLabel={`Card`}
123
+ style={[
124
+ style,
125
+ {
126
+ width: widthSection,
127
+ marginHorizontal: gridContext.margin,
128
+ padding: 12,
129
+ flexDirection: 'row',
130
+ flexWrap: 'wrap',
131
+ },
132
+ ]}>
133
+ {renderView(validateChildren(children, [Item]))}
134
+ {GRIDVIEW && renderOverlay()}
135
+ </View>
136
+ </GridContext.Provider>
78
137
  );
79
138
  };
80
139
 
81
- Card.defaultProps = {
82
- widthSpan: 12,
83
- usePadding: false,
84
- };
85
-
86
140
  Card.displayName = 'Card';
87
141
 
88
142
  export default Card;
@@ -1,13 +1,15 @@
1
1
  import React, {useContext} from 'react';
2
2
  import {useSafeAreaInsets} from 'react-native-safe-area-context';
3
3
  import {Dimensions, StyleSheet, View} from 'react-native';
4
- import {ApplicationContext} from '../Navigation';
4
+ import {ApplicationContext} from '../Application';
5
5
  import {Colors, Spacing} from '../Consts';
6
6
  import {GridContextProps} from './types';
7
+ import {useGridSystem} from './utils';
7
8
 
8
9
  const GridSystem: React.FC = () => {
9
10
  const {theme} = useContext(ApplicationContext);
10
- const numberOfColumns = 12;
11
+ const {numberOfColumns} = useGridSystem();
12
+
11
13
  const gutterSize = 12;
12
14
  const margin = 12;
13
15
  const widthSection = Dimensions.get('window').width - margin * 2;
@@ -0,0 +1,60 @@
1
+ import React, {useContext} from 'react';
2
+ import {View} from 'react-native';
3
+
4
+ import {ItemProps} from './types';
5
+ import {GridContext} from './index';
6
+ import {GRIDVIEW} from '../Consts';
7
+
8
+ const Item: React.FC<ItemProps> = ({
9
+ widthSpan,
10
+ heightSpan,
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
+ return (
37
+ <View
38
+ accessibilityLabel={`Item`}
39
+ style={[
40
+ style,
41
+ {
42
+ width: grid.getSizeSpan(widthSpan ?? grid.numberOfColumns),
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
+ ]}>
52
+ {children}
53
+ {GRIDVIEW && renderOverlay()}
54
+ </View>
55
+ );
56
+ };
57
+
58
+ Item.displayName = 'Item';
59
+
60
+ export default Item;
@@ -0,0 +1,188 @@
1
+ import {
2
+ Animated,
3
+ KeyboardAvoidingView,
4
+ Platform,
5
+ Text,
6
+ View,
7
+ } from 'react-native';
8
+ import {useHeaderHeight} from '@react-navigation/stack';
9
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
10
+ import React, {useContext, useEffect, useRef} from 'react';
11
+ import {ScreenProps} from '../Application/types';
12
+ import {Spacing, Styles} from '../Consts';
13
+ import {Card, Section, validateChildren} from './index';
14
+ import {ApplicationContext} from '../Application';
15
+ import Navigation from '../Application/Navigation';
16
+ import {HeaderTitle} from '../Application/Components';
17
+
18
+ const Screen: React.FC<ScreenProps> = ({
19
+ children,
20
+ enableKeyboardAvoidingView = false,
21
+ scrollable = false,
22
+ navigation,
23
+ marginHeader,
24
+ useAnimatedHeader = false,
25
+ useExtendedHeader = false,
26
+ headerBackground,
27
+ scrollViewProps,
28
+ footerComponent: Footer,
29
+ }) => {
30
+ const animatedValue = useRef<Animated.Value | undefined>(undefined);
31
+ const {theme} = useContext(ApplicationContext);
32
+ const insets = useSafeAreaInsets();
33
+ const headerTransparent = useAnimatedHeader || useExtendedHeader;
34
+
35
+ let handleScroll;
36
+ let imageAnimatedStyle = {};
37
+ let opacity;
38
+ let Component: any = View;
39
+ animatedValue.current = undefined;
40
+
41
+ /**
42
+ * automatic margin content if use header transparent
43
+ */
44
+ if (headerTransparent) {
45
+ animatedValue.current = new Animated.Value(0);
46
+ marginHeader = marginHeader ?? useHeaderHeight();
47
+ if (useExtendedHeader) {
48
+ headerBackground = theme.assets?.headerBackground;
49
+ }
50
+ }
51
+
52
+ useEffect(() => {
53
+ let title = {};
54
+ if (useExtendedHeader) {
55
+ title = {headerTitle: HeaderTitle};
56
+ }
57
+ navigation?.setOptions({
58
+ animatedValue: animatedValue.current,
59
+ headerTransparent,
60
+ ...title,
61
+ });
62
+ }, [useExtendedHeader, useAnimatedHeader]);
63
+
64
+ /**
65
+ * animated for header stack when used bottom tab
66
+ */
67
+ useEffect(() => {
68
+ const current: any = navigation;
69
+ if (headerTransparent) {
70
+ return current?.addListener?.('focus', () => {
71
+ const stackNavigation = new Navigation(current?.getParent(), theme);
72
+ stackNavigation?.setOptions({
73
+ animatedValue: animatedValue.current,
74
+ headerTransparent: true,
75
+ });
76
+ });
77
+ }
78
+ }, [useAnimatedHeader, useExtendedHeader, navigation]);
79
+
80
+ /**
81
+ * animated when use scroll && animated value
82
+ */
83
+ if (scrollable) {
84
+ Component = Animated.ScrollView;
85
+ if (useAnimatedHeader) {
86
+ opacity = animatedValue.current?.interpolate({
87
+ inputRange: [0, 100],
88
+ outputRange: [1, 0],
89
+ extrapolate: 'clamp',
90
+ });
91
+ imageAnimatedStyle = {
92
+ transform: [
93
+ {
94
+ scale: animatedValue.current?.interpolate?.({
95
+ inputRange: [-300, 0, 1],
96
+ outputRange: [1.75, 1, 1],
97
+ extrapolate: 'clamp',
98
+ }),
99
+ },
100
+ ],
101
+ };
102
+ handleScroll = Animated.event(
103
+ [
104
+ {
105
+ nativeEvent: {
106
+ contentOffset: {y: animatedValue.current as Animated.Value},
107
+ },
108
+ },
109
+ ],
110
+ {useNativeDriver: true},
111
+ );
112
+ }
113
+ }
114
+
115
+ /**
116
+ * build content for screen
117
+ */
118
+ const renderContent = () => {
119
+ const results = validateChildren(children, [Section, Card]);
120
+ if (Array.isArray(results)) {
121
+ return results.map((item, index) => {
122
+ const space = item.props?.useMargin === false ? 0 : Spacing.M;
123
+ return (
124
+ <View
125
+ key={`ScreenItem${index}`}
126
+ style={{
127
+ marginTop: space,
128
+ flex: item.props?.expanded ? 1 : undefined,
129
+ }}>
130
+ {item}
131
+ </View>
132
+ );
133
+ });
134
+ }
135
+ return results;
136
+ };
137
+
138
+ return (
139
+ <View style={Styles.flex} accessibilityLabel={`ScreenContainer`}>
140
+ <View
141
+ style={{
142
+ position: 'absolute',
143
+ maxHeight: 215,
144
+ width: '100%',
145
+ overflow: 'hidden',
146
+ }}>
147
+ {!!headerBackground && (
148
+ <Animated.Image
149
+ source={{
150
+ uri: headerBackground,
151
+ }}
152
+ style={{
153
+ opacity: opacity ?? 1,
154
+ aspectRatio: 1.75,
155
+ ...imageAnimatedStyle,
156
+ }}
157
+ />
158
+ )}
159
+ </View>
160
+ <KeyboardAvoidingView
161
+ style={Styles.flex}
162
+ enabled={enableKeyboardAvoidingView}
163
+ behavior={Platform.select({
164
+ ios: 'padding',
165
+ android: undefined,
166
+ })}>
167
+ <Component
168
+ {...scrollViewProps}
169
+ onScroll={handleScroll}
170
+ style={[Styles.flex, {marginTop: marginHeader}]}>
171
+ {renderContent()}
172
+ </Component>
173
+ {Footer && (
174
+ <View
175
+ style={{
176
+ paddingTop: Spacing.S,
177
+ paddingBottom: insets.bottom + Spacing.S,
178
+ backgroundColor: theme.colors.background.surface,
179
+ }}>
180
+ <Section>{Footer}</Section>
181
+ </View>
182
+ )}
183
+ </KeyboardAvoidingView>
184
+ </View>
185
+ );
186
+ };
187
+
188
+ export default Screen;
@@ -1,13 +1,18 @@
1
1
  import React from 'react';
2
2
  import {Dimensions, View} from 'react-native';
3
- import {validateChildren} from './utils';
4
- import Card from './Card';
3
+ import {useGridSystem, validateChildren} from './utils';
5
4
  import {GridContextProps, SectionProps} from './types';
6
5
  import {GridContext} from './index';
7
6
  import {GRIDVIEW} from '../Consts';
7
+ import Item from './Item';
8
+
9
+ const Section: React.FC<SectionProps> = ({
10
+ children,
11
+ useMargin = true,
12
+ backgroundColor,
13
+ }) => {
14
+ const {numberOfColumns} = useGridSystem();
8
15
 
9
- const Section: React.FC<SectionProps> = ({children, useMargin = true}) => {
10
- const numberOfColumns = 12;
11
16
  const gutterSize = 12;
12
17
  let margin = 0;
13
18
  if (useMargin) {
@@ -124,12 +129,13 @@ const Section: React.FC<SectionProps> = ({children, useMargin = true}) => {
124
129
  <View
125
130
  accessibilityLabel={`Section`}
126
131
  style={{
127
- width: gridContext.getSizeSpan(12),
132
+ width: widthSection,
128
133
  marginHorizontal: gridContext.margin,
129
134
  flexDirection: 'row',
130
135
  flexWrap: 'wrap',
136
+ backgroundColor: backgroundColor,
131
137
  }}>
132
- {renderView(validateChildren(children, Card))}
138
+ {renderView(validateChildren(children, [Item]))}
133
139
  {GRIDVIEW && renderOverlay()}
134
140
  </View>
135
141
  </GridContext.Provider>
@@ -138,7 +144,4 @@ const Section: React.FC<SectionProps> = ({children, useMargin = true}) => {
138
144
 
139
145
  Section.displayName = 'Section';
140
146
 
141
- Section.defaultProps = {
142
- useMargin: true,
143
- };
144
147
  export default Section;
package/Layout/index.ts CHANGED
@@ -4,6 +4,7 @@ import GridSystem from './GridSystem';
4
4
  import {validateChildren} from './utils';
5
5
  import {createContext} from 'react';
6
6
  import {GridContextProps} from './types';
7
+ import Item from './Item';
7
8
 
8
9
  const GridContext = createContext<GridContextProps>({
9
10
  numberOfColumns: 12,
@@ -13,4 +14,4 @@ const GridContext = createContext<GridContextProps>({
13
14
  getSizeSpan: span => 0,
14
15
  });
15
16
 
16
- export {GridContext, Card, Section, GridSystem, validateChildren};
17
+ export {GridContext, Card, Section, GridSystem, validateChildren, Item};
package/Layout/types.ts CHANGED
@@ -40,22 +40,22 @@ export interface SectionProps extends ViewProps {
40
40
  * Defaults to `false` if not provided.
41
41
  */
42
42
  useMargin?: boolean;
43
+
44
+ backgroundColor?: string;
43
45
  }
44
46
 
45
- export interface CardProps extends ViewProps {
47
+ export interface ItemProps extends ViewProps {
46
48
  /**
47
49
  * Represents the width of the Card component in terms of span numbers (1-12).
48
50
  */
49
- widthSpan: SpanNumber;
51
+ widthSpan?: SpanNumber;
50
52
 
51
53
  /**
52
54
  * Optional. Represents the height of the Card component in terms of span numbers (1-12).
53
55
  */
54
56
  heightSpan?: SpanNumber;
57
+ }
55
58
 
56
- /**
57
- * Optional. If `true`, padding will be applied to the Card component.
58
- * Defaults to `false` if not provided.
59
- */
60
- usePadding?: boolean;
59
+ export interface CardProps extends ViewProps {
60
+ background?: string;
61
61
  }