Skip to content

Commit 01535cf

Browse files
authored
fix(input, input-number): no longer removes trailing decimal separator (#7159)
**Related Issue:** #7039 ## Summary This PR will allow trailing decimal separator while user is editing the input value in `calcite-input` & `calcite-input-number` Before the Change: - If the user removes the `1` value from `0.00001` , the input will be sanitized and the new value will be `0` - If the user removes the `1` value from `0.1` , the input will be sanitized and the new value will be `0` After the Change: - If the user removes the `1` value from `0.01` , the input value will be `0.0` - If the user removes the `1` value from `0.1` , the input value will be `0.`
1 parent 122f142 commit 01535cf

File tree

6 files changed

+354
-23
lines changed

6 files changed

+354
-23
lines changed

packages/calcite-components/src/components/input-number/input-number.e2e.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,35 @@ describe("calcite-input-number", () => {
899899
expect(Number(await element.getProperty("value"))).toBe(195);
900900
});
901901

902+
it("allows deleting exponentail number from decimal and adding trailing zeros", async () => {
903+
const page = await newE2EPage();
904+
await page.setContent(html`<calcite-input-number></calcite-input-number>`);
905+
906+
const calciteInput = await page.find("calcite-input-number");
907+
const input = await page.find("calcite-input-number >>> input");
908+
await calciteInput.callMethod("setFocus");
909+
await page.waitForChanges();
910+
await typeNumberValue(page, "2.100e10");
911+
await page.waitForChanges();
912+
expect(await calciteInput.getProperty("value")).toBe("2.1e10");
913+
expect(await input.getProperty("value")).toBe("2.1e10");
914+
915+
await page.keyboard.press("Backspace");
916+
await page.waitForChanges();
917+
expect(await calciteInput.getProperty("value")).toBe("2.1e1");
918+
expect(await input.getProperty("value")).toBe("2.1e1");
919+
920+
await page.keyboard.press("Backspace");
921+
await page.waitForChanges();
922+
expect(await calciteInput.getProperty("value")).toBe("2.1");
923+
expect(await input.getProperty("value")).toBe("2.1");
924+
925+
await page.keyboard.type("000");
926+
await page.waitForChanges();
927+
expect(await calciteInput.getProperty("value")).toBe("2.1000");
928+
expect(await input.getProperty("value")).toBe("2.1000");
929+
});
930+
902931
it("disallows typing non-numeric characters with shift modifier key down", async () => {
903932
const page = await newE2EPage();
904933
await page.setContent(html`<calcite-input-number></calcite-input-number>`);
@@ -1114,6 +1143,80 @@ describe("calcite-input-number", () => {
11141143
expect(await calciteInput.getProperty("value")).toBe(assertedValue);
11151144
expect(await internalLocaleInput.getProperty("value")).toBe(numberStringFormatter.localize(assertedValue));
11161145
});
1146+
1147+
it(`should be able to append values after Backspace for ${locale} locale`, async () => {
1148+
const page = await newE2EPage();
1149+
await page.setContent(`
1150+
<calcite-input-number lang="${locale}"></calcite-input-number>
1151+
`);
1152+
1153+
numberStringFormatter.numberFormatOptions = {
1154+
locale,
1155+
numberingSystem: "latn",
1156+
useGrouping: false
1157+
};
1158+
const decimalSeparator = numberStringFormatter.decimal;
1159+
const calciteInput = await page.find("calcite-input-number");
1160+
const input = await page.find("calcite-input-number >>> input");
1161+
await calciteInput.callMethod("setFocus");
1162+
await typeNumberValue(page, `0${decimalSeparator}0000`);
1163+
await page.waitForChanges();
1164+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0000`);
1165+
1166+
await page.keyboard.press("Backspace");
1167+
await typeNumberValue(page, "1");
1168+
await page.waitForChanges();
1169+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0001`);
1170+
1171+
await typeNumberValue(page, "01");
1172+
await page.waitForChanges();
1173+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}000101`);
1174+
});
1175+
1176+
it(`should keep leading decimal separator while input is focused on Backspace ${locale} locale `, async () => {
1177+
const page = await newE2EPage();
1178+
await page.setContent(`
1179+
<calcite-input-number lang="${locale}"></calcite-input-number>
1180+
`);
1181+
1182+
numberStringFormatter.numberFormatOptions = {
1183+
locale,
1184+
numberingSystem: "latn",
1185+
useGrouping: false
1186+
};
1187+
const decimalSeparator = numberStringFormatter.decimal;
1188+
const calciteInput = await page.find("calcite-input-number");
1189+
const input = await page.find("calcite-input-number >>> input");
1190+
await calciteInput.callMethod("setFocus");
1191+
await typeNumberValue(page, `0${decimalSeparator}01`);
1192+
await page.waitForChanges();
1193+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}01`);
1194+
1195+
await page.keyboard.press("Backspace");
1196+
await page.waitForChanges();
1197+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0`);
1198+
1199+
await page.keyboard.press("Backspace");
1200+
await page.waitForChanges();
1201+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}`);
1202+
1203+
await typeNumberValue(page, "01");
1204+
await page.waitForChanges();
1205+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}01`);
1206+
});
1207+
1208+
it(`should sanitize leading decimal zeros on initial render ${locale} locale`, async () => {
1209+
const page = await newE2EPage();
1210+
await page.setContent(html`<calcite-input-number value="0.0000" lang="${locale}"></calcite-input-number>`);
1211+
1212+
numberStringFormatter.numberFormatOptions = {
1213+
locale,
1214+
numberingSystem: "latn",
1215+
useGrouping: false
1216+
};
1217+
const input = await page.find("calcite-input-number >>> input");
1218+
expect(await input.getProperty("value")).toBe("0");
1219+
});
11171220
});
11181221
});
11191222

@@ -1373,7 +1476,7 @@ describe("calcite-input-number", () => {
13731476

13741477
await page.keyboard.press("Backspace");
13751478
await page.waitForChanges();
1376-
expect(await element.getProperty("value")).toBe("1");
1479+
expect(await element.getProperty("value")).toBe("1.");
13771480
expect(calciteInputNumberInput).toHaveReceivedEventTimes(1);
13781481
});
13791482

packages/calcite-components/src/components/input-number/input-number.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ import {
4242
} from "../../utils/loadable";
4343
import {
4444
connectLocalized,
45-
defaultNumberingSystem,
4645
disconnectLocalized,
4746
LocalizedComponent,
4847
NumberingSystem,
4948
numberStringFormatter
5049
} from "../../utils/locale";
5150
import {
51+
addLocalizedTrailingDecimalZeros,
5252
BigDecimal,
5353
isValidNumber,
5454
parseNumberString,
@@ -840,12 +840,11 @@ export class InputNumber
840840
useGrouping: this.groupSeparator
841841
};
842842

843-
const sanitizedValue = sanitizeNumberString(
844-
// no need to delocalize a string that ia already in latn numerals
845-
(this.numberingSystem && this.numberingSystem !== "latn") || defaultNumberingSystem !== "latn"
846-
? numberStringFormatter.delocalize(value)
847-
: value
848-
);
843+
const isValueDeleted =
844+
this.previousValue?.length > value.length || this.value?.length > value.length;
845+
const hasTrailingDecimalSeparator = value.charAt(value.length - 1) === ".";
846+
const sanitizedValue =
847+
hasTrailingDecimalSeparator && isValueDeleted ? value : sanitizeNumberString(value);
849848

850849
const newValue =
851850
value && !sanitizedValue
@@ -854,8 +853,21 @@ export class InputNumber
854853
: ""
855854
: sanitizedValue;
856855

857-
const newLocalizedValue = numberStringFormatter.localize(newValue);
858-
this.localizedValue = newLocalizedValue;
856+
let newLocalizedValue = numberStringFormatter.localize(newValue);
857+
858+
if (origin !== "connected" && !hasTrailingDecimalSeparator) {
859+
newLocalizedValue = addLocalizedTrailingDecimalZeros(
860+
newLocalizedValue,
861+
newValue,
862+
numberStringFormatter
863+
);
864+
}
865+
866+
// adds localized trailing decimal separator
867+
this.localizedValue =
868+
hasTrailingDecimalSeparator && isValueDeleted
869+
? `${newLocalizedValue}${numberStringFormatter.decimal}`
870+
: newLocalizedValue;
859871

860872
this.setPreviousNumberValue(previousValue ?? this.value);
861873
this.previousValueOrigin = origin;

packages/calcite-components/src/components/input/input.e2e.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,35 @@ describe("calcite-input", () => {
10551055
expect(Number(await element.getProperty("value"))).toBe(195);
10561056
});
10571057

1058+
it("allows deleting exponentail number from decimal and adding trailing zeros", async () => {
1059+
const page = await newE2EPage();
1060+
await page.setContent(html`<calcite-input type="number"></calcite-input>`);
1061+
1062+
const calciteInput = await page.find("calcite-input");
1063+
const input = await page.find("calcite-input >>> input");
1064+
await calciteInput.callMethod("setFocus");
1065+
await page.waitForChanges();
1066+
await typeNumberValue(page, "2.100e10");
1067+
await page.waitForChanges();
1068+
expect(await calciteInput.getProperty("value")).toBe("2.1e10");
1069+
expect(await input.getProperty("value")).toBe("2.1e10");
1070+
1071+
await page.keyboard.press("Backspace");
1072+
await page.waitForChanges();
1073+
expect(await calciteInput.getProperty("value")).toBe("2.1e1");
1074+
expect(await input.getProperty("value")).toBe("2.1e1");
1075+
1076+
await page.keyboard.press("Backspace");
1077+
await page.waitForChanges();
1078+
expect(await calciteInput.getProperty("value")).toBe("2.1");
1079+
expect(await input.getProperty("value")).toBe("2.1");
1080+
1081+
await page.keyboard.type("000");
1082+
await page.waitForChanges();
1083+
expect(await calciteInput.getProperty("value")).toBe("2.1000");
1084+
expect(await input.getProperty("value")).toBe("2.1000");
1085+
});
1086+
10581087
it("disallows typing any non-numeric characters with shift modifier key down", async () => {
10591088
const page = await newE2EPage();
10601089
await page.setContent(html`<calcite-input type="number"></calcite-input>`);
@@ -1291,6 +1320,80 @@ describe("calcite-input", () => {
12911320
expect(await calciteInput.getProperty("value")).toBe(assertedValue);
12921321
expect(await internalLocaleInput.getProperty("value")).toBe(localizedValue);
12931322
});
1323+
1324+
it(`should be able to append values after Backspace for ${locale} locale`, async () => {
1325+
const page = await newE2EPage();
1326+
await page.setContent(`
1327+
<calcite-input lang="${locale}" type="number"></calcite-input>
1328+
`);
1329+
1330+
numberStringFormatter.numberFormatOptions = {
1331+
locale,
1332+
numberingSystem: "latn",
1333+
useGrouping: false
1334+
};
1335+
const decimalSeparator = numberStringFormatter.decimal;
1336+
const calciteInput = await page.find("calcite-input");
1337+
const input = await page.find("calcite-input >>> input");
1338+
await calciteInput.callMethod("setFocus");
1339+
await typeNumberValue(page, `0${decimalSeparator}0000`);
1340+
await page.waitForChanges();
1341+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0000`);
1342+
1343+
await page.keyboard.press("Backspace");
1344+
await typeNumberValue(page, "1");
1345+
await page.waitForChanges();
1346+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0001`);
1347+
1348+
await typeNumberValue(page, "01");
1349+
await page.waitForChanges();
1350+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}000101`);
1351+
});
1352+
1353+
it(`should keep leading decimal separator while input is focused on Backspace ${locale} locale `, async () => {
1354+
const page = await newE2EPage();
1355+
await page.setContent(`
1356+
<calcite-input lang="${locale}" type="number"></calcite-input>
1357+
`);
1358+
1359+
numberStringFormatter.numberFormatOptions = {
1360+
locale,
1361+
numberingSystem: "latn",
1362+
useGrouping: false
1363+
};
1364+
const decimalSeparator = numberStringFormatter.decimal;
1365+
const calciteInput = await page.find("calcite-input");
1366+
const input = await page.find("calcite-input >>> input");
1367+
await calciteInput.callMethod("setFocus");
1368+
await typeNumberValue(page, `0${decimalSeparator}01`);
1369+
await page.waitForChanges();
1370+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}01`);
1371+
1372+
await page.keyboard.press("Backspace");
1373+
await page.waitForChanges();
1374+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}0`);
1375+
1376+
await page.keyboard.press("Backspace");
1377+
await page.waitForChanges();
1378+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}`);
1379+
1380+
await typeNumberValue(page, "01");
1381+
await page.waitForChanges();
1382+
expect(await input.getProperty("value")).toBe(`0${decimalSeparator}01`);
1383+
});
1384+
1385+
it(`should sanitize leading decimal zeros on initial render ${locale} locale`, async () => {
1386+
const page = await newE2EPage();
1387+
await page.setContent(html`<calcite-input value="0.0000" lang="${locale}" type="number"></calcite-input>`);
1388+
1389+
numberStringFormatter.numberFormatOptions = {
1390+
locale,
1391+
numberingSystem: "latn",
1392+
useGrouping: false
1393+
};
1394+
const input = await page.find("calcite-input >>> input");
1395+
expect(await input.getProperty("value")).toBe("0");
1396+
});
12941397
});
12951398
});
12961399

@@ -1551,7 +1654,7 @@ describe("calcite-input", () => {
15511654

15521655
await page.keyboard.press("Backspace");
15531656
await page.waitForChanges();
1554-
expect(await element.getProperty("value")).toBe("1");
1657+
expect(await element.getProperty("value")).toBe("1.");
15551658
expect(calciteInputInput).toHaveReceivedEventTimes(1);
15561659
});
15571660

packages/calcite-components/src/components/input/input.tsx

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ import {
4242
} from "../../utils/loadable";
4343
import {
4444
connectLocalized,
45-
defaultNumberingSystem,
4645
disconnectLocalized,
4746
LocalizedComponent,
4847
NumberingSystem,
4948
numberStringFormatter
5049
} from "../../utils/locale";
5150

5251
import {
52+
addLocalizedTrailingDecimalZeros,
5353
BigDecimal,
5454
isValidNumber,
5555
parseNumberString,
@@ -975,13 +975,11 @@ export class Input
975975
signDisplay: "never"
976976
};
977977

978-
const sanitizedValue = sanitizeNumberString(
979-
// no need to delocalize a string that ia already in latn numerals
980-
(this.numberingSystem && this.numberingSystem !== "latn") ||
981-
defaultNumberingSystem !== "latn"
982-
? numberStringFormatter.delocalize(value)
983-
: value
984-
);
978+
const isValueDeleted =
979+
this.previousValue?.length > value.length || this.value?.length > value.length;
980+
const hasTrailingDecimalSeparator = value.charAt(value.length - 1) === ".";
981+
const sanitizedValue =
982+
hasTrailingDecimalSeparator && isValueDeleted ? value : sanitizeNumberString(value);
985983

986984
const newValue =
987985
value && !sanitizedValue
@@ -990,8 +988,21 @@ export class Input
990988
: ""
991989
: sanitizedValue;
992990

993-
const newLocalizedValue = numberStringFormatter.localize(newValue);
994-
this.localizedValue = newLocalizedValue;
991+
let newLocalizedValue = numberStringFormatter.localize(newValue);
992+
993+
if (origin !== "connected" && !hasTrailingDecimalSeparator) {
994+
newLocalizedValue = addLocalizedTrailingDecimalZeros(
995+
newLocalizedValue,
996+
newValue,
997+
numberStringFormatter
998+
);
999+
}
1000+
1001+
// adds localized trailing decimal separator
1002+
this.localizedValue =
1003+
hasTrailingDecimalSeparator && isValueDeleted
1004+
? `${newLocalizedValue}${numberStringFormatter.decimal}`
1005+
: newLocalizedValue;
9951006

9961007
this.userChangedValue = origin === "user" && this.value !== newValue;
9971008
// don't sanitize the start of negative/decimal numbers, but

0 commit comments

Comments
 (0)