diff --git a/packages/dial-slider/src/utils/dial-slider/ring-math.ts b/packages/dial-slider/src/utils/dial-slider/ring-math.ts index 837687d..d61755d 100644 --- a/packages/dial-slider/src/utils/dial-slider/ring-math.ts +++ b/packages/dial-slider/src/utils/dial-slider/ring-math.ts @@ -3,7 +3,10 @@ interface Point { y: number; } -/** Bipolar fill: + side vs maxValue, − side vs |minValue|. */ +/** + * Progress away from the neutral value. Neutral is zero when it is in range, + * otherwise the nearest range boundary. + */ export function getBipolarProgress( value: number, minValue: number, @@ -20,12 +23,18 @@ export function getBipolarProgress( const min = Math.min(minValue, maxValue); const max = Math.max(minValue, maxValue); const clampedValue = Math.min(max, Math.max(min, value)); - if (clampedValue >= 0) { - return max <= 0 ? 0 : Math.min(Math.max(clampedValue / max, 0), 1); + const neutral = Math.min(max, Math.max(min, 0)); + + if (clampedValue >= neutral) { + const positiveRange = max - neutral; + return positiveRange <= 0 + ? 0 + : Math.min(Math.max((clampedValue - neutral) / positiveRange, 0), 1); } - return min >= 0 + const negativeRange = neutral - min; + return negativeRange <= 0 ? 0 - : Math.min(Math.max(Math.abs(clampedValue) / Math.abs(min), 0), 1); + : Math.min(Math.max((neutral - clampedValue) / negativeRange, 0), 1); } export function getSignedProgressColor( diff --git a/packages/dial-slider/tests/ring-math.test.ts b/packages/dial-slider/tests/ring-math.test.ts index 9e823c5..81f9dd5 100644 --- a/packages/dial-slider/tests/ring-math.test.ts +++ b/packages/dial-slider/tests/ring-math.test.ts @@ -13,6 +13,16 @@ describe('preset progress ring', () => { expect(getBipolarProgress(0, -100, 100)).toBe(0); }); + test('starts one-sided ranges at their nearest-to-zero boundary', () => { + expect(getBipolarProgress(10, 10, 20)).toBe(0); + expect(getBipolarProgress(15, 10, 20)).toBe(0.5); + expect(getBipolarProgress(20, 10, 20)).toBe(1); + + expect(getBipolarProgress(-10, -20, -10)).toBe(0); + expect(getBipolarProgress(-15, -20, -10)).toBe(0.5); + expect(getBipolarProgress(-20, -20, -10)).toBe(1); + }); + test('clamps progress and safely rejects non-finite configuration', () => { expect(getBipolarProgress(500, -100, 100)).toBe(1); expect(getBipolarProgress(-500, -100, 100)).toBe(1);