@momo-kits/foundation 0.75.1-beta.10

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 (76) hide show
  1. package/Assets/header-background.png +0 -0
  2. package/Assets/icon.json +3947 -0
  3. package/Button/index.tsx +278 -0
  4. package/Button/styles.ts +41 -0
  5. package/CheckBox/index.tsx +61 -0
  6. package/CheckBox/styles.ts +15 -0
  7. package/CheckBox/types.ts +38 -0
  8. package/Consts/colors+spacing+radius.ts +214 -0
  9. package/Consts/index.ts +4 -0
  10. package/Consts/styles.ts +78 -0
  11. package/Consts/theme.ts +121 -0
  12. package/Divider/index.tsx +19 -0
  13. package/Icon/index.tsx +37 -0
  14. package/Icon/types.ts +27 -0
  15. package/IconButton/index.tsx +140 -0
  16. package/IconButton/styles.ts +19 -0
  17. package/Image/index.tsx +80 -0
  18. package/Image/styles.ts +13 -0
  19. package/Image/types.ts +3 -0
  20. package/Input/Input.tsx +136 -0
  21. package/Input/InputMoney.tsx +132 -0
  22. package/Input/InputSearch.tsx +161 -0
  23. package/Input/InputTextArea.tsx +152 -0
  24. package/Input/common.tsx +118 -0
  25. package/Input/index.tsx +96 -0
  26. package/Input/styles.ts +122 -0
  27. package/Input/utils.ts +69 -0
  28. package/Layout/Card.tsx +141 -0
  29. package/Layout/GridSystem.tsx +124 -0
  30. package/Layout/Item.tsx +60 -0
  31. package/Layout/ScreenContainer.tsx +121 -0
  32. package/Layout/Section.tsx +141 -0
  33. package/Layout/index.ts +17 -0
  34. package/Layout/types.ts +59 -0
  35. package/Layout/utils.ts +60 -0
  36. package/Navigation/BottomTab.tsx +39 -0
  37. package/Navigation/Components.tsx +365 -0
  38. package/Navigation/ModalScreen.tsx +226 -0
  39. package/Navigation/Navigation.ts +44 -0
  40. package/Navigation/NavigationButton.tsx +54 -0
  41. package/Navigation/NavigationContainer.tsx +77 -0
  42. package/Navigation/Navigator.ts +82 -0
  43. package/Navigation/StackScreen.tsx +27 -0
  44. package/Navigation/index.ts +14 -0
  45. package/Navigation/types.ts +158 -0
  46. package/Navigation/utils.tsx +138 -0
  47. package/Pagination/Dot.tsx +16 -0
  48. package/Pagination/PaginationDot.tsx +33 -0
  49. package/Pagination/PaginationNumber.tsx +23 -0
  50. package/Pagination/PaginationScroll.tsx +88 -0
  51. package/Pagination/PaginationWhiteDot.tsx +32 -0
  52. package/Pagination/index.tsx +25 -0
  53. package/Pagination/styles.ts +47 -0
  54. package/Pagination/types.ts +38 -0
  55. package/Popup/PopupNotify.tsx +215 -0
  56. package/Popup/PopupPromotion.tsx +77 -0
  57. package/Popup/index.tsx +4 -0
  58. package/Popup/types.ts +70 -0
  59. package/Radio/index.tsx +65 -0
  60. package/Radio/styles.ts +11 -0
  61. package/Radio/types.ts +38 -0
  62. package/Skeleton/index.tsx +72 -0
  63. package/Skeleton/styles.ts +5 -0
  64. package/Skeleton/types.ts +3 -0
  65. package/Switch/index.tsx +40 -0
  66. package/Switch/styles.ts +23 -0
  67. package/Switch/types.ts +26 -0
  68. package/Tag/index.tsx +79 -0
  69. package/Tag/styles.ts +24 -0
  70. package/Tag/types.ts +36 -0
  71. package/Text/index.tsx +123 -0
  72. package/Text/styles.ts +35 -0
  73. package/Text/types.ts +40 -0
  74. package/index.ts +38 -0
  75. package/package.json +41 -0
  76. package/publish.sh +26 -0
@@ -0,0 +1,122 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {Radius, Spacing} from '../Consts';
3
+
4
+ export default StyleSheet.create({
5
+ //input style
6
+ input: {width: '100%', paddingLeft: Spacing.M, height: '100%'},
7
+ wrapper: {
8
+ width: '100%',
9
+ },
10
+ container: {
11
+ borderWidth: 1,
12
+ borderRadius: Radius.S,
13
+ height: 56,
14
+ paddingVertical: 8,
15
+ },
16
+ smallContainer: {
17
+ borderRadius: Radius.S,
18
+ borderWidth: 1,
19
+ height: 48,
20
+ },
21
+ floatingView: {
22
+ position: 'absolute',
23
+ top: -10,
24
+ left: Spacing.S,
25
+ paddingHorizontal: Spacing.S,
26
+ flexDirection: 'row',
27
+ },
28
+ floatingIcon: {marginLeft: Spacing.XS},
29
+ errorIcon: {marginRight: Spacing.XS},
30
+ errorView: {
31
+ flexDirection: 'row',
32
+ alignItems: 'center',
33
+ marginTop: Spacing.XS,
34
+ },
35
+ inputView: {
36
+ justifyContent: 'space-between',
37
+ flex: 1,
38
+ },
39
+ iconView: {
40
+ flexDirection: 'row',
41
+ alignItems: 'center',
42
+ marginLeft: Spacing.XS,
43
+ marginRight: Spacing.M,
44
+ },
45
+ icon: {
46
+ width: 24,
47
+ height: 24,
48
+ },
49
+ iconWrapper: {
50
+ width: 24,
51
+ height: 24,
52
+ justifyContent: 'center',
53
+ alignItems: 'center',
54
+ },
55
+ inputWrapper: {
56
+ flexDirection: 'row',
57
+ marginTop: Spacing.S,
58
+ },
59
+
60
+ //text area style
61
+ textAreaView: {
62
+ flex: 1,
63
+ },
64
+ textArea: {
65
+ width: '100%',
66
+ flex: 1,
67
+ paddingRight: Spacing.XS,
68
+ },
69
+ textAreaWrapper: {
70
+ borderWidth: 1,
71
+ borderRadius: Radius.S,
72
+ paddingVertical: Spacing.S,
73
+ paddingLeft: Spacing.M,
74
+ paddingRight: Spacing.S,
75
+ },
76
+ countingView: {
77
+ width: '100%',
78
+ alignItems: 'flex-end',
79
+ paddingRight: Spacing.XS,
80
+ },
81
+ rowArea: {
82
+ flexDirection: 'row',
83
+ width: '100%',
84
+ flex: 1,
85
+ marginBottom: Spacing.XS,
86
+ },
87
+
88
+ //searchInput
89
+ searchInputWrapper: {
90
+ flexDirection: 'row',
91
+ borderRadius: Radius.XL,
92
+ borderWidth: 1,
93
+ paddingHorizontal: Spacing.S,
94
+ alignItems: 'center',
95
+ flex: 1,
96
+ },
97
+ searchInput: {
98
+ height: 36,
99
+ marginLeft: Spacing.S,
100
+ flex: 1,
101
+ },
102
+ searchInputView: {
103
+ flexDirection: 'row',
104
+ alignItems: 'center',
105
+ },
106
+ iconSearchInput: {
107
+ marginLeft: Spacing.S,
108
+ },
109
+ searchInputContainer: {flexDirection: 'row', alignItems: 'center'},
110
+ textButton: {marginLeft: Spacing.L},
111
+ divider: {
112
+ width: 1,
113
+ marginLeft: Spacing.XS,
114
+ },
115
+ moneyInput: {
116
+ width: '100%',
117
+ paddingLeft: Spacing.M,
118
+ height: '100%',
119
+ fontSize: 20,
120
+ fontWeight: 'bold',
121
+ },
122
+ });
package/Input/utils.ts ADDED
@@ -0,0 +1,69 @@
1
+ const formatNumberToMoney = (number: number, currency = '') => {
2
+ if (!number || isNaN(number) || Number(number) === 0) {
3
+ return `0${currency}`;
4
+ }
5
+
6
+ const array = [];
7
+ let result = '';
8
+ let isNegative = false;
9
+
10
+ if (number < 0) {
11
+ isNegative = true;
12
+ }
13
+
14
+ const numberString = Math.abs(number).toString();
15
+ if (numberString.length < 3) {
16
+ return numberString + currency;
17
+ }
18
+
19
+ let count = 0;
20
+ for (let i = numberString.length - 1; i >= 0; i -= 1) {
21
+ count += 1;
22
+ if (numberString[i] === '.' || numberString[i] === ',') {
23
+ array.push(',');
24
+ count = 0;
25
+ } else {
26
+ array.push(numberString[i]);
27
+ }
28
+ if (count === 3 && i >= 1) {
29
+ array.push('.');
30
+ count = 0;
31
+ }
32
+ }
33
+
34
+ for (let i = array.length - 1; i >= 0; i -= 1) {
35
+ result += array[i];
36
+ }
37
+
38
+ if (isNegative) {
39
+ result = `-${result}`;
40
+ }
41
+
42
+ return result + currency;
43
+ };
44
+
45
+ const formatMoneyToNumber = (money: string, currencyUnit: string) => {
46
+ if (money && money.length > 0) {
47
+ const moneyString = money
48
+ .replace(currencyUnit, '')
49
+ .replace(/,/g, '')
50
+ .replace(/đ/g, '')
51
+ .replace(/\./g, '')
52
+ .replace(/ /g, '');
53
+ const number = Number(moneyString);
54
+ if (isNaN(number)) {
55
+ return 0;
56
+ }
57
+ return number;
58
+ }
59
+
60
+ return Number(money);
61
+ };
62
+ const checkTyping = (text: string, value: boolean, setValue: any) => {
63
+ let typing = text?.length > 0;
64
+ if (typing != value) {
65
+ setValue(typing);
66
+ }
67
+ };
68
+
69
+ export {formatMoneyToNumber, formatNumberToMoney, checkTyping};
@@ -0,0 +1,141 @@
1
+ import React from 'react';
2
+ import {Dimensions, View} from 'react-native';
3
+ import {validateChildren} from './utils';
4
+ import {CardProps, GridContextProps} from './types';
5
+ import {GridContext} from './index';
6
+ import {GRIDVIEW} from '../Consts';
7
+ import Item from './Item';
8
+
9
+ const Card: React.FC<CardProps> = ({children, style}) => {
10
+ const numberOfColumns = 12;
11
+ const gutterSize = 8;
12
+ const margin = 12;
13
+
14
+ const widthSection = Dimensions.get('window').width - margin * 2;
15
+ const totalGutterSize = gutterSize * (numberOfColumns - 1);
16
+ const sizePerSpan = (widthSection - totalGutterSize - 24) / numberOfColumns;
17
+
18
+ const gridContext: GridContextProps = {
19
+ numberOfColumns,
20
+ gutterSize,
21
+ margin,
22
+ sizePerSpan,
23
+ getSizeSpan: span => {
24
+ return span * sizePerSpan + (span - 1) * gutterSize;
25
+ },
26
+ };
27
+ /**
28
+ * render overlay only dev mode
29
+ */
30
+ const renderOverlay = () => {
31
+ return (
32
+ <View
33
+ pointerEvents={'none'}
34
+ style={{
35
+ position: 'absolute',
36
+ top: 0,
37
+ bottom: 0,
38
+ left: 0,
39
+ right: 0,
40
+ borderColor: 'red',
41
+ borderWidth: 1,
42
+ }}
43
+ />
44
+ );
45
+ };
46
+
47
+ /**
48
+ * build a row view in side session
49
+ * @param rows
50
+ * @param cursor
51
+ * @param endRow
52
+ */
53
+ const addRowView = (
54
+ rows: any[],
55
+ cursor: number = 0,
56
+ endRow: boolean = false,
57
+ ) => {
58
+ return (
59
+ <View
60
+ key={`Item${cursor}`}
61
+ style={{
62
+ flexDirection: 'row',
63
+ marginBottom: endRow ? 0 : gridContext.gutterSize,
64
+ }}>
65
+ {rows.map((i: React.ReactElement, index: number) => {
66
+ return (
67
+ <View key={`Item${cursor}${index}`} style={{flexDirection: 'row'}}>
68
+ {index != 0 && (
69
+ <View style={{width: gridContext.gutterSize}}></View>
70
+ )}
71
+ {i}
72
+ </View>
73
+ );
74
+ })}
75
+ </View>
76
+ );
77
+ };
78
+
79
+ /**
80
+ * render children content for card
81
+ * @param children
82
+ */
83
+ const renderView = (
84
+ children: any,
85
+ ): React.ReactElement | React.ReactElement[] => {
86
+ const element: React.ReactElement | React.ReactElement[] = [];
87
+ if (Array.isArray(children)) {
88
+ let cursor = 0;
89
+ let rows: any[] = [];
90
+ for (let i = 0; i < children.length; ++i) {
91
+ const item = children[i];
92
+ const totalSpan = rows
93
+ .concat([item])
94
+ .map(i => i.props?.widthSpan)
95
+ .reduce((previousValue, currentValue) => {
96
+ return previousValue + currentValue;
97
+ });
98
+
99
+ if (totalSpan <= gridContext.numberOfColumns) {
100
+ rows.push(item);
101
+ } else {
102
+ cursor += 1;
103
+ element.push(addRowView(rows, cursor));
104
+ rows = [item];
105
+ }
106
+
107
+ if (i == children.length - 1) {
108
+ cursor += 1;
109
+ element.push(addRowView(rows, cursor, true));
110
+ }
111
+ }
112
+ } else {
113
+ element.push(children);
114
+ }
115
+ return element;
116
+ };
117
+
118
+ const styles: any = style ?? {};
119
+
120
+ return (
121
+ <GridContext.Provider value={gridContext}>
122
+ <View
123
+ accessibilityLabel={`Card`}
124
+ style={{
125
+ ...styles,
126
+ width: widthSection,
127
+ marginHorizontal: gridContext.margin,
128
+ padding: 12,
129
+ flexDirection: 'row',
130
+ flexWrap: 'wrap',
131
+ }}>
132
+ {renderView(validateChildren(children, [Item]))}
133
+ {GRIDVIEW && renderOverlay()}
134
+ </View>
135
+ </GridContext.Provider>
136
+ );
137
+ };
138
+
139
+ Card.displayName = 'Card';
140
+
141
+ export default Card;
@@ -0,0 +1,124 @@
1
+ import React, {useContext} from 'react';
2
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
3
+ import {Dimensions, StyleSheet, View} from 'react-native';
4
+ import {ApplicationContext} from '../Navigation';
5
+ import {Colors, Spacing} from '../Consts';
6
+ import {GridContextProps} from './types';
7
+
8
+ const GridSystem: React.FC = () => {
9
+ const {theme} = useContext(ApplicationContext);
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
+ };
26
+ const insets = useSafeAreaInsets();
27
+
28
+ const list = [];
29
+ for (let i = 1; i <= grid.numberOfColumns; i++) {
30
+ list.push(i);
31
+ }
32
+
33
+ return (
34
+ <>
35
+ <View
36
+ pointerEvents="none"
37
+ style={[
38
+ styles.gridContainer,
39
+ insets,
40
+ {
41
+ borderColor: theme.colors.error.primary,
42
+ marginHorizontal: grid.margin,
43
+ },
44
+ ]}>
45
+ {list.map((i, index) => {
46
+ return (
47
+ <View style={{flexDirection: 'row'}} key={index.toString()}>
48
+ {index != -0 && <View style={{width: grid.gutterSize}} />}
49
+ <View
50
+ key={index.toString()}
51
+ pointerEvents="none"
52
+ style={[
53
+ styles.gridColumn,
54
+ {
55
+ width: grid.sizePerSpan,
56
+ },
57
+ ]}
58
+ />
59
+ </View>
60
+ );
61
+ })}
62
+ </View>
63
+ <View pointerEvents="none" style={styles.dangerLeftContainer} />
64
+ <View pointerEvents="none" style={styles.dangerRightContainer} />
65
+ <View
66
+ pointerEvents="none"
67
+ style={[styles.dangerTopContainer, {height: insets.top}]}
68
+ />
69
+ <View
70
+ pointerEvents="none"
71
+ style={[styles.dangerBottomContainer, {height: insets.bottom}]}
72
+ />
73
+ </>
74
+ );
75
+ };
76
+
77
+ const styles = StyleSheet.create({
78
+ gridContainer: {
79
+ position: 'absolute',
80
+ top: 0,
81
+ bottom: 0,
82
+ left: 0,
83
+ right: 0,
84
+ flexDirection: 'row',
85
+ borderWidth: 1,
86
+ },
87
+ gridColumn: {
88
+ height: '100%',
89
+ opacity: 0.2,
90
+ backgroundColor: Colors.blue_07,
91
+ },
92
+ dangerTopContainer: {
93
+ opacity: 0.2,
94
+ backgroundColor: Colors.red_03,
95
+ width: '100%',
96
+ top: 0,
97
+ position: 'absolute',
98
+ },
99
+ dangerBottomContainer: {
100
+ opacity: 0.2,
101
+ backgroundColor: Colors.red_03,
102
+ width: '100%',
103
+ bottom: 0,
104
+ position: 'absolute',
105
+ },
106
+ dangerLeftContainer: {
107
+ opacity: 0.2,
108
+ backgroundColor: Colors.red_03,
109
+ width: Spacing.M,
110
+ height: '100%',
111
+ left: 0,
112
+ position: 'absolute',
113
+ },
114
+ dangerRightContainer: {
115
+ opacity: 0.2,
116
+ backgroundColor: Colors.red_03,
117
+ width: Spacing.M,
118
+ height: '100%',
119
+ right: 0,
120
+ position: 'absolute',
121
+ },
122
+ });
123
+
124
+ export default GridSystem;
@@ -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 = 12,
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
+ const styles: any = style ?? {};
37
+
38
+ return (
39
+ <View
40
+ accessibilityLabel={`Item`}
41
+ style={{
42
+ ...styles,
43
+ width: grid.getSizeSpan(widthSpan),
44
+ height: heightSpan ? grid.getSizeSpan(heightSpan) : undefined,
45
+ overflow: 'hidden',
46
+ margin: undefined,
47
+ marginTop: undefined,
48
+ marginBottom: undefined,
49
+ marginLeft: undefined,
50
+ marginRight: undefined,
51
+ }}>
52
+ {children}
53
+ {GRIDVIEW && renderOverlay()}
54
+ </View>
55
+ );
56
+ };
57
+
58
+ Item.displayName = 'Item';
59
+
60
+ export default Item;
@@ -0,0 +1,121 @@
1
+ import {Animated, KeyboardAvoidingView, Platform, View} from 'react-native';
2
+ import {useHeaderHeight} from '@react-navigation/stack';
3
+ import {useSafeAreaInsets} from 'react-native-safe-area-context';
4
+ import React, {useContext} from 'react';
5
+ import {ScreenContainerProps} from '../Navigation/types';
6
+ import {Spacing, Styles} from '../Consts';
7
+ import {Section, Card, validateChildren} from './index';
8
+ import {ApplicationContext} from '../Navigation';
9
+
10
+ const ScreenContainer: React.FC<ScreenContainerProps> = ({
11
+ children,
12
+ enableKeyboardAvoidingView,
13
+ scrollable,
14
+ scrollY,
15
+ headerBackground,
16
+ scrollViewProps,
17
+ footerComponent: Footer,
18
+ }) => {
19
+ const {theme} = useContext(ApplicationContext);
20
+ const insets = useSafeAreaInsets();
21
+ let marginHeader = 0;
22
+ let handleScroll;
23
+ let imageAnimatedStyle = {};
24
+ let Component: any = View;
25
+ if (scrollable) {
26
+ Component = Animated.ScrollView;
27
+ }
28
+ if (scrollY) {
29
+ marginHeader = useHeaderHeight();
30
+ imageAnimatedStyle = {
31
+ transform: [
32
+ {
33
+ scale: scrollY.interpolate?.({
34
+ inputRange: [-300, 0, 1],
35
+ outputRange: [1.75, 1, 1],
36
+ extrapolate: 'clamp',
37
+ }),
38
+ },
39
+ ],
40
+ };
41
+ handleScroll = Animated.event(
42
+ [{nativeEvent: {contentOffset: {y: scrollY}}}],
43
+ {useNativeDriver: true},
44
+ );
45
+ }
46
+
47
+ /**
48
+ * build content for screen
49
+ */
50
+ const renderContent = () => {
51
+ const results = validateChildren(children, [Section, Card]);
52
+ if (Array.isArray(results)) {
53
+ return results.map((item, index) => {
54
+ return (
55
+ <View
56
+ key={`ScreenItem${index}`}
57
+ style={{
58
+ marginTop: Spacing.M,
59
+ flex: item.props?.expanded ? 1 : undefined,
60
+ }}>
61
+ {item}
62
+ </View>
63
+ );
64
+ });
65
+ }
66
+ return results;
67
+ };
68
+
69
+ return (
70
+ <View style={Styles.flex} accessibilityLabel={`ScreenContainer`}>
71
+ <View
72
+ style={{
73
+ position: 'absolute',
74
+ height: 300,
75
+ width: '100%',
76
+ }}>
77
+ {!!headerBackground && (
78
+ <Animated.Image
79
+ source={{
80
+ uri: headerBackground,
81
+ }}
82
+ style={{
83
+ aspectRatio: 1.3,
84
+ ...imageAnimatedStyle,
85
+ }}
86
+ />
87
+ )}
88
+ </View>
89
+ <KeyboardAvoidingView
90
+ style={Styles.flex}
91
+ enabled={enableKeyboardAvoidingView}
92
+ behavior={Platform.select({
93
+ ios: 'padding',
94
+ android: undefined,
95
+ })}>
96
+ <Component
97
+ {...scrollViewProps}
98
+ onScroll={handleScroll}
99
+ style={[Styles.flex, {marginTop: marginHeader}]}>
100
+ {renderContent()}
101
+ </Component>
102
+ {Footer && (
103
+ <View
104
+ style={{
105
+ paddingTop: Spacing.S,
106
+ paddingBottom: insets.bottom,
107
+ backgroundColor: theme.colors.background.surface,
108
+ }}>
109
+ <Section>{Footer}</Section>
110
+ </View>
111
+ )}
112
+ </KeyboardAvoidingView>
113
+ </View>
114
+ );
115
+ };
116
+
117
+ ScreenContainer.defaultProps = {
118
+ enableKeyboardAvoidingView: false,
119
+ scrollable: false,
120
+ };
121
+ export default ScreenContainer;