import React, {ChangeEventHandler, useState} from 'react'; export default function ValidatingInputNumberField({ id, label, value = 0, constraints = undefined, validatorFn = (value) => { return {valid: true, value: Number(value)}; }, disabled = false, onChange = () => { } }: { id: string; label: string; value?: number; constraints?: { min?: number; max?: number; }; validatorFn: ValidatorFunction<string, number>; disabled: boolean; onChange: (v: number) => void; }) { const [error, setError] = useState<string>(); const handleValueChange: ChangeEventHandler<HTMLInputElement> = (e) => { const value = e.target.value; const validation = validatorFn(value); if (!validation.valid) { setError(validation.message); } else { setError(undefined); } if (validation.value) { onChange(validation.value); } }; return ( <> <label htmlFor={id}>{label}: </label> <input id={id} type={"number"} onChange={handleValueChange} value={value || ""} min={constraints?.min} max={constraints?.max} disabled={disabled} /> <span>{error}</span> </> ); } export interface Validation<T> { valid: boolean; message?: string; value?: T; } export type ValidatorFunction<I, T> = (v: I) => Validation<T>;