Skip to content

Commit ff8a1d6

Browse files
committed
fix(utils): Update getPercentage to optionally not throw errors
1 parent 05ec620 commit ff8a1d6

File tree

5 files changed

+130
-32
lines changed

5 files changed

+130
-32
lines changed

packages/form/src/slider/utils.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,19 @@ export const getDragPercentage = ({
248248
let thumb1Percentage =
249249
dragging && draggingIndex === 0
250250
? dragValue
251-
: getPercentage(min, max, thumb1Value);
251+
: getPercentage({
252+
min,
253+
max,
254+
value: thumb1Value,
255+
});
252256

253257
let thumb2Percentage: number | undefined;
254258
if (typeof thumb2Value === "number") {
255-
const percentage = getPercentage(min, max, thumb2Value);
259+
const percentage = getPercentage({
260+
min,
261+
max,
262+
value: thumb2Value,
263+
});
256264
thumb1Percentage = Math.min(thumb1Percentage, percentage);
257265
thumb2Percentage =
258266
dragging && draggingIndex === 1

packages/progress/src/CircularProgress.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export const CircularProgress = forwardRef<
110110
) {
111111
let progress: number | undefined;
112112
if (typeof value === "number") {
113-
progress = getPercentage(min, max, value);
113+
progress = getPercentage({ min, max, value });
114114
}
115115

116116
const svgStyle = useMemo<CSSProperties | undefined>(() => {

packages/progress/src/LinearProgress.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const LinearProgress = forwardRef<HTMLSpanElement, LinearProgressProps>(
7676

7777
let progress: number | undefined;
7878
if (typeof value === "number") {
79-
progress = getPercentage(min, max, value);
79+
progress = getPercentage({ min, max, value });
8080
}
8181
const barStyle = useMemo(() => {
8282
if (typeof progress !== "number") {
Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,95 @@
1-
import { getPercentage } from "../getPercentage";
1+
import { getPercentage, GetPercentageOptions } from "../getPercentage";
22

33
describe("getPercentage", () => {
44
it("should throw a RangeError if the min is greater than the max", () => {
55
const expected = new RangeError(
66
"A range must have the min value less than the max value"
77
);
8-
expect(() => getPercentage(0, -100, 0)).toThrow(expected);
9-
expect(() => getPercentage(0, 0, 0)).toThrow(expected);
10-
expect(() => getPercentage(0, -100, 20)).toThrow(expected);
11-
expect(() => getPercentage(0, 0, 20)).toThrow(expected);
8+
const options1: GetPercentageOptions = {
9+
min: 0,
10+
max: -100,
11+
value: 0,
12+
};
13+
const options2: GetPercentageOptions = {
14+
min: 0,
15+
max: 0,
16+
value: 0,
17+
};
18+
const options3: GetPercentageOptions = {
19+
min: 0,
20+
max: -100,
21+
value: 20,
22+
};
23+
const options4: GetPercentageOptions = {
24+
min: 0,
25+
max: 0,
26+
value: 20,
27+
};
28+
expect(() => getPercentage(options1)).toThrow(expected);
29+
expect(() => getPercentage(options2)).toThrow(expected);
30+
expect(() => getPercentage(options3)).toThrow(expected);
31+
expect(() => getPercentage(options4)).toThrow(expected);
32+
expect(() => getPercentage({ ...options1, validate: false })).not.toThrow(
33+
expected
34+
);
35+
expect(() => getPercentage({ ...options2, validate: false })).not.toThrow(
36+
expected
37+
);
38+
expect(() => getPercentage({ ...options3, validate: false })).not.toThrow(
39+
expected
40+
);
41+
expect(() => getPercentage({ ...options4, validate: false })).not.toThrow(
42+
expected
43+
);
1244
});
1345

1446
it("should throw a RangeError if the value is not between the min anx max", () => {
1547
const expected = new RangeError(
1648
"A value must be between the min and max values"
1749
);
18-
expect(() => getPercentage(0, 100, -1)).toThrow(expected);
19-
expect(() => getPercentage(0, 1, -1)).toThrow(expected);
20-
expect(() => getPercentage(0, 1, -0.5)).toThrow(expected);
50+
const options1: GetPercentageOptions = {
51+
min: 0,
52+
max: 100,
53+
value: -1,
54+
};
55+
const options2: GetPercentageOptions = {
56+
min: 0,
57+
max: 1,
58+
value: -1,
59+
};
60+
const options3: GetPercentageOptions = {
61+
min: 0,
62+
max: 1,
63+
value: -0.5,
64+
};
65+
66+
expect(() => getPercentage(options1)).toThrow(expected);
67+
expect(() => getPercentage(options2)).toThrow(expected);
68+
expect(() => getPercentage(options3)).toThrow(expected);
69+
expect(() => getPercentage({ ...options1, validate: false })).not.toThrow(
70+
expected
71+
);
72+
expect(() => getPercentage({ ...options2, validate: false })).not.toThrow(
73+
expected
74+
);
75+
expect(() => getPercentage({ ...options3, validate: false })).not.toThrow(
76+
expected
77+
);
2178
});
2279

2380
it("should return the value as a decimal between 0 and 1 representing the current percentage", () => {
24-
expect(getPercentage(0, 100, 20)).toBe(0.2);
25-
expect(getPercentage(0, 10, 3)).toBe(0.3);
26-
expect(getPercentage(0, 1, 0.5)).toBe(0.5);
81+
expect(getPercentage({ min: 0, max: 100, value: 20 })).toBe(0.2);
82+
expect(getPercentage({ min: 0, max: 10, value: 3 })).toBe(0.3);
83+
expect(getPercentage({ min: 0, max: 1, value: 0.5 })).toBe(0.5);
2784
});
2885

2986
it("should always return a positive percentage", () => {
30-
expect(getPercentage(-100, 0, -20)).toBe(0.8);
31-
expect(getPercentage(-10, 0, -3)).toBe(0.7);
32-
expect(getPercentage(-1, 0, -0.5)).toBe(0.5);
87+
expect(getPercentage({ min: -100, max: 0, value: -20 })).toBe(0.8);
88+
expect(getPercentage({ min: -10, max: 0, value: -3 })).toBe(0.7);
89+
expect(getPercentage({ min: -1, max: 0, value: -0.5 })).toBe(0.5);
3390

34-
expect(getPercentage(-100, 100, 0)).toBe(0.5);
35-
expect(getPercentage(-100, 0, 0)).toBe(1);
36-
expect(getPercentage(-100, 0, -25)).toBe(0.75);
91+
expect(getPercentage({ min: -100, max: 100, value: 0 })).toBe(0.5);
92+
expect(getPercentage({ min: -100, max: 0, value: 0 })).toBe(1);
93+
expect(getPercentage({ min: -100, max: 0, value: -25 })).toBe(0.75);
3794
});
3895
});

packages/utils/src/getPercentage.ts

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
1+
/** @remarks \@since 4.0.1 */
2+
export interface GetPercentageOptions {
3+
/**
4+
* The min value allowed.
5+
*/
6+
min: number;
7+
8+
/**
9+
* The max value allowed.
10+
*/
11+
max: number;
12+
13+
/**
14+
* The current value
15+
*/
16+
value: number;
17+
18+
/**
19+
* Boolean if the min, max, and value options should be validated to make sure
20+
* they are within the correct range relative to each other.
21+
*
22+
* @defaultValue `true`
23+
*/
24+
validate?: boolean;
25+
}
26+
127
/**
228
* Gets the current percentage based on the min, max, and current value.
329
*
4-
* @param min - the min value
5-
* @param max - the max value
6-
* @param value - the current value to compare against
730
* @returns the percentage that the `value` is between the `min` and `max`
831
* values.
32+
* @internal
33+
* @remarks \@since 4.0.1 uses an object for options instead of multiple
34+
* arguments.
935
*/
10-
export function getPercentage(min: number, max: number, value: number): number {
11-
if (min >= max) {
12-
throw new RangeError(
13-
"A range must have the min value less than the max value"
14-
);
15-
}
36+
export function getPercentage({
37+
min,
38+
max,
39+
value,
40+
validate = true,
41+
}: GetPercentageOptions): number {
42+
if (validate) {
43+
if (min >= max) {
44+
throw new RangeError(
45+
"A range must have the min value less than the max value"
46+
);
47+
}
1648

17-
if (value > max || value < min) {
18-
throw new RangeError("A value must be between the min and max values");
49+
if (value > max || value < min) {
50+
throw new RangeError("A value must be between the min and max values");
51+
}
1952
}
2053

2154
const range = max - min;

0 commit comments

Comments
 (0)