@momo-kits/foundation 0.167.1-beta.13 → 0.167.1-beta.14
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 +246 -42
- package/Application/BottomTab/BottomTabBar.tsx +6 -3
- package/Application/BottomTab/CustomBottomTabItem.tsx +3 -5
- package/Application/BottomTab/DuoBarCompression.tsx +135 -0
- package/Application/BottomTab/DuoTabBar.tsx +537 -0
- package/Application/BottomTab/index.tsx +145 -134
- package/Application/Components/DuoGlassBackground.tsx +158 -0
- package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
- package/Application/Components/HeaderAnimated.tsx +9 -3
- package/Application/Components/HeaderExtendHeader.tsx +70 -28
- package/Application/Components/HeaderLeft.tsx +38 -0
- package/Application/Components/HeaderRight.tsx +144 -9
- package/Application/Components/HeaderTitle.tsx +43 -8
- package/Application/Components/SearchHeader.tsx +20 -15
- package/Application/Components/SideBarButton.tsx +134 -0
- package/Application/ModalScreen.tsx +20 -2
- package/Application/NavigationContainer.tsx +22 -38
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/device.ts +52 -0
- package/Application/types.ts +10 -1
- package/Application/utils.tsx +10 -7
- package/Badge/Badge.tsx +2 -3
- package/Badge/BadgeDotAnimation.tsx +3 -3
- package/Button/index.tsx +11 -11
- package/Consts/theme.ts +3 -4
- package/Input/Input.tsx +3 -4
- package/Input/InputMoney.tsx +123 -195
- package/Input/InputOTP.tsx +9 -12
- package/Input/InputPhoneNumber.tsx +3 -7
- package/Input/InputSearch.tsx +17 -14
- package/Input/InputTextArea.tsx +3 -4
- package/Input/SystemTextInput.tsx +2 -3
- package/Input/TextTyping.tsx +11 -6
- package/Input/styles.ts +9 -0
- package/Input/utils.ts +2 -3
- package/Layout/Card.tsx +8 -26
- package/Layout/FloatingButton.tsx +3 -4
- package/Layout/Item.tsx +1 -10
- package/Layout/ReservedRegions.tsx +78 -0
- package/Layout/Screen.tsx +242 -48
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +5 -0
- package/Layout/utils.ts +478 -5
- package/Pagination/Dot.tsx +3 -6
- package/Popup/PopupNotify.tsx +49 -28
- package/Popup/PopupPromotion.tsx +21 -8
- package/Popup/utils.ts +26 -0
- package/Radio/index.tsx +2 -3
- package/Text/index.tsx +4 -0
- package/Text/utils.ts +2 -3
- package/Title/index.tsx +8 -11
- package/Title/styles.ts +0 -1
- package/package.json +10 -7
- package/Layout/GridSystem.tsx +0 -137
package/Input/InputMoney.tsx
CHANGED
|
@@ -4,15 +4,15 @@ import React, {
|
|
|
4
4
|
useContext,
|
|
5
5
|
useEffect,
|
|
6
6
|
useImperativeHandle,
|
|
7
|
-
useLayoutEffect,
|
|
8
7
|
useRef,
|
|
9
8
|
useState,
|
|
10
9
|
} from 'react';
|
|
11
10
|
import {
|
|
12
|
-
|
|
11
|
+
Platform,
|
|
12
|
+
Pressable,
|
|
13
|
+
Text,
|
|
13
14
|
TextInput,
|
|
14
|
-
|
|
15
|
-
TextInputSelectionChangeEventData,
|
|
15
|
+
TextInputFocusEvent,
|
|
16
16
|
TouchableOpacity,
|
|
17
17
|
View,
|
|
18
18
|
} from 'react-native';
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
} from '../Context';
|
|
25
25
|
import { Icon } from '../Icon';
|
|
26
26
|
import { useScaleSize, exportFontFamily } from '../Text';
|
|
27
|
-
import { Spacing } from '../Consts';
|
|
28
27
|
import {
|
|
29
28
|
ErrorView,
|
|
30
29
|
FloatingView,
|
|
@@ -36,97 +35,22 @@ import { InputMoneyProps } from './index';
|
|
|
36
35
|
import styles from './styles';
|
|
37
36
|
import SystemTextInput from './SystemTextInput';
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
type Edit = { start: number; end: number; inserted: string };
|
|
38
|
+
const moneyFormatter = new Intl.NumberFormat('vi-VN');
|
|
41
39
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Caret position right after the `digitIndex`-th digit of `display`.
|
|
48
|
-
const caretFromDigitIndex = (display: string, digitIndex: number) => {
|
|
49
|
-
let count = 0;
|
|
50
|
-
for (let i = 0; i < display.length && count < digitIndex; i++) {
|
|
51
|
-
if (/\d/.test(display[i])) {
|
|
52
|
-
count += 1;
|
|
53
|
-
if (count === digitIndex) return i + 1;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return 0;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const detectEdit = (old: string, next: string, selection: Selection): Edit => {
|
|
60
|
-
const { start, end } = selection;
|
|
61
|
-
const removed = old.length - next.length;
|
|
62
|
-
const candidates: Edit[] = [
|
|
63
|
-
{
|
|
64
|
-
start,
|
|
65
|
-
end,
|
|
66
|
-
inserted: next.slice(start, next.length - (old.length - end)),
|
|
67
|
-
},
|
|
68
|
-
{ start: start - removed, end: start, inserted: '' },
|
|
69
|
-
{ start, end: start + removed, inserted: '' },
|
|
70
|
-
];
|
|
71
|
-
const match = candidates.find(
|
|
72
|
-
e =>
|
|
73
|
-
e.start >= 0 &&
|
|
74
|
-
e.end >= e.start &&
|
|
75
|
-
e.end <= old.length &&
|
|
76
|
-
old.slice(0, e.start) + e.inserted + old.slice(e.end) === next,
|
|
77
|
-
);
|
|
78
|
-
if (match) return match;
|
|
79
|
-
|
|
80
|
-
let prefix = 0;
|
|
81
|
-
while (
|
|
82
|
-
prefix < Math.min(old.length, next.length) &&
|
|
83
|
-
old[prefix] === next[prefix]
|
|
84
|
-
) {
|
|
85
|
-
prefix += 1;
|
|
40
|
+
const findEdit = (old: string, text: string) => {
|
|
41
|
+
let start = 0;
|
|
42
|
+
while (start < text.length && old[start] === text[start]) {
|
|
43
|
+
start += 1;
|
|
86
44
|
}
|
|
87
45
|
let suffix = 0;
|
|
88
46
|
while (
|
|
89
|
-
suffix < Math.min(
|
|
90
|
-
old[old.length - 1 - suffix] ===
|
|
47
|
+
suffix < Math.min(text.length, old.length) - start &&
|
|
48
|
+
old[old.length - 1 - suffix] === text[text.length - 1 - suffix]
|
|
91
49
|
) {
|
|
92
50
|
suffix += 1;
|
|
93
51
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
end: old.length - suffix,
|
|
97
|
-
inserted: next.slice(prefix, next.length - suffix),
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// Applies `edit` to the digits of `display`. Separators and currency are never
|
|
102
|
-
// deleted: removing a separator deletes the digit before it instead, removing
|
|
103
|
-
// only the currency leaves the digits untouched.
|
|
104
|
-
const applyEdit = (display: string, edit: Edit, digitLimit: number) => {
|
|
105
|
-
const digits = display.replace(/\D/g, '');
|
|
106
|
-
let left = countDigits(display.slice(0, edit.start));
|
|
107
|
-
let removed = countDigits(display.slice(edit.start, edit.end));
|
|
108
|
-
const inserted = edit.inserted.replace(/\D/g, '');
|
|
109
|
-
if (
|
|
110
|
-
!removed &&
|
|
111
|
-
!inserted &&
|
|
112
|
-
left > 0 &&
|
|
113
|
-
display.slice(edit.start, edit.end).includes('.')
|
|
114
|
-
) {
|
|
115
|
-
left -= 1;
|
|
116
|
-
removed = 1;
|
|
117
|
-
}
|
|
118
|
-
const next = digits.slice(0, left) + inserted + digits.slice(left + removed);
|
|
119
|
-
const trimmed = next.replace(/^0+(?=\d)/, '');
|
|
120
|
-
if ((!removed && !inserted) || trimmed.length > digitLimit) {
|
|
121
|
-
return { digits, caretDigit: left };
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
digits: trimmed,
|
|
125
|
-
caretDigit: Math.max(
|
|
126
|
-
0,
|
|
127
|
-
left + inserted.length - (next.length - trimmed.length),
|
|
128
|
-
),
|
|
129
|
-
};
|
|
52
|
+
const size = old.length + text.length - 2 * (start + suffix);
|
|
53
|
+
return { old, start, suffix, size };
|
|
130
54
|
};
|
|
131
55
|
|
|
132
56
|
const InputMoney = forwardRef(
|
|
@@ -167,14 +91,14 @@ const InputMoney = forwardRef(
|
|
|
167
91
|
const [focused, setFocused] = useState(false);
|
|
168
92
|
const [displayValue, setDisplayValue] = useState('');
|
|
169
93
|
const [numericValue, setNumericValue] = useState('');
|
|
170
|
-
const [
|
|
171
|
-
const displayRef = useRef('');
|
|
172
|
-
const selectionRef = useRef<Selection>({ start: 0, end: 0 });
|
|
173
|
-
// Caret to push to native once the committed text is rendered.
|
|
174
|
-
const pendingCaretRef = useRef<number | null>(null);
|
|
175
|
-
const pendingSelectionRef = useRef<Selection | null>(null);
|
|
176
|
-
const editingRef = useRef(false);
|
|
94
|
+
const [lastDisplayValue, setLastDisplayValue] = useState('');
|
|
177
95
|
const inputRef = useRef<TextInput>(null);
|
|
96
|
+
const caretDigitsAfter = useRef<number | undefined>(undefined);
|
|
97
|
+
const lastRawText = useRef('');
|
|
98
|
+
const [caretSelection, setCaretSelection] = useState<{
|
|
99
|
+
start: number;
|
|
100
|
+
end: number;
|
|
101
|
+
}>();
|
|
178
102
|
const componentName = 'InputMoney';
|
|
179
103
|
|
|
180
104
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
@@ -184,127 +108,121 @@ const InputMoney = forwardRef(
|
|
|
184
108
|
props.accessibilityLabel,
|
|
185
109
|
);
|
|
186
110
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
: Number.POSITIVE_INFINITY;
|
|
111
|
+
const maxLength = (props as any)?.maxLength;
|
|
112
|
+
const hasMaxLength = typeof maxLength === 'number';
|
|
113
|
+
const digitLimit = hasMaxLength ? maxLength : Number.POSITIVE_INFINITY;
|
|
191
114
|
|
|
192
115
|
useEffect(() => {
|
|
193
116
|
if (value !== undefined && typeof value === 'string') {
|
|
194
117
|
const cleanValue = value.replace(/\D/g, '').replace(/^0+(?=\d)/, '');
|
|
195
118
|
if (cleanValue !== numericValue) {
|
|
196
|
-
|
|
119
|
+
caretDigitsAfter.current = undefined;
|
|
120
|
+
setNumericValue(cleanValue);
|
|
121
|
+
updateDisplayValue(cleanValue);
|
|
197
122
|
}
|
|
198
123
|
}
|
|
199
124
|
}, [value]);
|
|
200
125
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
useLayoutEffect(() => {
|
|
205
|
-
const caret = pendingCaretRef.current;
|
|
206
|
-
if (caret === null) return;
|
|
207
|
-
pendingCaretRef.current = null;
|
|
208
|
-
if (inputRef.current?.isFocused()) {
|
|
209
|
-
inputRef.current.setSelection(caret, caret);
|
|
210
|
-
}
|
|
211
|
-
}, [commitCount]);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
setLastDisplayValue(displayValue);
|
|
128
|
+
}, [displayValue]);
|
|
212
129
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (!caretSelection) return;
|
|
132
|
+
setCaretSelection(current =>
|
|
133
|
+
current === caretSelection ? undefined : current,
|
|
134
|
+
);
|
|
135
|
+
}, [caretSelection]);
|
|
136
|
+
|
|
137
|
+
const updateDisplayValue = (numeric: string) => {
|
|
138
|
+
const next = numeric ? moneyFormatter.format(Number(numeric)) : '';
|
|
139
|
+
setDisplayValue(next);
|
|
140
|
+
|
|
141
|
+
const digitsAfter = caretDigitsAfter.current;
|
|
142
|
+
caretDigitsAfter.current = undefined;
|
|
143
|
+
if (Platform.OS !== 'android' || digitsAfter === undefined) return;
|
|
144
|
+
let before = parseInputText(next).length - digitsAfter;
|
|
145
|
+
let caret = 0;
|
|
146
|
+
while (before > 0 && caret < next.length) {
|
|
147
|
+
if (/\d/.test(next[caret])) before -= 1;
|
|
148
|
+
caret += 1;
|
|
149
|
+
}
|
|
150
|
+
setCaretSelection({ start: caret, end: caret });
|
|
224
151
|
};
|
|
225
152
|
|
|
226
|
-
const parseInputText = (text: string): string =>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
153
|
+
const parseInputText = (text: string): string => text.replace(/\D/g, '');
|
|
154
|
+
|
|
155
|
+
const updateNumericValue = (val: string) => {
|
|
156
|
+
let next = val.replace(/[^\d]/g, '').replace(/^0+(?=\d)/, '');
|
|
157
|
+
if (next.length > digitLimit) next = next.slice(0, digitLimit);
|
|
158
|
+
if (/^\d*$/.test(next)) {
|
|
159
|
+
setNumericValue(next);
|
|
160
|
+
updateDisplayValue(next);
|
|
161
|
+
onChangeText?.(next);
|
|
162
|
+
}
|
|
231
163
|
};
|
|
232
164
|
|
|
233
165
|
const onClearText = () => {
|
|
234
166
|
inputRef?.current?.clear();
|
|
235
167
|
inputRef.current?.setNativeProps({ text: '' });
|
|
236
|
-
|
|
168
|
+
setDisplayValue('');
|
|
169
|
+
setNumericValue('');
|
|
237
170
|
onChangeText?.('');
|
|
238
171
|
};
|
|
239
172
|
|
|
240
173
|
const _onChangeText = (text: string) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
});
|
|
248
|
-
if (text) {
|
|
249
|
-
const edit = detectEdit(displayRef.current, text, selectionRef.current);
|
|
250
|
-
({ digits, caretDigit } = applyEdit(
|
|
251
|
-
displayRef.current,
|
|
252
|
-
edit,
|
|
253
|
-
digitLimit,
|
|
254
|
-
));
|
|
174
|
+
if (!text) {
|
|
175
|
+
lastRawText.current = '';
|
|
176
|
+
setDisplayValue('');
|
|
177
|
+
setNumericValue('');
|
|
178
|
+
onChangeText?.('');
|
|
179
|
+
return;
|
|
255
180
|
}
|
|
256
|
-
|
|
257
|
-
|
|
181
|
+
const digits = parseInputText(text);
|
|
182
|
+
const raw = lastRawText.current;
|
|
183
|
+
lastRawText.current = text;
|
|
184
|
+
const formattedEdit = findEdit(lastDisplayValue, text);
|
|
185
|
+
const rawEdit = findEdit(raw, text);
|
|
186
|
+
const { old, start, suffix } =
|
|
187
|
+
raw && rawEdit.size < formattedEdit.size ? rawEdit : formattedEdit;
|
|
188
|
+
caretDigitsAfter.current = parseInputText(
|
|
189
|
+
text.slice(text.length - suffix),
|
|
190
|
+
).length;
|
|
191
|
+
if (text.length < old.length && digits === numericValue) {
|
|
192
|
+
const index = parseInputText(text.slice(0, start)).length - 1;
|
|
193
|
+
if (index >= 0) {
|
|
194
|
+
updateNumericValue(digits.slice(0, index) + digits.slice(index + 1));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
258
197
|
}
|
|
198
|
+
updateNumericValue(digits);
|
|
259
199
|
};
|
|
260
200
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
) => {
|
|
265
|
-
props.onSelectionChange?.(e);
|
|
266
|
-
if (editingRef.current) return;
|
|
267
|
-
const selection = e.nativeEvent.selection;
|
|
268
|
-
pendingSelectionRef.current = selection;
|
|
269
|
-
setTimeout(() => {
|
|
270
|
-
if (pendingSelectionRef.current !== selection) return;
|
|
271
|
-
pendingSelectionRef.current = null;
|
|
272
|
-
const { start, end } = selection;
|
|
273
|
-
const display = displayRef.current;
|
|
274
|
-
const max = display ? display.length - currency.length : 0;
|
|
275
|
-
const clamped = {
|
|
276
|
-
start: Math.min(start, max),
|
|
277
|
-
end: Math.min(end, max),
|
|
278
|
-
};
|
|
279
|
-
selectionRef.current = clamped;
|
|
280
|
-
if (clamped.start !== start || clamped.end !== end) {
|
|
281
|
-
inputRef.current?.setSelection(clamped.start, clamped.end);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
201
|
+
const focusAtEnd = () => {
|
|
202
|
+
inputRef.current?.focus();
|
|
203
|
+
inputRef.current?.setSelection(displayValue.length, displayValue.length);
|
|
284
204
|
};
|
|
285
205
|
|
|
286
|
-
const _onFocus = (e:
|
|
206
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
287
207
|
setFocused(true);
|
|
288
208
|
onFocus?.(e);
|
|
289
209
|
};
|
|
290
210
|
|
|
291
|
-
const _onBlur = (e:
|
|
211
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
292
212
|
setFocused(false);
|
|
293
213
|
onBlur?.(e);
|
|
294
214
|
};
|
|
295
215
|
|
|
296
216
|
const _setText = (text: string) => {
|
|
217
|
+
caretDigitsAfter.current = undefined;
|
|
297
218
|
if (!text) {
|
|
298
|
-
|
|
219
|
+
setDisplayValue('');
|
|
220
|
+
setNumericValue('');
|
|
299
221
|
onChangeText?.('');
|
|
300
222
|
return;
|
|
301
223
|
}
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
.slice(0, digitLimit);
|
|
305
|
-
if (commit(digits, digits.length)) {
|
|
306
|
-
onChangeText?.(digits);
|
|
307
|
-
}
|
|
224
|
+
const newNumericValue = parseInputText(text);
|
|
225
|
+
updateNumericValue(newNumericValue);
|
|
308
226
|
};
|
|
309
227
|
|
|
310
228
|
useImperativeHandle(ref, () => {
|
|
@@ -326,6 +244,14 @@ const InputMoney = forwardRef(
|
|
|
326
244
|
placeholderColor = disabledColor;
|
|
327
245
|
iconTintColor = disabledColor;
|
|
328
246
|
}
|
|
247
|
+
const textStyle = {
|
|
248
|
+
fontSize: scaledFontSize,
|
|
249
|
+
fontFamily: inputFontFamily,
|
|
250
|
+
};
|
|
251
|
+
const placeholderHasCurrency = placeholder.endsWith(currency);
|
|
252
|
+
const inputPlaceholder = placeholderHasCurrency
|
|
253
|
+
? placeholder.slice(0, -currency.length)
|
|
254
|
+
: placeholder;
|
|
329
255
|
return (
|
|
330
256
|
<View
|
|
331
257
|
style={[
|
|
@@ -344,7 +270,11 @@ const InputMoney = forwardRef(
|
|
|
344
270
|
onPress={onPressFloatingIcon}
|
|
345
271
|
componentId={componentId}
|
|
346
272
|
/>
|
|
347
|
-
<
|
|
273
|
+
<Pressable
|
|
274
|
+
style={[styles.inputView, styles.moneyInputView]}
|
|
275
|
+
onPress={focusAtEnd}
|
|
276
|
+
disabled={disabled}
|
|
277
|
+
>
|
|
348
278
|
<SystemTextInput
|
|
349
279
|
{...props}
|
|
350
280
|
accessibilityLabel={`${componentId}`}
|
|
@@ -354,34 +284,32 @@ const InputMoney = forwardRef(
|
|
|
354
284
|
disabled: disabled,
|
|
355
285
|
...props.accessibilityState,
|
|
356
286
|
}}
|
|
357
|
-
style={[
|
|
358
|
-
{
|
|
359
|
-
width: '100%',
|
|
360
|
-
paddingLeft: Spacing.M,
|
|
361
|
-
height: '100%',
|
|
362
|
-
fontSize: scaledFontSize,
|
|
363
|
-
paddingVertical: Spacing.S,
|
|
364
|
-
fontWeight: 'bold',
|
|
365
|
-
fontFamily: inputFontFamily,
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
color: textColor,
|
|
369
|
-
},
|
|
370
|
-
]}
|
|
287
|
+
style={[textStyle, styles.moneyTextInput, { color: textColor }]}
|
|
371
288
|
allowFontScaling={false}
|
|
372
289
|
textBreakStrategy="highQuality"
|
|
373
290
|
value={displayValue}
|
|
291
|
+
selection={caretSelection ?? props.selection}
|
|
374
292
|
onChangeText={_onChangeText}
|
|
375
|
-
onSelectionChange={_onSelectionChange}
|
|
376
293
|
onFocus={_onFocus}
|
|
377
294
|
onBlur={_onBlur}
|
|
378
|
-
placeholder={
|
|
295
|
+
placeholder={inputPlaceholder}
|
|
379
296
|
selectionColor={theme.colors.primary}
|
|
380
297
|
placeholderTextColor={placeholderColor}
|
|
381
298
|
keyboardType={'numeric'}
|
|
382
299
|
maxLength={undefined}
|
|
383
300
|
/>
|
|
384
|
-
|
|
301
|
+
{displayValue || placeholderHasCurrency ? (
|
|
302
|
+
<Text
|
|
303
|
+
style={[
|
|
304
|
+
textStyle,
|
|
305
|
+
{ color: displayValue ? textColor : placeholderColor },
|
|
306
|
+
]}
|
|
307
|
+
allowFontScaling={false}
|
|
308
|
+
>
|
|
309
|
+
{currency}
|
|
310
|
+
</Text>
|
|
311
|
+
) : null}
|
|
312
|
+
</Pressable>
|
|
385
313
|
<View style={styles.iconView}>
|
|
386
314
|
{showClearIcon && focused && displayValue ? (
|
|
387
315
|
<TouchableOpacity
|
package/Input/InputOTP.tsx
CHANGED
|
@@ -64,8 +64,8 @@ const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
|
64
64
|
opacity: opacity.value,
|
|
65
65
|
}));
|
|
66
66
|
|
|
67
|
-
const
|
|
68
|
-
|
|
67
|
+
const hasNextInput = !isNaN(Number(length)) && index !== Number(length) - 1;
|
|
68
|
+
const spacingStyle = hasNextInput && { marginRight: Spacing.L };
|
|
69
69
|
|
|
70
70
|
return (
|
|
71
71
|
<View style={[Styles.rowCenter, spacingStyle]}>
|
|
@@ -162,6 +162,7 @@ const InputOTP = forwardRef(
|
|
|
162
162
|
|
|
163
163
|
const renderInputs = (inputLength: number) => {
|
|
164
164
|
const TextInputs: React.ReactNode[] = [];
|
|
165
|
+
const textColors = theme.colors.text;
|
|
165
166
|
for (let i = 0; i < inputLength; i++) {
|
|
166
167
|
TextInputs.push(
|
|
167
168
|
<View key={`otp-input-${i}`}>
|
|
@@ -170,9 +171,7 @@ const InputOTP = forwardRef(
|
|
|
170
171
|
) : (
|
|
171
172
|
<Text
|
|
172
173
|
style={i !== inputLength - 1 && { marginRight: Spacing.L }}
|
|
173
|
-
color={
|
|
174
|
-
value[i] ? theme.colors.text.default : theme.colors.text.hint
|
|
175
|
-
}
|
|
174
|
+
color={value[i] ? textColors.default : textColors.hint}
|
|
176
175
|
typography={value[i] ? 'header_m_bold' : 'body_default_regular'}
|
|
177
176
|
>
|
|
178
177
|
{value[i] || '-'}
|
|
@@ -201,16 +200,14 @@ const InputOTP = forwardRef(
|
|
|
201
200
|
return (
|
|
202
201
|
<View style={Styles.row}>
|
|
203
202
|
{splitValue.map((letter, index) => {
|
|
203
|
+
const isLast = index === value.length - 1;
|
|
204
|
+
const isTyping = focused && value.length !== MAX_LENGTH;
|
|
205
|
+
const isCompact = fontScale > 1 && value.length > 6;
|
|
206
|
+
const marginRight = isCompact ? Spacing.M : Spacing.L;
|
|
204
207
|
return (
|
|
205
208
|
<Text
|
|
206
209
|
key={`otp-letter-${index}`}
|
|
207
|
-
style={
|
|
208
|
-
(index !== value.length - 1 ||
|
|
209
|
-
(focused && value.length !== MAX_LENGTH)) && {
|
|
210
|
-
marginRight:
|
|
211
|
-
fontScale > 1 && value.length > 6 ? Spacing.M : Spacing.L,
|
|
212
|
-
}
|
|
213
|
-
}
|
|
210
|
+
style={(!isLast || isTyping) && { marginRight }}
|
|
214
211
|
typography={'header_m_bold'}
|
|
215
212
|
>
|
|
216
213
|
{letter}
|
|
@@ -6,10 +6,9 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
-
NativeSyntheticEvent,
|
|
10
9
|
StyleSheet,
|
|
11
10
|
TextInput,
|
|
12
|
-
|
|
11
|
+
TextInputFocusEvent,
|
|
13
12
|
TouchableOpacity,
|
|
14
13
|
View,
|
|
15
14
|
} from 'react-native';
|
|
@@ -93,12 +92,12 @@ const InputPhoneNumber = forwardRef(
|
|
|
93
92
|
onChangeText?.(text);
|
|
94
93
|
};
|
|
95
94
|
|
|
96
|
-
const _onFocus = (e:
|
|
95
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
97
96
|
setFocused(true);
|
|
98
97
|
onFocus?.(e);
|
|
99
98
|
};
|
|
100
99
|
|
|
101
|
-
const _onBlur = (e:
|
|
100
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
102
101
|
setFocused(false);
|
|
103
102
|
onBlur?.(e);
|
|
104
103
|
};
|
|
@@ -134,7 +133,6 @@ const InputPhoneNumber = forwardRef(
|
|
|
134
133
|
if (size === 'small') {
|
|
135
134
|
inputTextStyles = {
|
|
136
135
|
fontSize: size14,
|
|
137
|
-
fontWeight: '600',
|
|
138
136
|
fontFamily: semiboldFontFamily,
|
|
139
137
|
};
|
|
140
138
|
dividerHeight = 24;
|
|
@@ -142,7 +140,6 @@ const InputPhoneNumber = forwardRef(
|
|
|
142
140
|
} else {
|
|
143
141
|
inputTextStyles = {
|
|
144
142
|
fontSize: size18,
|
|
145
|
-
fontWeight: '700',
|
|
146
143
|
fontFamily: boldFontFamily,
|
|
147
144
|
};
|
|
148
145
|
dividerHeight = 32;
|
|
@@ -215,7 +212,6 @@ const InputPhoneNumber = forwardRef(
|
|
|
215
212
|
styles.input,
|
|
216
213
|
{
|
|
217
214
|
color: textColor,
|
|
218
|
-
fontFamily: exportFontFamily('regular'),
|
|
219
215
|
},
|
|
220
216
|
inputTextStyles,
|
|
221
217
|
secure && haveValue && { fontSize: size === 'small' ? 18 : 22 },
|
package/Input/InputSearch.tsx
CHANGED
|
@@ -10,9 +10,8 @@ import React, {
|
|
|
10
10
|
useState,
|
|
11
11
|
} from 'react';
|
|
12
12
|
import {
|
|
13
|
-
NativeSyntheticEvent,
|
|
14
13
|
TextInput,
|
|
15
|
-
|
|
14
|
+
TextInputFocusEvent,
|
|
16
15
|
TouchableOpacity,
|
|
17
16
|
View,
|
|
18
17
|
} from 'react-native';
|
|
@@ -59,9 +58,11 @@ const TextTyping: FC<any> = ({
|
|
|
59
58
|
listChar.length !== 0 && showChar(listChar?.[currentCharIndex.current]);
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
currentIndex.current >= data?.length
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
if (currentIndex.current >= data?.length) {
|
|
62
|
+
handleResetList();
|
|
63
|
+
} else {
|
|
64
|
+
handleAnimation();
|
|
65
|
+
}
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
const showChar = (char?: string) => {
|
|
@@ -82,9 +83,12 @@ const TextTyping: FC<any> = ({
|
|
|
82
83
|
}, timeDelayNextChar);
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
const textLength = data?.[currentIndex.current]?.length || 0;
|
|
87
|
+
if (currentCharIndex.current >= textLength) {
|
|
88
|
+
handleResetString();
|
|
89
|
+
} else {
|
|
90
|
+
handleShowChar();
|
|
91
|
+
}
|
|
88
92
|
};
|
|
89
93
|
|
|
90
94
|
const reset = () => {
|
|
@@ -166,12 +170,12 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
166
170
|
props.accessibilityLabel,
|
|
167
171
|
);
|
|
168
172
|
|
|
169
|
-
const _onFocus = (e:
|
|
173
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
170
174
|
setFocused(true);
|
|
171
175
|
onFocus?.(e);
|
|
172
176
|
};
|
|
173
177
|
|
|
174
|
-
const _onBlur = (e:
|
|
178
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
175
179
|
setFocused(false);
|
|
176
180
|
onBlur?.(e);
|
|
177
181
|
};
|
|
@@ -303,6 +307,8 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
303
307
|
inputState = 'filled';
|
|
304
308
|
}
|
|
305
309
|
|
|
310
|
+
const inputBackground = backgroundColor ?? theme.colors.background.surface;
|
|
311
|
+
|
|
306
312
|
return (
|
|
307
313
|
<ComponentContext.Provider
|
|
308
314
|
value={{
|
|
@@ -322,10 +328,7 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
322
328
|
<View
|
|
323
329
|
style={[
|
|
324
330
|
styles.searchInputWrapper,
|
|
325
|
-
{
|
|
326
|
-
backgroundColor:
|
|
327
|
-
backgroundColor ?? theme.colors.background.surface,
|
|
328
|
-
},
|
|
331
|
+
{ backgroundColor: inputBackground },
|
|
329
332
|
]}
|
|
330
333
|
>
|
|
331
334
|
<Icon
|
package/Input/InputTextArea.tsx
CHANGED
|
@@ -7,9 +7,8 @@ import React, {
|
|
|
7
7
|
useState,
|
|
8
8
|
} from 'react';
|
|
9
9
|
import {
|
|
10
|
-
NativeSyntheticEvent,
|
|
11
10
|
TextInput,
|
|
12
|
-
|
|
11
|
+
TextInputFocusEvent,
|
|
13
12
|
TouchableOpacity,
|
|
14
13
|
View,
|
|
15
14
|
} from 'react-native';
|
|
@@ -79,12 +78,12 @@ const InputTextArea = forwardRef(
|
|
|
79
78
|
setInputValue(text);
|
|
80
79
|
};
|
|
81
80
|
|
|
82
|
-
const _onFocus = (e:
|
|
81
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
83
82
|
setFocused(true);
|
|
84
83
|
onFocus?.(e);
|
|
85
84
|
};
|
|
86
85
|
|
|
87
|
-
const _onBlur = (e:
|
|
86
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
88
87
|
setFocused(false);
|
|
89
88
|
onBlur?.(e);
|
|
90
89
|
};
|
|
@@ -17,11 +17,10 @@ const SystemTextInput: FC<SystemTextInputProps> = props => {
|
|
|
17
17
|
const needsAndroidWrapper =
|
|
18
18
|
Platform.OS === 'android' && !editable && (onPressIn || onPressOut);
|
|
19
19
|
|
|
20
|
+
const noPressHandlers = { onPressIn: undefined, onPressOut: undefined };
|
|
20
21
|
const inputProps: TextInputProps = {
|
|
21
22
|
...props,
|
|
22
|
-
...(needsAndroidWrapper
|
|
23
|
-
? { onPressIn: undefined, onPressOut: undefined }
|
|
24
|
-
: null),
|
|
23
|
+
...(needsAndroidWrapper ? noPressHandlers : null),
|
|
25
24
|
...(editable === false ? { accessibilityState: undefined } : null),
|
|
26
25
|
};
|
|
27
26
|
|
package/Input/TextTyping.tsx
CHANGED
|
@@ -36,9 +36,11 @@ const TextTyping: FC<TextTypingProps> = ({
|
|
|
36
36
|
listChar.length !== 0 && showChar(listChar?.[currentCharIndex.current]);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
currentIndex.current >= data?.length
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if (currentIndex.current >= data?.length) {
|
|
40
|
+
handleResetList();
|
|
41
|
+
} else {
|
|
42
|
+
handleAnimation();
|
|
43
|
+
}
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
const showChar = (char?: string) => {
|
|
@@ -59,9 +61,12 @@ const TextTyping: FC<TextTypingProps> = ({
|
|
|
59
61
|
}, timeDelayNextChar);
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
const textLength = data?.[currentIndex.current]?.length || 0;
|
|
65
|
+
if (currentCharIndex.current >= textLength) {
|
|
66
|
+
handleResetString();
|
|
67
|
+
} else {
|
|
68
|
+
handleShowChar();
|
|
69
|
+
}
|
|
65
70
|
};
|
|
66
71
|
|
|
67
72
|
const reset = () => {
|