@momo-kits/foundation 0.168.1-beta.5 → 0.168.1-beta.7
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/Input/InputMoney.tsx +47 -45
- package/Input/styles.ts +10 -0
- package/package.json +1 -1
package/Input/InputMoney.tsx
CHANGED
|
@@ -9,6 +9,8 @@ import React, {
|
|
|
9
9
|
} from 'react';
|
|
10
10
|
import {
|
|
11
11
|
Platform,
|
|
12
|
+
Pressable,
|
|
13
|
+
Text,
|
|
12
14
|
TextInput,
|
|
13
15
|
TextInputFocusEvent,
|
|
14
16
|
TouchableOpacity,
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
} from '../Context';
|
|
23
25
|
import { Icon } from '../Icon';
|
|
24
26
|
import { useScaleSize, exportFontFamily } from '../Text';
|
|
25
|
-
import { Spacing } from '../Consts';
|
|
26
27
|
import {
|
|
27
28
|
ErrorView,
|
|
28
29
|
FloatingView,
|
|
@@ -34,6 +35,8 @@ import { InputMoneyProps } from './index';
|
|
|
34
35
|
import styles from './styles';
|
|
35
36
|
import SystemTextInput from './SystemTextInput';
|
|
36
37
|
|
|
38
|
+
const moneyFormatter = new Intl.NumberFormat('vi-VN');
|
|
39
|
+
|
|
37
40
|
// Finds the common prefix and suffix of `old` and `text`; `size` counts the
|
|
38
41
|
// characters removed plus inserted between them.
|
|
39
42
|
const findEdit = (old: string, text: string) => {
|
|
@@ -137,15 +140,12 @@ const InputMoney = forwardRef(
|
|
|
137
140
|
}, [caretSelection]);
|
|
138
141
|
|
|
139
142
|
const updateDisplayValue = (numeric: string) => {
|
|
140
|
-
|
|
141
|
-
// digits and switches to "1e+21" notation past 20.
|
|
142
|
-
const formatted = numeric.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
|
143
|
-
const next = formatted ? `${formatted}${currency}` : '';
|
|
143
|
+
const next = numeric ? moneyFormatter.format(Number(numeric)) : '';
|
|
144
144
|
setDisplayValue(next);
|
|
145
145
|
|
|
146
146
|
// Android moves the caret proportionally when the text is replaced, so
|
|
147
147
|
// it lands before the typed digit once a separator is added. Send the
|
|
148
|
-
// caret together with the text
|
|
148
|
+
// caret together with the text, keeping the same digits after it.
|
|
149
149
|
const digitsAfter = caretDigitsAfter.current;
|
|
150
150
|
caretDigitsAfter.current = undefined;
|
|
151
151
|
if (Platform.OS !== 'android' || digitsAfter === undefined) return;
|
|
@@ -158,12 +158,7 @@ const InputMoney = forwardRef(
|
|
|
158
158
|
setCaretSelection({ start: caret, end: caret });
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
-
const parseInputText = (text: string): string =>
|
|
162
|
-
if (!text) return '';
|
|
163
|
-
const currencyRegex = new RegExp(` ?${currency}$`, 'g');
|
|
164
|
-
const textWithoutCurrency = text.replace(currencyRegex, '').trim();
|
|
165
|
-
return textWithoutCurrency.replace(/[^\d]/g, '');
|
|
166
|
-
};
|
|
161
|
+
const parseInputText = (text: string): string => text.replace(/\D/g, '');
|
|
167
162
|
|
|
168
163
|
const updateNumericValue = (val: string) => {
|
|
169
164
|
let next = val.replace(/[^\d]/g, '').replace(/^0+(?=\d)/, '');
|
|
@@ -191,7 +186,8 @@ const InputMoney = forwardRef(
|
|
|
191
186
|
onChangeText?.('');
|
|
192
187
|
return;
|
|
193
188
|
}
|
|
194
|
-
|
|
189
|
+
const digits = parseInputText(text);
|
|
190
|
+
// When typing outpaces JS (slow devices) native rejects the stale
|
|
195
191
|
// formatted text and keeps the raw one, so the edit may apply to either.
|
|
196
192
|
// Pick the one that differs from the new text by a single edit.
|
|
197
193
|
const raw = lastRawText.current;
|
|
@@ -200,25 +196,18 @@ const InputMoney = forwardRef(
|
|
|
200
196
|
const rawEdit = findEdit(raw, text);
|
|
201
197
|
const { old, start, suffix } =
|
|
202
198
|
raw && rawEdit.size < formattedEdit.size ? rawEdit : formattedEdit;
|
|
203
|
-
caretDigitsAfter.current =
|
|
204
|
-
.slice(text.length - suffix)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
: numericValue.length - 1;
|
|
212
|
-
if (index >= 0) {
|
|
213
|
-
updateNumericValue(
|
|
214
|
-
numericValue.slice(0, index) + numericValue.slice(index + 1),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
199
|
+
caretDigitsAfter.current = parseInputText(
|
|
200
|
+
text.slice(text.length - suffix),
|
|
201
|
+
).length;
|
|
202
|
+
// Deleting a separator removes the digit before it.
|
|
203
|
+
if (text.length < old.length && digits === numericValue) {
|
|
204
|
+
const index = parseInputText(text.slice(0, start)).length - 1;
|
|
205
|
+
if (index >= 0) {
|
|
206
|
+
updateNumericValue(digits.slice(0, index) + digits.slice(index + 1));
|
|
217
207
|
return;
|
|
218
208
|
}
|
|
219
209
|
}
|
|
220
|
-
|
|
221
|
-
updateNumericValue(newNumericValue);
|
|
210
|
+
updateNumericValue(digits);
|
|
222
211
|
};
|
|
223
212
|
|
|
224
213
|
const _onFocus = (e: TextInputFocusEvent) => {
|
|
@@ -262,6 +251,14 @@ const InputMoney = forwardRef(
|
|
|
262
251
|
placeholderColor = disabledColor;
|
|
263
252
|
iconTintColor = disabledColor;
|
|
264
253
|
}
|
|
254
|
+
const textStyle = {
|
|
255
|
+
fontSize: scaledFontSize,
|
|
256
|
+
fontFamily: inputFontFamily,
|
|
257
|
+
};
|
|
258
|
+
const placeholderHasCurrency = placeholder.endsWith(currency);
|
|
259
|
+
const inputPlaceholder = placeholderHasCurrency
|
|
260
|
+
? placeholder.slice(0, -currency.length)
|
|
261
|
+
: placeholder;
|
|
265
262
|
return (
|
|
266
263
|
<View
|
|
267
264
|
style={[
|
|
@@ -280,7 +277,11 @@ const InputMoney = forwardRef(
|
|
|
280
277
|
onPress={onPressFloatingIcon}
|
|
281
278
|
componentId={componentId}
|
|
282
279
|
/>
|
|
283
|
-
<
|
|
280
|
+
<Pressable
|
|
281
|
+
style={[styles.inputView, styles.moneyInputView]}
|
|
282
|
+
onPress={() => inputRef.current?.focus()}
|
|
283
|
+
disabled={disabled}
|
|
284
|
+
>
|
|
284
285
|
<SystemTextInput
|
|
285
286
|
{...props}
|
|
286
287
|
accessibilityLabel={`${componentId}`}
|
|
@@ -290,19 +291,9 @@ const InputMoney = forwardRef(
|
|
|
290
291
|
disabled: disabled,
|
|
291
292
|
...props.accessibilityState,
|
|
292
293
|
}}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
paddingLeft: Spacing.M,
|
|
297
|
-
height: '100%',
|
|
298
|
-
fontSize: scaledFontSize,
|
|
299
|
-
paddingVertical: Spacing.S,
|
|
300
|
-
fontFamily: inputFontFamily,
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
color: textColor,
|
|
304
|
-
},
|
|
305
|
-
]}
|
|
294
|
+
// No width: the input sizes to its text natively, so the
|
|
295
|
+
// currency follows it without waiting for JS.
|
|
296
|
+
style={[textStyle, styles.moneyTextInput, { color: textColor }]}
|
|
306
297
|
allowFontScaling={false}
|
|
307
298
|
textBreakStrategy="highQuality"
|
|
308
299
|
value={displayValue}
|
|
@@ -310,13 +301,24 @@ const InputMoney = forwardRef(
|
|
|
310
301
|
onChangeText={_onChangeText}
|
|
311
302
|
onFocus={_onFocus}
|
|
312
303
|
onBlur={_onBlur}
|
|
313
|
-
placeholder={
|
|
304
|
+
placeholder={inputPlaceholder}
|
|
314
305
|
selectionColor={theme.colors.primary}
|
|
315
306
|
placeholderTextColor={placeholderColor}
|
|
316
307
|
keyboardType={'numeric'}
|
|
317
308
|
maxLength={undefined}
|
|
318
309
|
/>
|
|
319
|
-
|
|
310
|
+
{displayValue || placeholderHasCurrency ? (
|
|
311
|
+
<Text
|
|
312
|
+
style={[
|
|
313
|
+
textStyle,
|
|
314
|
+
{ color: displayValue ? textColor : placeholderColor },
|
|
315
|
+
]}
|
|
316
|
+
allowFontScaling={false}
|
|
317
|
+
>
|
|
318
|
+
{currency}
|
|
319
|
+
</Text>
|
|
320
|
+
) : null}
|
|
321
|
+
</Pressable>
|
|
320
322
|
<View style={styles.iconView}>
|
|
321
323
|
{showClearIcon && focused && displayValue ? (
|
|
322
324
|
<TouchableOpacity
|
package/Input/styles.ts
CHANGED
|
@@ -218,4 +218,14 @@ export default StyleSheet.create({
|
|
|
218
218
|
marginLeft: Spacing.M,
|
|
219
219
|
},
|
|
220
220
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
221
|
+
moneyInputView: {
|
|
222
|
+
paddingLeft: Spacing.M,
|
|
223
|
+
},
|
|
224
|
+
moneyTextInput: {
|
|
225
|
+
flexShrink: 1,
|
|
226
|
+
height: '100%',
|
|
227
|
+
paddingLeft: 0,
|
|
228
|
+
paddingRight: Spacing.XXS,
|
|
229
|
+
paddingVertical: Spacing.S,
|
|
230
|
+
},
|
|
221
231
|
});
|