@momo-kits/foundation 0.81.49 → 0.81.51-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.
- package/Application/BottomSheet.tsx +216 -0
- package/Application/BottomTab/BottomTabBar.tsx +278 -0
- package/Application/{BottomTab.tsx → BottomTab/index.tsx} +42 -18
- package/Application/Components.tsx +356 -91
- package/Application/Localize.ts +44 -0
- package/Application/ModalScreen.tsx +14 -185
- package/Application/Navigation.ts +5 -19
- package/Application/NavigationContainer.tsx +62 -72
- package/Application/Navigator.ts +154 -48
- package/Application/StackScreen.tsx +289 -32
- package/Application/constants.ts +9 -0
- package/Application/index.ts +13 -15
- package/Application/types.ts +81 -35
- package/Application/utils.tsx +76 -30
- package/Assets/icon_bank.json +1 -1
- package/Badge/Badge.tsx +1 -1
- package/Badge/BadgeDotAnimation.tsx +95 -0
- package/Badge/index.tsx +2 -1
- package/Badge/styles.ts +50 -6
- package/Button/index.tsx +44 -26
- package/CheckBox/index.tsx +37 -26
- package/CheckBox/types.ts +5 -3
- package/Consts/colors+spacing+radius.ts +14 -0
- package/Icon/index.tsx +9 -8
- package/Icon/types.ts +2 -2
- package/IconButton/index.tsx +24 -14
- package/Image/index.tsx +23 -8
- package/Image/types.ts +2 -0
- package/Input/Input.tsx +116 -26
- package/Input/InputDropDown.tsx +66 -51
- package/Input/InputMoney.tsx +106 -15
- package/Input/InputOTP.tsx +49 -26
- package/Input/InputSearch.tsx +252 -99
- package/Input/InputTextArea.tsx +26 -6
- package/Input/TextTyping.tsx +113 -0
- package/Input/common.tsx +48 -22
- package/Input/index.tsx +112 -77
- package/Input/styles.ts +48 -11
- package/Input/utils.ts +1 -1
- package/Layout/Card.tsx +4 -3
- package/Layout/FloatingButton.tsx +168 -0
- package/Layout/GridSystem.tsx +1 -1
- package/Layout/ItemList.tsx +3 -2
- package/Layout/Screen.tsx +242 -121
- package/Layout/Section.tsx +4 -3
- package/Layout/styles.ts +11 -13
- package/Layout/types.ts +1 -1
- package/Layout/utils.ts +4 -4
- package/Loader/index.tsx +2 -0
- package/Pagination/PaginationScroll.tsx +2 -2
- package/Pagination/styles.ts +1 -1
- package/Popup/PopupNotify.tsx +57 -46
- package/Popup/PopupPromotion.tsx +6 -8
- package/Popup/types.ts +1 -7
- package/Radio/index.tsx +35 -20
- package/Radio/types.ts +5 -3
- package/Switch/index.tsx +32 -18
- package/Switch/types.ts +5 -3
- package/Tag/index.tsx +9 -2
- package/Tag/styles.ts +3 -2
- package/Tag/types.ts +12 -0
- package/Text/index.tsx +24 -5
- package/Text/styles.ts +8 -8
- package/Text/types.ts +19 -1
- package/Title/index.tsx +170 -103
- package/Title/styles.ts +36 -9
- package/Title/types.ts +16 -48
- package/code-scanner.js +125 -16
- package/index.ts +7 -0
- package/migrate_typo.js +56 -0
- package/package.json +10 -9
- package/publish.sh +16 -21
- package/tsconfig.json +1 -1
package/Input/Input.tsx
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
ReactNode,
|
|
4
|
+
useContext,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
2
9
|
import {
|
|
3
10
|
NativeSyntheticEvent,
|
|
11
|
+
Platform,
|
|
4
12
|
TextInput,
|
|
5
13
|
TextInputFocusEventData,
|
|
6
14
|
TouchableOpacity,
|
|
7
15
|
View,
|
|
8
16
|
} from 'react-native';
|
|
9
|
-
import {ApplicationContext} from '../Application';
|
|
10
|
-
import
|
|
17
|
+
import {ApplicationContext, ComponentContext} from '../Application';
|
|
18
|
+
import {Icon} from '../Icon';
|
|
19
|
+
import {Loader} from '../Loader';
|
|
20
|
+
import {Text} from '../Text';
|
|
11
21
|
import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
|
|
12
22
|
import {InputProps} from './index';
|
|
13
|
-
import
|
|
23
|
+
import styles from './styles';
|
|
14
24
|
import {checkTyping} from './utils';
|
|
15
|
-
import {Loader} from '../Loader';
|
|
16
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Input default component
|
|
28
|
+
*/
|
|
17
29
|
const Input = forwardRef(
|
|
18
30
|
(
|
|
19
31
|
{
|
|
@@ -27,27 +39,36 @@ const Input = forwardRef(
|
|
|
27
39
|
onFocus,
|
|
28
40
|
errorMessage,
|
|
29
41
|
icon,
|
|
42
|
+
iconColor,
|
|
43
|
+
onPressIcon,
|
|
44
|
+
trailing,
|
|
45
|
+
trailingColor,
|
|
46
|
+
onPressTrailing,
|
|
30
47
|
disabled = false,
|
|
31
48
|
floatingIconColor,
|
|
32
|
-
iconColor,
|
|
33
49
|
required = false,
|
|
34
50
|
errorSpacing,
|
|
35
51
|
loading = false,
|
|
36
52
|
leadingIcon,
|
|
37
53
|
leadingIconColor,
|
|
38
54
|
fontWeight = 'Regular',
|
|
39
|
-
onPressIcon,
|
|
40
55
|
secureTextEntry,
|
|
56
|
+
keyboardType,
|
|
41
57
|
style,
|
|
58
|
+
params,
|
|
59
|
+
hintText,
|
|
60
|
+
accessibilityLabel,
|
|
61
|
+
editable = true,
|
|
62
|
+
onPressFloatingIcon,
|
|
42
63
|
...props
|
|
43
64
|
}: InputProps,
|
|
44
|
-
ref
|
|
65
|
+
ref
|
|
45
66
|
) => {
|
|
46
67
|
const {theme} = useContext(ApplicationContext);
|
|
47
68
|
const [focused, setFocused] = useState(false);
|
|
48
69
|
const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
|
|
49
70
|
const [secureTextInput, setSecureTextInput] = useState(secureTextEntry);
|
|
50
|
-
const inputRef =
|
|
71
|
+
const inputRef = useRef<TextInput | null>(null);
|
|
51
72
|
|
|
52
73
|
const onClearText = () => {
|
|
53
74
|
inputRef?.current?.clear();
|
|
@@ -69,7 +90,20 @@ const Input = forwardRef(
|
|
|
69
90
|
onBlur?.(e);
|
|
70
91
|
};
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
useImperativeHandle(ref, () => {
|
|
94
|
+
return {
|
|
95
|
+
clear: onClearText,
|
|
96
|
+
focus: () => inputRef.current?.focus(),
|
|
97
|
+
blur: () => inputRef.current?.blur(),
|
|
98
|
+
setText: (text: string) => _onChangeText(text),
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Render trailing icon or text
|
|
104
|
+
* @param color
|
|
105
|
+
*/
|
|
106
|
+
const renderTrailing = (color?: string) => {
|
|
73
107
|
if (loading) {
|
|
74
108
|
return <Loader type={'spinner'} color={color} style={styles.icon} />;
|
|
75
109
|
}
|
|
@@ -88,24 +122,46 @@ const Input = forwardRef(
|
|
|
88
122
|
</TouchableOpacity>
|
|
89
123
|
);
|
|
90
124
|
}
|
|
91
|
-
if (icon) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
125
|
+
if (icon || trailing) {
|
|
126
|
+
const renderIconTouchable = (icon: ReactNode) => {
|
|
127
|
+
return (
|
|
128
|
+
<TouchableOpacity
|
|
129
|
+
onPress={onPressTrailing ?? onPressIcon}
|
|
130
|
+
style={styles.icon}>
|
|
131
|
+
{icon}
|
|
132
|
+
</TouchableOpacity>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
const trailingValue = icon || trailing;
|
|
136
|
+
if (trailingValue?.includes('_') || trailingValue?.includes('http')) {
|
|
137
|
+
return renderIconTouchable(
|
|
138
|
+
<Icon
|
|
139
|
+
color={color}
|
|
140
|
+
source={(icon || trailing) as string}
|
|
141
|
+
size={24}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return renderIconTouchable(
|
|
146
|
+
<Text
|
|
147
|
+
typography="action_xs_bold"
|
|
148
|
+
color={color ?? theme.colors.primary}
|
|
149
|
+
numberOfLines={1}>
|
|
150
|
+
{trailingValue!.substring(0, 15)}
|
|
151
|
+
</Text>
|
|
99
152
|
);
|
|
100
153
|
}
|
|
101
154
|
};
|
|
102
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Render input view
|
|
158
|
+
*/
|
|
103
159
|
const renderInputView = () => {
|
|
104
160
|
const disabledColor = theme.colors.text.disable;
|
|
105
161
|
const secure = secureTextInput && secureTextEntry;
|
|
106
162
|
let textColor = theme.colors.text.default;
|
|
107
163
|
let placeholderColor = theme.colors.text.hint;
|
|
108
|
-
let iconTintColor = iconColor;
|
|
164
|
+
let iconTintColor = trailingColor ?? iconColor;
|
|
109
165
|
|
|
110
166
|
if (disabled) {
|
|
111
167
|
textColor = disabledColor;
|
|
@@ -113,6 +169,13 @@ const Input = forwardRef(
|
|
|
113
169
|
iconTintColor = disabledColor;
|
|
114
170
|
}
|
|
115
171
|
|
|
172
|
+
if (secureTextEntry) {
|
|
173
|
+
keyboardType = Platform.select({
|
|
174
|
+
ios: 'ascii-capable',
|
|
175
|
+
android: 'visible-password',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
116
179
|
return (
|
|
117
180
|
<View
|
|
118
181
|
style={[
|
|
@@ -127,6 +190,7 @@ const Input = forwardRef(
|
|
|
127
190
|
disabled={disabled}
|
|
128
191
|
required={required}
|
|
129
192
|
floatingIcon={floatingIcon}
|
|
193
|
+
onPress={onPressFloatingIcon}
|
|
130
194
|
/>
|
|
131
195
|
<View style={styles.inputView}>
|
|
132
196
|
{!!leadingIcon && (
|
|
@@ -140,7 +204,8 @@ const Input = forwardRef(
|
|
|
140
204
|
)}
|
|
141
205
|
<TextInput
|
|
142
206
|
{...props}
|
|
143
|
-
|
|
207
|
+
accessibilityLabel={accessibilityLabel}
|
|
208
|
+
editable={editable && !disabled}
|
|
144
209
|
secureTextEntry={secure}
|
|
145
210
|
textAlignVertical="center"
|
|
146
211
|
ref={inputRef}
|
|
@@ -160,6 +225,7 @@ const Input = forwardRef(
|
|
|
160
225
|
placeholder={placeholder}
|
|
161
226
|
selectionColor={theme.colors.primary}
|
|
162
227
|
placeholderTextColor={placeholderColor}
|
|
228
|
+
keyboardType={keyboardType}
|
|
163
229
|
/>
|
|
164
230
|
</View>
|
|
165
231
|
<View style={styles.iconView}>
|
|
@@ -174,19 +240,43 @@ const Input = forwardRef(
|
|
|
174
240
|
/>
|
|
175
241
|
</TouchableOpacity>
|
|
176
242
|
)}
|
|
177
|
-
{
|
|
243
|
+
{renderTrailing(iconTintColor)}
|
|
178
244
|
</View>
|
|
179
245
|
</View>
|
|
180
246
|
);
|
|
181
247
|
};
|
|
182
248
|
|
|
249
|
+
let inputState = 'active';
|
|
250
|
+
if (value && value?.length > 0) {
|
|
251
|
+
inputState = 'filled';
|
|
252
|
+
}
|
|
253
|
+
if (errorMessage && errorMessage?.length > 0) {
|
|
254
|
+
inputState = 'error';
|
|
255
|
+
}
|
|
256
|
+
if (disabled) {
|
|
257
|
+
inputState = 'disabled';
|
|
258
|
+
}
|
|
259
|
+
|
|
183
260
|
return (
|
|
184
|
-
<
|
|
185
|
-
{
|
|
186
|
-
|
|
187
|
-
|
|
261
|
+
<ComponentContext.Provider
|
|
262
|
+
value={{
|
|
263
|
+
componentName: 'Input',
|
|
264
|
+
params,
|
|
265
|
+
componentLabel: floatingValue,
|
|
266
|
+
state: inputState,
|
|
267
|
+
componentId: accessibilityLabel,
|
|
268
|
+
}}>
|
|
269
|
+
<View style={[style, styles.wrapper]}>
|
|
270
|
+
{renderInputView()}
|
|
271
|
+
<ErrorView
|
|
272
|
+
errorMessage={errorMessage}
|
|
273
|
+
errorSpacing={errorSpacing}
|
|
274
|
+
hintText={hintText}
|
|
275
|
+
/>
|
|
276
|
+
</View>
|
|
277
|
+
</ComponentContext.Provider>
|
|
188
278
|
);
|
|
189
|
-
}
|
|
279
|
+
}
|
|
190
280
|
);
|
|
191
281
|
|
|
192
282
|
export default Input;
|
package/Input/InputDropDown.tsx
CHANGED
|
@@ -1,63 +1,55 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {ApplicationContext} from '../Application';
|
|
4
|
-
import
|
|
2
|
+
import {TouchableOpacity, View} from 'react-native';
|
|
3
|
+
import {ApplicationContext, ComponentContext} from '../Application';
|
|
4
|
+
import {Icon} from '../Icon';
|
|
5
5
|
import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
|
|
6
6
|
import {InputDropDownProps} from './index';
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
7
|
+
import {Text} from '../Text';
|
|
8
|
+
import styles from './styles';
|
|
9
|
+
import {Spacing} from '../Consts';
|
|
10
10
|
|
|
11
11
|
const InputDropDown = ({
|
|
12
12
|
value,
|
|
13
13
|
floatingValue,
|
|
14
14
|
floatingIcon,
|
|
15
|
+
onPressFloatingIcon,
|
|
15
16
|
size = 'small',
|
|
16
17
|
onPress,
|
|
17
18
|
placeholder,
|
|
18
19
|
errorMessage,
|
|
19
|
-
icon = 'arrow_chevron_down_small',
|
|
20
20
|
disabled = false,
|
|
21
21
|
floatingIconColor,
|
|
22
|
-
iconColor,
|
|
23
22
|
required = false,
|
|
24
23
|
errorSpacing,
|
|
25
|
-
loading = false,
|
|
26
24
|
leadingIcon,
|
|
27
25
|
leadingIconColor,
|
|
28
26
|
style,
|
|
29
|
-
|
|
27
|
+
params,
|
|
28
|
+
accessibilityLabel,
|
|
29
|
+
hintText,
|
|
30
|
+
multiline,
|
|
30
31
|
}: InputDropDownProps) => {
|
|
31
32
|
const {theme} = useContext(ApplicationContext);
|
|
32
|
-
const full = !!value || !!placeholder;
|
|
33
|
-
|
|
34
|
-
const renderIcon = (color: string | undefined) => {
|
|
35
|
-
if (loading) {
|
|
36
|
-
return <Loader type={'spinner'} color={color} />;
|
|
37
|
-
}
|
|
38
|
-
if (icon) {
|
|
39
|
-
return <Icon color={color} source={icon} size={24} />;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Render the input view
|
|
36
|
+
*/
|
|
43
37
|
const renderInputView = () => {
|
|
44
38
|
const disabledColor = theme.colors.text.disable;
|
|
45
39
|
let textColor = theme.colors.text.default;
|
|
46
40
|
let placeholderColor = theme.colors.text.hint;
|
|
47
|
-
let iconTintColor = iconColor;
|
|
48
41
|
|
|
49
42
|
if (disabled) {
|
|
50
43
|
textColor = disabledColor;
|
|
51
44
|
placeholderColor = disabledColor;
|
|
52
|
-
iconTintColor = disabledColor;
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
return (
|
|
56
48
|
<View
|
|
57
49
|
style={[
|
|
58
|
-
styles.
|
|
50
|
+
styles.inputDropDownWrapper,
|
|
59
51
|
{backgroundColor: theme.colors.background.surface},
|
|
60
|
-
getSizeStyle(size),
|
|
52
|
+
getSizeStyle(size, multiline),
|
|
61
53
|
getBorderColor(theme, false, errorMessage, disabled),
|
|
62
54
|
]}>
|
|
63
55
|
<FloatingView
|
|
@@ -66,10 +58,18 @@ const InputDropDown = ({
|
|
|
66
58
|
disabled={disabled}
|
|
67
59
|
required={required}
|
|
68
60
|
floatingIcon={floatingIcon}
|
|
61
|
+
onPress={onPressFloatingIcon}
|
|
69
62
|
/>
|
|
70
|
-
<View style={
|
|
63
|
+
<View style={styles.inputDropDownView}>
|
|
71
64
|
{!!leadingIcon && (
|
|
72
|
-
<View
|
|
65
|
+
<View
|
|
66
|
+
style={[
|
|
67
|
+
styles.leadingIconContainerDropDown,
|
|
68
|
+
{
|
|
69
|
+
marginTop: Spacing.M,
|
|
70
|
+
marginRight: Spacing.S,
|
|
71
|
+
},
|
|
72
|
+
]}>
|
|
73
73
|
<Icon
|
|
74
74
|
color={leadingIconColor}
|
|
75
75
|
source={leadingIcon}
|
|
@@ -77,37 +77,52 @@ const InputDropDown = ({
|
|
|
77
77
|
/>
|
|
78
78
|
</View>
|
|
79
79
|
)}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
80
|
+
<View
|
|
81
|
+
accessibilityLabel={accessibilityLabel}
|
|
82
|
+
style={styles.textViewDropDown}>
|
|
83
|
+
<Text
|
|
84
|
+
numberOfLines={multiline ? undefined : 1}
|
|
85
|
+
typography={'body_default_regular'}
|
|
86
|
+
color={value ? textColor : placeholderColor}>
|
|
87
|
+
{value || placeholder}
|
|
88
|
+
</Text>
|
|
89
|
+
</View>
|
|
90
|
+
</View>
|
|
91
|
+
<View
|
|
92
|
+
style={[
|
|
93
|
+
styles.iconViewDropDown,
|
|
94
|
+
{
|
|
95
|
+
alignItems: multiline ? 'flex-start' : 'center',
|
|
96
|
+
paddingTop: multiline ? Spacing.M : 0,
|
|
97
|
+
},
|
|
98
|
+
]}>
|
|
99
|
+
<Icon source={'arrow_chevron_down_small'} />
|
|
100
100
|
</View>
|
|
101
|
-
<View style={styles.iconView}>{renderIcon(iconTintColor)}</View>
|
|
102
101
|
</View>
|
|
103
102
|
);
|
|
104
103
|
};
|
|
105
104
|
|
|
106
105
|
return (
|
|
107
|
-
<
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
<ComponentContext.Provider
|
|
107
|
+
value={{
|
|
108
|
+
componentName: 'InputDropDown',
|
|
109
|
+
params,
|
|
110
|
+
state: 'enabled',
|
|
111
|
+
componentLabel: floatingValue,
|
|
112
|
+
componentId: accessibilityLabel,
|
|
113
|
+
}}>
|
|
114
|
+
<TouchableOpacity
|
|
115
|
+
activeOpacity={0.6}
|
|
116
|
+
onPress={onPress}
|
|
117
|
+
style={[style, styles.wrapper]}>
|
|
118
|
+
{renderInputView()}
|
|
119
|
+
<ErrorView
|
|
120
|
+
errorMessage={errorMessage}
|
|
121
|
+
errorSpacing={errorSpacing}
|
|
122
|
+
hintText={hintText}
|
|
123
|
+
/>
|
|
124
|
+
</TouchableOpacity>
|
|
125
|
+
</ComponentContext.Provider>
|
|
111
126
|
);
|
|
112
127
|
};
|
|
113
128
|
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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
|
-
{
|
|
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
|
-
<
|
|
156
|
-
{
|
|
157
|
-
|
|
158
|
-
|
|
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;
|