@momo-kits/foundation 0.76.1-beta.2 → 0.77.1-optimize.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 (100) hide show
  1. package/Application/BottomTab/BottomTabBar.tsx +439 -0
  2. package/Application/BottomTab/index.tsx +138 -0
  3. package/Application/Components.tsx +348 -167
  4. package/Application/ModalScreen.tsx +135 -98
  5. package/Application/Navigation.ts +22 -16
  6. package/Application/NavigationContainer.tsx +99 -48
  7. package/Application/Navigator.ts +110 -41
  8. package/Application/StackScreen.tsx +129 -8
  9. package/Application/index.ts +23 -4
  10. package/Application/types.ts +86 -34
  11. package/Application/utils.tsx +67 -49
  12. package/Assets/DotAnimation.json +256 -0
  13. package/Assets/SpinnerAnimation.json +1027 -0
  14. package/Assets/icon.json +83 -5
  15. package/Assets/icon_bank.json +506 -0
  16. package/Assets/language.json +202 -0
  17. package/Badge/Badge.tsx +56 -0
  18. package/Badge/BadgeDot.tsx +11 -0
  19. package/Badge/BadgeRibbon.tsx +125 -0
  20. package/Badge/Shape.tsx +29 -0
  21. package/Badge/index.tsx +7 -0
  22. package/Badge/styles.ts +58 -0
  23. package/Badge/types.ts +63 -0
  24. package/Button/index.tsx +91 -40
  25. package/Button/styles.ts +19 -0
  26. package/CheckBox/index.tsx +58 -43
  27. package/CheckBox/styles.ts +1 -1
  28. package/CheckBox/types.ts +6 -4
  29. package/Consts/colors+spacing+radius.ts +18 -0
  30. package/Consts/styles.ts +0 -26
  31. package/Consts/theme.ts +4 -0
  32. package/Divider/index.tsx +2 -0
  33. package/Icon/index.tsx +14 -9
  34. package/Icon/types.ts +4 -3
  35. package/IconButton/index.tsx +24 -15
  36. package/Image/index.tsx +63 -47
  37. package/Image/styles.ts +1 -9
  38. package/Image/types.ts +5 -1
  39. package/Input/Input.tsx +227 -116
  40. package/Input/InputDropDown.tsx +132 -0
  41. package/Input/InputMoney.tsx +173 -111
  42. package/Input/InputOTP.tsx +257 -0
  43. package/Input/InputSearch.tsx +160 -132
  44. package/Input/InputTextArea.tsx +150 -123
  45. package/Input/common.tsx +35 -17
  46. package/Input/index.tsx +211 -18
  47. package/Input/styles.ts +44 -7
  48. package/Input/utils.ts +2 -2
  49. package/Layout/Card.tsx +67 -29
  50. package/Layout/FloatingButton.tsx +168 -0
  51. package/Layout/GridSystem.tsx +31 -21
  52. package/Layout/Item.tsx +21 -25
  53. package/Layout/ItemList.tsx +55 -0
  54. package/Layout/ItemSectionList.tsx +39 -0
  55. package/Layout/Screen.tsx +355 -153
  56. package/Layout/Section.tsx +66 -34
  57. package/Layout/index.ts +13 -3
  58. package/Layout/styles.ts +101 -0
  59. package/Layout/types.ts +1 -39
  60. package/Layout/utils.ts +27 -52
  61. package/Loader/DotLoader.tsx +37 -0
  62. package/Loader/Loader.tsx +13 -0
  63. package/Loader/ProgressBar.tsx +44 -0
  64. package/Loader/Spinner.tsx +29 -0
  65. package/Loader/index.tsx +4 -0
  66. package/Loader/styles.ts +10 -0
  67. package/Loader/types.ts +35 -0
  68. package/Loader/utils.ts +25 -0
  69. package/Pagination/PaginationDot.tsx +7 -2
  70. package/Pagination/PaginationNumber.tsx +8 -6
  71. package/Pagination/PaginationScroll.tsx +0 -1
  72. package/Pagination/PaginationWhiteDot.tsx +8 -5
  73. package/Pagination/styles.ts +3 -0
  74. package/Pagination/types.ts +2 -0
  75. package/Popup/PopupNotify.tsx +108 -46
  76. package/Popup/PopupPromotion.tsx +63 -22
  77. package/Popup/types.ts +15 -4
  78. package/Radio/index.tsx +35 -21
  79. package/Radio/types.ts +7 -5
  80. package/Skeleton/index.tsx +1 -1
  81. package/Skeleton/types.ts +3 -0
  82. package/Switch/index.tsx +35 -24
  83. package/Switch/types.ts +5 -3
  84. package/Tag/index.tsx +2 -4
  85. package/Text/index.tsx +27 -22
  86. package/Text/styles.ts +38 -0
  87. package/Text/types.ts +25 -13
  88. package/Text/utils.ts +1 -1
  89. package/Title/index.tsx +186 -0
  90. package/Title/styles.ts +79 -0
  91. package/Title/types.ts +20 -0
  92. package/code-scanner.js +143 -0
  93. package/index.ts +6 -0
  94. package/migrate_typo.js +56 -0
  95. package/package.json +14 -9
  96. package/tsconfig.json +24 -0
  97. package/verify.js +47 -0
  98. package/Application/BottomTab.tsx +0 -52
  99. package/Application/NavigationButton.tsx +0 -54
  100. package/Assets/header-background.png +0 -0
package/Input/common.tsx CHANGED
@@ -1,10 +1,11 @@
1
- import {View} from 'react-native';
2
- import styles from './styles';
3
- import {Text} from '../Text';
4
1
  import React, {FC, useContext} from 'react';
2
+ import {View, ViewStyle} from 'react-native';
5
3
  import {ApplicationContext} from '../Application';
6
- import {Icon} from '../Icon';
4
+ import {Theme} from '../Application/types';
7
5
  import {Styles} from '../Consts';
6
+ import {Icon} from '../Icon';
7
+ import {scaleSize, Text} from '../Text';
8
+ import styles from './styles';
8
9
 
9
10
  type FloatingViewProps = {
10
11
  floatingValue?: string;
@@ -12,18 +13,18 @@ type FloatingViewProps = {
12
13
  disabled?: boolean;
13
14
  floatingIcon?: string;
14
15
  required?: boolean;
16
+ style?: ViewStyle;
15
17
  };
16
18
 
17
- export const DEFAULT_HEIGHT = 112;
19
+ export const DEFAULT_HEIGHT = scaleSize(104);
18
20
  export const MAX_LENGTH = 300;
19
21
 
20
22
  export const getBorderColor = (
23
+ theme: Theme,
21
24
  focused: boolean,
22
25
  errorMessage?: string,
23
26
  disabled?: boolean,
24
27
  ) => {
25
- const {theme} = useContext(ApplicationContext);
26
-
27
28
  let borderColor = theme.colors.border.default;
28
29
 
29
30
  if (focused) {
@@ -47,26 +48,39 @@ export const getSizeStyle = (size?: 'small' | 'large') => {
47
48
  }
48
49
  return styles.container;
49
50
  };
50
- export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
51
+ export const ErrorView: FC<{
52
+ errorMessage?: string;
53
+ errorSpacing?: boolean;
54
+ hintText?: string;
55
+ }> = ({errorMessage, errorSpacing, hintText}) => {
51
56
  const {theme} = useContext(ApplicationContext);
52
57
  const errorColor = theme.colors.error.primary;
53
- if (errorMessage) {
58
+ const hintColor = theme.colors.text.hint;
59
+ const hintTextDefault = hintText ?? 'Không thể chỉnh sửa';
60
+ if (errorMessage || hintText) {
54
61
  return (
55
62
  <View style={styles.errorView}>
56
63
  <View style={styles.errorIcon}>
57
- <Icon color={errorColor} source="ic_error" size={16} />
64
+ <Icon
65
+ color={errorMessage ? errorColor : hintColor}
66
+ source="ic_error"
67
+ size={16}
68
+ />
58
69
  </View>
59
70
  <Text
60
71
  style={Styles.flex}
61
- color={errorColor}
62
- numberOfLines={1}
63
- typography={'description_s'}>
64
- {errorMessage}
72
+ color={errorMessage ? errorColor : hintColor}
73
+ numberOfLines={2}
74
+ typography={'description_default_regular'}>
75
+ {errorMessage ?? hintTextDefault}
65
76
  </Text>
66
77
  </View>
67
78
  );
68
79
  }
69
- return null;
80
+ if (errorSpacing) {
81
+ return <View style={[styles.errorView, {height: 18}]} />;
82
+ }
83
+ return <View />;
70
84
  };
71
85
 
72
86
  export const FloatingView: FC<FloatingViewProps> = ({
@@ -75,6 +89,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
75
89
  disabled,
76
90
  floatingIcon,
77
91
  required,
92
+ style,
78
93
  }) => {
79
94
  const {theme} = useContext(ApplicationContext);
80
95
 
@@ -94,11 +109,14 @@ export const FloatingView: FC<FloatingViewProps> = ({
94
109
  backgroundColor: theme.colors.background.surface,
95
110
  zIndex: 10,
96
111
  },
112
+ style,
97
113
  ]}>
98
- <Text color={floatingTextColor} typography={'label_s'}>
114
+ <Text color={floatingTextColor} typography={'label_s_medium'}>
99
115
  {floatingValue}
100
116
  {required && (
101
- <Text typography={'label_s'} color={theme.colors.error.primary}>
117
+ <Text
118
+ typography={'label_s_medium'}
119
+ color={theme.colors.error.primary}>
102
120
  *
103
121
  </Text>
104
122
  )}
package/Input/index.tsx CHANGED
@@ -1,8 +1,17 @@
1
+ import {TextInputProps, ViewStyle} from 'react-native';
1
2
  import Input from './Input';
2
- import InputTextArea from './InputTextArea';
3
- import InputSearch from './InputSearch';
3
+ import InputDropDown from './InputDropDown';
4
4
  import InputMoney from './InputMoney';
5
- import {TextInputProps} from 'react-native';
5
+ import InputOTP from './InputOTP';
6
+ import InputSearch from './InputSearch';
7
+ import InputTextArea from './InputTextArea';
8
+
9
+ export interface InputRef {
10
+ focus: () => void;
11
+ blur: () => void;
12
+ clear: () => void;
13
+ setText: (text: string) => void;
14
+ }
6
15
 
7
16
  export interface InputProps extends TextInputProps {
8
17
  /**
@@ -30,6 +39,11 @@ export interface InputProps extends TextInputProps {
30
39
  */
31
40
  icon?: string;
32
41
 
42
+ /**
43
+ * Optional. Represents the color of the icon in the Input component.
44
+ */
45
+ iconColor?: string;
46
+
33
47
  /**
34
48
  * Optional. If `true`, the user won't be able to interact with the Input component.
35
49
  * Defaults to `false` if not provided.
@@ -41,27 +55,61 @@ export interface InputProps extends TextInputProps {
41
55
  */
42
56
  floatingIconColor?: string;
43
57
 
44
- /**
45
- * Optional. Represents the color of the icon in the Input component.
46
- */
47
- iconColor?: string;
48
-
49
58
  /**
50
59
  * Optional. If `true`, the Input component is marked as required,
51
60
  * indicating that the user must provide a value before submitting a form.
52
61
  * Defaults to `false` if not provided.
53
62
  */
54
63
  required?: boolean;
64
+
65
+ /**
66
+ * Optional. If `true`,
67
+ * include spacing when Input not have error message.
68
+ * Defaults to `false` if not provided.
69
+ */
70
+ errorSpacing?: boolean;
71
+
72
+ /**
73
+ * If true, the icon of input will use be show indicator loading.
74
+ */
75
+ loading?: boolean;
76
+
77
+ /**
78
+ * Optional. Represents the leading icon in the Input component.
79
+ */
80
+ leadingIcon?: string;
81
+
82
+ /**
83
+ * Optional. Represents the color of the leading icon in the Input component.
84
+ */
85
+ leadingIconColor?: string;
86
+
87
+ /**
88
+ * Optional. Represents the font weight of the text in the Input component.
89
+ */
90
+ fontWeight?: 'Regular' | 'Bold';
91
+
92
+ /**
93
+ * Optional. callback function to be called when the icon is pressed.
94
+ */
95
+ onPressIcon?: () => void;
96
+
97
+ /**
98
+ * Optional. params for element tracking.
99
+ */
100
+ params?: any;
101
+
102
+ /**
103
+ * Optional. Represents text below the Input component.
104
+ */
105
+ hintText?: string;
55
106
  }
56
107
 
57
108
  type InputPropsWithoutSizeAndIcon = Omit<
58
109
  InputProps,
59
110
  'size' | 'icon' | 'iconColor'
60
111
  >;
61
- type InputPropsOmitForSearch = Omit<
62
- InputProps,
63
- 'required' | 'size' | 'errorMessage' | 'disabled'
64
- >;
112
+
65
113
  type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
66
114
 
67
115
  export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
@@ -72,7 +120,7 @@ export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
72
120
  height?: number;
73
121
  }
74
122
 
75
- export interface InputSearchProps extends InputPropsOmitForSearch {
123
+ export interface InputSearchProps extends TextInputProps {
76
124
  /**
77
125
  * Optional. Represents the text to be displayed on the search button within the InputSearch component.
78
126
  */
@@ -84,15 +132,160 @@ export interface InputSearchProps extends InputPropsOmitForSearch {
84
132
  */
85
133
  showButtonText?: boolean;
86
134
 
135
+ onPressButtonText?: () => void;
136
+
87
137
  /**
88
- * Optional. If `true`, a border will be displayed around the InputSearch component.
89
- * Defaults to `true` if not provided.
138
+ * Optional. Represents the color of the icon in the Input component.
90
139
  */
91
- showBorder?: boolean;
140
+ iconColor?: string;
92
141
 
93
- onPressButtonText?: () => void;
142
+ /**
143
+ * Optional. Represents the name or key of the icon to be displayed in the Input component.
144
+ */
145
+ icon?: string;
146
+
147
+ /**
148
+ *
149
+ */
150
+ hasColorBG?: boolean;
151
+
152
+ params?: any;
94
153
  }
95
154
 
96
155
  export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
97
156
 
98
- export {Input, InputTextArea, InputSearch, InputMoney};
157
+ export type OTPInputLength = 2 | 4 | 6 | 8 | 10;
158
+
159
+ export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
160
+ /**
161
+ * Optional. Defines the length of the OTP (One Time Password) input.
162
+ * Can be 2, 4, 6, 8, or 10.
163
+ */
164
+ length?: OTPInputLength;
165
+
166
+ /**
167
+ * Optional. Defines the data type of the OTP input.
168
+ * 'string' - The OTP input will be treated as a string.
169
+ * 'number' - The OTP input will be treated as a number.
170
+ */
171
+ dataType?: 'string' | 'number';
172
+
173
+ floatingValue: string;
174
+ }
175
+
176
+ export type CaretProps = {
177
+ /**
178
+ * Optional. The index of the caret in the input field.
179
+ * Represents the position where the caret is located.
180
+ */
181
+ index?: number;
182
+
183
+ /**
184
+ * Optional. The total length of the input field in which the caret is present.
185
+ * This dictates the maximum value of the 'index' property.
186
+ */
187
+ length?: number;
188
+ };
189
+
190
+ export interface InputDropDownProps extends InputProps {
191
+ /**
192
+ * Optional. Defines the size of the InputDropDown component.
193
+ * 'small' - A smaller, less prominent input.
194
+ * 'large' - A larger, more prominent input.
195
+ */
196
+ size?: 'small' | 'large';
197
+
198
+ /**
199
+ * Optional. The current value of the InputDropDown.
200
+ */
201
+ value?: string;
202
+
203
+ /**
204
+ * Optional. Text that is displayed when there is no value set in the InputDropDown.
205
+ */
206
+ placeholder?: string;
207
+
208
+ /**
209
+ * Optional. Function to be called when the InputDropDown is pressed.
210
+ */
211
+ onPress?: () => void;
212
+
213
+ /**
214
+ * Optional. Represents the value for the floating title in the InputDropDown component.
215
+ */
216
+ floatingValue?: string;
217
+
218
+ /**
219
+ * Optional. Represents the name or key of the floating icon to be displayed in the InputDropDown component.
220
+ */
221
+ floatingIcon?: string;
222
+
223
+ /**
224
+ * Optional. Represents the error message to be displayed below the InputDropDown component when there is an error.
225
+ */
226
+ errorMessage?: string;
227
+
228
+ /**
229
+ * Optional. Represents the name or key of the icon to be displayed in the InputDropDown component.
230
+ */
231
+ icon?: string;
232
+
233
+ /**
234
+ * Optional. Represents the color of the icon in the InputDropDown component.
235
+ */
236
+ iconColor?: string;
237
+
238
+ /**
239
+ * Optional. If `true`, the user won't be able to interact with the InputDropDown component.
240
+ * Defaults to `false` if not provided.
241
+ */
242
+ disabled?: boolean;
243
+
244
+ /**
245
+ * Optional. Represents the color of the floating icon in the InputDropDown component.
246
+ */
247
+ floatingIconColor?: string;
248
+
249
+ /**
250
+ * Optional. If `true`, the InputDropDown component is marked as required,
251
+ * indicating that the user must provide a value before submitting a form.
252
+ * Defaults to `false` if not provided.
253
+ */
254
+ required?: boolean;
255
+
256
+ /**
257
+ * Optional. If `true`,
258
+ * includes spacing when InputDropDown does not have an error message.
259
+ * Defaults to `false` if not provided.
260
+ */
261
+ errorSpacing?: boolean;
262
+
263
+ /**
264
+ * If `true`, the icon of the input will show an indicator for loading.
265
+ */
266
+ loading?: boolean;
267
+
268
+ /**
269
+ * Optional. Represents the leading icon in the InputDropDown component.
270
+ */
271
+ leadingIcon?: string;
272
+
273
+ /**
274
+ * Optional. Represents the color of the leading icon in the InputDropDown component.
275
+ */
276
+ leadingIconColor?: string;
277
+
278
+ /**
279
+ * Optional. params for element tracking.
280
+ */
281
+ params?: {
282
+ [key: string]: any;
283
+ };
284
+
285
+ /**
286
+ * Optional. Represents the style of the InputDropDown component.
287
+ */
288
+ style?: ViewStyle | ViewStyle[];
289
+ }
290
+
291
+ export {Input, InputDropDown, InputMoney, InputOTP, InputSearch, InputTextArea};
package/Input/styles.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import {StyleSheet} from 'react-native';
2
2
  import {Radius, Spacing} from '../Consts';
3
+ import {scaleSize} from '../Text';
3
4
 
4
5
  export default StyleSheet.create({
5
6
  //input style
6
- input: {width: '100%', paddingLeft: Spacing.M, height: '100%'},
7
+ input: {
8
+ flex: 1,
9
+ paddingLeft: Spacing.M,
10
+ fontSize: scaleSize(14),
11
+ },
7
12
  wrapper: {
8
13
  width: '100%',
9
14
  },
@@ -11,7 +16,6 @@ export default StyleSheet.create({
11
16
  borderWidth: 1,
12
17
  borderRadius: Radius.S,
13
18
  height: 56,
14
- paddingVertical: 8,
15
19
  },
16
20
  smallContainer: {
17
21
  borderRadius: Radius.S,
@@ -33,8 +37,14 @@ export default StyleSheet.create({
33
37
  marginTop: Spacing.XS,
34
38
  },
35
39
  inputView: {
36
- justifyContent: 'space-between',
37
40
  flex: 1,
41
+ flexDirection: 'row',
42
+ alignItems: 'center',
43
+ },
44
+ leadingIconContainer: {
45
+ marginLeft: Spacing.M,
46
+ borderRadius: Radius.XS,
47
+ overflow: 'hidden',
38
48
  },
39
49
  iconView: {
40
50
  flexDirection: 'row',
@@ -43,8 +53,7 @@ export default StyleSheet.create({
43
53
  marginRight: Spacing.M,
44
54
  },
45
55
  icon: {
46
- width: 24,
47
- height: 24,
56
+ marginLeft: Spacing.S,
48
57
  },
49
58
  iconWrapper: {
50
59
  width: 24,
@@ -65,6 +74,8 @@ export default StyleSheet.create({
65
74
  width: '100%',
66
75
  flex: 1,
67
76
  paddingRight: Spacing.XS,
77
+ paddingVertical: Spacing.XS,
78
+ fontSize: scaleSize(14),
68
79
  },
69
80
  textAreaWrapper: {
70
81
  borderWidth: 1,
@@ -89,7 +100,6 @@ export default StyleSheet.create({
89
100
  searchInputWrapper: {
90
101
  flexDirection: 'row',
91
102
  borderRadius: Radius.XL,
92
- borderWidth: 1,
93
103
  paddingHorizontal: Spacing.S,
94
104
  alignItems: 'center',
95
105
  flex: 1,
@@ -98,6 +108,8 @@ export default StyleSheet.create({
98
108
  height: 36,
99
109
  marginLeft: Spacing.S,
100
110
  flex: 1,
111
+ fontSize: scaleSize(14),
112
+ paddingVertical: Spacing.XS,
101
113
  },
102
114
  searchInputView: {
103
115
  flexDirection: 'row',
@@ -116,7 +128,32 @@ export default StyleSheet.create({
116
128
  width: '100%',
117
129
  paddingLeft: Spacing.M,
118
130
  height: '100%',
119
- fontSize: 20,
131
+ fontSize: scaleSize(20),
132
+ paddingVertical: Spacing.S,
120
133
  fontWeight: 'bold',
121
134
  },
135
+
136
+ //OTP
137
+ otpWrapper: {
138
+ width: '100%',
139
+ marginTop: Spacing.M,
140
+ },
141
+ otpInput: {
142
+ height: scaleSize(56),
143
+ borderRadius: Radius.S,
144
+ borderWidth: 1,
145
+ },
146
+ otpFloatingView: {
147
+ position: 'absolute',
148
+ top: scaleSize(-Spacing.M + 2),
149
+ alignSelf: 'center',
150
+ paddingHorizontal: Spacing.S,
151
+ },
152
+ otpInputsView: {
153
+ width: '100%',
154
+ height: '100%',
155
+ flexDirection: 'row',
156
+ alignItems: 'center',
157
+ justifyContent: 'center',
158
+ },
122
159
  });
package/Input/utils.ts CHANGED
@@ -3,7 +3,7 @@ const formatNumberToMoney = (number: number, currency = '') => {
3
3
  return `0${currency}`;
4
4
  }
5
5
 
6
- const array = [];
6
+ const array: string[] = [];
7
7
  let result = '';
8
8
  let isNegative = false;
9
9
 
@@ -23,7 +23,7 @@ const formatNumberToMoney = (number: number, currency = '') => {
23
23
  array.push(',');
24
24
  count = 0;
25
25
  } else {
26
- array.push(numberString[i]);
26
+ array.push(numberString[i] as string);
27
27
  }
28
28
  if (count === 3 && i >= 1) {
29
29
  array.push('.');
package/Layout/Card.tsx CHANGED
@@ -1,12 +1,35 @@
1
- import React from 'react';
2
- import {Dimensions, View} from 'react-native';
1
+ import React, {Fragment, useContext} from 'react';
2
+ import {Dimensions, View, ViewProps} from 'react-native';
3
3
  import {useGridSystem, validateChildren} from './utils';
4
- import {CardProps, GridContextProps} from './types';
5
- import {GridContext} from './index';
6
- import {GRIDVIEW} from '../Consts';
4
+ import {GridContextProps} from './types';
5
+ import {GridContext, GridSystem} from './index';
7
6
  import Item from './Item';
7
+ import {Image} from '../Image';
8
+ import {ApplicationContext} from '../Application';
9
+ import styles from './styles';
10
+ import {Colors, Radius, Shadow, Spacing} from '../Consts';
11
+ import ItemList from './ItemList';
8
12
 
9
- const Card: React.FC<CardProps> = ({children, style}) => {
13
+ export interface CardProps extends ViewProps {
14
+ /**
15
+ * Optional. Background image for the card.
16
+ */
17
+ backgroundImage?: string;
18
+
19
+ /**
20
+ * Optional. Use shadow for the card.
21
+ */
22
+ useShadow?: boolean;
23
+ }
24
+
25
+ const Card: React.FC<CardProps> = ({
26
+ children,
27
+ style,
28
+ backgroundImage,
29
+ useShadow = false,
30
+ ...props
31
+ }) => {
32
+ const {showGrid, theme} = useContext(ApplicationContext);
10
33
  const {numberOfColumns} = useGridSystem();
11
34
 
12
35
  const gutterSize = 8;
@@ -19,29 +42,26 @@ const Card: React.FC<CardProps> = ({children, style}) => {
19
42
  const gridContext: GridContextProps = {
20
43
  numberOfColumns,
21
44
  gutterSize,
22
- margin,
23
45
  sizePerSpan,
24
46
  getSizeSpan: span => {
25
47
  return span * sizePerSpan + (span - 1) * gutterSize;
26
48
  },
27
49
  };
50
+
28
51
  /**
29
52
  * render overlay only dev mode
30
53
  */
31
54
  const renderOverlay = () => {
32
55
  return (
33
- <View
34
- pointerEvents={'none'}
35
- style={{
36
- position: 'absolute',
37
- top: 0,
38
- bottom: 0,
39
- left: 0,
40
- right: 0,
41
- borderColor: 'red',
42
- borderWidth: 1,
43
- }}
44
- />
56
+ <>
57
+ <GridSystem
58
+ width={widthSection}
59
+ gutterSize={Spacing.S}
60
+ screenGrid={false}
61
+ gridColor={Colors.red_01}
62
+ />
63
+ <View pointerEvents={'none'} style={styles.boxGridCard} />
64
+ </>
45
65
  );
46
66
  };
47
67
 
@@ -88,8 +108,9 @@ const Card: React.FC<CardProps> = ({children, style}) => {
88
108
  if (Array.isArray(children)) {
89
109
  let cursor = 0;
90
110
  let rows: any[] = [];
91
- for (let i = 0; i < children.length; ++i) {
92
- const item = children[i];
111
+ const arrayChild = children.filter(item => !!item);
112
+ for (let i = 0; i < arrayChild.length; ++i) {
113
+ const item = arrayChild[i];
93
114
  const totalSpan = rows
94
115
  .concat([item])
95
116
  .map(i => i.props?.widthSpan)
@@ -105,13 +126,16 @@ const Card: React.FC<CardProps> = ({children, style}) => {
105
126
  rows = [item];
106
127
  }
107
128
 
108
- if (i == children.length - 1) {
129
+ if (i == arrayChild.length - 1) {
109
130
  cursor += 1;
110
131
  element.push(addRowView(rows, cursor, true));
111
132
  }
112
133
  }
113
134
  } else {
114
135
  element.push(children);
136
+ if (children?.type == Fragment) {
137
+ return renderView(children?.props.children);
138
+ }
115
139
  }
116
140
  return element;
117
141
  };
@@ -119,19 +143,33 @@ const Card: React.FC<CardProps> = ({children, style}) => {
119
143
  return (
120
144
  <GridContext.Provider value={gridContext}>
121
145
  <View
122
- accessibilityLabel={`Card`}
146
+ {...props}
123
147
  style={[
148
+ {backgroundColor: theme.colors.background.surface},
124
149
  style,
150
+ styles.protectedStyle,
151
+ styles.card,
125
152
  {
126
153
  width: widthSection,
127
- marginHorizontal: gridContext.margin,
128
- padding: 12,
129
- flexDirection: 'row',
130
- flexWrap: 'wrap',
154
+ marginHorizontal: margin,
131
155
  },
156
+ !!backgroundImage && {backgroundColor: undefined},
157
+ useShadow && Shadow.Light,
132
158
  ]}>
133
- {renderView(validateChildren(children, [Item]))}
134
- {GRIDVIEW && renderOverlay()}
159
+ {!!backgroundImage && (
160
+ <Image
161
+ source={{uri: backgroundImage}}
162
+ style={[
163
+ styles.imageBackground,
164
+ {
165
+ width: widthSection,
166
+ borderRadius: Radius.M,
167
+ },
168
+ ]}
169
+ />
170
+ )}
171
+ {renderView(validateChildren(children, [Item, ItemList]))}
172
+ {showGrid && renderOverlay()}
135
173
  </View>
136
174
  </GridContext.Provider>
137
175
  );