sapo-components-ui-rn 1.0.76 → 1.0.78
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/dist/components/NumberKeyboard/index.d.ts +2 -0
- package/dist/components/SelectionField/index.d.ts +1 -2
- package/dist/index.esm.js +88 -31
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +88 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/NumberKeyboard/index.tsx +51 -12
- package/src/components/SelectionField/index.tsx +0 -3
- package/src/components/TextInput/TextInputNumber.tsx +45 -14
package/package.json
CHANGED
|
@@ -21,6 +21,8 @@ export interface NumberKeyboardProps {
|
|
|
21
21
|
onChangeText?: (value: string) => void;
|
|
22
22
|
/** Giá trị tối đa cho phép */
|
|
23
23
|
maxValue?: number;
|
|
24
|
+
/** Giá trị tối thiểu cho phép */
|
|
25
|
+
minValue?: number;
|
|
24
26
|
/** Loại input: integer hoặc float */
|
|
25
27
|
type?: "integer" | "float";
|
|
26
28
|
/** Số chữ số thập phân cho phép */
|
|
@@ -53,6 +55,7 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
53
55
|
label = "",
|
|
54
56
|
onChangeText,
|
|
55
57
|
maxValue = 999999999999,
|
|
58
|
+
minValue = 0,
|
|
56
59
|
type = "integer",
|
|
57
60
|
formatDecimal = 3,
|
|
58
61
|
visible,
|
|
@@ -63,6 +66,7 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
63
66
|
|
|
64
67
|
const [inputValue, setInputValue] = useState<string>(value?.toString() || "");
|
|
65
68
|
const [isFirstInput, setIsFirstInput] = useState<boolean>(true);
|
|
69
|
+
const [canSave, setCanSave] = useState<boolean>(true);
|
|
66
70
|
|
|
67
71
|
useEffect(() => {
|
|
68
72
|
if (visible) {
|
|
@@ -71,6 +75,16 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
71
75
|
}
|
|
72
76
|
}, [visible, value]);
|
|
73
77
|
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const currentValue = Number(inputValue);
|
|
80
|
+
const minValueNumber = Number(minValue);
|
|
81
|
+
setCanSave(
|
|
82
|
+
!isNaN(currentValue) &&
|
|
83
|
+
!isNaN(minValueNumber) &&
|
|
84
|
+
currentValue >= minValueNumber
|
|
85
|
+
);
|
|
86
|
+
}, [inputValue, minValue]);
|
|
87
|
+
|
|
74
88
|
const handleKeyPress = useCallback(
|
|
75
89
|
(key: string) => {
|
|
76
90
|
if (key === "del") {
|
|
@@ -81,7 +95,17 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
81
95
|
|
|
82
96
|
if (key === "000") {
|
|
83
97
|
if (type === "integer" && inputValue.length > 0) {
|
|
84
|
-
|
|
98
|
+
const newInputValue = inputValue + "000";
|
|
99
|
+
const newValue = Number(newInputValue);
|
|
100
|
+
const maxValueNumber = Number(maxValue);
|
|
101
|
+
|
|
102
|
+
if (
|
|
103
|
+
!isNaN(newValue) &&
|
|
104
|
+
!isNaN(maxValueNumber) &&
|
|
105
|
+
newValue <= maxValueNumber
|
|
106
|
+
) {
|
|
107
|
+
setInputValue(newInputValue);
|
|
108
|
+
}
|
|
85
109
|
setIsFirstInput(false);
|
|
86
110
|
}
|
|
87
111
|
return;
|
|
@@ -89,7 +113,6 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
89
113
|
|
|
90
114
|
if (key === ".") {
|
|
91
115
|
if (type === "float" && !inputValue.includes(".")) {
|
|
92
|
-
// Nếu inputValue là "0" hoặc rỗng, giữ lại số 0 và thêm dấu "."
|
|
93
116
|
if (inputValue === "0" || inputValue === "") {
|
|
94
117
|
setInputValue("0.");
|
|
95
118
|
} else {
|
|
@@ -106,6 +129,19 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
106
129
|
return;
|
|
107
130
|
}
|
|
108
131
|
|
|
132
|
+
// Kiểm tra nếu input bắt đầu bằng 0 và không có dấu chấm
|
|
133
|
+
if (inputValue === "0") {
|
|
134
|
+
if (key === ".") {
|
|
135
|
+
setInputValue("0.");
|
|
136
|
+
return;
|
|
137
|
+
} else if (key >= "1" && key <= "9") {
|
|
138
|
+
setInputValue(key);
|
|
139
|
+
return;
|
|
140
|
+
} else {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
109
145
|
const newInputValue = inputValue + key;
|
|
110
146
|
const newValue = Number(newInputValue);
|
|
111
147
|
const maxValueNumber = Number(maxValue);
|
|
@@ -133,18 +169,20 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
133
169
|
);
|
|
134
170
|
|
|
135
171
|
const handleClear = useCallback(() => {
|
|
136
|
-
setInputValue("
|
|
172
|
+
setInputValue("");
|
|
137
173
|
setIsFirstInput(true);
|
|
138
174
|
}, []);
|
|
139
175
|
|
|
140
176
|
const handleSave = useCallback(() => {
|
|
177
|
+
if (!canSave) return;
|
|
178
|
+
|
|
141
179
|
let finalValue = inputValue;
|
|
142
180
|
if (inputValue.endsWith(".")) {
|
|
143
181
|
finalValue = inputValue.slice(0, -1);
|
|
144
182
|
}
|
|
145
183
|
onChangeText?.(finalValue);
|
|
146
184
|
onClose();
|
|
147
|
-
}, [inputValue, onChangeText, onClose]);
|
|
185
|
+
}, [inputValue, onChangeText, onClose, canSave]);
|
|
148
186
|
|
|
149
187
|
const handleClose = useCallback(() => {
|
|
150
188
|
onClose();
|
|
@@ -169,10 +207,10 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
169
207
|
backgroundColor={colors.surfacePrimaryDefault}
|
|
170
208
|
style={styles.modalContent}
|
|
171
209
|
>
|
|
172
|
-
<Text style={styles.modalTitle}>{label}</Text>
|
|
210
|
+
<Text style={[styles.text18, styles.modalTitle]}>{label}</Text>
|
|
173
211
|
<View width={"100%"}>
|
|
174
212
|
<View paddingHorizontal={SPACE_40}>
|
|
175
|
-
<Text numberOfLines={1} style={styles.valueText}>
|
|
213
|
+
<Text numberOfLines={1} style={[styles.text30, styles.valueText]}>
|
|
176
214
|
{formatNumberInput(inputValue, formatDecimal) || "0"}
|
|
177
215
|
</Text>
|
|
178
216
|
</View>
|
|
@@ -216,6 +254,7 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
216
254
|
<Text
|
|
217
255
|
style={[
|
|
218
256
|
styles.keyText,
|
|
257
|
+
styles.text22,
|
|
219
258
|
key === "000" &&
|
|
220
259
|
type === "float" &&
|
|
221
260
|
styles.disabledKeyText,
|
|
@@ -238,7 +277,7 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
238
277
|
style={styles.actionButton}
|
|
239
278
|
onPress={handleClose}
|
|
240
279
|
>
|
|
241
|
-
<Text style={styles.actionText}>Đóng</Text>
|
|
280
|
+
<Text style={[styles.actionText, styles.text16]}>Đóng</Text>
|
|
242
281
|
</TouchableOpacity>
|
|
243
282
|
<Spacer
|
|
244
283
|
style={{ height: "100%" }}
|
|
@@ -251,7 +290,11 @@ const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
|
|
251
290
|
onPress={handleSave}
|
|
252
291
|
>
|
|
253
292
|
<Text
|
|
254
|
-
style={[
|
|
293
|
+
style={[
|
|
294
|
+
styles.actionText,
|
|
295
|
+
styles.text16,
|
|
296
|
+
{ color: colors.textBrandDefault },
|
|
297
|
+
]}
|
|
255
298
|
>
|
|
256
299
|
Lưu
|
|
257
300
|
</Text>
|
|
@@ -278,13 +321,11 @@ const styles = StyleSheet.create({
|
|
|
278
321
|
alignItems: "center",
|
|
279
322
|
},
|
|
280
323
|
modalTitle: {
|
|
281
|
-
fontSize: 18,
|
|
282
324
|
textAlign: "center",
|
|
283
325
|
marginTop: 16,
|
|
284
326
|
marginBottom: 8,
|
|
285
327
|
},
|
|
286
328
|
valueText: {
|
|
287
|
-
fontSize: 30,
|
|
288
329
|
textAlign: "center",
|
|
289
330
|
},
|
|
290
331
|
clearButton: {
|
|
@@ -311,7 +352,6 @@ const styles = StyleSheet.create({
|
|
|
311
352
|
height: 48,
|
|
312
353
|
},
|
|
313
354
|
keyText: {
|
|
314
|
-
fontSize: 22,
|
|
315
355
|
fontWeight: "500",
|
|
316
356
|
},
|
|
317
357
|
actionRow: {
|
|
@@ -327,7 +367,6 @@ const styles = StyleSheet.create({
|
|
|
327
367
|
paddingVertical: 12,
|
|
328
368
|
},
|
|
329
369
|
actionText: {
|
|
330
|
-
fontSize: 16,
|
|
331
370
|
fontWeight: "600",
|
|
332
371
|
},
|
|
333
372
|
disabledKey: {
|
|
@@ -38,7 +38,6 @@ export interface SelectionFieldProps extends TouchableOpacityProps {
|
|
|
38
38
|
textProps?: IText;
|
|
39
39
|
textColor?: string;
|
|
40
40
|
labelColor?: string;
|
|
41
|
-
size?: number;
|
|
42
41
|
textStyle?: TextStyle;
|
|
43
42
|
labelStyle?: TextStyle;
|
|
44
43
|
disabled?: boolean;
|
|
@@ -61,7 +60,6 @@ const SelectionField = ({
|
|
|
61
60
|
disabled = false,
|
|
62
61
|
textColor,
|
|
63
62
|
labelColor,
|
|
64
|
-
size = 16,
|
|
65
63
|
theme: themeOverrides,
|
|
66
64
|
required = false,
|
|
67
65
|
...props
|
|
@@ -138,7 +136,6 @@ const SelectionField = ({
|
|
|
138
136
|
<Text
|
|
139
137
|
numberOfLines={1}
|
|
140
138
|
color={getColor()}
|
|
141
|
-
size={size}
|
|
142
139
|
style={[disabled && disabledTextStyle, textStyle]}
|
|
143
140
|
{...textProps}
|
|
144
141
|
>
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import ScaleButton from "../ScaleButton";
|
|
25
25
|
import Text from "../Text";
|
|
26
26
|
import View from "../View";
|
|
27
|
-
import { useInternalTheme } from "
|
|
27
|
+
import { useInternalTheme } from "../../core/theming";
|
|
28
28
|
import { ThemeProp } from "../../types";
|
|
29
29
|
import Spacer from "../Spacer";
|
|
30
30
|
import Icon from "../Icon";
|
|
@@ -138,8 +138,18 @@ const TextInputNumber = ({
|
|
|
138
138
|
if (key === "del") {
|
|
139
139
|
setInputValue((prev) => prev.slice(0, -1));
|
|
140
140
|
} else if (key === "000") {
|
|
141
|
-
if (type === "integer"
|
|
142
|
-
|
|
141
|
+
if (type === "integer") {
|
|
142
|
+
const newInputValue = inputValue + "000";
|
|
143
|
+
const newValue = Number(newInputValue);
|
|
144
|
+
const maxValueNumber = Number(maxValue);
|
|
145
|
+
|
|
146
|
+
if (
|
|
147
|
+
!isNaN(newValue) &&
|
|
148
|
+
!isNaN(maxValueNumber) &&
|
|
149
|
+
newValue <= maxValueNumber
|
|
150
|
+
) {
|
|
151
|
+
setInputValue(newInputValue);
|
|
152
|
+
}
|
|
143
153
|
setIsFirstInput(false);
|
|
144
154
|
}
|
|
145
155
|
} else if (key === ".") {
|
|
@@ -157,6 +167,19 @@ const TextInputNumber = ({
|
|
|
157
167
|
setInputValue(key);
|
|
158
168
|
setIsFirstInput(false);
|
|
159
169
|
} else {
|
|
170
|
+
// Kiểm tra nếu input bắt đầu bằng 0 và không có dấu chấm
|
|
171
|
+
if (inputValue === "0") {
|
|
172
|
+
if (key === ".") {
|
|
173
|
+
setInputValue("0.");
|
|
174
|
+
return;
|
|
175
|
+
} else if (key >= "1" && key <= "9") {
|
|
176
|
+
setInputValue(key);
|
|
177
|
+
return;
|
|
178
|
+
} else {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
160
183
|
const newInputValue = inputValue + key;
|
|
161
184
|
const newValue = Number(newInputValue);
|
|
162
185
|
const maxValueNumber = Number(maxValue);
|
|
@@ -168,13 +191,13 @@ const TextInputNumber = ({
|
|
|
168
191
|
) {
|
|
169
192
|
if (inputValue.includes(".")) {
|
|
170
193
|
const [intPart, decimalPart = ""] = inputValue.split(".");
|
|
171
|
-
if (
|
|
194
|
+
if (newInputValue.length <= 12 && decimalPart.length === 0) {
|
|
172
195
|
setInputValue((prev) => prev + key);
|
|
173
|
-
} else if (decimalPart.length < 3) {
|
|
196
|
+
} else if (newInputValue.length <= 12 && decimalPart.length < 3) {
|
|
174
197
|
setInputValue((prev) => prev + key);
|
|
175
198
|
}
|
|
176
199
|
} else {
|
|
177
|
-
if (
|
|
200
|
+
if (newInputValue.length <= 12) {
|
|
178
201
|
setInputValue((prev) => prev + key);
|
|
179
202
|
}
|
|
180
203
|
}
|
|
@@ -246,7 +269,14 @@ const TextInputNumber = ({
|
|
|
246
269
|
borderRadius: BORDER_RADIUS_6,
|
|
247
270
|
},
|
|
248
271
|
|
|
249
|
-
[
|
|
272
|
+
[
|
|
273
|
+
styles.border,
|
|
274
|
+
{
|
|
275
|
+
borderColor: isShowModalKeyboard
|
|
276
|
+
? colors.borderBrandDefault
|
|
277
|
+
: colors.borderPrimaryDefault,
|
|
278
|
+
},
|
|
279
|
+
],
|
|
250
280
|
|
|
251
281
|
textError.length > 0 && [
|
|
252
282
|
{
|
|
@@ -379,10 +409,13 @@ const TextInputNumber = ({
|
|
|
379
409
|
backgroundColor={colors.surfacePrimaryDefault}
|
|
380
410
|
style={styles.modalContent}
|
|
381
411
|
>
|
|
382
|
-
<Text style={styles.modalTitle}>{label}</Text>
|
|
412
|
+
<Text style={[styles.modalTitle, styles.text18]}>{label}</Text>
|
|
383
413
|
<View width={"100%"}>
|
|
384
414
|
<View paddingHorizontal={SPACE_40}>
|
|
385
|
-
<Text
|
|
415
|
+
<Text
|
|
416
|
+
numberOfLines={1}
|
|
417
|
+
style={[styles.text30, styles.valueText]}
|
|
418
|
+
>
|
|
386
419
|
{formatNumberInput(inputValue, formatDecimal) || "0"}
|
|
387
420
|
</Text>
|
|
388
421
|
</View>
|
|
@@ -429,6 +462,7 @@ const TextInputNumber = ({
|
|
|
429
462
|
<Text
|
|
430
463
|
style={[
|
|
431
464
|
styles.keyText,
|
|
465
|
+
styles.text22,
|
|
432
466
|
key === "000" &&
|
|
433
467
|
type === "float" &&
|
|
434
468
|
styles.disabledKeyText,
|
|
@@ -451,7 +485,7 @@ const TextInputNumber = ({
|
|
|
451
485
|
style={styles.actionButton}
|
|
452
486
|
onPress={onCloseModalKeyboard}
|
|
453
487
|
>
|
|
454
|
-
<Text style={styles.actionText}>Đóng</Text>
|
|
488
|
+
<Text style={[styles.actionText, styles.text16]}>Đóng</Text>
|
|
455
489
|
</TouchableOpacity>
|
|
456
490
|
<Spacer
|
|
457
491
|
style={{
|
|
@@ -469,6 +503,7 @@ const TextInputNumber = ({
|
|
|
469
503
|
<Text
|
|
470
504
|
style={[
|
|
471
505
|
styles.actionText,
|
|
506
|
+
styles.text16,
|
|
472
507
|
{ color: colors.textBrandDefault },
|
|
473
508
|
!canSave && { color: colors.textSecondary },
|
|
474
509
|
]}
|
|
@@ -513,14 +548,12 @@ const styles = StyleSheet.create({
|
|
|
513
548
|
alignItems: "center",
|
|
514
549
|
},
|
|
515
550
|
modalTitle: {
|
|
516
|
-
fontSize: 18,
|
|
517
551
|
textAlign: "center",
|
|
518
552
|
marginTop: 16,
|
|
519
553
|
marginBottom: 8,
|
|
520
554
|
},
|
|
521
555
|
|
|
522
556
|
valueText: {
|
|
523
|
-
fontSize: 30,
|
|
524
557
|
textAlign: "center",
|
|
525
558
|
},
|
|
526
559
|
clearButton: {
|
|
@@ -547,7 +580,6 @@ const styles = StyleSheet.create({
|
|
|
547
580
|
height: 48,
|
|
548
581
|
},
|
|
549
582
|
keyText: {
|
|
550
|
-
fontSize: 22,
|
|
551
583
|
fontWeight: "500",
|
|
552
584
|
},
|
|
553
585
|
actionRow: {
|
|
@@ -563,7 +595,6 @@ const styles = StyleSheet.create({
|
|
|
563
595
|
paddingVertical: 12,
|
|
564
596
|
},
|
|
565
597
|
actionText: {
|
|
566
|
-
fontSize: 16,
|
|
567
598
|
fontWeight: "600",
|
|
568
599
|
},
|
|
569
600
|
disabledKey: {
|