Skip to content

Commit b2d7658

Browse files
committed
fix: round to correct precision when step uses exponential notation
1 parent 77b3442 commit b2d7658

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

packages/@react-stately/utils/src/number.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,18 @@ export function clamp(value: number, min: number = -Infinity, max: number = Infi
2020

2121
export function roundToStepPrecision(value: number, step: number): number {
2222
let roundedValue = value;
23+
let precision = 0;
2324
let stepString = step.toString();
2425
let pointIndex = stepString.indexOf('.');
25-
let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
26+
if (pointIndex >= 0) {
27+
precision = stepString.length - pointIndex;
28+
} else {
29+
// Handle negative exponents in exponential notation (e.g., "1e-7" → precision 8)
30+
let eIndex = stepString.toLowerCase().indexOf('e-');
31+
if (eIndex > 0) {
32+
precision = Math.abs(Number(stepString.slice(eIndex + 1))) + 1;
33+
}
34+
}
2635
if (precision > 0) {
2736
let pow = Math.pow(10, precision);
2837
roundedValue = Math.round(roundedValue * pow) / pow;

packages/@react-stately/utils/test/number.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {clamp, snapValueToStep} from '../src/number';
1+
import {clamp, roundToStepPrecision, snapValueToStep} from '../src/number';
22

33
describe('number utils', () => {
44
describe('clamp', () => {
@@ -8,6 +8,30 @@ describe('number utils', () => {
88
});
99
});
1010

11+
describe('roundToStepPrecision', () => {
12+
it('should return the input unchanged for integer steps', () => {
13+
expect(roundToStepPrecision(7.123, 1)).toBe(7.123);
14+
expect(roundToStepPrecision(5, 10)).toBe(5);
15+
});
16+
it('should round to the correct decimal places for steps with decimals', () => {
17+
expect(roundToStepPrecision(1.24, 0.1)).toBe(1.24);
18+
expect(roundToStepPrecision(1.456, 0.01)).toBe(1.456);
19+
// Should not overcount precision
20+
expect(roundToStepPrecision(2.349, 0.100)).toBe(2.35);
21+
expect(roundToStepPrecision(2.35, 0.100)).toBe(2.35);
22+
// Should handle negative values
23+
expect(roundToStepPrecision(-1.456, 0.01)).toBe(-1.456);
24+
// Should handle zero value
25+
expect(roundToStepPrecision(0, 0.01)).toBe(0);
26+
});
27+
it('should handle rounding for exponential step values', () => {
28+
expect(roundToStepPrecision(0.123456789, 1e-3)).toBe(0.1235);
29+
expect(roundToStepPrecision(0.123456789, 1e-7)).toBe(0.12345679);
30+
// Should handle exponential notation steps regardless of e/E case
31+
expect(roundToStepPrecision(0.123456789, 1E-8)).toBe(0.123456789);
32+
});
33+
});
34+
1135
describe('snapValueToStep', () => {
1236
it('should snap value to nearest step based on min and max', () => {
1337
expect(snapValueToStep(2, -0.5, 100, 3)).toBe(2.5);

0 commit comments

Comments
 (0)