@momo-kits/foundation 0.81.52 → 0.81.53-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/Application/BottomSheet.tsx +216 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +278 -0
  3. package/Application/{BottomTab.tsx → BottomTab/index.tsx} +43 -18
  4. package/Application/Components.tsx +71 -53
  5. package/Application/ModalScreen.tsx +12 -183
  6. package/Application/Navigation.ts +2 -2
  7. package/Application/NavigationContainer.tsx +54 -53
  8. package/Application/Navigator.ts +53 -35
  9. package/Application/StackScreen.tsx +225 -30
  10. package/Application/index.ts +8 -12
  11. package/Application/types.ts +45 -27
  12. package/Application/utils.tsx +19 -15
  13. package/Assets/icon_bank.json +1 -1
  14. package/Badge/Badge.tsx +1 -1
  15. package/Button/index.tsx +44 -25
  16. package/CheckBox/index.tsx +37 -26
  17. package/CheckBox/types.ts +5 -3
  18. package/Consts/colors+spacing+radius.ts +14 -0
  19. package/Icon/index.tsx +9 -8
  20. package/Icon/types.ts +2 -2
  21. package/IconButton/index.tsx +24 -14
  22. package/Image/index.tsx +23 -8
  23. package/Image/types.ts +2 -0
  24. package/Input/Input.tsx +116 -26
  25. package/Input/InputDropDown.tsx +66 -51
  26. package/Input/InputMoney.tsx +106 -15
  27. package/Input/InputOTP.tsx +45 -22
  28. package/Input/InputSearch.tsx +92 -44
  29. package/Input/InputTextArea.tsx +26 -6
  30. package/Input/common.tsx +48 -22
  31. package/Input/index.tsx +94 -77
  32. package/Input/styles.ts +35 -5
  33. package/Input/utils.ts +1 -1
  34. package/Layout/Card.tsx +4 -3
  35. package/Layout/FloatingButton.tsx +168 -0
  36. package/Layout/GridSystem.tsx +1 -1
  37. package/Layout/ItemList.tsx +3 -2
  38. package/Layout/Screen.tsx +87 -49
  39. package/Layout/Section.tsx +4 -3
  40. package/Layout/styles.ts +11 -7
  41. package/Layout/utils.ts +4 -4
  42. package/Loader/index.tsx +2 -0
  43. package/Popup/PopupNotify.tsx +55 -44
  44. package/Popup/PopupPromotion.tsx +5 -7
  45. package/Popup/types.ts +1 -7
  46. package/Radio/index.tsx +35 -20
  47. package/Radio/types.ts +5 -3
  48. package/Switch/index.tsx +32 -18
  49. package/Switch/types.ts +5 -3
  50. package/Tag/styles.ts +3 -2
  51. package/Text/index.tsx +24 -5
  52. package/Text/styles.ts +8 -8
  53. package/Title/index.tsx +170 -103
  54. package/Title/styles.ts +36 -9
  55. package/Title/types.ts +16 -48
  56. package/code-scanner.js +125 -16
  57. package/index.ts +7 -0
  58. package/package.json +6 -6
  59. package/publish.sh +16 -21
  60. package/tsconfig.json +1 -1
package/Input/index.tsx CHANGED
@@ -1,10 +1,12 @@
1
+ import {GestureResponderEvent, 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
5
  import InputOTP from './InputOTP';
6
- import InputDropDown from './InputDropDown';
7
- import {TextInputProps, ViewStyle} from 'react-native';
6
+ import InputSearch from './InputSearch';
7
+ import InputTextArea from './InputTextArea';
8
+
9
+ export type OTPInputLength = 2 | 4 | 6 | 8 | 10;
8
10
 
9
11
  export interface InputProps extends TextInputProps {
10
12
  /**
@@ -28,15 +30,38 @@ export interface InputProps extends TextInputProps {
28
30
  errorMessage?: string;
29
31
 
30
32
  /**
33
+ * @deprecated Use `trailing` instead.
31
34
  * Optional. Represents the name or key of the icon to be displayed in the Input component.
32
35
  */
33
36
  icon?: string;
34
37
 
35
38
  /**
39
+ * @deprecated Use `trailingColor` instead.
36
40
  * Optional. Represents the color of the icon in the Input component.
37
41
  */
38
42
  iconColor?: string;
39
43
 
44
+ /**
45
+ * @deprecated Use `onPressTrailing` instead.
46
+ * Optional. callback function to be called when the icon is pressed.
47
+ */
48
+ onPressIcon?: () => void;
49
+
50
+ /**
51
+ * Optional. Represents the name or key of the icon to be displayed in the Input component.
52
+ */
53
+ trailing?: string;
54
+
55
+ /**
56
+ * Optional. Represents the color of the icon in the Input component.
57
+ */
58
+ trailingColor?: string;
59
+
60
+ /**
61
+ * Optional. callback function to be called when the icon is pressed.
62
+ */
63
+ onPressTrailing?: () => void;
64
+
40
65
  /**
41
66
  * Optional. If `true`, the user won't be able to interact with the Input component.
42
67
  * Defaults to `false` if not provided.
@@ -77,19 +102,25 @@ export interface InputProps extends TextInputProps {
77
102
  */
78
103
  leadingIconColor?: string;
79
104
 
105
+ /**
106
+ * Optional. Represents the font weight of the text in the Input component.
107
+ */
80
108
  fontWeight?: 'Regular' | 'Bold';
81
109
 
82
- onPressIcon?: () => void;
83
- }
110
+ /**
111
+ * Optional. params for element tracking.
112
+ */
113
+ params?: any;
84
114
 
85
- type InputPropsWithoutSizeAndIcon = Omit<
86
- InputProps,
87
- 'size' | 'icon' | 'iconColor'
88
- >;
115
+ /**
116
+ * Optional. Represents text below the Input component.
117
+ */
118
+ hintText?: string;
89
119
 
90
- type InputPropsWithoutPlaceholder = Omit<InputProps, 'placeholder'>;
120
+ onPressFloatingIcon?: (e: GestureResponderEvent) => void;
121
+ }
91
122
 
92
- export interface InputTextAreaProps extends InputPropsWithoutSizeAndIcon {
123
+ export interface InputTextAreaProps extends Omit<InputProps, 'size'> {
93
124
  /**
94
125
  * Optional. Defines the height of the InputTextArea component.
95
126
  * It can be used to set a specific height for the text area.
@@ -109,26 +140,59 @@ export interface InputSearchProps extends TextInputProps {
109
140
  */
110
141
  showButtonText?: boolean;
111
142
 
143
+ /**
144
+ * Optional. Represents the value for the floating title in the InputSearch component.
145
+ */
112
146
  onPressButtonText?: () => void;
113
147
 
114
148
  /**
149
+ * @deprecated Use `trailing` instead.
150
+ * Optional. Represents the name or key of the icon to be displayed in the Input component.
151
+ */
152
+ icon?: string;
153
+
154
+ /**
155
+ * @deprecated Use `trailingColor` instead.
115
156
  * Optional. Represents the color of the icon in the Input component.
116
157
  */
117
158
  iconColor?: string;
118
159
 
160
+ /**
161
+ * @deprecated Use `onPressTrailing` instead.
162
+ * Optional. callback function to be called when the icon is pressed.
163
+ */
164
+ onPressIcon?: () => void;
165
+
119
166
  /**
120
167
  * Optional. Represents the name or key of the icon to be displayed in the Input component.
121
168
  */
122
- icon?: string;
169
+ trailing?: string;
123
170
 
124
- hasColorBG?: boolean
125
- }
171
+ /**
172
+ * Optional. Represents the color of the icon in the Input component.
173
+ */
174
+ trailingColor?: string;
126
175
 
127
- export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
176
+ /**
177
+ * Optional. callback function to be called when the icon is pressed.
178
+ */
179
+ onPressTrailing?: () => void;
128
180
 
129
- export type OTPInputLength = 2 | 4 | 6 | 8 | 10;
181
+ /**
182
+ * Optional. If `true`, the user won't be able to interact with the Input component.
183
+ */
184
+ hasColorBG?: boolean;
130
185
 
131
- export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
186
+ /**
187
+ * Optional. Represents the style of the InputSearch component.
188
+ */
189
+ params?: any;
190
+ }
191
+
192
+ export interface InputMoneyProps extends Omit<InputProps, 'placeholder'> {}
193
+
194
+ export interface InputOTPProps
195
+ extends Omit<InputProps, 'size' | 'icon' | 'iconColor'> {
132
196
  /**
133
197
  * Optional. Defines the length of the OTP (One Time Password) input.
134
198
  * Can be 2, 4, 6, 8, or 10.
@@ -141,6 +205,8 @@ export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
141
205
  * 'number' - The OTP input will be treated as a number.
142
206
  */
143
207
  dataType?: 'string' | 'number';
208
+
209
+ floatingValue: string;
144
210
  }
145
211
 
146
212
  export type CaretProps = {
@@ -157,7 +223,8 @@ export type CaretProps = {
157
223
  length?: number;
158
224
  };
159
225
 
160
- export interface InputDropDownProps {
226
+ export interface InputDropDownProps
227
+ extends Omit<InputProps, 'trailing' | 'trailingColor' | 'onPressTrailing'> {
161
228
  /**
162
229
  * Optional. Defines the size of the InputDropDown component.
163
230
  * 'small' - A smaller, less prominent input.
@@ -165,57 +232,17 @@ export interface InputDropDownProps {
165
232
  */
166
233
  size?: 'small' | 'large';
167
234
 
168
- /**
169
- * Optional. The current value of the InputDropDown.
170
- */
171
- value?: string;
172
-
173
- /**
174
- * Optional. Text that is displayed when there is no value set in the InputDropDown.
175
- */
176
- placeholder?: string;
177
-
178
235
  /**
179
236
  * Optional. Function to be called when the InputDropDown is pressed.
180
237
  */
181
238
  onPress?: () => void;
182
239
 
183
- /**
184
- * Optional. Represents the value for the floating title in the InputDropDown component.
185
- */
186
- floatingValue?: string;
187
-
188
- /**
189
- * Optional. Represents the name or key of the floating icon to be displayed in the InputDropDown component.
190
- */
191
- floatingIcon?: string;
192
-
193
- /**
194
- * Optional. Represents the error message to be displayed below the InputDropDown component when there is an error.
195
- */
196
- errorMessage?: string;
197
-
198
- /**
199
- * Optional. Represents the name or key of the icon to be displayed in the InputDropDown component.
200
- */
201
- icon?: string;
202
-
203
- /**
204
- * Optional. Represents the color of the icon in the InputDropDown component.
205
- */
206
- iconColor?: string;
207
-
208
240
  /**
209
241
  * Optional. If `true`, the user won't be able to interact with the InputDropDown component.
210
242
  * Defaults to `false` if not provided.
211
243
  */
212
244
  disabled?: boolean;
213
245
 
214
- /**
215
- * Optional. Represents the color of the floating icon in the InputDropDown component.
216
- */
217
- floatingIconColor?: string;
218
-
219
246
  /**
220
247
  * Optional. If `true`, the InputDropDown component is marked as required,
221
248
  * indicating that the user must provide a value before submitting a form.
@@ -224,28 +251,18 @@ export interface InputDropDownProps {
224
251
  required?: boolean;
225
252
 
226
253
  /**
227
- * Optional. If `true`,
228
- * includes spacing when InputDropDown does not have an error message.
229
- * Defaults to `false` if not provided.
230
- */
231
- errorSpacing?: boolean;
232
-
233
- /**
234
- * If `true`, the icon of the input will show an indicator for loading.
254
+ * Optional. params for element tracking.
235
255
  */
236
- loading?: boolean;
237
-
238
- /**
239
- * Optional. Represents the leading icon in the InputDropDown component.
240
- */
241
- leadingIcon?: string;
256
+ params?: {
257
+ [key: string]: any;
258
+ };
242
259
 
243
260
  /**
244
- * Optional. Represents the color of the leading icon in the InputDropDown component.
261
+ * Optional. Represents the style of the InputDropDown component.
245
262
  */
246
- leadingIconColor?: string;
263
+ style?: ViewStyle | ViewStyle[];
247
264
 
248
- style: ViewStyle | ViewStyle[];
265
+ multiline?: boolean;
249
266
  }
250
267
 
251
- export {Input, InputTextArea, InputSearch, InputMoney, InputOTP, InputDropDown};
268
+ export {Input, InputDropDown, InputMoney, InputOTP, InputSearch, InputTextArea};
package/Input/styles.ts CHANGED
@@ -7,7 +7,8 @@ export default StyleSheet.create({
7
7
  input: {
8
8
  flex: 1,
9
9
  paddingLeft: Spacing.M,
10
- fontSize: scaleSize(15),
10
+ fontSize: scaleSize(14),
11
+ height: '100%',
11
12
  },
12
13
  wrapper: {
13
14
  width: '100%',
@@ -53,7 +54,7 @@ export default StyleSheet.create({
53
54
  marginRight: Spacing.M,
54
55
  },
55
56
  icon: {
56
- marginLeft: Spacing.S
57
+ marginLeft: Spacing.S,
57
58
  },
58
59
  iconWrapper: {
59
60
  width: 24,
@@ -75,7 +76,7 @@ export default StyleSheet.create({
75
76
  flex: 1,
76
77
  paddingRight: Spacing.XS,
77
78
  paddingVertical: Spacing.XS,
78
- fontSize: scaleSize(15),
79
+ fontSize: scaleSize(14),
79
80
  },
80
81
  textAreaWrapper: {
81
82
  borderWidth: 1,
@@ -108,7 +109,7 @@ export default StyleSheet.create({
108
109
  height: 36,
109
110
  marginLeft: Spacing.S,
110
111
  flex: 1,
111
- fontSize: scaleSize(15),
112
+ fontSize: scaleSize(14),
112
113
  paddingVertical: Spacing.XS,
113
114
  },
114
115
  searchInputView: {
@@ -145,7 +146,7 @@ export default StyleSheet.create({
145
146
  },
146
147
  otpFloatingView: {
147
148
  position: 'absolute',
148
- top: -Spacing.S,
149
+ top: scaleSize(-Spacing.M + 2),
149
150
  alignSelf: 'center',
150
151
  paddingHorizontal: Spacing.S,
151
152
  },
@@ -156,4 +157,33 @@ export default StyleSheet.create({
156
157
  alignItems: 'center',
157
158
  justifyContent: 'center',
158
159
  },
160
+
161
+ //DropDown
162
+ inputDropDownWrapper: {
163
+ flexDirection: 'row',
164
+ marginTop: Spacing.S,
165
+ },
166
+ inputDropDownView: {
167
+ flex: 1,
168
+ flexDirection: 'row',
169
+ paddingLeft: Spacing.M,
170
+ },
171
+ iconViewDropDown: {
172
+ flexDirection: 'row',
173
+ marginRight: Spacing.M,
174
+ },
175
+ textViewDropDown: {
176
+ flex: 1,
177
+ marginVertical: Spacing.M,
178
+ marginRight: Spacing.S,
179
+ justifyContent: 'center',
180
+ },
181
+ multilineContainer: {
182
+ borderWidth: 1,
183
+ borderRadius: Radius.S,
184
+ },
185
+ leadingIconContainerDropDown: {
186
+ borderRadius: Radius.XS,
187
+ overflow: 'hidden',
188
+ },
159
189
  });
package/Input/utils.ts CHANGED
@@ -61,7 +61,7 @@ const formatMoneyToNumber = (money: string, currencyUnit: string) => {
61
61
  };
62
62
  const checkTyping = (text: string, value: boolean, setValue: any) => {
63
63
  let typing = text?.length > 0;
64
- if (typing != value) {
64
+ if (typing !== value) {
65
65
  setValue(typing);
66
66
  }
67
67
  };
package/Layout/Card.tsx CHANGED
@@ -86,7 +86,7 @@ const Card: React.FC<CardProps> = ({
86
86
  {rows.map((i: React.ReactElement, index: number) => {
87
87
  return (
88
88
  <View key={`Item${cursor}${index}`} style={{flexDirection: 'row'}}>
89
- {index != 0 && (
89
+ {index !== 0 && (
90
90
  <View style={{width: gridContext.gutterSize}}></View>
91
91
  )}
92
92
  {i}
@@ -126,14 +126,14 @@ const Card: React.FC<CardProps> = ({
126
126
  rows = [item];
127
127
  }
128
128
 
129
- if (i == arrayChild.length - 1) {
129
+ if (i === arrayChild.length - 1) {
130
130
  cursor += 1;
131
131
  element.push(addRowView(rows, cursor, true));
132
132
  }
133
133
  }
134
134
  } else {
135
135
  element.push(children);
136
- if (children?.type == Fragment) {
136
+ if (children?.type === Fragment) {
137
137
  return renderView(children?.props.children);
138
138
  }
139
139
  }
@@ -144,6 +144,7 @@ const Card: React.FC<CardProps> = ({
144
144
  <GridContext.Provider value={gridContext}>
145
145
  <View
146
146
  {...props}
147
+ onLayout={undefined}
147
148
  style={[
148
149
  {backgroundColor: theme.colors.background.surface},
149
150
  style,
@@ -0,0 +1,168 @@
1
+ import {default as React, useContext, useEffect, useRef, useState} from 'react';
2
+ import {
3
+ Animated,
4
+ LayoutChangeEvent,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ View,
8
+ } from 'react-native';
9
+ import {ApplicationContext} from '../Application';
10
+ import {Icon} from '../Icon';
11
+
12
+ export interface FloatingButtonProps {
13
+ label?: string;
14
+ onPress?: () => void;
15
+ position?: 'center' | 'right';
16
+ icon?: string;
17
+ iconColor?: string;
18
+ size?: 'small' | 'large';
19
+ animatedValue?: Animated.Value;
20
+ bottom?: number;
21
+ renderComponent?: () => React.ReactNode;
22
+ }
23
+
24
+ export const FloatingButton: React.FC<FloatingButtonProps> = ({
25
+ renderComponent,
26
+ label = '',
27
+ onPress = () => {},
28
+ position = 'right',
29
+ icon = '',
30
+ iconColor = '',
31
+ size = 'small',
32
+ animatedValue,
33
+ bottom = 12,
34
+ }: FloatingButtonProps) => {
35
+ const {theme} = useContext(ApplicationContext);
36
+ const maxWidth = useRef(0);
37
+ const minWidth = size === 'small' ? 36 : 48;
38
+ const [opacityAnimated] = useState(new Animated.Value(0)); // Initial opacity set to 0
39
+ const [widthAnimated, setWidthAnimated] = useState<Animated.Value>();
40
+ const lastOffset = useRef(0);
41
+ const lastDirection = useRef<string>();
42
+ const [showText, setShowText] = React.useState(true);
43
+
44
+ useEffect(() => {
45
+ if (!label) return;
46
+
47
+ Animated.timing(opacityAnimated, {
48
+ toValue: 1,
49
+ duration: 100,
50
+ useNativeDriver: true,
51
+ }).start();
52
+
53
+ const listener = animatedValue?.addListener(({value}) => {
54
+ if (value !== lastOffset.current && value > 0) {
55
+ const direction = value > lastOffset.current ? 'down' : 'up';
56
+ lastOffset.current = value;
57
+ if (lastDirection.current !== direction) {
58
+ lastDirection.current = direction;
59
+ if (direction === 'down') {
60
+ Animated.timing(opacityAnimated, {
61
+ toValue: 0,
62
+ duration: 100,
63
+ useNativeDriver: true,
64
+ }).start();
65
+ Animated.timing(widthAnimated!, {
66
+ toValue: minWidth,
67
+ duration: 100,
68
+ useNativeDriver: false,
69
+ }).start(() => setShowText(false));
70
+ } else {
71
+ Animated.timing(opacityAnimated, {
72
+ toValue: 1,
73
+ duration: 100,
74
+ useNativeDriver: true,
75
+ }).start();
76
+ Animated.timing(widthAnimated!, {
77
+ toValue: maxWidth.current,
78
+ duration: 100,
79
+ useNativeDriver: false,
80
+ }).start(() => setShowText(true));
81
+ }
82
+ }
83
+ }
84
+ });
85
+
86
+ return () => {
87
+ if (listener) {
88
+ animatedValue?.removeListener(listener);
89
+ }
90
+ };
91
+ }, [label, widthAnimated]);
92
+
93
+ const handleLayout = (event: LayoutChangeEvent) => {
94
+ const layout = event.nativeEvent.layout;
95
+ if (widthAnimated) return;
96
+ maxWidth.current = layout.width;
97
+ setWidthAnimated(new Animated.Value(layout.width));
98
+ };
99
+
100
+ if (renderComponent) {
101
+ return (
102
+ <View
103
+ onLayout={handleLayout}
104
+ style={[
105
+ styles.container,
106
+ {
107
+ right: position === 'right' ? 12 : undefined,
108
+ alignSelf: position === 'center' ? 'center' : 'flex-end',
109
+ bottom,
110
+ },
111
+ ]}>
112
+ {renderComponent()}
113
+ </View>
114
+ );
115
+ }
116
+
117
+ return (
118
+ <Animated.View
119
+ onLayout={handleLayout}
120
+ style={[
121
+ styles.container,
122
+ {
123
+ right: position === 'right' ? 12 : undefined,
124
+ alignSelf: position === 'center' ? 'center' : 'flex-end',
125
+ width: widthAnimated,
126
+ height: size === 'small' ? 36 : 48,
127
+ backgroundColor: theme.colors.primary,
128
+ bottom,
129
+ },
130
+ ]}>
131
+ <TouchableOpacity
132
+ style={{flexDirection: 'row', alignItems: 'center'}}
133
+ onPress={onPress}>
134
+ <Icon
135
+ source={icon}
136
+ size={size === 'small' ? 12 : 24}
137
+ color={iconColor}
138
+ />
139
+ {showText && !!label && (
140
+ <Animated.Text
141
+ style={[styles.label, {opacity: opacityAnimated, color: 'white'}]}
142
+ numberOfLines={1}>
143
+ {label}
144
+ </Animated.Text>
145
+ )}
146
+ </TouchableOpacity>
147
+ </Animated.View>
148
+ );
149
+ };
150
+
151
+ const styles = StyleSheet.create({
152
+ container: {
153
+ flexDirection: 'row',
154
+ alignContent: 'center',
155
+ alignItems: 'center',
156
+ position: 'absolute',
157
+ borderRadius: 100,
158
+ paddingHorizontal: 12,
159
+ flexWrap: 'wrap',
160
+ alignSelf: 'flex-end',
161
+ },
162
+ label: {
163
+ marginLeft: 8,
164
+ fontSize: 16,
165
+ lineHeight: 22,
166
+ fontWeight: '700',
167
+ },
168
+ });
@@ -53,7 +53,7 @@ const GridSystem: React.FC<any> = ({
53
53
  {list.map((_, index) => {
54
54
  return (
55
55
  <View style={{flexDirection: 'row'}} key={index.toString()}>
56
- {index != -0 && <View style={{width: grid.gutterSize}} />}
56
+ {index !== 0 && <View style={{width: grid.gutterSize}} />}
57
57
  <View
58
58
  key={`Grid${index.toString()}`}
59
59
  pointerEvents="none"
@@ -20,7 +20,7 @@ const ItemList = forwardRef(
20
20
  contentContainerStyle,
21
21
  ...props
22
22
  }: ItemListProps,
23
- ref,
23
+ ref
24
24
  ) => {
25
25
  const {gutterSize, numberOfColumns} = useContext(GridContext);
26
26
  const widthItem = (widthSpan ?? numberOfColumns) as SpanNumber;
@@ -41,6 +41,7 @@ const ItemList = forwardRef(
41
41
  <FlatList
42
42
  ref={ref as React.RefObject<FlatList>}
43
43
  {...props}
44
+ key={`ItemList-${numColumns}`}
44
45
  numColumns={numColumns}
45
46
  renderItem={_renderItem}
46
47
  horizontal={false}
@@ -49,7 +50,7 @@ const ItemList = forwardRef(
49
50
  contentContainerStyle={[contentContainerStyle, styles.protectedStyle]}
50
51
  />
51
52
  );
52
- },
53
+ }
53
54
  );
54
55
 
55
56
  export default ItemList;