50 lines
1.8 KiB
JavaScript
50 lines
1.8 KiB
JavaScript
|
import React, {useState} from 'react';
|
||
|
|
||
|
export default function ValidatingInputNumberField({
|
||
|
id,
|
||
|
label,
|
||
|
defaultValue = 0,
|
||
|
constraints = {},
|
||
|
validatorFn = (value) => {
|
||
|
return {valid: true, value};
|
||
|
},
|
||
|
disabled = false,
|
||
|
onChange = _ => {
|
||
|
}
|
||
|
}) {
|
||
|
const [error, setError] = useState(null);
|
||
|
const [value, setValue] = useState(defaultValue);
|
||
|
|
||
|
const handleValueChange = (e) => {
|
||
|
const value = e.target.value;
|
||
|
const validation = validatorFn(value);
|
||
|
if (!validation.valid) {
|
||
|
setError(validation.message);
|
||
|
} else {
|
||
|
setError(null);
|
||
|
onChange(validation.value);
|
||
|
}
|
||
|
setValue(validation.value);
|
||
|
};
|
||
|
let errorComponent;
|
||
|
if (!!error) {
|
||
|
errorComponent = <span>{error}</span>;
|
||
|
} else {
|
||
|
errorComponent = <span/>;
|
||
|
}
|
||
|
return (
|
||
|
<span>
|
||
|
<label htmlFor={id}>{label}: </label>
|
||
|
<input id={id}
|
||
|
type={"number"}
|
||
|
onChange={handleValueChange}
|
||
|
value={value || ""}
|
||
|
min={constraints.min || null}
|
||
|
max={constraints.max || null}
|
||
|
disabled={disabled}
|
||
|
/>
|
||
|
{errorComponent}
|
||
|
</span>
|
||
|
);
|
||
|
}
|