@momo-kits/foundation 0.76.1-beta.2 → 0.77.1-optimize.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 (100) hide show
  1. package/Application/BottomTab/BottomTabBar.tsx +478 -0
  2. package/Application/BottomTab/index.tsx +134 -0
  3. package/Application/Components.tsx +339 -161
  4. package/Application/ModalScreen.tsx +113 -99
  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 +126 -8
  9. package/Application/index.ts +23 -4
  10. package/Application/types.ts +84 -33
  11. package/Application/utils.tsx +90 -50
  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 +90 -39
  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 +13 -9
  34. package/Icon/types.ts +4 -3
  35. package/IconButton/index.tsx +24 -15
  36. package/Image/index.tsx +60 -48
  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 +174 -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 +42 -17
  46. package/Input/index.tsx +204 -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 +128 -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 +348 -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 +102 -44
  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 +8 -1
  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
@@ -1,4 +1,10 @@
1
- import React, {FC, 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,128 +12,185 @@ import {
6
12
  TouchableOpacity,
7
13
  View,
8
14
  } from 'react-native';
9
- import {ApplicationContext} from '../Application';
10
- import styles from './styles';
15
+ import {ApplicationContext, ComponentContext} from '../Application';
16
+ import {Icon} from '../Icon';
11
17
  import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
12
18
  import {InputMoneyProps} from './index';
13
- import {Icon} from '../Icon';
19
+ import styles from './styles';
14
20
  import {formatMoneyToNumber, formatNumberToMoney} from './utils';
15
21
 
16
- const InputMoney: FC<InputMoneyProps> = ({
17
- onChangeText,
18
- floatingValue,
19
- floatingIcon,
20
- size = 'small',
21
- onBlur,
22
- onFocus,
23
- errorMessage,
24
- icon,
25
- disabled,
26
- floatingIconColor,
27
- iconColor,
28
- required,
29
- ...props
30
- }) => {
31
- const {theme} = useContext(ApplicationContext);
32
- const [focused, setFocused] = useState(false);
33
- const inputRef = useRef<any>(null);
34
- const [value, setValue] = useState('');
35
- const onClearText = () => {
36
- inputRef?.current?.clear();
37
- setValue('');
38
- onChangeText?.('');
39
- };
40
- const _onChangeText = (text: string) => {
41
- if (text.length < value.length && value.indexOf(text) === 0) {
42
- text = value.slice(0, -2) + 'đ';
22
+ const InputMoney = forwardRef(
23
+ (
24
+ {
25
+ onChangeText,
26
+ floatingValue,
27
+ floatingIcon,
28
+ size = 'small',
29
+ onBlur,
30
+ onFocus,
31
+ errorMessage,
32
+ icon,
33
+ disabled = false,
34
+ floatingIconColor,
35
+ iconColor,
36
+ required = false,
37
+ errorSpacing,
38
+ style,
39
+ params,
40
+ defaultValue = '',
41
+ accessibilityLabel,
42
+ hintText,
43
+ ...props
44
+ }: InputMoneyProps,
45
+ ref,
46
+ ) => {
47
+ const {theme} = useContext(ApplicationContext);
48
+ const [focused, setFocused] = useState(false);
49
+ const inputRef = useRef<TextInput>(null);
50
+
51
+ const validateText = (text: string) => {
52
+ const valueFormat = formatMoneyToNumber(text, 'đ');
53
+ return formatNumberToMoney(valueFormat, 'đ');
54
+ };
55
+
56
+ const [value, setValue] = useState(
57
+ defaultValue ? validateText(defaultValue) : '',
58
+ );
59
+
60
+ const onClearText = () => {
61
+ inputRef?.current?.clear();
62
+ setValue('');
63
+ onChangeText?.('');
64
+ };
65
+
66
+ const _onChangeText = (text: string) => {
67
+ if (text.length < value.length && value.indexOf(text) === 0) {
68
+ text = value.slice(0, -2) + 'đ';
69
+ }
70
+ setValue(validateText(text));
71
+ onChangeText?.(formatMoneyToNumber(text, 'đ').toString());
72
+ };
73
+
74
+ useImperativeHandle(ref, () => {
75
+ return {
76
+ clear: onClearText,
77
+ focus: () => inputRef.current?.focus(),
78
+ blur: () => inputRef.current?.blur(),
79
+ changeText: (text: string) => _onChangeText(text),
80
+ setText: _onChangeText,
81
+ };
82
+ });
83
+
84
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
85
+ setFocused(true);
86
+ onFocus?.(e);
87
+ };
88
+
89
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
90
+ setFocused(false);
91
+ onBlur?.(e);
92
+ };
93
+
94
+ const renderInputView = () => {
95
+ const disabledColor = theme.colors.text.disable;
96
+ let textColor = theme.colors.text.default;
97
+ let placeholderColor = theme.colors.text.hint;
98
+ let iconTintColor = iconColor;
99
+
100
+ if (disabled) {
101
+ textColor = disabledColor;
102
+ placeholderColor = disabledColor;
103
+ iconTintColor = disabledColor;
104
+ }
105
+
106
+ return (
107
+ <View
108
+ style={[
109
+ styles.inputWrapper,
110
+ {backgroundColor: theme.colors.background.surface},
111
+ getSizeStyle(size),
112
+ getBorderColor(theme, focused, errorMessage, disabled),
113
+ ]}>
114
+ <FloatingView
115
+ floatingValue={floatingValue}
116
+ floatingIconColor={floatingIconColor}
117
+ disabled={disabled}
118
+ required={required}
119
+ floatingIcon={floatingIcon}
120
+ />
121
+ <View style={styles.inputView}>
122
+ <TextInput
123
+ {...props}
124
+ accessibilityLabel={accessibilityLabel}
125
+ editable={!disabled}
126
+ ref={inputRef}
127
+ keyboardType={'number-pad'}
128
+ style={[
129
+ styles.moneyInput,
130
+ {
131
+ color: textColor,
132
+ },
133
+ ]}
134
+ value={value}
135
+ onChangeText={_onChangeText}
136
+ onFocus={_onFocus}
137
+ onBlur={_onBlur}
138
+ selectionColor={theme.colors.primary}
139
+ placeholderTextColor={placeholderColor}
140
+ placeholder={'0đ'}
141
+ />
142
+ </View>
143
+ <View style={styles.iconView}>
144
+ {focused && (
145
+ <TouchableOpacity
146
+ style={styles.iconWrapper}
147
+ onPress={onClearText}>
148
+ <Icon
149
+ source="24_navigation_close_circle_full"
150
+ size={16}
151
+ color={theme.colors.text.hint}
152
+ />
153
+ </TouchableOpacity>
154
+ )}
155
+ {!!icon && <Icon color={iconTintColor} source={icon} />}
156
+ </View>
157
+ </View>
158
+ );
159
+ };
160
+
161
+ let inputState = 'active';
162
+
163
+ if (value && value?.length > 0) {
164
+ inputState = 'filled';
165
+ }
166
+ if (errorMessage && errorMessage?.length > 0) {
167
+ inputState = 'error';
43
168
  }
44
- const valueFormat = formatMoneyToNumber(text, 'đ');
45
- setValue(formatNumberToMoney(valueFormat, 'đ'));
46
- onChangeText?.(formatMoneyToNumber(text, 'đ').toString());
47
- };
48
-
49
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
50
- setFocused(true);
51
- onFocus?.(e);
52
- };
53
-
54
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
55
- setFocused(false);
56
- onBlur?.(e);
57
- };
58
-
59
- const renderInputView = () => {
60
- const disabledColor = theme.colors.text.disable;
61
- let textColor = theme.colors.text.default;
62
- let placeholderColor = theme.colors.text.hint;
63
- let iconTintColor = iconColor;
64
169
 
65
170
  if (disabled) {
66
- textColor = disabledColor;
67
- placeholderColor = disabledColor;
68
- iconTintColor = disabledColor;
171
+ inputState = 'disabled';
69
172
  }
70
173
 
71
174
  return (
72
- <View
73
- style={[
74
- getSizeStyle(size),
75
- getBorderColor(focused, errorMessage, disabled),
76
- styles.inputWrapper,
77
- {backgroundColor: theme.colors.background.surface},
78
- ]}>
79
- <FloatingView
80
- floatingValue={floatingValue}
81
- floatingIconColor={floatingIconColor}
82
- disabled={disabled}
83
- required={required}
84
- floatingIcon={floatingIcon}
85
- />
86
- <View style={styles.inputView}>
87
- <TextInput
88
- {...props}
89
- accessibilityLabel={`TextInput`}
90
- editable={!disabled}
91
- textAlignVertical="top"
92
- ref={inputRef}
93
- keyboardType={'number-pad'}
94
- style={[
95
- styles.moneyInput,
96
- {
97
- color: textColor,
98
- },
99
- ]}
100
- value={value}
101
- onChangeText={_onChangeText}
102
- onFocus={_onFocus}
103
- onBlur={_onBlur}
104
- selectionColor={theme.colors.primary}
105
- placeholderTextColor={placeholderColor}
106
- placeholder={'0đ'}
175
+ <ComponentContext.Provider
176
+ value={{
177
+ componentName: 'InputMoney',
178
+ params,
179
+ componentLabel: floatingValue,
180
+ state: inputState,
181
+ componentId: accessibilityLabel,
182
+ }}>
183
+ <View style={[style, styles.wrapper]}>
184
+ {renderInputView()}
185
+ <ErrorView
186
+ errorMessage={errorMessage}
187
+ errorSpacing={errorSpacing}
188
+ hintText={hintText}
107
189
  />
108
190
  </View>
109
- <View style={styles.iconView}>
110
- {focused && (
111
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
112
- <Icon
113
- source="24_navigation_close_circle_full"
114
- size={16}
115
- color={theme.colors.text.hint}
116
- />
117
- </TouchableOpacity>
118
- )}
119
- {!!icon && <Icon color={iconTintColor} source={icon} />}
120
- </View>
121
- </View>
191
+ </ComponentContext.Provider>
122
192
  );
123
- };
124
-
125
- return (
126
- <View style={styles.wrapper} accessibilityLabel={`InputMoney`}>
127
- {renderInputView()}
128
- <ErrorView errorMessage={errorMessage} />
129
- </View>
130
- );
131
- };
193
+ },
194
+ );
132
195
 
133
196
  export default InputMoney;
@@ -0,0 +1,257 @@
1
+ import React, {
2
+ FC,
3
+ forwardRef,
4
+ useContext,
5
+ useEffect,
6
+ useImperativeHandle,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import {
11
+ Animated,
12
+ NativeSyntheticEvent,
13
+ TextInput,
14
+ TextInputFocusEventData,
15
+ TouchableOpacity,
16
+ View,
17
+ } from 'react-native';
18
+ import {ApplicationContext, ComponentContext} from '../Application';
19
+ import {Spacing} from '../Consts';
20
+ import {scaleSize, Text} from '../Text';
21
+ import {ErrorView, getBorderColor} from './common';
22
+ import {CaretProps, InputOTPProps} from './index';
23
+ import styles from './styles';
24
+
25
+ const OTPCaret: FC<CaretProps> = ({index, length}) => {
26
+ const DURATION = 300;
27
+ const {theme} = useContext(ApplicationContext);
28
+ const opacity = useRef(new Animated.Value(0)).current;
29
+
30
+ useEffect(() => {
31
+ Animated.loop(
32
+ Animated.sequence([
33
+ Animated.timing(opacity, {
34
+ toValue: 1,
35
+ duration: DURATION,
36
+ useNativeDriver: true,
37
+ }),
38
+ Animated.delay(DURATION * 2),
39
+ Animated.timing(opacity, {
40
+ toValue: 0,
41
+ duration: DURATION,
42
+ useNativeDriver: true,
43
+ }),
44
+ ]),
45
+ ).start();
46
+ }, []);
47
+ const spacingStyle = !isNaN(Number(length)) &&
48
+ index !== Number(length) - 1 && {marginRight: Spacing.L};
49
+
50
+ return (
51
+ <View style={[{flexDirection: 'row', alignItems: 'center'}, spacingStyle]}>
52
+ <Animated.View
53
+ style={{
54
+ height: scaleSize(12),
55
+ width: 1,
56
+ backgroundColor: theme.colors.primary,
57
+ opacity,
58
+ }}
59
+ />
60
+ <Text color={theme.colors.text.hint} typography={'body_default_regular'}>
61
+ -
62
+ </Text>
63
+ </View>
64
+ );
65
+ };
66
+
67
+ const InputOTP = forwardRef(
68
+ (
69
+ {
70
+ length,
71
+ errorMessage,
72
+ errorSpacing,
73
+ floatingValue = 'Label',
74
+ floatingIconColor,
75
+ floatingIcon,
76
+ placeholder,
77
+ onChangeText,
78
+ onFocus,
79
+ onBlur,
80
+ dataType = 'number',
81
+ params,
82
+ style,
83
+ accessibilityLabel,
84
+ hintText,
85
+ ...props
86
+ }: InputOTPProps,
87
+ ref,
88
+ ) => {
89
+ const MAX_LENGTH = 10;
90
+ const [value, setValue] = useState('');
91
+ const [focused, setFocused] = useState(false);
92
+ const inputRef = useRef<TextInput | null>(null);
93
+ const {theme} = useContext(ApplicationContext);
94
+
95
+ useImperativeHandle(ref, () => ({
96
+ onChangeText: (text: string) => {
97
+ _onChangeText(text);
98
+ },
99
+ focus: () => inputRef.current?.focus(),
100
+ blur: () => inputRef.current?.blur(),
101
+ setText: (text: string) => _onChangeText(text),
102
+ }));
103
+
104
+ const onFocusInput = () => {
105
+ setFocused(true);
106
+ inputRef.current?.focus();
107
+ };
108
+
109
+ const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
110
+ setFocused(false);
111
+ onBlur?.(e);
112
+ };
113
+
114
+ const _onChangeText = (text: string) => {
115
+ if (text.length > MAX_LENGTH) return;
116
+ if (dataType === 'number' && isNaN(Number(text))) return;
117
+ if (
118
+ !isNaN(Number(text)) &&
119
+ value.length >= Number(length) &&
120
+ text.length >= value.length
121
+ )
122
+ return;
123
+
124
+ setValue(text);
125
+ onChangeText?.(text);
126
+ };
127
+
128
+ const renderInputs = (length: number) => {
129
+ const TextInputs: React.ReactNode[] = [];
130
+ for (let i = 0; i < length; i++) {
131
+ TextInputs.push(
132
+ <View>
133
+ {focused && value.length === i ? (
134
+ <OTPCaret index={i} length={length} />
135
+ ) : (
136
+ <Text
137
+ style={i !== length - 1 && {marginRight: Spacing.L}}
138
+ color={
139
+ !!value[i]
140
+ ? theme.colors.text.default
141
+ : theme.colors.text.hint
142
+ }
143
+ typography={
144
+ !!value[i] ? 'header_m_bold' : 'body_default_regular'
145
+ }>
146
+ {value[i] || '-'}
147
+ </Text>
148
+ )}
149
+ </View>,
150
+ );
151
+ }
152
+ return TextInputs;
153
+ };
154
+
155
+ const renderUnidentifiedInputs = () => {
156
+ const splitValue = value.split('');
157
+
158
+ if (!focused && value.length === 0 && !!placeholder) {
159
+ return (
160
+ <Text
161
+ color={theme.colors.text.hint}
162
+ typography={'description_default_regular'}>
163
+ {placeholder}
164
+ </Text>
165
+ );
166
+ }
167
+
168
+ return (
169
+ <View style={{flexDirection: 'row'}}>
170
+ {splitValue.map((letter, index) => {
171
+ return (
172
+ <Text
173
+ style={
174
+ (index !== value.length - 1 ||
175
+ (focused && value.length !== MAX_LENGTH)) && {
176
+ marginRight: Spacing.L,
177
+ }
178
+ }
179
+ typography={'header_m_bold'}>
180
+ {letter}
181
+ </Text>
182
+ );
183
+ })}
184
+ {focused && value.length !== MAX_LENGTH && <OTPCaret />}
185
+ </View>
186
+ );
187
+ };
188
+
189
+ const renderInputView = () => {
190
+ return (
191
+ <View
192
+ style={[
193
+ styles.otpInput,
194
+ {backgroundColor: theme.colors.background.surface},
195
+ getBorderColor(theme, focused, errorMessage),
196
+ ]}>
197
+ {!!floatingValue && (
198
+ <View
199
+ style={[
200
+ styles.otpFloatingView,
201
+ {backgroundColor: theme.colors.background.surface},
202
+ ]}>
203
+ <Text
204
+ typography={'description_default_regular'}
205
+ color={theme.colors.text.hint}>
206
+ {floatingValue}
207
+ </Text>
208
+ </View>
209
+ )}
210
+ <View style={styles.otpInputsView}>
211
+ {length ? renderInputs(length) : renderUnidentifiedInputs()}
212
+ </View>
213
+ <View style={styles.inputView}>
214
+ <TextInput
215
+ {...props}
216
+ accessibilityLabel={accessibilityLabel}
217
+ ref={inputRef}
218
+ value={value}
219
+ onChangeText={_onChangeText}
220
+ keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
221
+ onFocus={onFocusInput}
222
+ onBlur={onBlurInput}
223
+ style={{opacity: 0}}
224
+ selectionColor={theme.colors.primary}
225
+ placeholderTextColor={theme.colors.text.hint}
226
+ />
227
+ </View>
228
+ </View>
229
+ );
230
+ };
231
+
232
+ return (
233
+ <ComponentContext.Provider
234
+ value={{
235
+ componentName: 'InputOTP',
236
+ params,
237
+ componentLabel: floatingValue,
238
+ state: 'enabled',
239
+ componentId: accessibilityLabel,
240
+ }}>
241
+ <TouchableOpacity
242
+ activeOpacity={1}
243
+ onPress={onFocusInput}
244
+ style={[style, styles.otpWrapper]}>
245
+ {renderInputView()}
246
+ <ErrorView
247
+ errorMessage={errorMessage}
248
+ errorSpacing={errorSpacing}
249
+ hintText={hintText}
250
+ />
251
+ </TouchableOpacity>
252
+ </ComponentContext.Provider>
253
+ );
254
+ },
255
+ );
256
+
257
+ export default InputOTP;