@momo-kits/foundation 0.80.8 → 0.81.1-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 (87) hide show
  1. package/Application/BottomSheet.tsx +212 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +278 -0
  3. package/Application/BottomTab/index.tsx +143 -0
  4. package/Application/Components.tsx +384 -213
  5. package/Application/ModalScreen.tsx +14 -178
  6. package/Application/Navigation.ts +15 -19
  7. package/Application/NavigationContainer.tsx +66 -63
  8. package/Application/Navigator.ts +106 -53
  9. package/Application/StackScreen.tsx +123 -9
  10. package/Application/index.ts +19 -6
  11. package/Application/types.ts +83 -26
  12. package/Application/utils.tsx +62 -74
  13. package/Assets/icon.json +83 -5
  14. package/Assets/icon_bank.json +506 -0
  15. package/Assets/language.json +3 -1
  16. package/Badge/Badge.tsx +56 -0
  17. package/Badge/BadgeDot.tsx +11 -0
  18. package/Badge/BadgeRibbon.tsx +125 -0
  19. package/Badge/Shape.tsx +29 -0
  20. package/Badge/index.tsx +7 -0
  21. package/Badge/styles.ts +58 -0
  22. package/Badge/types.ts +63 -0
  23. package/Button/index.tsx +64 -28
  24. package/Button/styles.ts +19 -0
  25. package/CheckBox/index.tsx +37 -27
  26. package/CheckBox/types.ts +5 -3
  27. package/Consts/colors+spacing+radius.ts +18 -0
  28. package/Icon/index.tsx +14 -9
  29. package/Icon/types.ts +4 -3
  30. package/IconButton/index.tsx +24 -15
  31. package/Image/index.tsx +62 -47
  32. package/Image/styles.ts +1 -9
  33. package/Image/types.ts +5 -1
  34. package/Input/Input.tsx +104 -25
  35. package/Input/InputDropDown.tsx +115 -110
  36. package/Input/InputMoney.tsx +79 -18
  37. package/Input/InputOTP.tsx +190 -149
  38. package/Input/InputSearch.tsx +96 -44
  39. package/Input/InputTextArea.tsx +33 -17
  40. package/Input/common.tsx +26 -17
  41. package/Input/index.tsx +108 -41
  42. package/Input/styles.ts +5 -7
  43. package/Input/utils.ts +1 -1
  44. package/Layout/AnimatedInputSearch.tsx +44 -0
  45. package/Layout/Card.tsx +37 -13
  46. package/Layout/FloatingButton.tsx +168 -0
  47. package/Layout/GridSystem.tsx +2 -3
  48. package/Layout/Item.tsx +1 -2
  49. package/Layout/ItemList.tsx +55 -0
  50. package/Layout/ItemSectionList.tsx +39 -0
  51. package/Layout/Screen.tsx +404 -181
  52. package/Layout/Section.tsx +22 -22
  53. package/Layout/TextTyping.tsx +114 -0
  54. package/Layout/index.ts +12 -2
  55. package/Layout/styles.ts +46 -13
  56. package/Layout/types.ts +13 -5
  57. package/Layout/utils.ts +7 -12
  58. package/Loader/index.tsx +2 -0
  59. package/Pagination/PaginationDot.tsx +6 -1
  60. package/Pagination/PaginationNumber.tsx +7 -4
  61. package/Pagination/PaginationScroll.tsx +0 -1
  62. package/Pagination/PaginationWhiteDot.tsx +6 -1
  63. package/Pagination/styles.ts +3 -0
  64. package/Pagination/types.ts +2 -0
  65. package/Popup/PopupNotify.tsx +108 -40
  66. package/Popup/PopupPromotion.tsx +45 -10
  67. package/Popup/types.ts +13 -10
  68. package/Radio/index.tsx +35 -21
  69. package/Radio/types.ts +7 -5
  70. package/Skeleton/index.tsx +1 -1
  71. package/Switch/index.tsx +32 -19
  72. package/Switch/types.ts +5 -3
  73. package/Tag/index.tsx +2 -4
  74. package/Text/index.tsx +26 -6
  75. package/Text/styles.ts +38 -0
  76. package/Text/types.ts +25 -13
  77. package/Title/index.tsx +177 -64
  78. package/Title/styles.ts +48 -15
  79. package/Title/types.ts +16 -7
  80. package/code-scanner.js +125 -16
  81. package/index.ts +9 -0
  82. package/migrate_typo.js +56 -0
  83. package/package.json +8 -7
  84. package/publish.sh +21 -16
  85. package/tsconfig.json +1 -2
  86. package/verify.js +24 -6
  87. package/Application/BottomTab.tsx +0 -65
@@ -1,19 +1,26 @@
1
- import React, {FC, useContext, useEffect, useRef, useState} from 'react';
1
+ import React, {
2
+ FC,
3
+ forwardRef,
4
+ useContext,
5
+ useEffect,
6
+ useImperativeHandle,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
2
10
  import {
3
11
  Animated,
4
- KeyboardType,
5
12
  NativeSyntheticEvent,
6
13
  TextInput,
7
14
  TextInputFocusEventData,
8
15
  TouchableOpacity,
9
16
  View,
10
17
  } from 'react-native';
11
- import {CaretProps, InputOTPProps} from './index';
18
+ import {ApplicationContext, ComponentContext} from '../Application';
19
+ import {Spacing} from '../Consts';
12
20
  import {scaleSize, Text} from '../Text';
13
- import styles from './styles';
14
21
  import {ErrorView, getBorderColor} from './common';
15
- import {ApplicationContext} from '../Application';
16
- import {Spacing} from '../Consts';
22
+ import {CaretProps, InputOTPProps} from './index';
23
+ import styles from './styles';
17
24
 
18
25
  const OTPCaret: FC<CaretProps> = ({index, length}) => {
19
26
  const DURATION = 300;
@@ -50,164 +57,198 @@ const OTPCaret: FC<CaretProps> = ({index, length}) => {
50
57
  opacity,
51
58
  }}
52
59
  />
53
- <Text color={theme.colors.text.hint} typography={'paragraph_default'}>
60
+ <Text color={theme.colors.text.hint} typography={'body_default_regular'}>
54
61
  -
55
62
  </Text>
56
63
  </View>
57
64
  );
58
65
  };
59
66
 
60
- const InputOTP: FC<InputOTPProps> = ({
61
- length,
62
- errorMessage,
63
- errorSpacing,
64
- floatingValue,
65
- floatingIconColor,
66
- floatingIcon,
67
- placeholder,
68
- onChangeText,
69
- onFocus,
70
- onBlur,
71
- dataType = 'number',
72
- ...props
73
- }) => {
74
- const MAX_LENGTH = 10;
75
- const [value, setValue] = useState('');
76
- const [focused, setFocused] = useState(false);
77
- const inputRef = useRef<TextInput>(null);
78
- const {theme} = useContext(ApplicationContext);
67
+ const InputOTP = forwardRef(
68
+ (
69
+ {
70
+ length,
71
+ errorMessage,
72
+ errorSpacing,
73
+ floatingValue = 'Label',
74
+ placeholder,
75
+ onChangeText,
76
+ onBlur,
77
+ dataType = 'number',
78
+ params,
79
+ style,
80
+ accessibilityLabel,
81
+ hintText,
82
+ ...props
83
+ }: InputOTPProps,
84
+ ref,
85
+ ) => {
86
+ const MAX_LENGTH = 10;
87
+ const [value, setValue] = useState('');
88
+ const [focused, setFocused] = useState(false);
89
+ const inputRef = useRef<TextInput | null>(null);
90
+ const {theme} = useContext(ApplicationContext);
79
91
 
80
- const onFocusInput = () => {
81
- setFocused(true);
82
- inputRef.current?.focus();
83
- };
84
-
85
- const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
86
- setFocused(false);
87
- onBlur?.(e);
88
- };
89
-
90
- const _onChangeText = (text: string) => {
91
- if (text.length > MAX_LENGTH) return;
92
- if (dataType === 'number' && isNaN(Number(text))) return;
93
- if (
94
- !isNaN(Number(text)) &&
95
- value.length >= Number(length) &&
96
- text.length >= value.length
97
- )
98
- return;
99
-
100
- setValue(text);
101
- onChangeText?.(text);
102
- };
103
-
104
- const renderInputs = (length: number) => {
105
- const TextInputs = [];
106
- for (let i = 0; i < length; i++) {
107
- TextInputs.push(
108
- <View>
109
- {focused && value.length === i ? (
110
- <OTPCaret index={i} length={length} />
111
- ) : (
112
- <Text
113
- style={i !== length - 1 && {marginRight: Spacing.L}}
114
- color={
115
- !!value[i] ? theme.colors.text.default : theme.colors.text.hint
116
- }
117
- typography={!!value[i] ? 'title_s' : 'paragraph_default'}>
118
- {value[i] || '-'}
119
- </Text>
120
- )}
121
- </View>,
122
- );
123
- }
124
- return TextInputs;
125
- };
92
+ useImperativeHandle(ref, () => ({
93
+ onChangeText: (text: string) => {
94
+ _onChangeText(text);
95
+ },
96
+ focus: () => inputRef.current?.focus(),
97
+ blur: () => inputRef.current?.blur(),
98
+ setText: (text: string) => _onChangeText(text),
99
+ }));
126
100
 
127
- const renderUnidentifiedInputs = () => {
128
- const splitValue = value.split('');
101
+ const onFocusInput = () => {
102
+ setFocused(true);
103
+ inputRef.current?.focus();
104
+ };
129
105
 
130
- if (!focused && value.length === 0 && !!placeholder) {
131
- return (
132
- <Text color={theme.colors.text.hint} typography={'description_s'}>
133
- {placeholder}
134
- </Text>
135
- );
136
- }
106
+ const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
107
+ setFocused(false);
108
+ onBlur?.(e);
109
+ };
137
110
 
138
- return (
139
- <View style={{flexDirection: 'row'}}>
140
- {splitValue.map((letter, index) => {
141
- return (
142
- <Text
143
- style={
144
- (index !== value.length - 1 ||
145
- (focused && value.length !== MAX_LENGTH)) && {
146
- marginRight: Spacing.L,
111
+ const _onChangeText = (text: string) => {
112
+ if (text.length > MAX_LENGTH) return;
113
+ if (dataType === 'number' && isNaN(Number(text))) return;
114
+ if (
115
+ !isNaN(Number(text)) &&
116
+ value.length >= Number(length) &&
117
+ text.length >= value.length
118
+ )
119
+ return;
120
+
121
+ setValue(text);
122
+ onChangeText?.(text);
123
+ };
124
+
125
+ const renderInputs = (inputLength: number) => {
126
+ const TextInputs: React.ReactNode[] = [];
127
+ for (let i = 0; i < inputLength; i++) {
128
+ TextInputs.push(
129
+ <View>
130
+ {focused && value.length === i ? (
131
+ <OTPCaret index={i} length={inputLength} />
132
+ ) : (
133
+ <Text
134
+ style={i !== inputLength - 1 && {marginRight: Spacing.L}}
135
+ color={
136
+ !!value[i]
137
+ ? theme.colors.text.default
138
+ : theme.colors.text.hint
147
139
  }
148
- }
149
- typography={'title_s'}>
150
- {letter}
151
- </Text>
152
- );
153
- })}
154
- {focused && value.length !== MAX_LENGTH && <OTPCaret />}
155
- </View>
156
- );
157
- };
140
+ typography={
141
+ !!value[i] ? 'header_m_bold' : 'body_default_regular'
142
+ }>
143
+ {value[i] || '-'}
144
+ </Text>
145
+ )}
146
+ </View>,
147
+ );
148
+ }
149
+ return TextInputs;
150
+ };
158
151
 
159
- const renderInputView = () => {
160
- let placeholderColor = theme.colors.text.hint;
161
- const keyboardType: KeyboardType =
162
- dataType === 'number' ? 'number-pad' : 'default';
163
- return (
164
- <View
165
- style={[
166
- styles.otpInput,
167
- {backgroundColor: theme.colors.background.surface},
168
- getBorderColor(theme, focused, errorMessage),
169
- ]}>
170
- {!!floatingValue && (
171
- <View
172
- style={[
173
- styles.otpFloatingView,
174
- {backgroundColor: theme.colors.background.surface},
175
- ]}>
176
- <Text typography={'description_s'}>{floatingValue}</Text>
152
+ const renderUnidentifiedInputs = () => {
153
+ const splitValue = value.split('');
154
+
155
+ if (!focused && value.length === 0 && !!placeholder) {
156
+ return (
157
+ <Text
158
+ color={theme.colors.text.hint}
159
+ typography={'description_default_regular'}>
160
+ {placeholder}
161
+ </Text>
162
+ );
163
+ }
164
+
165
+ return (
166
+ <View style={{flexDirection: 'row'}}>
167
+ {splitValue.map((letter, index) => {
168
+ return (
169
+ <Text
170
+ style={
171
+ (index !== value.length - 1 ||
172
+ (focused && value.length !== MAX_LENGTH)) && {
173
+ marginRight: Spacing.L,
174
+ }
175
+ }
176
+ typography={'header_m_bold'}>
177
+ {letter}
178
+ </Text>
179
+ );
180
+ })}
181
+ {focused && value.length !== MAX_LENGTH && <OTPCaret />}
182
+ </View>
183
+ );
184
+ };
185
+
186
+ const renderInputView = () => {
187
+ return (
188
+ <View
189
+ style={[
190
+ styles.otpInput,
191
+ {backgroundColor: theme.colors.background.surface},
192
+ getBorderColor(theme, focused, errorMessage),
193
+ ]}>
194
+ {!!floatingValue && (
195
+ <View
196
+ style={[
197
+ styles.otpFloatingView,
198
+ {backgroundColor: theme.colors.background.surface},
199
+ ]}>
200
+ <Text
201
+ typography={'description_default_regular'}
202
+ color={theme.colors.text.hint}>
203
+ {floatingValue}
204
+ </Text>
205
+ </View>
206
+ )}
207
+ <View style={styles.otpInputsView}>
208
+ {length ? renderInputs(length) : renderUnidentifiedInputs()}
209
+ </View>
210
+ <View style={styles.inputView}>
211
+ <TextInput
212
+ {...props}
213
+ accessibilityLabel={accessibilityLabel}
214
+ ref={inputRef}
215
+ value={value}
216
+ onChangeText={_onChangeText}
217
+ keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
218
+ onFocus={onFocusInput}
219
+ onBlur={onBlurInput}
220
+ style={{opacity: 0}}
221
+ selectionColor={theme.colors.primary}
222
+ placeholderTextColor={theme.colors.text.hint}
223
+ />
177
224
  </View>
178
- )}
179
- <View style={styles.otpInputsView}>
180
- {length ? renderInputs(length) : renderUnidentifiedInputs()}
181
225
  </View>
182
- <View style={styles.inputView}>
183
- <TextInput
184
- {...props}
185
- accessibilityLabel={`TextInput`}
186
- ref={inputRef}
187
- value={value}
188
- onChangeText={_onChangeText}
189
- keyboardType={keyboardType}
190
- onFocus={onFocusInput}
191
- onBlur={onBlurInput}
192
- style={{opacity: 0}}
193
- selectionColor={theme.colors.primary}
194
- placeholderTextColor={placeholderColor}
226
+ );
227
+ };
228
+
229
+ return (
230
+ <ComponentContext.Provider
231
+ value={{
232
+ componentName: 'InputOTP',
233
+ params,
234
+ componentLabel: floatingValue,
235
+ state: 'enabled',
236
+ componentId: accessibilityLabel,
237
+ }}>
238
+ <TouchableOpacity
239
+ activeOpacity={1}
240
+ onPress={onFocusInput}
241
+ style={[style, styles.otpWrapper]}>
242
+ {renderInputView()}
243
+ <ErrorView
244
+ errorMessage={errorMessage}
245
+ errorSpacing={errorSpacing}
246
+ hintText={hintText}
195
247
  />
196
- </View>
197
- </View>
248
+ </TouchableOpacity>
249
+ </ComponentContext.Provider>
198
250
  );
199
- };
200
-
201
- return (
202
- <TouchableOpacity
203
- activeOpacity={1}
204
- onPress={onFocusInput}
205
- style={styles.otpWrapper}
206
- accessibilityLabel={`Input/${floatingValue}`}>
207
- {renderInputView()}
208
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
209
- </TouchableOpacity>
210
- );
211
- };
251
+ },
252
+ );
212
253
 
213
254
  export default InputOTP;
@@ -1,4 +1,10 @@
1
- import React, {forwardRef, useContext, useRef, useState} from 'react';
1
+ import React, {
2
+ forwardRef,
3
+ useContext,
4
+ useImperativeHandle,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
2
8
  import {
3
9
  NativeSyntheticEvent,
4
10
  TextInput,
@@ -6,12 +12,13 @@ import {
6
12
  TouchableOpacity,
7
13
  View,
8
14
  } from 'react-native';
9
- import {InputSearchProps} from './index';
10
- import {ApplicationContext} from '../Application';
11
- import styles from './styles';
15
+ import {ApplicationContext, ComponentContext} from '../Application';
12
16
  import {Icon} from '../Icon';
13
17
  import {Text} from '../Text';
18
+ import {InputSearchProps} from './index';
19
+ import styles from './styles';
14
20
  import {checkTyping} from './utils';
21
+ import TextTyping from '../Layout/TextTyping';
15
22
 
16
23
  const InputSearch = forwardRef(
17
24
  (
@@ -25,19 +32,22 @@ const InputSearch = forwardRef(
25
32
  icon,
26
33
  buttonText = 'Hủy',
27
34
  showButtonText = true,
28
- showBorder = true,
29
35
  style,
30
36
  defaultValue,
31
37
  onPressButtonText,
38
+ params,
39
+ hasColorBG = false,
40
+ accessibilityLabel,
41
+ typingData = [],
42
+ onPress,
32
43
  ...props
33
44
  }: InputSearchProps,
34
- ref,
45
+ ref
35
46
  ) => {
36
47
  const {theme} = useContext(ApplicationContext);
37
48
  const [focused, setFocused] = useState(false);
38
49
  const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
39
- const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
40
- let iconTintColor = iconColor;
50
+ const inputRef = useRef<TextInput | null>(null);
41
51
 
42
52
  const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
43
53
  setFocused(true);
@@ -59,20 +69,42 @@ const InputSearch = forwardRef(
59
69
  onChangeText?.(text);
60
70
  };
61
71
 
72
+ useImperativeHandle(ref, () => {
73
+ return {
74
+ clear: onClearText,
75
+ focus: () => inputRef.current?.focus(),
76
+ blur: () => inputRef.current?.blur(),
77
+ setText: (text: string) => _onChangeText(text),
78
+ };
79
+ });
80
+
62
81
  const renderInputView = () => {
63
- let textColor = theme.colors.text.default;
64
- let placeholderColor = theme.colors.text.hint;
82
+ if (typingData?.length > 0) {
83
+ return (
84
+ <TouchableOpacity
85
+ style={[
86
+ styles.searchInput,
87
+ {
88
+ justifyContent: 'center',
89
+ },
90
+ ]}
91
+ onPress={onPress}
92
+ activeOpacity={onPress ? 0.6 : 1}>
93
+ <TextTyping data={typingData} />
94
+ </TouchableOpacity>
95
+ );
96
+ }
65
97
 
66
98
  return (
67
99
  <TextInput
68
100
  {...props}
69
- accessibilityLabel={`TextInput`}
70
- textAlignVertical="top"
101
+ accessibilityLabel={accessibilityLabel}
102
+ textAlignVertical="center"
71
103
  ref={inputRef}
72
104
  style={[
73
105
  styles.searchInput,
74
106
  {
75
- color: textColor,
107
+ color: theme.colors.text.default,
76
108
  },
77
109
  ]}
78
110
  value={value}
@@ -81,7 +113,7 @@ const InputSearch = forwardRef(
81
113
  onBlur={_onBlur}
82
114
  placeholder={placeholder}
83
115
  selectionColor={theme.colors.primary}
84
- placeholderTextColor={placeholderColor}
116
+ placeholderTextColor={theme.colors.text.hint}
85
117
  />
86
118
  );
87
119
  };
@@ -112,7 +144,7 @@ const InputSearch = forwardRef(
112
144
  ]}
113
145
  />
114
146
  <Icon
115
- color={iconTintColor}
147
+ color={iconColor}
116
148
  source={icon}
117
149
  style={styles.iconSearchInput}
118
150
  />
@@ -121,38 +153,58 @@ const InputSearch = forwardRef(
121
153
  </View>
122
154
  );
123
155
  };
156
+
157
+ let inputState = 'empty';
158
+
159
+ if (focused) {
160
+ inputState = 'focus';
161
+ }
162
+
163
+ if (value && value?.length > 0) {
164
+ inputState = 'filled';
165
+ }
166
+
167
+ const backgroundColor = hasColorBG
168
+ ? theme.colors.background.default
169
+ : theme.colors.background.surface;
170
+
124
171
  return (
125
- <View
126
- style={[style, styles.searchInputContainer]}
127
- accessibilityLabel={`InputSearch/${placeholder}`}>
128
- <View
129
- style={[
130
- styles.searchInputWrapper,
131
- {
132
- backgroundColor: theme.colors.background.surface,
133
- borderColor: theme.colors.background.surface,
134
- },
135
- showBorder && {borderColor: theme.colors.border.default},
136
- focused && {borderColor: theme.colors.primary},
137
- ]}>
138
- <Icon
139
- source={'navigation_search'}
140
- size={24}
141
- color={theme.colors.text.hint}
142
- />
143
- {renderInputView()}
144
- {renderIconView()}
172
+ <ComponentContext.Provider
173
+ value={{
174
+ componentName: 'InputSearch',
175
+ params,
176
+ state: inputState,
177
+ componentId: accessibilityLabel,
178
+ }}>
179
+ <View style={[style, styles.searchInputContainer]}>
180
+ <View
181
+ style={[
182
+ styles.searchInputWrapper,
183
+ {
184
+ backgroundColor,
185
+ },
186
+ ]}>
187
+ <Icon
188
+ source={'navigation_search'}
189
+ size={24}
190
+ color={theme.colors.text.hint}
191
+ />
192
+ {renderInputView()}
193
+ {renderIconView()}
194
+ </View>
195
+ {showButtonText && (
196
+ <TouchableOpacity onPress={onPressButtonText}>
197
+ <Text
198
+ typography={'action_default_bold'}
199
+ style={styles.textButton}>
200
+ {buttonText}
201
+ </Text>
202
+ </TouchableOpacity>
203
+ )}
145
204
  </View>
146
- {showButtonText && (
147
- <TouchableOpacity onPress={onPressButtonText}>
148
- <Text typography={'action_default'} style={styles.textButton}>
149
- {buttonText}
150
- </Text>
151
- </TouchableOpacity>
152
- )}
153
- </View>
205
+ </ComponentContext.Provider>
154
206
  );
155
- },
207
+ }
156
208
  );
157
209
 
158
210
  export default InputSearch;