@momo-kits/foundation 0.89.5 → 0.89.6-rc.2

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 (73) 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} +42 -18
  4. package/Application/Components.tsx +350 -86
  5. package/Application/Localize.ts +44 -0
  6. package/Application/ModalScreen.tsx +14 -185
  7. package/Application/Navigation.ts +5 -19
  8. package/Application/NavigationContainer.tsx +62 -72
  9. package/Application/Navigator.ts +53 -35
  10. package/Application/StackScreen.tsx +289 -32
  11. package/Application/index.ts +13 -15
  12. package/Application/types.ts +64 -35
  13. package/Application/utils.tsx +76 -30
  14. package/Assets/icon_bank.json +1 -1
  15. package/Badge/Badge.tsx +1 -1
  16. package/Badge/BadgeDotAnimation.tsx +95 -0
  17. package/Badge/index.tsx +2 -1
  18. package/Badge/styles.ts +50 -6
  19. package/Button/index.tsx +44 -26
  20. package/CheckBox/index.tsx +37 -26
  21. package/CheckBox/types.ts +5 -3
  22. package/Consts/colors+spacing+radius.ts +14 -0
  23. package/Icon/index.tsx +9 -8
  24. package/Icon/types.ts +2 -2
  25. package/IconButton/index.tsx +24 -14
  26. package/Image/index.tsx +23 -8
  27. package/Image/types.ts +2 -0
  28. package/Input/Input.tsx +116 -26
  29. package/Input/InputDropDown.tsx +66 -51
  30. package/Input/InputMoney.tsx +106 -15
  31. package/Input/InputOTP.tsx +49 -26
  32. package/Input/InputSearch.tsx +252 -99
  33. package/Input/InputTextArea.tsx +26 -6
  34. package/Input/TextTyping.tsx +113 -0
  35. package/Input/common.tsx +48 -22
  36. package/Input/index.tsx +112 -77
  37. package/Input/styles.ts +48 -11
  38. package/Input/utils.ts +1 -1
  39. package/Layout/Card.tsx +4 -3
  40. package/Layout/FloatingButton.tsx +168 -0
  41. package/Layout/GridSystem.tsx +1 -1
  42. package/Layout/ItemList.tsx +3 -2
  43. package/Layout/Screen.tsx +242 -121
  44. package/Layout/Section.tsx +4 -3
  45. package/Layout/styles.ts +11 -13
  46. package/Layout/types.ts +1 -1
  47. package/Layout/utils.ts +4 -4
  48. package/Loader/index.tsx +2 -0
  49. package/Pagination/PaginationScroll.tsx +2 -2
  50. package/Pagination/styles.ts +1 -1
  51. package/Popup/PopupNotify.tsx +56 -45
  52. package/Popup/PopupPromotion.tsx +5 -7
  53. package/Popup/types.ts +1 -7
  54. package/Radio/index.tsx +35 -20
  55. package/Radio/types.ts +5 -3
  56. package/Switch/index.tsx +32 -18
  57. package/Switch/types.ts +5 -3
  58. package/Tag/index.tsx +9 -2
  59. package/Tag/styles.ts +3 -2
  60. package/Tag/types.ts +12 -0
  61. package/Text/index.tsx +24 -5
  62. package/Text/styles.ts +8 -8
  63. package/Text/types.ts +19 -1
  64. package/Title/index.tsx +170 -103
  65. package/Title/styles.ts +36 -9
  66. package/Title/types.ts +16 -48
  67. package/code-scanner.js +125 -16
  68. package/index.ts +7 -0
  69. package/migrate_typo.js +56 -0
  70. package/package.json +11 -10
  71. package/publish.sh +16 -21
  72. package/tsconfig.json +1 -1
  73. package/verify.js +37 -40
@@ -1,6 +1,8 @@
1
1
  import React, {
2
2
  forwardRef,
3
+ ReactNode,
3
4
  useContext,
5
+ useEffect,
4
6
  useImperativeHandle,
5
7
  useRef,
6
8
  useState,
@@ -12,12 +14,14 @@ import {
12
14
  TouchableOpacity,
13
15
  View,
14
16
  } from 'react-native';
15
- import {ApplicationContext} from '../Application';
16
- import styles from './styles';
17
+ import {ApplicationContext, ComponentContext} from '../Application';
18
+ import {Icon} from '../Icon';
17
19
  import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
18
20
  import {InputMoneyProps} from './index';
19
- import {Icon} from '../Icon';
21
+ import styles from './styles';
20
22
  import {formatMoneyToNumber, formatNumberToMoney} from './utils';
23
+ import {Text} from '../Text';
24
+ import {Loader} from '../Loader';
21
25
 
22
26
  const InputMoney = forwardRef(
23
27
  (
@@ -26,24 +30,41 @@ const InputMoney = forwardRef(
26
30
  floatingValue,
27
31
  floatingIcon,
28
32
  size = 'small',
33
+ loading,
29
34
  onBlur,
30
35
  onFocus,
31
36
  errorMessage,
32
37
  icon,
38
+ iconColor,
39
+ onPressIcon,
40
+ trailing,
41
+ trailingColor,
42
+ onPressTrailing,
33
43
  disabled = false,
34
44
  floatingIconColor,
35
- iconColor,
36
45
  required = false,
37
46
  errorSpacing,
38
47
  style,
48
+ params,
39
49
  defaultValue = '',
50
+ accessibilityLabel,
51
+ hintText,
52
+ value: _value,
53
+ onPressFloatingIcon,
40
54
  ...props
41
55
  }: InputMoneyProps,
42
- ref,
56
+ ref
43
57
  ) => {
44
58
  const {theme} = useContext(ApplicationContext);
45
59
  const [focused, setFocused] = useState(false);
46
- const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
60
+ const inputRef = useRef<TextInput>(null);
61
+
62
+ useEffect(() => {
63
+ if (_value) {
64
+ setValue(validateText(_value));
65
+ onChangeText?.(formatMoneyToNumber(_value, 'đ').toString());
66
+ }
67
+ }, [_value]);
47
68
 
48
69
  const validateText = (text: string) => {
49
70
  const valueFormat = formatMoneyToNumber(text, 'đ');
@@ -51,7 +72,7 @@ const InputMoney = forwardRef(
51
72
  };
52
73
 
53
74
  const [value, setValue] = useState(
54
- defaultValue ? validateText(defaultValue) : '',
75
+ defaultValue ? validateText(defaultValue) : ''
55
76
  );
56
77
 
57
78
  const onClearText = () => {
@@ -70,6 +91,9 @@ const InputMoney = forwardRef(
70
91
 
71
92
  useImperativeHandle(ref, () => {
72
93
  return {
94
+ clear: onClearText,
95
+ focus: () => inputRef.current?.focus(),
96
+ blur: () => inputRef.current?.blur(),
73
97
  setText: _onChangeText,
74
98
  };
75
99
  });
@@ -84,11 +108,51 @@ const InputMoney = forwardRef(
84
108
  onBlur?.(e);
85
109
  };
86
110
 
111
+ /**
112
+ * Render trailing icon or text
113
+ * @param color
114
+ */
115
+ const renderTrailing = (color?: string) => {
116
+ if (loading) {
117
+ return <Loader type={'spinner'} color={color} style={styles.icon} />;
118
+ }
119
+
120
+ if (icon || trailing) {
121
+ const renderIconTouchable = (icon: ReactNode) => {
122
+ return (
123
+ <TouchableOpacity
124
+ onPress={onPressTrailing ?? onPressIcon}
125
+ style={styles.icon}>
126
+ {icon}
127
+ </TouchableOpacity>
128
+ );
129
+ };
130
+ const trailingValue = icon || trailing;
131
+ if (trailingValue?.includes('_') || trailingValue?.includes('http')) {
132
+ return renderIconTouchable(
133
+ <Icon
134
+ color={color}
135
+ source={(icon || trailing) as string}
136
+ size={24}
137
+ />
138
+ );
139
+ }
140
+ return renderIconTouchable(
141
+ <Text
142
+ typography="action_xs_bold"
143
+ color={color ?? theme.colors.primary}
144
+ numberOfLines={1}>
145
+ {trailingValue!.substring(0, 15)}
146
+ </Text>
147
+ );
148
+ }
149
+ };
150
+
87
151
  const renderInputView = () => {
88
152
  const disabledColor = theme.colors.text.disable;
89
153
  let textColor = theme.colors.text.default;
90
154
  let placeholderColor = theme.colors.text.hint;
91
- let iconTintColor = iconColor;
155
+ let iconTintColor = trailingColor ?? iconColor;
92
156
 
93
157
  if (disabled) {
94
158
  textColor = disabledColor;
@@ -110,12 +174,13 @@ const InputMoney = forwardRef(
110
174
  disabled={disabled}
111
175
  required={required}
112
176
  floatingIcon={floatingIcon}
177
+ onPress={onPressFloatingIcon}
113
178
  />
114
179
  <View style={styles.inputView}>
115
180
  <TextInput
116
181
  {...props}
182
+ accessibilityLabel={accessibilityLabel}
117
183
  editable={!disabled}
118
- textAlignVertical="top"
119
184
  ref={inputRef}
120
185
  keyboardType={'number-pad'}
121
186
  style={[
@@ -145,19 +210,45 @@ const InputMoney = forwardRef(
145
210
  />
146
211
  </TouchableOpacity>
147
212
  )}
148
- {!!icon && <Icon color={iconTintColor} source={icon} />}
213
+ {renderTrailing(iconTintColor)}
149
214
  </View>
150
215
  </View>
151
216
  );
152
217
  };
153
218
 
219
+ let inputState = 'active';
220
+
221
+ if (value && value?.length > 0) {
222
+ inputState = 'filled';
223
+ }
224
+ if (errorMessage && errorMessage?.length > 0) {
225
+ inputState = 'error';
226
+ }
227
+
228
+ if (disabled) {
229
+ inputState = 'disabled';
230
+ }
231
+
154
232
  return (
155
- <View style={[style, styles.wrapper]}>
156
- {renderInputView()}
157
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
158
- </View>
233
+ <ComponentContext.Provider
234
+ value={{
235
+ componentName: 'InputMoney',
236
+ params,
237
+ componentLabel: floatingValue,
238
+ state: inputState,
239
+ componentId: accessibilityLabel,
240
+ }}>
241
+ <View style={[style, styles.wrapper]}>
242
+ {renderInputView()}
243
+ <ErrorView
244
+ errorMessage={errorMessage}
245
+ errorSpacing={errorSpacing}
246
+ hintText={hintText}
247
+ />
248
+ </View>
249
+ </ComponentContext.Provider>
159
250
  );
160
- },
251
+ }
161
252
  );
162
253
 
163
254
  export default InputMoney;
@@ -15,12 +15,12 @@ import {
15
15
  TouchableOpacity,
16
16
  View,
17
17
  } from 'react-native';
18
- import {CaretProps, InputOTPProps} from './index';
18
+ import {ApplicationContext, ComponentContext} from '../Application';
19
+ import {Spacing} from '../Consts';
19
20
  import {scaleSize, Text} from '../Text';
20
- import styles from './styles';
21
21
  import {ErrorView, getBorderColor} from './common';
22
- import {ApplicationContext} from '../Application';
23
- import {Spacing} from '../Consts';
22
+ import {CaretProps, InputOTPProps} from './index';
23
+ import styles from './styles';
24
24
 
25
25
  const OTPCaret: FC<CaretProps> = ({index, length}) => {
26
26
  const DURATION = 300;
@@ -41,7 +41,7 @@ const OTPCaret: FC<CaretProps> = ({index, length}) => {
41
41
  duration: DURATION,
42
42
  useNativeDriver: true,
43
43
  }),
44
- ]),
44
+ ])
45
45
  ).start();
46
46
  }, []);
47
47
  const spacingStyle = !isNaN(Number(length)) &&
@@ -70,29 +70,36 @@ const InputOTP = forwardRef(
70
70
  length,
71
71
  errorMessage,
72
72
  errorSpacing,
73
- floatingValue,
74
- floatingIconColor,
75
- floatingIcon,
73
+ floatingValue = 'Label',
76
74
  placeholder,
77
75
  onChangeText,
78
- onFocus,
79
76
  onBlur,
77
+ onFocus,
80
78
  dataType = 'number',
79
+ params,
81
80
  style,
81
+ accessibilityLabel,
82
+ hintText,
82
83
  ...props
83
84
  }: InputOTPProps,
84
- ref,
85
+ ref
85
86
  ) => {
86
87
  const MAX_LENGTH = 10;
87
88
  const [value, setValue] = useState('');
88
89
  const [focused, setFocused] = useState(false);
89
- const inputRef = useRef<TextInput>(null);
90
+ const inputRef = useRef<TextInput | null>(null);
90
91
  const {theme} = useContext(ApplicationContext);
91
92
 
92
93
  useImperativeHandle(ref, () => ({
93
94
  onChangeText: (text: string) => {
94
95
  _onChangeText(text);
95
96
  },
97
+ focus: () => {
98
+ setFocused(true);
99
+ inputRef.current?.focus()
100
+ },
101
+ blur: () => inputRef.current?.blur(),
102
+ setText: (text: string) => _onChangeText(text),
96
103
  }));
97
104
 
98
105
  const onFocusInput = () => {
@@ -119,16 +126,16 @@ const InputOTP = forwardRef(
119
126
  onChangeText?.(text);
120
127
  };
121
128
 
122
- const renderInputs = (length: number) => {
129
+ const renderInputs = (inputLength: number) => {
123
130
  const TextInputs: React.ReactNode[] = [];
124
- for (let i = 0; i < length; i++) {
131
+ for (let i = 0; i < inputLength; i++) {
125
132
  TextInputs.push(
126
133
  <View>
127
134
  {focused && value.length === i ? (
128
- <OTPCaret index={i} length={length} />
135
+ <OTPCaret index={i} length={inputLength} />
129
136
  ) : (
130
137
  <Text
131
- style={i !== length - 1 && {marginRight: Spacing.L}}
138
+ style={i !== inputLength - 1 && {marginRight: Spacing.L}}
132
139
  color={
133
140
  !!value[i]
134
141
  ? theme.colors.text.default
@@ -140,7 +147,7 @@ const InputOTP = forwardRef(
140
147
  {value[i] || '-'}
141
148
  </Text>
142
149
  )}
143
- </View>,
150
+ </View>
144
151
  );
145
152
  }
146
153
  return TextInputs;
@@ -194,7 +201,9 @@ const InputOTP = forwardRef(
194
201
  styles.otpFloatingView,
195
202
  {backgroundColor: theme.colors.background.surface},
196
203
  ]}>
197
- <Text typography={'description_default_regular'}>
204
+ <Text
205
+ typography={'description_default_regular'}
206
+ color={theme.colors.text.hint}>
198
207
  {floatingValue}
199
208
  </Text>
200
209
  </View>
@@ -205,11 +214,12 @@ const InputOTP = forwardRef(
205
214
  <View style={styles.inputView}>
206
215
  <TextInput
207
216
  {...props}
217
+ accessibilityLabel={accessibilityLabel}
208
218
  ref={inputRef}
209
219
  value={value}
210
220
  onChangeText={_onChangeText}
211
221
  keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
212
- onFocus={onFocusInput}
222
+ onFocus={onFocus}
213
223
  onBlur={onBlurInput}
214
224
  style={{opacity: 0}}
215
225
  selectionColor={theme.colors.primary}
@@ -221,15 +231,28 @@ const InputOTP = forwardRef(
221
231
  };
222
232
 
223
233
  return (
224
- <TouchableOpacity
225
- activeOpacity={1}
226
- onPress={onFocusInput}
227
- style={[style, styles.otpWrapper]}>
228
- {renderInputView()}
229
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
230
- </TouchableOpacity>
234
+ <ComponentContext.Provider
235
+ value={{
236
+ componentName: 'InputOTP',
237
+ params,
238
+ componentLabel: floatingValue,
239
+ state: 'enabled',
240
+ componentId: accessibilityLabel,
241
+ }}>
242
+ <TouchableOpacity
243
+ activeOpacity={1}
244
+ onPress={onFocusInput}
245
+ style={[style, styles.otpWrapper]}>
246
+ {renderInputView()}
247
+ <ErrorView
248
+ errorMessage={errorMessage}
249
+ errorSpacing={errorSpacing}
250
+ hintText={hintText}
251
+ />
252
+ </TouchableOpacity>
253
+ </ComponentContext.Provider>
231
254
  );
232
- },
255
+ }
233
256
  );
234
257
 
235
258
  export default InputOTP;