import { useRef, type InputHTMLAttributes } from "react"; type defaultValues = Record; interface Props { initialValues?: Partial; } type InputElements = | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement ; interface UseFormReturns { getValue: () => T; setValue: (name: keyof T, value: string | number) => void; setValues: (values: Partial) => void; bindInput: (name: keyof T) => InputHTMLAttributes; // onSubmit: (values: T) => (ev: React.FormEvent) => void onSubmit: (fn: (values: T) => void) => (ev: React.FormEvent) => void } const isCheckBox = (el: HTMLElement) => { return el instanceof HTMLInputElement && el.type === "checkbox"; } function useForm({ initialValues }: Props) { const inputs = useRef>>({}); const values = useRef({ ...initialValues } as T); const inst = useRef>(); if (!inst.current) { const getValue = () => { return values.current; } const setValue = (name, value) => { const el = inputs.current[name]; console.log(el, name); if (el) { values.current[name as keyof T] = value; if (el instanceof HTMLInputElement && el.type === "checkbox") { el.checked = value; return; } inputs.current[name].value = value; } } const setValues = (values) => { Object.keys(values).forEach((key) => { setValue(key, values[key]); }); } const bindInput = (name: string) => { return { name, id: name, ref: (target) => { console.log('ref', target); if (target) { inputs.current[name as keyof T] = target; if (isCheckBox(target)) { target.checked = initialValues?.[name]; } else if (name in initialValues) { target.value = initialValues[name]; } } }, onChange: (ev) => { const { name, value, checked } = ev.target; if (isCheckBox(ev.target)) { values.current[name as keyof T] = checked; return; } values.current[name as keyof T] = value; }, } } const onSubmit = (fn: (values: T) => void) => { return (ev: React.FormEvent) => { ev.preventDefault(); fn(getValue()); } } inst.current = { getValue, setValue, setValues, bindInput, onSubmit, }; } return inst.current; } export default useForm;