Extract NumberStepControl

This commit is contained in:
araemer 2025-10-21 07:54:13 +02:00
parent f980d4d86d
commit 13fe0ee852
4 changed files with 134 additions and 83 deletions

View file

@ -0,0 +1,74 @@
import {Minus, Plus} from "lucide-react";
import {defaultIconSize} from "./SvgIcon.tsx";
type NumberStepControlProps = {
/** Current numeric value */
value: number;
/** Callback when value changes */
onChange: (newValue: number) => void;
/** Optional: minimum allowed value */
min?: number;
/** Optional: maximum allowed value */
max?: number;
/** Optional: step increment (default = 1) */
step?: number;
/** Optional: additional Tailwind classes */
className?: string;
};
/**
* A compact number input with +/ buttons.
* Removes native browser spinners and supports min/max limits.
*/
export function NumberStepControl({
value,
onChange,
min = Number.NEGATIVE_INFINITY,
max = Number.POSITIVE_INFINITY,
step = 1,
className = "",
}: NumberStepControlProps) {
const handleDecrease = () => {
const newValue = Math.max(value - step, min);
onChange(newValue);
};
const handleIncrease = () => {
const newValue = Math.min(value + step, max);
onChange(newValue);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const num = Number(e.target.value);
if (!isNaN(num)) onChange(Math.min(Math.max(num, min), max));
};
return (
<div className={`flex items-center gap-2 ${className}`}>
<button
type="button"
onClick={handleDecrease}
className="circular-container primary-button-bg"
>
<Minus size={defaultIconSize}/>
</button>
<input
type="text"
inputMode="numeric"
pattern="[0-9]*"
value={value}
onChange={handleInputChange}
className="w-16 text-center input-field"
/>
<button
type="button"
onClick={handleIncrease}
className="circular-container primary-button-bg"
>
<Plus size={defaultIconSize}/>
</button>
</div>
);
}