stud-manager / components /NumberInput.tsx
dvc890's picture
Upload 53 files
842b4cd verified
import React from 'react';
import { Minus, Plus } from 'lucide-react';
interface NumberInputProps {
value: number;
onChange: (val: number) => void;
min?: number;
max?: number;
className?: string;
}
export const NumberInput: React.FC<NumberInputProps> = ({ value, onChange, min = 0, max = 9999, className = '' }) => {
const handleDec = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (value > min) onChange(value - 1);
};
const handleInc = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (value < max) onChange(value + 1);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let val = parseInt(e.target.value);
if (isNaN(val)) val = min;
if (val < min) val = min;
if (val > max) val = max;
onChange(val);
};
return (
<div className={`flex items-center border border-gray-300 rounded-lg overflow-hidden bg-white shadow-sm shrink-0 ${className}`}>
<button
type="button"
onClick={handleDec}
disabled={value <= min}
className="p-2 md:p-1.5 bg-gray-50 text-gray-600 hover:bg-gray-100 disabled:opacity-30 border-r border-gray-200 active:bg-gray-200 transition-colors touch-manipulation"
>
<Minus size={14} strokeWidth={3} />
</button>
<input
type="number"
className="w-10 md:w-12 text-center text-sm font-bold text-gray-800 outline-none p-1 appearance-none bg-transparent"
value={value}
onChange={handleChange}
style={{MozAppearance: 'textfield'}}
/>
<button
type="button"
onClick={handleInc}
disabled={value >= max}
className="p-2 md:p-1.5 bg-gray-50 text-gray-600 hover:bg-gray-100 disabled:opacity-30 border-l border-gray-200 active:bg-gray-200 transition-colors touch-manipulation"
>
<Plus size={14} strokeWidth={3} />
</button>
</div>
);
};