From 634177705783d2e874290868e35d76f8811f465d Mon Sep 17 00:00:00 2001 From: Fabrice Francois Date: Tue, 30 Jan 2024 06:26:05 -0500 Subject: [PATCH] refactor increment/decrement logic; review changes --- .../input/inputNumber/inputNumber.test.tsx | 44 +++---- .../input/inputNumber/inputNumber.tsx | 115 ++++-------------- 2 files changed, 40 insertions(+), 119 deletions(-) diff --git a/src/components/input/inputNumber/inputNumber.test.tsx b/src/components/input/inputNumber/inputNumber.test.tsx index b57750730..72fba2a87 100644 --- a/src/components/input/inputNumber/inputNumber.test.tsx +++ b/src/components/input/inputNumber/inputNumber.test.tsx @@ -72,24 +72,16 @@ describe(' component', () => { }); it('should return the maximum when the newly generated value exceeds the maximum', () => { - const max = '5'; - const step = '2'; + const max = 5; + const step = 2; const value = '4'; - testIncrementLogic({ max, step, value, expectedValue: max }); - }); - - it('should increment to the minimum when the newly generated value is less than the minimum', () => { - const max = '5'; - const min = '0'; - const step = '2'; - const value = '-7'; - testIncrementLogic({ max, min, step, value, expectedValue: min }); + testIncrementLogic({ max, step, value, expectedValue: max.toString() }); }); it('should increment by floating point value when the step is a float', () => { - const value = 1; + const value = '1'; const step = 0.5; - testIncrementLogic({ step, value, expectedValue: (value + step).toString() }); + testIncrementLogic({ step, value, expectedValue: (Number(value) + step).toString() }); }); it('should round down to the nearest multiple of the step before incrementing by the step value', () => { @@ -98,18 +90,11 @@ describe(' component', () => { testIncrementLogic({ step, value, expectedValue: '1.2' }); }); - it('should increment to the minimum when the newly generated increment value is less than the minimum', () => { - const value = '0'; - const step = '1'; - const min = '5'; - testIncrementLogic({ step, value, min, expectedValue: min }); - }); - it('should increment to the minimum when no value is provided', () => { const step = 6; - const min = '5'; + const min = 5; const max = 10; - testIncrementLogic({ step, min, max, expectedValue: min }); + testIncrementLogic({ step, min, max, expectedValue: min.toString() }); }); }); @@ -141,29 +126,28 @@ describe(' component', () => { }; it('should decrement by step', () => { - const value = 10; + const value = '10'; const step = 2; const expectedValue = (10 - 2).toString(); testDecrementLogic({ value, step, expectedValue }); }); - it('should not decrement when the value is less than the minimum', () => { - const value = '-1'; + it('should decrement to the minimum when no value provided', () => { const step = 2; const min = 1; - testDecrementLogic({ value, step, min, expectedValue: value }); + testDecrementLogic({ step, min, expectedValue: min.toString() }); }); it('should decrement to maximum if the initial value minus the step is greater than the maximum', () => { - const value = 100; + const value = '100'; const step = 2; const min = 1; - const max = '50'; - testDecrementLogic({ value, step, min, max, expectedValue: max }); + const max = 50; + testDecrementLogic({ value, step, min, max, expectedValue: max.toString() }); }); it('should decrement to the closest multiple of the step smaller than the value', () => { - const value = 10; + const value = '10'; const step = 3; testDecrementLogic({ value, step, expectedValue: '9' }); }); diff --git a/src/components/input/inputNumber/inputNumber.tsx b/src/components/input/inputNumber/inputNumber.tsx index ed922308f..6cfad1275 100644 --- a/src/components/input/inputNumber/inputNumber.tsx +++ b/src/components/input/inputNumber/inputNumber.tsx @@ -6,7 +6,14 @@ import { IconType } from '../../icon'; import { useInputProps, useNumberMask, type IUseNumberMaskProps } from '../hooks'; import { InputContainer, type IInputComponentProps } from '../inputContainer'; -export interface IInputNumberProps extends Omit { +export interface IInputNumberProps extends Omit { + min?: number; + max?: number; + step?: number; + /** + * The value of the number input. + */ + value?: string | number; /** * Optional string appended to the input value. */ @@ -18,23 +25,21 @@ export interface IInputNumberProps extends Omit = (props) => { - const { suffix, onChange, ...otherProps } = props; + const { + suffix, + onChange, + max = Number.MAX_SAFE_INTEGER, + min = Number.MIN_SAFE_INTEGER, + step: inputStep = 1, + value, + ...otherProps + } = props; + + const step = inputStep <= 0 ? 1 : inputStep; const { containerProps, inputProps } = useInputProps(otherProps); const { className: containerClassName, isDisabled, ...otherContainerProps } = containerProps; - const { - max: inputMax, - min: inputMin, - step: inputStep, - value: inputValue, - onBlur, - onFocus, - onKeyDown, - className: inputClassName, - ...otherInputProps - } = inputProps; - - const { step, min, max, value } = parseInputs(inputValue, inputStep, inputMin, inputMax); + const { onBlur, onFocus, onKeyDown, className: inputClassName, ...otherInputProps } = inputProps; const [isFocused, setIsFocused] = useState(false); const { @@ -74,51 +79,24 @@ export const InputNumber: React.FC = (props) => { const handleIncrement = () => { const parsedValue = Number(unmaskedValue ?? 0); - // return the input value if it's bigger than the max - if (parsedValue > max) { - setValue(parsedValue.toString()); - return; - } - // increment directly to the minimum if value is less than the minimum if (parsedValue < min) { setValue(min.toString()); return; } - // round down to the nearest multiple of the step when the value - // is not already a multiple of the step - let newValue = parsedValue + step; - if (parsedValue % step !== 0) { - newValue = Math.floor(parsedValue / step) * step; - } + // ensure value is multiple of step + const newValue = (Math.floor(parsedValue / step) + 1) * step; - // increment value with step if it's smaller than the initial value - if (newValue < parsedValue) { - newValue += step; - } - - // ensure the new value is within the min and max range - newValue = Math.max(min, Math.min(max, newValue)); - setValue(newValue.toString()); + // ensure the new value is than the + setValue(Math.min(max, newValue).toString()); }; const handleDecrement = () => { const parsedValue = Number(unmaskedValue ?? 0); - // if the current value is less than the min, don't decrement - if (parsedValue < min) { - setValue(parsedValue.toString()); - } - // decrement value by the step - let newValue = parsedValue - step; - - // if the value is not a multiple of the step, - // decrement to the biggest multiple of the step that is less than the value - if (parsedValue % step !== 0) { - newValue = Math.floor(parsedValue / step) * step; - } + let newValue = parsedValue % step !== 0 ? Math.floor(parsedValue / step) * step : parsedValue - step; // ensure the new value is within the min and max range newValue = Math.max(min, Math.min(max, newValue)); @@ -126,11 +104,7 @@ export const InputNumber: React.FC = (props) => { }; return ( - + {!isDisabled && (