-
Notifications
You must be signed in to change notification settings - Fork 80
fix(input, input-number): increment/decrement unsafe numbers without loss of precision #6580
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
Changes from 11 commits
09e8307
4ab1bd5
81cdff0
f659eb9
e3c746f
da95105
7cddcac
e7897be
c062ee3
b4f7544
1a95696
7c2ac43
32cc977
0c2e026
19ca244
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 |
---|---|---|
|
@@ -44,8 +44,13 @@ import { | |
NumberingSystem, | ||
numberStringFormatter | ||
} from "../../utils/locale"; | ||
import { decimalPlaces } from "../../utils/math"; | ||
import { isValidNumber, parseNumberString, sanitizeNumberString } from "../../utils/number"; | ||
|
||
import { | ||
BigDecimal, | ||
isValidNumber, | ||
parseNumberString, | ||
sanitizeNumberString | ||
} from "../../utils/number"; | ||
import { createObserver } from "../../utils/observers"; | ||
import { CSS_UTILITY } from "../../utils/resources"; | ||
import { | ||
|
@@ -610,26 +615,32 @@ export class Input | |
nativeEvent: KeyboardEvent | MouseEvent | ||
): void { | ||
const { value } = this; | ||
const adjustment = direction === "up" ? 1 : -1; | ||
const inputStep = this.step === "any" ? 1 : Math.abs(this.step || 1); | ||
const inputVal = value && value !== "" ? parseFloat(value) : 0; | ||
const inputVal = new BigDecimal(value !== "" ? value : "0"); | ||
const nudgedValue = inputVal.add(`${inputStep * adjustment}`); | ||
|
||
const adjustment = direction === "up" ? 1 : -1; | ||
const nudgedValue = inputVal + inputStep * adjustment; | ||
const finalValue = | ||
typeof inputMin === "number" && !isNaN(inputMin) && nudgedValue < inputMin | ||
? inputMin | ||
: typeof inputMax === "number" && !isNaN(inputMax) && nudgedValue > inputMax | ||
? inputMax | ||
: nudgedValue; | ||
const nudgedValueBelowInputMin = | ||
typeof inputMin === "number" && | ||
!isNaN(inputMin) && | ||
nudgedValue.subtract(`${inputMin}`).isNegative; | ||
|
||
const nudgedValueAboveInputMax = | ||
typeof inputMax === "number" && | ||
!isNaN(inputMax) && | ||
!nudgedValue.subtract(`${inputMax}`).isNegative; | ||
|
||
const inputValPlaces = decimalPlaces(inputVal); | ||
const inputStepPlaces = decimalPlaces(inputStep); | ||
const finalValue = nudgedValueBelowInputMin | ||
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. Suggestion: can this be refactored to compute and evaluate a nudged value check at a time? It's currently computing two values where one might possibly be thrown away. |
||
? `${inputMin}` | ||
: nudgedValueAboveInputMax | ||
? `${inputMax}` | ||
: nudgedValue.toString(); | ||
|
||
this.setValue({ | ||
committing: true, | ||
nativeEvent, | ||
origin: "user", | ||
value: finalValue.toFixed(Math.max(inputValPlaces, inputStepPlaces)) | ||
value: finalValue | ||
}); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -863,7 +863,7 @@ export class Slider | |
return; | ||
} | ||
event.preventDefault(); | ||
const fixedDecimalAdjustment = Number(adjustment.toFixed(decimalPlaces(step))); | ||
const fixedDecimalAdjustment = Number(adjustment.toFixed(decimalPlaces(`${step}`))); | ||
this.setValue({ | ||
[activeProp as SetValueProperty]: this.clamp(fixedDecimalAdjustment, activeProp) | ||
}); | ||
|
@@ -1200,7 +1200,7 @@ export class Slider | |
const percent = (x - left) / width; | ||
const mirror = this.shouldMirror(); | ||
const clampedValue = this.clamp(this.min + range * (mirror ? 1 - percent : percent)); | ||
let value = Number(clampedValue.toFixed(decimalPlaces(this.step))); | ||
let value = Number(clampedValue.toFixed(decimalPlaces(`${this.step}`))); | ||
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 this fixes precision on the slider, can you update the PR title to reflect this? If it's to fix types, can you submit this in a separate PR? If it's the latter, we can merge the separate PR first and we can skip rolling it back here. 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. The parameter needs to be a string so the decimalPlaces function can also be used with BigDecimal. Previously 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. Nevermind, Input isn't using decimalPlaces anymore, removing! |
||
if (this.snap && this.step) { | ||
value = this.getClosestStep(value); | ||
} | ||
|
@@ -1214,10 +1214,10 @@ export class Slider | |
* @internal | ||
*/ | ||
private getClosestStep(num: number): number { | ||
num = Number(this.clamp(num).toFixed(decimalPlaces(this.step))); | ||
num = Number(this.clamp(num).toFixed(decimalPlaces(`${this.step}`))); | ||
if (this.step) { | ||
const step = Math.round(num / this.step) * this.step; | ||
num = Number(this.clamp(step).toFixed(decimalPlaces(this.step))); | ||
num = Number(this.clamp(step).toFixed(decimalPlaces(`${this.step}`))); | ||
} | ||
return num; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,8 @@ describe("calcite-tooltip", () => { | |
/** | ||
* Helps assert the canceled Esc key press when closing tooltips | ||
* Must be called before the tooltip is closed via keyboard. | ||
* | ||
* @param page | ||
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. Can you roll this file back? I think it was auto-fixed by the linter, but the file is unrelated to this PR. |
||
*/ | ||
async function setUpEscapeKeyCancelListener(page: E2EPage): Promise<void> { | ||
await page.evaluate(() => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
export const clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(value, max)); | ||
|
||
export const decimalPlaces = (value: number): number => { | ||
const match = ("" + value).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); | ||
const decimalNumberRegex = new RegExp(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); | ||
|
||
export const decimalPlaces = (value: string): number => { | ||
const match = value.match(decimalNumberRegex); | ||
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. Suggestion: would 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. We need to use the values of the match a couple lines down |
||
if (!match) { | ||
return 0; | ||
} | ||
|
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.
✨🏆✨