import { ChangeEvent, ReactNode, useState } from 'react'; type InputProps = { value: T; onBlur: () => void; onChange: (e: ChangeEvent) => void; // TODO? type property would allow checkboxes and radios } type Validator = (value: T) => string | undefined; const isFalsy = (value: any) => { return (value === false) || (value === 0) || (value === '') || (value === null) || (value === undefined); } function useValidatedInput(defaultValue: T, validator: Validator, validateImmediately = false, validateOnChange = false): [T, InputProps, ReactNode, boolean] { const [value, setValue] = useState(defaultValue); const [touched, setTouched] = useState(validateImmediately); const feedback = touched && validator(value); const onChange = (newValue: T) => { if (validateOnChange) setTouched(true); setValue(newValue); } return [ value, { value, onBlur: () => setTouched(true), onChange: event => onChange((event.target as any).value), }, feedback, (touched && !isFalsy(feedback)), // TODO? support async/promise ]; }; export default useValidatedInput;