@momo-kits/foundation 0.169.10-beta.1 → 0.169.10
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.hooks.ts +27 -17
- package/Application/BottomSheet.tsx +35 -27
- package/Application/BottomTab/BottomTabBar.tsx +6 -6
- package/Application/BottomTab/DuoRailTabBar.tsx +5 -5
- package/Application/BottomTab/TabScreen.tsx +11 -10
- package/Application/BottomTab/index.tsx +5 -5
- package/Application/BottomTab/usePressLift.ts +3 -3
- package/Application/Components/HeaderToolkitAction.tsx +16 -13
- package/Application/Components/useToolkitActions.tsx +22 -21
- package/Application/ModalScreen.tsx +19 -15
- package/Application/StackScreen.tsx +13 -9
- package/Application/modalLayout.ts +1 -0
- package/Context/index.ts +3 -1
- package/Image/index.tsx +6 -6
- package/Input/ErrorView.tsx +59 -0
- package/Input/FloatingView.tsx +101 -0
- package/Input/Input.tsx +40 -37
- package/Input/InputDropDown.tsx +13 -10
- package/Input/InputMoney.tsx +17 -17
- package/Input/InputMoneyView.tsx +12 -12
- package/Input/InputOTP.tsx +46 -34
- package/Input/InputPhoneNumber.tsx +48 -43
- package/Input/InputSearch.tsx +24 -23
- package/Input/InputTextArea.tsx +29 -23
- package/Input/RenderTrailing.tsx +79 -0
- package/Input/constants.ts +8 -0
- package/Input/utils.ts +126 -7
- package/Layout/FloatingButton.tsx +38 -24
- package/Layout/layoutMetrics.ts +43 -34
- package/Layout/screenTypes.ts +2 -3
- package/Pagination/PaginationScroll.tsx +5 -3
- package/Pagination/types.ts +3 -5
- package/Popup/PopupNotify.tsx +17 -14
- package/Popup/PopupPromotion.tsx +5 -4
- package/Popup/types.ts +2 -4
- package/Popup/utils.ts +7 -4
- package/Skeleton/index.tsx +15 -12
- package/package.json +1 -1
- package/Input/common.tsx +0 -257
- package/Input/moneyUtils.ts +0 -23
package/Input/InputMoney.tsx
CHANGED
|
@@ -10,11 +10,11 @@ import React, {
|
|
|
10
10
|
import { Platform, TextInput, TextInputFocusEvent, View } from 'react-native';
|
|
11
11
|
import { useComponentId } from '../Application';
|
|
12
12
|
import { ComponentContext, MiniAppContext } from '../Context';
|
|
13
|
-
import { ErrorView } from './
|
|
13
|
+
import { ErrorView } from './ErrorView';
|
|
14
14
|
import { InputMoneyProps } from './index';
|
|
15
15
|
import { InputMoneyView } from './InputMoneyView';
|
|
16
|
-
import { findEdit, moneyFormatter } from './moneyUtils';
|
|
17
16
|
import styles from './styles';
|
|
17
|
+
import { findEdit, moneyFormatter } from './utils';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Money input: keeps digits only, shows them grouped with a currency suffix and
|
|
@@ -52,7 +52,7 @@ const InputMoney = forwardRef(
|
|
|
52
52
|
ref,
|
|
53
53
|
) => {
|
|
54
54
|
const context = useContext<any>(MiniAppContext);
|
|
55
|
-
const [
|
|
55
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
56
56
|
const [displayValue, setDisplayValue] = useState('');
|
|
57
57
|
const [numericValue, setNumericValue] = useState('');
|
|
58
58
|
const [lastDisplayValue, setLastDisplayValue] = useState('');
|
|
@@ -126,7 +126,7 @@ const InputMoney = forwardRef(
|
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
-
const
|
|
129
|
+
const handleClearText = () => {
|
|
130
130
|
inputRef?.current?.clear();
|
|
131
131
|
inputRef.current?.setNativeProps({ text: '' });
|
|
132
132
|
setDisplayValue('');
|
|
@@ -134,7 +134,7 @@ const InputMoney = forwardRef(
|
|
|
134
134
|
onChangeText?.('');
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
const
|
|
137
|
+
const handleChangeText = (text: string) => {
|
|
138
138
|
if (!text) {
|
|
139
139
|
lastRawText.current = '';
|
|
140
140
|
setDisplayValue('');
|
|
@@ -166,17 +166,17 @@ const InputMoney = forwardRef(
|
|
|
166
166
|
inputRef.current?.setSelection(displayValue.length, displayValue.length);
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
-
const
|
|
170
|
-
|
|
169
|
+
const handleFocus = (e: TextInputFocusEvent) => {
|
|
170
|
+
setIsFocused(true);
|
|
171
171
|
onFocus?.(e);
|
|
172
172
|
};
|
|
173
173
|
|
|
174
|
-
const
|
|
175
|
-
|
|
174
|
+
const handleBlur = (e: TextInputFocusEvent) => {
|
|
175
|
+
setIsFocused(false);
|
|
176
176
|
onBlur?.(e);
|
|
177
177
|
};
|
|
178
178
|
|
|
179
|
-
const
|
|
179
|
+
const handleSetText = (text: string) => {
|
|
180
180
|
caretDigitsAfter.current = undefined;
|
|
181
181
|
if (!text) {
|
|
182
182
|
setDisplayValue('');
|
|
@@ -190,10 +190,10 @@ const InputMoney = forwardRef(
|
|
|
190
190
|
|
|
191
191
|
useImperativeHandle(ref, () => {
|
|
192
192
|
return {
|
|
193
|
-
clear:
|
|
193
|
+
clear: handleClearText,
|
|
194
194
|
focus: () => inputRef.current?.focus(),
|
|
195
195
|
blur: () => inputRef.current?.blur(),
|
|
196
|
-
setText:
|
|
196
|
+
setText: handleSetText,
|
|
197
197
|
};
|
|
198
198
|
});
|
|
199
199
|
|
|
@@ -240,16 +240,16 @@ const InputMoney = forwardRef(
|
|
|
240
240
|
showClearIcon={showClearIcon}
|
|
241
241
|
placeholder={placeholder}
|
|
242
242
|
currency={currency}
|
|
243
|
-
focused={
|
|
243
|
+
focused={isFocused}
|
|
244
244
|
componentId={componentId}
|
|
245
245
|
displayValue={displayValue}
|
|
246
246
|
caretSelection={caretSelection}
|
|
247
247
|
inputRef={inputRef}
|
|
248
248
|
focusAtEnd={focusAtEnd}
|
|
249
|
-
onClearText={
|
|
250
|
-
onChangeText={
|
|
251
|
-
onFocus={
|
|
252
|
-
onBlur={
|
|
249
|
+
onClearText={handleClearText}
|
|
250
|
+
onChangeText={handleChangeText}
|
|
251
|
+
onFocus={handleFocus}
|
|
252
|
+
onBlur={handleBlur}
|
|
253
253
|
inputProps={props}
|
|
254
254
|
/>
|
|
255
255
|
<ErrorView
|
package/Input/InputMoneyView.tsx
CHANGED
|
@@ -11,15 +11,15 @@ import {
|
|
|
11
11
|
import { ApplicationContext } from '../Context';
|
|
12
12
|
import { Icon } from '../Icon';
|
|
13
13
|
import { useScaleSize, exportFontFamily } from '../Text';
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
getBorderColor,
|
|
17
|
-
getSizeStyle,
|
|
18
|
-
RenderTrailing,
|
|
19
|
-
} from './common';
|
|
14
|
+
import { CLEAR_ICON_SIZE } from './constants';
|
|
15
|
+
import { FloatingView } from './FloatingView';
|
|
20
16
|
import { InputMoneyProps } from './index';
|
|
17
|
+
import { RenderTrailing } from './RenderTrailing';
|
|
21
18
|
import styles from './styles';
|
|
22
19
|
import SystemTextInput from './SystemTextInput';
|
|
20
|
+
import { getBorderColor, getInputHeight, getSizeStyle } from './utils';
|
|
21
|
+
|
|
22
|
+
const MONEY_FONT_SIZE = 20;
|
|
23
23
|
|
|
24
24
|
type InputMoneyViewProps = Pick<
|
|
25
25
|
InputMoneyProps,
|
|
@@ -85,8 +85,8 @@ export const InputMoneyView = ({
|
|
|
85
85
|
inputProps: props,
|
|
86
86
|
}: InputMoneyViewProps) => {
|
|
87
87
|
const { theme } = useContext(ApplicationContext);
|
|
88
|
-
const scaleHeight = useScaleSize(size
|
|
89
|
-
const scaledFontSize = useScaleSize(
|
|
88
|
+
const scaleHeight = useScaleSize(getInputHeight(size));
|
|
89
|
+
const scaledFontSize = useScaleSize(MONEY_FONT_SIZE);
|
|
90
90
|
const inputFontFamily = exportFontFamily('bold');
|
|
91
91
|
const disabledColor = theme.colors.text.disable;
|
|
92
92
|
let textColor = theme.colors.text.default;
|
|
@@ -101,11 +101,11 @@ export const InputMoneyView = ({
|
|
|
101
101
|
fontSize: scaledFontSize,
|
|
102
102
|
fontFamily: inputFontFamily,
|
|
103
103
|
};
|
|
104
|
-
const
|
|
105
|
-
const shouldShowCurrency = !!displayValue ||
|
|
104
|
+
const hasCurrencyInPlaceholder = placeholder.endsWith(currency);
|
|
105
|
+
const shouldShowCurrency = !!displayValue || hasCurrencyInPlaceholder;
|
|
106
106
|
const shouldShowClearIcon = !!(showClearIcon && focused && displayValue);
|
|
107
107
|
let inputPlaceholder = placeholder;
|
|
108
|
-
if (
|
|
108
|
+
if (hasCurrencyInPlaceholder) {
|
|
109
109
|
inputPlaceholder = placeholder.slice(0, -currency.length);
|
|
110
110
|
}
|
|
111
111
|
return (
|
|
@@ -175,7 +175,7 @@ export const InputMoneyView = ({
|
|
|
175
175
|
>
|
|
176
176
|
<Icon
|
|
177
177
|
source="24_navigation_close_circle_full"
|
|
178
|
-
size={
|
|
178
|
+
size={CLEAR_ICON_SIZE}
|
|
179
179
|
color={theme.colors.text.hint}
|
|
180
180
|
accessibilityLabel={`${componentId}|clear-icon`}
|
|
181
181
|
/>
|
package/Input/InputOTP.tsx
CHANGED
|
@@ -26,31 +26,37 @@ import Animated, {
|
|
|
26
26
|
} from 'react-native-reanimated';
|
|
27
27
|
import { useComponentId } from '../Application';
|
|
28
28
|
import { Spacing, Styles } from '../Consts';
|
|
29
|
-
import { useScaleSize, Text } from '../Text';
|
|
30
|
-
import { ErrorView, getBorderColor } from './common';
|
|
31
|
-
import { CaretProps, InputOTPProps } from './index';
|
|
32
|
-
import styles from './styles';
|
|
33
|
-
import { Icon } from '../Icon';
|
|
34
|
-
import SystemTextInput from './SystemTextInput';
|
|
35
29
|
import {
|
|
36
30
|
ApplicationContext,
|
|
37
31
|
ComponentContext,
|
|
38
32
|
MiniAppContext,
|
|
39
33
|
} from '../Context';
|
|
34
|
+
import { Icon } from '../Icon';
|
|
35
|
+
import { useScaleSize, Text } from '../Text';
|
|
36
|
+
import { ErrorView } from './ErrorView';
|
|
37
|
+
import { CaretProps, InputOTPProps } from './index';
|
|
38
|
+
import styles from './styles';
|
|
39
|
+
import SystemTextInput from './SystemTextInput';
|
|
40
|
+
import { getBorderColor } from './utils';
|
|
41
|
+
|
|
42
|
+
const BLINK_DURATION = 300;
|
|
43
|
+
const CARET_HEIGHT = 12;
|
|
44
|
+
const OTP_CLEAR_ICON_SIZE = 12;
|
|
45
|
+
const MAX_LENGTH = 10;
|
|
46
|
+
const COMPACT_LENGTH_THRESHOLD = 6;
|
|
40
47
|
|
|
41
48
|
/** Blinking caret shown in the OTP slot being typed. */
|
|
42
49
|
const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
43
|
-
const DURATION = 300;
|
|
44
50
|
const { theme } = useContext(ApplicationContext);
|
|
45
51
|
const opacity = useSharedValue(0);
|
|
46
52
|
|
|
47
53
|
useEffect(() => {
|
|
48
54
|
opacity.value = withRepeat(
|
|
49
55
|
withSequence(
|
|
50
|
-
withTiming(1, { duration:
|
|
56
|
+
withTiming(1, { duration: BLINK_DURATION, easing: Easing.linear }),
|
|
51
57
|
withDelay(
|
|
52
|
-
|
|
53
|
-
withTiming(0, { duration:
|
|
58
|
+
BLINK_DURATION * 2,
|
|
59
|
+
withTiming(0, { duration: BLINK_DURATION, easing: Easing.linear }),
|
|
54
60
|
),
|
|
55
61
|
),
|
|
56
62
|
-1,
|
|
@@ -72,7 +78,7 @@ const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
|
72
78
|
style={[
|
|
73
79
|
styles.otpCursor,
|
|
74
80
|
{
|
|
75
|
-
height: useScaleSize(
|
|
81
|
+
height: useScaleSize(CARET_HEIGHT),
|
|
76
82
|
backgroundColor: theme.colors.primary,
|
|
77
83
|
},
|
|
78
84
|
animatedStyle,
|
|
@@ -108,9 +114,8 @@ const InputOTP = forwardRef(
|
|
|
108
114
|
}: InputOTPProps,
|
|
109
115
|
ref,
|
|
110
116
|
) => {
|
|
111
|
-
const MAX_LENGTH = 10;
|
|
112
117
|
const [value, setValue] = useState('');
|
|
113
|
-
const [
|
|
118
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
114
119
|
const inputRef = useRef<TextInput | null>(null);
|
|
115
120
|
const { theme } = useContext(ApplicationContext);
|
|
116
121
|
const context = useContext<any>(MiniAppContext);
|
|
@@ -127,25 +132,25 @@ const InputOTP = forwardRef(
|
|
|
127
132
|
useImperativeHandle(ref, () => {
|
|
128
133
|
return {
|
|
129
134
|
onChangeText: (text: string) => {
|
|
130
|
-
|
|
135
|
+
handleChangeText(text);
|
|
131
136
|
},
|
|
132
137
|
focus: () => inputRef.current?.focus(),
|
|
133
138
|
blur: () => inputRef.current?.blur(),
|
|
134
|
-
setText: (text: string) =>
|
|
139
|
+
setText: (text: string) => handleChangeText(text),
|
|
135
140
|
};
|
|
136
141
|
});
|
|
137
142
|
|
|
138
|
-
const
|
|
139
|
-
|
|
143
|
+
const handleFocusInput = (e: TextInputFocusEvent) => {
|
|
144
|
+
setIsFocused(true);
|
|
140
145
|
onFocus?.(e);
|
|
141
146
|
};
|
|
142
147
|
|
|
143
|
-
const
|
|
144
|
-
|
|
148
|
+
const handleBlurInput = (e: TextInputFocusEvent) => {
|
|
149
|
+
setIsFocused(false);
|
|
145
150
|
onBlur?.(e);
|
|
146
151
|
};
|
|
147
152
|
|
|
148
|
-
const
|
|
153
|
+
const handleChangeText = (text: string) => {
|
|
149
154
|
if (text.length > MAX_LENGTH) return;
|
|
150
155
|
const isNumeric = !isNaN(Number(text));
|
|
151
156
|
if (dataType === 'number' && !isNumeric) return;
|
|
@@ -156,8 +161,8 @@ const InputOTP = forwardRef(
|
|
|
156
161
|
onChangeText?.(text);
|
|
157
162
|
};
|
|
158
163
|
|
|
159
|
-
const
|
|
160
|
-
|
|
164
|
+
const handleClearText = () => {
|
|
165
|
+
handleChangeText('');
|
|
161
166
|
};
|
|
162
167
|
|
|
163
168
|
const fontScale = PixelRatio.getFontScale();
|
|
@@ -167,7 +172,7 @@ const InputOTP = forwardRef(
|
|
|
167
172
|
const textColors = theme.colors.text;
|
|
168
173
|
for (let i = 0; i < inputLength; i++) {
|
|
169
174
|
let slot: React.ReactNode;
|
|
170
|
-
if (
|
|
175
|
+
if (isFocused && value.length === i) {
|
|
171
176
|
slot = <OTPCaret index={i} length={inputLength} />;
|
|
172
177
|
} else {
|
|
173
178
|
slot = (
|
|
@@ -188,7 +193,7 @@ const InputOTP = forwardRef(
|
|
|
188
193
|
const renderUnidentifiedInputs = () => {
|
|
189
194
|
const splitValue = value.split('');
|
|
190
195
|
|
|
191
|
-
if (!
|
|
196
|
+
if (!isFocused && value.length === 0 && !!placeholder) {
|
|
192
197
|
return (
|
|
193
198
|
<Text
|
|
194
199
|
color={theme.colors.text.hint}
|
|
@@ -203,8 +208,9 @@ const InputOTP = forwardRef(
|
|
|
203
208
|
<View style={Styles.row}>
|
|
204
209
|
{splitValue.map((letter, index) => {
|
|
205
210
|
const isLast = index === value.length - 1;
|
|
206
|
-
const isTyping =
|
|
207
|
-
const
|
|
211
|
+
const isTyping = isFocused && value.length !== MAX_LENGTH;
|
|
212
|
+
const isLongCode = value.length > COMPACT_LENGTH_THRESHOLD;
|
|
213
|
+
const isCompact = fontScale > 1 && isLongCode;
|
|
208
214
|
const marginRight = isCompact ? Spacing.M : Spacing.L;
|
|
209
215
|
return (
|
|
210
216
|
<Text
|
|
@@ -216,7 +222,7 @@ const InputOTP = forwardRef(
|
|
|
216
222
|
</Text>
|
|
217
223
|
);
|
|
218
224
|
})}
|
|
219
|
-
{
|
|
225
|
+
{isFocused && value.length !== MAX_LENGTH && <OTPCaret />}
|
|
220
226
|
</View>
|
|
221
227
|
);
|
|
222
228
|
};
|
|
@@ -229,7 +235,7 @@ const InputOTP = forwardRef(
|
|
|
229
235
|
style={[
|
|
230
236
|
styles.otpInput,
|
|
231
237
|
{ backgroundColor: theme.colors.background.surface },
|
|
232
|
-
getBorderColor(theme,
|
|
238
|
+
getBorderColor(theme, isFocused, errorMessage),
|
|
233
239
|
]}
|
|
234
240
|
>
|
|
235
241
|
{!!floatingValue && (
|
|
@@ -248,9 +254,15 @@ const InputOTP = forwardRef(
|
|
|
248
254
|
</Text>
|
|
249
255
|
</View>
|
|
250
256
|
)}
|
|
251
|
-
{value.length > 0 &&
|
|
252
|
-
<TouchableOpacity
|
|
253
|
-
|
|
257
|
+
{value.length > 0 && isFocused && (
|
|
258
|
+
<TouchableOpacity
|
|
259
|
+
onPress={handleClearText}
|
|
260
|
+
style={styles.clearIcon}
|
|
261
|
+
>
|
|
262
|
+
<Icon
|
|
263
|
+
source={'24_navigation_close_circle_full'}
|
|
264
|
+
size={OTP_CLEAR_ICON_SIZE}
|
|
265
|
+
/>
|
|
254
266
|
</TouchableOpacity>
|
|
255
267
|
)}
|
|
256
268
|
<View style={styles.otpInputsView}>
|
|
@@ -262,11 +274,11 @@ const InputOTP = forwardRef(
|
|
|
262
274
|
ref={inputRef}
|
|
263
275
|
value={value}
|
|
264
276
|
textAlign={'center'}
|
|
265
|
-
onChangeText={
|
|
277
|
+
onChangeText={handleChangeText}
|
|
266
278
|
keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
|
|
267
279
|
allowFontScaling={false}
|
|
268
|
-
onFocus={
|
|
269
|
-
onBlur={
|
|
280
|
+
onFocus={handleFocusInput}
|
|
281
|
+
onBlur={handleBlurInput}
|
|
270
282
|
style={styles.otpRealInput}
|
|
271
283
|
selectionColor={theme.colors.primary}
|
|
272
284
|
placeholderTextColor={theme.colors.text.hint}
|
|
@@ -20,18 +20,23 @@ import {
|
|
|
20
20
|
} from '../Context';
|
|
21
21
|
import { Colors, Spacing, Styles } from '../Consts';
|
|
22
22
|
import { Icon } from '../Icon';
|
|
23
|
+
import { Image } from '../Image';
|
|
23
24
|
import { useScaleSize, Text, exportFontFamily } from '../Text';
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
getSizeStyle,
|
|
28
|
-
RenderTrailing,
|
|
29
|
-
} from './common';
|
|
25
|
+
import { Typography } from '../Text/types';
|
|
26
|
+
import { CLEAR_ICON_SIZE } from './constants';
|
|
27
|
+
import { ErrorView } from './ErrorView';
|
|
30
28
|
import { InputPhoneNumberProps } from './index';
|
|
29
|
+
import { RenderTrailing } from './RenderTrailing';
|
|
31
30
|
import styles from './styles';
|
|
32
31
|
import SystemTextInput from './SystemTextInput';
|
|
33
|
-
import {
|
|
34
|
-
|
|
32
|
+
import { getBorderColor, getInputHeight, getSizeStyle } from './utils';
|
|
33
|
+
|
|
34
|
+
const SMALL_FONT_SIZE = 14;
|
|
35
|
+
const LARGE_FONT_SIZE = 18;
|
|
36
|
+
const SMALL_DIVIDER_HEIGHT = 24;
|
|
37
|
+
const LARGE_DIVIDER_HEIGHT = 32;
|
|
38
|
+
const FOCUSED_BORDER_WIDTH = 1.5;
|
|
39
|
+
const FLAG_SIZE = 24;
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Vietnamese phone number input with a fixed flag and `+84` prefix, number pad
|
|
@@ -67,10 +72,10 @@ const InputPhoneNumber = forwardRef(
|
|
|
67
72
|
) => {
|
|
68
73
|
const { theme } = useContext(ApplicationContext);
|
|
69
74
|
const context = useContext<any>(MiniAppContext);
|
|
70
|
-
const scaleHeight = useScaleSize(size
|
|
71
|
-
const [
|
|
75
|
+
const scaleHeight = useScaleSize(getInputHeight(size));
|
|
76
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
72
77
|
const [internalText, setInternalText] = useState(defaultValue || '');
|
|
73
|
-
const
|
|
78
|
+
const hasValue = value !== undefined ? !!value : !!internalText;
|
|
74
79
|
const inputRef = useRef<TextInput | null>(null);
|
|
75
80
|
const componentName = 'InputPhoneNumber';
|
|
76
81
|
|
|
@@ -81,29 +86,29 @@ const InputPhoneNumber = forwardRef(
|
|
|
81
86
|
props.accessibilityLabel,
|
|
82
87
|
);
|
|
83
88
|
|
|
84
|
-
const
|
|
89
|
+
const handleClearText = () => {
|
|
85
90
|
inputRef?.current?.clear();
|
|
86
|
-
|
|
91
|
+
handleChangeText('');
|
|
87
92
|
};
|
|
88
93
|
|
|
89
|
-
const
|
|
94
|
+
const handleChangeText = (text: string) => {
|
|
90
95
|
if (value === undefined) {
|
|
91
96
|
setInternalText(text);
|
|
92
97
|
}
|
|
93
98
|
onChangeText?.(text);
|
|
94
99
|
};
|
|
95
100
|
|
|
96
|
-
const
|
|
97
|
-
|
|
101
|
+
const handleFocus = (e: TextInputFocusEvent) => {
|
|
102
|
+
setIsFocused(true);
|
|
98
103
|
onFocus?.(e);
|
|
99
104
|
};
|
|
100
105
|
|
|
101
|
-
const
|
|
102
|
-
|
|
106
|
+
const handleBlur = (e: TextInputFocusEvent) => {
|
|
107
|
+
setIsFocused(false);
|
|
103
108
|
onBlur?.(e);
|
|
104
109
|
};
|
|
105
110
|
|
|
106
|
-
const
|
|
111
|
+
const handleSetText = (text: string) => {
|
|
107
112
|
if (__DEV__ && value !== undefined) {
|
|
108
113
|
console.error(
|
|
109
114
|
`${componentName}: calling ref.setText() on a controlled input (\`value\` is provided) is an anti-pattern. ` +
|
|
@@ -112,48 +117,48 @@ const InputPhoneNumber = forwardRef(
|
|
|
112
117
|
);
|
|
113
118
|
}
|
|
114
119
|
inputRef?.current?.setNativeProps({ text });
|
|
115
|
-
|
|
120
|
+
handleChangeText(text);
|
|
116
121
|
};
|
|
117
122
|
|
|
118
123
|
useImperativeHandle(ref, () => {
|
|
119
124
|
return {
|
|
120
|
-
clear:
|
|
125
|
+
clear: handleClearText,
|
|
121
126
|
focus: () => inputRef.current?.focus(),
|
|
122
127
|
blur: () => inputRef.current?.blur(),
|
|
123
|
-
setText:
|
|
128
|
+
setText: handleSetText,
|
|
124
129
|
};
|
|
125
130
|
});
|
|
126
131
|
|
|
127
132
|
let inputTextStyles = {};
|
|
128
|
-
let dividerHeight =
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
let dividerHeight = SMALL_DIVIDER_HEIGHT;
|
|
134
|
+
const smallFontSize = useScaleSize(SMALL_FONT_SIZE);
|
|
135
|
+
const largeFontSize = useScaleSize(LARGE_FONT_SIZE);
|
|
131
136
|
const semiboldFontFamily = exportFontFamily('semibold');
|
|
132
137
|
const boldFontFamily = exportFontFamily('bold');
|
|
133
138
|
let typography: Typography;
|
|
134
139
|
if (size === 'small') {
|
|
135
140
|
inputTextStyles = {
|
|
136
|
-
fontSize:
|
|
141
|
+
fontSize: smallFontSize,
|
|
137
142
|
fontFamily: semiboldFontFamily,
|
|
138
143
|
};
|
|
139
|
-
dividerHeight =
|
|
144
|
+
dividerHeight = SMALL_DIVIDER_HEIGHT;
|
|
140
145
|
typography = 'header_s_semibold';
|
|
141
146
|
} else {
|
|
142
147
|
inputTextStyles = {
|
|
143
|
-
fontSize:
|
|
148
|
+
fontSize: largeFontSize,
|
|
144
149
|
fontFamily: boldFontFamily,
|
|
145
150
|
};
|
|
146
|
-
dividerHeight =
|
|
151
|
+
dividerHeight = LARGE_DIVIDER_HEIGHT;
|
|
147
152
|
typography = 'header_m_bold';
|
|
148
153
|
}
|
|
149
154
|
|
|
150
155
|
const renderInputView = () => {
|
|
151
156
|
const disabledColor = theme.colors.text.disable;
|
|
152
|
-
const
|
|
157
|
+
const isSecure = secureTextEntry;
|
|
153
158
|
let textColor = theme.colors.text.default;
|
|
154
159
|
let placeholderColor = theme.colors.text.hint;
|
|
155
160
|
let iconTintColor = trailingColor ?? theme.colors.text.default;
|
|
156
|
-
const borderWidth =
|
|
161
|
+
const borderWidth = isFocused ? FOCUSED_BORDER_WIDTH : 1;
|
|
157
162
|
let secureTextStyle = styles.secureTextLarge;
|
|
158
163
|
|
|
159
164
|
if (size === 'small') {
|
|
@@ -173,7 +178,7 @@ const InputPhoneNumber = forwardRef(
|
|
|
173
178
|
{ backgroundColor: theme.colors.background.surface },
|
|
174
179
|
getSizeStyle(size, undefined, scaleHeight),
|
|
175
180
|
{ borderWidth },
|
|
176
|
-
getBorderColor(theme,
|
|
181
|
+
getBorderColor(theme, isFocused, errorMessage, disabled),
|
|
177
182
|
]}
|
|
178
183
|
>
|
|
179
184
|
<View style={styles.inputView}>
|
|
@@ -204,7 +209,7 @@ const InputPhoneNumber = forwardRef(
|
|
|
204
209
|
{...props}
|
|
205
210
|
accessibilityLabel={`${componentId}`}
|
|
206
211
|
editable={editable && !disabled}
|
|
207
|
-
secureTextEntry={
|
|
212
|
+
secureTextEntry={isSecure}
|
|
208
213
|
textAlignVertical="center"
|
|
209
214
|
ref={inputRef}
|
|
210
215
|
accessibilityState={{
|
|
@@ -217,15 +222,15 @@ const InputPhoneNumber = forwardRef(
|
|
|
217
222
|
color: textColor,
|
|
218
223
|
},
|
|
219
224
|
inputTextStyles,
|
|
220
|
-
|
|
225
|
+
isSecure && hasValue && secureTextStyle,
|
|
221
226
|
]}
|
|
222
227
|
defaultValue={defaultValue}
|
|
223
228
|
allowFontScaling={false}
|
|
224
229
|
textBreakStrategy="highQuality"
|
|
225
230
|
value={value}
|
|
226
|
-
onChangeText={
|
|
227
|
-
onFocus={
|
|
228
|
-
onBlur={
|
|
231
|
+
onChangeText={handleChangeText}
|
|
232
|
+
onFocus={handleFocus}
|
|
233
|
+
onBlur={handleBlur}
|
|
229
234
|
placeholder={placeholder}
|
|
230
235
|
selectionColor={theme.colors.primary}
|
|
231
236
|
placeholderTextColor={placeholderColor}
|
|
@@ -233,16 +238,16 @@ const InputPhoneNumber = forwardRef(
|
|
|
233
238
|
/>
|
|
234
239
|
</View>
|
|
235
240
|
<View style={styles.iconView}>
|
|
236
|
-
{showClearIcon &&
|
|
241
|
+
{showClearIcon && isFocused && hasValue && (
|
|
237
242
|
<TouchableOpacity
|
|
238
243
|
accessibilityLabel={`${componentId}|clear-icon-touch`}
|
|
239
244
|
accessible={false}
|
|
240
245
|
style={styles.iconWrapper}
|
|
241
|
-
onPress={
|
|
246
|
+
onPress={handleClearText}
|
|
242
247
|
>
|
|
243
248
|
<Icon
|
|
244
249
|
source="24_navigation_close_circle_full"
|
|
245
|
-
size={
|
|
250
|
+
size={CLEAR_ICON_SIZE}
|
|
246
251
|
color={theme.colors.text.hint}
|
|
247
252
|
accessibilityLabel={`${componentId}|clear-icon`}
|
|
248
253
|
/>
|
|
@@ -299,9 +304,9 @@ const InputPhoneNumber = forwardRef(
|
|
|
299
304
|
|
|
300
305
|
const innerStyle = StyleSheet.create({
|
|
301
306
|
iconFlag: {
|
|
302
|
-
width:
|
|
303
|
-
height:
|
|
304
|
-
marginHorizontal:
|
|
307
|
+
width: FLAG_SIZE,
|
|
308
|
+
height: FLAG_SIZE,
|
|
309
|
+
marginHorizontal: Spacing.XXS,
|
|
305
310
|
},
|
|
306
311
|
});
|
|
307
312
|
|