@canutin/svelte-currency-input 1.1.0 → 1.1.2
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/currency-input.svelte +246 -348
- package/dist/utils/parseAbbrValue.js +10 -1
- package/package.json +1 -1
|
@@ -1,351 +1,249 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const stringValueWithoutSeparator = decimalSeparator
|
|
249
|
-
? newValue.replace(decimalSeparator, '.')
|
|
250
|
-
: newValue;
|
|
251
|
-
|
|
252
|
-
const numberValue = parseFloat(stringValueWithoutSeparator);
|
|
253
|
-
|
|
254
|
-
const formattedValue = formatValue({
|
|
255
|
-
...formatValueOptions,
|
|
256
|
-
value: newValue
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
if (formatValueOnBlur) {
|
|
260
|
-
stateValue = formattedValue;
|
|
261
|
-
value = newValue;
|
|
262
|
-
|
|
263
|
-
const values: CurrencyInputValues = {
|
|
264
|
-
float: numberValue,
|
|
265
|
-
formatted: formattedValue,
|
|
266
|
-
value: newValue
|
|
267
|
-
};
|
|
268
|
-
onchangevalue?.(values);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
dirty = false;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function handleKeyDown(event: KeyboardEvent): void {
|
|
275
|
-
const { key } = event;
|
|
276
|
-
|
|
277
|
-
lastKeyStroke = key;
|
|
278
|
-
|
|
279
|
-
if (step && (key === 'ArrowUp' || key === 'ArrowDown')) {
|
|
280
|
-
event.preventDefault();
|
|
281
|
-
cursor = stateValue.length;
|
|
282
|
-
|
|
283
|
-
const stringValueWithoutSeparator =
|
|
284
|
-
decimalSeparator && value ? value.replace(decimalSeparator, '.') : value;
|
|
285
|
-
|
|
286
|
-
const currentValue =
|
|
287
|
-
parseFloat(
|
|
288
|
-
stringValueWithoutSeparator != null && stringValueWithoutSeparator !== ''
|
|
289
|
-
? stringValueWithoutSeparator
|
|
290
|
-
: cleanValue({ value: stateValue, ...cleanValueOptions })
|
|
291
|
-
) || 0;
|
|
292
|
-
const newValue = key === 'ArrowUp' ? currentValue + step : currentValue - step;
|
|
293
|
-
|
|
294
|
-
if ((min !== undefined && newValue < min) || (!allowNegativeValue && newValue < 0)) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (max !== undefined && newValue > max) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const fixedLength = String(step).includes('.')
|
|
303
|
-
? Number(String(step).split('.')[1].length)
|
|
304
|
-
: undefined;
|
|
305
|
-
|
|
306
|
-
processChange(
|
|
307
|
-
String(fixedLength ? newValue.toFixed(fixedLength) : newValue).replace(
|
|
308
|
-
'.',
|
|
309
|
-
decimalSeparator
|
|
310
|
-
)
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function handleKeyUp(event: KeyboardEvent): void {
|
|
316
|
-
const { key } = event;
|
|
317
|
-
const target = event.currentTarget as HTMLInputElement;
|
|
318
|
-
const { selectionStart } = target;
|
|
319
|
-
|
|
320
|
-
if (key !== 'ArrowUp' && key !== 'ArrowDown' && stateValue !== '-') {
|
|
321
|
-
const suffixValue = getSuffix(stateValue, { groupSeparator, decimalSeparator });
|
|
322
|
-
|
|
323
|
-
if (
|
|
324
|
-
suffixValue &&
|
|
325
|
-
selectionStart &&
|
|
326
|
-
selectionStart > stateValue.length - suffixValue.length
|
|
327
|
-
) {
|
|
328
|
-
if (ref) {
|
|
329
|
-
const newCursor = stateValue.length - suffixValue.length;
|
|
330
|
-
ref.setSelectionRange(newCursor, newCursor);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
let displayValue = $derived.by(() => {
|
|
337
|
-
if (stateValue === '-' || stateValue === decimalSeparator) {
|
|
338
|
-
return stateValue;
|
|
339
|
-
}
|
|
340
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
341
|
-
return formatValue({
|
|
342
|
-
...formatValueOptions,
|
|
343
|
-
decimalScale: dirty ? undefined : decimalScale,
|
|
344
|
-
value: String(value)
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
return stateValue;
|
|
348
|
-
});
|
|
1
|
+
<script lang="ts">import {
|
|
2
|
+
isNumber,
|
|
3
|
+
cleanValue,
|
|
4
|
+
fixedDecimalValue,
|
|
5
|
+
formatValue,
|
|
6
|
+
getLocaleConfig,
|
|
7
|
+
padTrimValue,
|
|
8
|
+
getSuffix,
|
|
9
|
+
repositionCursor
|
|
10
|
+
} from "./utils/index";
|
|
11
|
+
let {
|
|
12
|
+
value = $bindable(""),
|
|
13
|
+
intlConfig,
|
|
14
|
+
prefix: userPrefix,
|
|
15
|
+
suffix: userSuffix,
|
|
16
|
+
decimalSeparator: _decimalSeparator,
|
|
17
|
+
groupSeparator: _groupSeparator,
|
|
18
|
+
allowDecimals = true,
|
|
19
|
+
decimalsLimit,
|
|
20
|
+
decimalScale,
|
|
21
|
+
fixedDecimalLength,
|
|
22
|
+
allowNegativeValue = true,
|
|
23
|
+
min,
|
|
24
|
+
max,
|
|
25
|
+
maxLength: userMaxLength,
|
|
26
|
+
step,
|
|
27
|
+
disableGroupSeparators = false,
|
|
28
|
+
disableAbbreviations = false,
|
|
29
|
+
formatValueOnBlur = true,
|
|
30
|
+
transformRawValue,
|
|
31
|
+
oninputvalue,
|
|
32
|
+
onchangevalue,
|
|
33
|
+
ref = $bindable(null),
|
|
34
|
+
...restProps
|
|
35
|
+
} = $props();
|
|
36
|
+
$effect(() => {
|
|
37
|
+
if (_decimalSeparator && isNumber(_decimalSeparator)) {
|
|
38
|
+
throw new Error("decimalSeparator cannot be a number");
|
|
39
|
+
}
|
|
40
|
+
if (_groupSeparator && isNumber(_groupSeparator)) {
|
|
41
|
+
throw new Error("groupSeparator cannot be a number");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
let localeConfig = $derived(getLocaleConfig(intlConfig));
|
|
45
|
+
let decimalSeparator = $derived(_decimalSeparator || localeConfig.decimalSeparator || "");
|
|
46
|
+
let groupSeparator = $derived(_groupSeparator || localeConfig.groupSeparator || "");
|
|
47
|
+
let prefix = $derived(userPrefix ?? localeConfig.prefix);
|
|
48
|
+
let suffix = $derived(userSuffix ?? "");
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (decimalSeparator && groupSeparator && decimalSeparator === groupSeparator && disableGroupSeparators === false) {
|
|
51
|
+
throw new Error("decimalSeparator cannot be the same as groupSeparator");
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
let formatValueOptions = $derived({
|
|
55
|
+
decimalSeparator,
|
|
56
|
+
groupSeparator,
|
|
57
|
+
disableGroupSeparators,
|
|
58
|
+
intlConfig,
|
|
59
|
+
prefix,
|
|
60
|
+
suffix
|
|
61
|
+
});
|
|
62
|
+
let cleanValueOptions = $derived({
|
|
63
|
+
decimalSeparator,
|
|
64
|
+
groupSeparator,
|
|
65
|
+
allowDecimals,
|
|
66
|
+
decimalsLimit: decimalsLimit ?? fixedDecimalLength ?? 2,
|
|
67
|
+
allowNegativeValue,
|
|
68
|
+
disableAbbreviations,
|
|
69
|
+
prefix,
|
|
70
|
+
transformRawValue
|
|
71
|
+
});
|
|
72
|
+
let stateValue = $state("");
|
|
73
|
+
let dirty = $state(false);
|
|
74
|
+
let cursor = $state(0);
|
|
75
|
+
let changeCount = $state(0);
|
|
76
|
+
let lastKeyStroke = $state(null);
|
|
77
|
+
$effect(() => {
|
|
78
|
+
if (stateValue === "-" || decimalSeparator && stateValue === decimalSeparator) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
82
|
+
const formatted = formatValue({
|
|
83
|
+
...formatValueOptions,
|
|
84
|
+
decimalScale: dirty ? void 0 : decimalScale,
|
|
85
|
+
value: String(value)
|
|
86
|
+
});
|
|
87
|
+
if (!dirty) {
|
|
88
|
+
stateValue = formatted;
|
|
89
|
+
}
|
|
90
|
+
} else if (!dirty) {
|
|
91
|
+
stateValue = "";
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
$effect(() => {
|
|
95
|
+
if (dirty && stateValue !== "-" && ref && document.activeElement === ref) {
|
|
96
|
+
ref.setSelectionRange(cursor, cursor);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
function processChange(inputValue, selectionStart) {
|
|
100
|
+
dirty = true;
|
|
101
|
+
const { modifiedValue, cursorPosition } = repositionCursor({
|
|
102
|
+
selectionStart,
|
|
103
|
+
value: inputValue,
|
|
104
|
+
lastKeyStroke,
|
|
105
|
+
stateValue,
|
|
106
|
+
groupSeparator
|
|
107
|
+
});
|
|
108
|
+
const stringValue = cleanValue({ value: modifiedValue, ...cleanValueOptions });
|
|
109
|
+
if (userMaxLength && stringValue.replace(/-/g, "").length > userMaxLength) {
|
|
110
|
+
if (ref) {
|
|
111
|
+
ref.value = stateValue;
|
|
112
|
+
const cursorPos = Math.min(selectionStart ?? 0, stateValue.length);
|
|
113
|
+
ref.setSelectionRange(cursorPos, cursorPos);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (stringValue === "" || stringValue === "-" || stringValue === decimalSeparator) {
|
|
118
|
+
value = "";
|
|
119
|
+
stateValue = stringValue;
|
|
120
|
+
cursor = 1;
|
|
121
|
+
if (ref) {
|
|
122
|
+
ref.value = stringValue;
|
|
123
|
+
ref.setSelectionRange(cursor, cursor);
|
|
124
|
+
}
|
|
125
|
+
const values2 = { float: null, formatted: "", value: "" };
|
|
126
|
+
oninputvalue?.(values2);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const stringValueWithoutSeparator = decimalSeparator ? stringValue.replace(decimalSeparator, ".") : stringValue;
|
|
130
|
+
const numberValue = parseFloat(stringValueWithoutSeparator);
|
|
131
|
+
const formattedValue = formatValue({
|
|
132
|
+
value: stringValue,
|
|
133
|
+
...formatValueOptions
|
|
134
|
+
});
|
|
135
|
+
let newCursor = cursorPosition ?? formattedValue.length;
|
|
136
|
+
if (cursorPosition != null) {
|
|
137
|
+
newCursor = cursorPosition + (formattedValue.length - inputValue.length);
|
|
138
|
+
newCursor = newCursor <= 0 ? prefix ? prefix.length : 0 : newCursor;
|
|
139
|
+
}
|
|
140
|
+
cursor = newCursor;
|
|
141
|
+
changeCount = changeCount + 1;
|
|
142
|
+
stateValue = formattedValue;
|
|
143
|
+
value = stringValue;
|
|
144
|
+
if (ref) {
|
|
145
|
+
ref.value = formattedValue;
|
|
146
|
+
ref.setSelectionRange(cursor, cursor);
|
|
147
|
+
}
|
|
148
|
+
const values = {
|
|
149
|
+
float: numberValue,
|
|
150
|
+
formatted: formattedValue,
|
|
151
|
+
value: stringValue
|
|
152
|
+
};
|
|
153
|
+
oninputvalue?.(values);
|
|
154
|
+
}
|
|
155
|
+
function handleInput(event) {
|
|
156
|
+
const target = event.target;
|
|
157
|
+
const { value: inputValue, selectionStart } = target;
|
|
158
|
+
processChange(inputValue, selectionStart);
|
|
159
|
+
}
|
|
160
|
+
function handleBlur(event) {
|
|
161
|
+
const target = event.target;
|
|
162
|
+
const { value: inputValue } = target;
|
|
163
|
+
const valueOnly = cleanValue({ value: inputValue, ...cleanValueOptions });
|
|
164
|
+
if (valueOnly === "-" || valueOnly === decimalSeparator || !valueOnly) {
|
|
165
|
+
stateValue = "";
|
|
166
|
+
value = "";
|
|
167
|
+
dirty = false;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const fixedDecimals = fixedDecimalValue(valueOnly, decimalSeparator, fixedDecimalLength);
|
|
171
|
+
const newValue = padTrimValue(
|
|
172
|
+
fixedDecimals,
|
|
173
|
+
decimalSeparator,
|
|
174
|
+
decimalScale !== void 0 ? decimalScale : fixedDecimalLength
|
|
175
|
+
);
|
|
176
|
+
const stringValueWithoutSeparator = decimalSeparator ? newValue.replace(decimalSeparator, ".") : newValue;
|
|
177
|
+
const numberValue = parseFloat(stringValueWithoutSeparator);
|
|
178
|
+
const formattedValue = formatValue({
|
|
179
|
+
...formatValueOptions,
|
|
180
|
+
value: newValue
|
|
181
|
+
});
|
|
182
|
+
if (formatValueOnBlur) {
|
|
183
|
+
stateValue = formattedValue;
|
|
184
|
+
value = newValue;
|
|
185
|
+
const values = {
|
|
186
|
+
float: numberValue,
|
|
187
|
+
formatted: formattedValue,
|
|
188
|
+
value: newValue
|
|
189
|
+
};
|
|
190
|
+
onchangevalue?.(values);
|
|
191
|
+
}
|
|
192
|
+
dirty = false;
|
|
193
|
+
}
|
|
194
|
+
function handleKeyDown(event) {
|
|
195
|
+
const { key } = event;
|
|
196
|
+
lastKeyStroke = key;
|
|
197
|
+
if (step && (key === "ArrowUp" || key === "ArrowDown")) {
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
cursor = stateValue.length;
|
|
200
|
+
const stringValueWithoutSeparator = decimalSeparator && value ? value.replace(decimalSeparator, ".") : value;
|
|
201
|
+
const currentValue = parseFloat(
|
|
202
|
+
stringValueWithoutSeparator != null && stringValueWithoutSeparator !== "" ? stringValueWithoutSeparator : cleanValue({ value: stateValue, ...cleanValueOptions })
|
|
203
|
+
) || 0;
|
|
204
|
+
const newValue = key === "ArrowUp" ? currentValue + step : currentValue - step;
|
|
205
|
+
if (min !== void 0 && newValue < min || !allowNegativeValue && newValue < 0) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (max !== void 0 && newValue > max) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const fixedLength = String(step).includes(".") ? Number(String(step).split(".")[1].length) : void 0;
|
|
212
|
+
processChange(
|
|
213
|
+
String(fixedLength ? newValue.toFixed(fixedLength) : newValue).replace(
|
|
214
|
+
".",
|
|
215
|
+
decimalSeparator
|
|
216
|
+
)
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function handleKeyUp(event) {
|
|
221
|
+
const { key } = event;
|
|
222
|
+
const target = event.currentTarget;
|
|
223
|
+
const { selectionStart } = target;
|
|
224
|
+
if (key !== "ArrowUp" && key !== "ArrowDown" && stateValue !== "-") {
|
|
225
|
+
const suffixValue = getSuffix(stateValue, { groupSeparator, decimalSeparator });
|
|
226
|
+
if (suffixValue && selectionStart && selectionStart > stateValue.length - suffixValue.length) {
|
|
227
|
+
if (ref) {
|
|
228
|
+
const newCursor = stateValue.length - suffixValue.length;
|
|
229
|
+
ref.setSelectionRange(newCursor, newCursor);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
let displayValue = $derived.by(() => {
|
|
235
|
+
if (stateValue === "-" || stateValue === decimalSeparator) {
|
|
236
|
+
return stateValue;
|
|
237
|
+
}
|
|
238
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
239
|
+
return formatValue({
|
|
240
|
+
...formatValueOptions,
|
|
241
|
+
decimalScale: dirty ? void 0 : decimalScale,
|
|
242
|
+
value: String(value)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return stateValue;
|
|
246
|
+
});
|
|
349
247
|
</script>
|
|
350
248
|
|
|
351
249
|
<input
|
|
@@ -17,7 +17,16 @@ export const parseAbbrValue = (value, decimalSeparator = '.') => {
|
|
|
17
17
|
if (match) {
|
|
18
18
|
const [, digits, , abbr] = match;
|
|
19
19
|
const multiplier = abbrMap[abbr.toLowerCase()];
|
|
20
|
-
|
|
20
|
+
const result = Number(digits.replace(decimalSeparator, '.')) * multiplier;
|
|
21
|
+
// Round based on input precision to avoid floating-point errors
|
|
22
|
+
// e.g. 4.1 * 1000000 = 4099999.9999999995 should become 4100000
|
|
23
|
+
// but 1.12345678 * 1000 = 1123.45678 should preserve all decimals
|
|
24
|
+
const decimalPart = digits.split(decimalSeparator)[1] || '';
|
|
25
|
+
const inputDecimals = decimalPart.length;
|
|
26
|
+
const multiplierZeros = Math.log10(multiplier);
|
|
27
|
+
const resultDecimals = Math.max(0, inputDecimals - multiplierZeros);
|
|
28
|
+
const precision = Math.pow(10, resultDecimals);
|
|
29
|
+
return Math.round(result * precision) / precision;
|
|
21
30
|
}
|
|
22
31
|
return undefined;
|
|
23
32
|
};
|