-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(input, input-number): no longer removes trailing decimal separator #7159
Changes from 13 commits
59b5a85
4613212
f241c17
387db5b
54b7143
5d6f507
c6a1e71
cffe278
1c60d07
eacde2d
c447239
7a0480a
87f15d7
63dff04
d06003b
6751aaa
688b98a
f7b9f94
43b3075
cd4a3ac
98c86d4
ce04bab
ecbc697
fbc3831
de31f7c
05b771c
c507400
4a57130
dfc9311
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,7 @@ import { | |
numberStringFormatter | ||
} from "../../utils/locale"; | ||
import { | ||
addLocalizedTrailingDecimalZeros, | ||
BigDecimal, | ||
isValidNumber, | ||
parseNumberString, | ||
|
@@ -840,12 +841,22 @@ export class InputNumber | |
useGrouping: this.groupSeparator | ||
}; | ||
|
||
const sanitizedValue = sanitizeNumberString( | ||
// no need to delocalize a string that ia already in latn numerals | ||
(this.numberingSystem && this.numberingSystem !== "latn") || defaultNumberingSystem !== "latn" | ||
? numberStringFormatter.delocalize(value) | ||
: value | ||
); | ||
const isValueDeleted = | ||
this.previousValue?.length > value.length || this.value?.length > value.length; | ||
|
||
const hasTrailingDecimalSeparator = | ||
value.charAt(value.length - 1) === numberStringFormatter.decimal; | ||
|
||
const sanitizedValue = | ||
hasTrailingDecimalSeparator && isValueDeleted | ||
? value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason why the value doesn't need to be delocalized when there is a trailing 0 and it is a delete action? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i assume you are referring to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the value is already delocalized by then, we could remove the delocalization a couple lines down right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think so, it was added here . When removed , all the tests are passing which is a good sign. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure it is already delocalized in all cases? (e.g. typing, pasting, and setting the value via JS?)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup, while typing or pasting InputNumberInput handler will delocalize the strings. For setting the value via JS, i don't think users can parse non latin number values which sounds strange tbh. I guess it is intentional to avoid localization twice. |
||
: sanitizeNumberString( | ||
// no need to delocalize a string that ia already in latn numerals | ||
(this.numberingSystem && this.numberingSystem !== "latn") || | ||
defaultNumberingSystem !== "latn" | ||
? numberStringFormatter.delocalize(value) | ||
: value | ||
); | ||
|
||
const newValue = | ||
value && !sanitizedValue | ||
|
@@ -854,8 +865,26 @@ export class InputNumber | |
: "" | ||
: sanitizedValue; | ||
|
||
const newLocalizedValue = numberStringFormatter.localize(newValue); | ||
this.localizedValue = newLocalizedValue; | ||
let newLocalizedValue = numberStringFormatter.localize(newValue); | ||
|
||
// adds localized trailing decimal zero values | ||
if ( | ||
newLocalizedValue.length !== newValue.length && | ||
origin !== "connected" && | ||
!hasTrailingDecimalSeparator | ||
) { | ||
newLocalizedValue = addLocalizedTrailingDecimalZeros( | ||
newLocalizedValue, | ||
newValue, | ||
numberStringFormatter | ||
); | ||
} | ||
|
||
// adds localized trailing decimal separator | ||
this.localizedValue = | ||
hasTrailingDecimalSeparator && isValueDeleted | ||
? `${newLocalizedValue}${numberStringFormatter.decimal}` | ||
: newLocalizedValue; | ||
|
||
this.setPreviousNumberValue(previousValue ?? this.value); | ||
this.previousValueOrigin = origin; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -137,14 +137,27 @@ export const sanitizeNumberString = (numberString: string): string => | |
.replace(allHyphensExceptTheStart, "") | ||
.replace(decimalOnlyAtEndOfString, "") | ||
.replace(allLeadingZerosOptionallyNegative, "$1"); | ||
|
||
return isValidNumber(sanitizedValue) | ||
? isNegativeDecimalOnlyZeros.test(sanitizedValue) | ||
? sanitizedValue | ||
: new BigDecimal(sanitizedValue).toString() | ||
: getBigDecimalAsString(sanitizedValue) | ||
: nonExpoNumString; | ||
}); | ||
|
||
export function getBigDecimalAsString(sanitizedValue: string): string { | ||
const decimals = sanitizedValue.split(".")[1]; | ||
const newdecimals = new BigDecimal(sanitizedValue).toString().split(".")[1]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: const bigDecimalValue = new BigDecimal(sanitizedValue).toString()
const newDecimals = bigDecimalValue.split(".")[1] And then you can return |
||
|
||
// adds back trailing decimal zeros | ||
if (decimals && !newdecimals && BigInt(decimals) === BigInt(0) && decimals !== newdecimals) { | ||
const value = new BigDecimal(sanitizedValue).toString() + "."; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const value = `${bigDecimalValue}.` |
||
const newvalue = value.padEnd(value.length + decimals.length, "0"); | ||
return newvalue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: we can skip the extra memory allocation required by declaring return value.padEnd(value.length + decimals.length, "0"); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been more conscious about overworking our garbage collectors after seeing the results of their strike in France. |
||
} | ||
|
||
return new BigDecimal(sanitizedValue).toString(); | ||
} | ||
|
||
export function sanitizeExponentialNumberString(numberString: string, func: (s: string) => string): string { | ||
if (!numberString) { | ||
return numberString; | ||
|
@@ -217,3 +230,33 @@ export function expandExponentialNumberString(numberString: string): string { | |
function stringContainsNumbers(string: string): boolean { | ||
return numberKeys.some((number) => string.includes(number)); | ||
} | ||
|
||
/** | ||
* Adds localized trailing decimals zero values to the number string. | ||
* BigInt conversion to string removes the trailing decimal zero values (Ex: 1.000 is returned as 1). This method helps adding them back. | ||
* | ||
* @param {string} localizedValue - localized number string value | ||
* @param {string} value - current value in the input field | ||
* @param {NumberStringFormat} numberStringFormatter - numberStringFormatter instance to localize the number value | ||
* @returns {string} localized number string value | ||
*/ | ||
export function addLocalizedTrailingDecimalZeros( | ||
localizedValue: string, | ||
value: string, | ||
formatter: NumberStringFormat | ||
): string { | ||
let localizedDecimals; | ||
const decimalSeparator = formatter.decimal; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: this line can be moved into the if statement |
||
if (localizedValue.includes(decimalSeparator)) { | ||
localizedDecimals = localizedValue.split(".")[1]; | ||
} | ||
const decimals = value.split(".")[1]; | ||
|
||
if (decimals && localizedDecimals !== decimals) { | ||
localizedValue = localizedValue + decimalSeparator; | ||
[...decimals].forEach((decimal) => { | ||
localizedValue += formatter.localize(decimal); | ||
}); | ||
} | ||
return localizedValue; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is a bit confusing to me. Is it only for adding trailing 0s? If so, then why is it iterating over all of the initial value's decimal places and concat'ing them to the localizedValue? For example value is would this function return Also, can you use template literals instead of concatenating and add some unit tests for this function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Example of changing the concat'ing to template literals is this: if (decimals && localizedDecimals !== decimals) {
localizedValue = localizedValue + decimalSeparator;
[...decimals].forEach((decimal) => {
localizedValue += formatter.localize(decimal);
});
}
return localizedValue; to something like: return decimals && localizedDecimals !== decimals
? `${localizedValue}${decimalSeparator}${Array.from(decimals)
.map((d) => formatter.localize(d))
.join("")}`
: localizedValue; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, it is supposed to add only trailing zeros since those are the ones that are trimmed off during localization and sanitization. Great catch and i agree that iteration can be avoided and didn't factored in numbering systems like french There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To clarify, the template literals vs string concatenation thing is about weirdness with RTL langauges. Other than that the two snippets above are pretty much the same. I just used |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the component's value should still be
1
. You will need to go into the shadowRoot and check the value of the internal input to verify it is1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind that is what you were doing it was other input tests failing. I need read closer before opening my big mouth lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no problem. The issues with other tests is the immutation of
localizedValue
when the user tries to delete the decimal part. The logic applies even if the user is typing out a value like0.05
. By the time user types0.0
the validation is happening hence changing the localizedValue to0
again. Current logic in default branch avoids this by not changing thelocalizedValue
variable until the user inputs a valid value which allows users to type the value of their without any auto correction.Trying to figure out a reliable way to identify if the user is adding a value in the input field or deleting the value so that we can apply the logic only for deletion case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha.
Some potential options for investigation:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i was using the second option which is not feasible with
inputEvent
. i had to create a combination of above. Realized there was an another bug with the input when the user has leading0
's in the decimal. If the user deletes the2
in0.00002
then the value becomes0
which is similar to #7039 . I tried adding those trailing zero's back in the decimal but the localize method is removing them too. We may have to follow similar technique of adding back those zeros like we did for decimal separator.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or we can refactor this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the input lifecycle methods will probably need a refactor. Once you start doing crazy stuff like this to fix bugs you know you've gone too far lol.