Home-Toolbox-Plugin/hooks/useForm.ts

115 lines
2.6 KiB
TypeScript

import { useRef, type InputHTMLAttributes } from "react";
type defaultValues = Record<string, any>;
interface Props<T extends defaultValues = defaultValues> {
initialValues?: Partial<T>;
}
type InputElements =
| HTMLInputElement
| HTMLSelectElement
| HTMLTextAreaElement
;
interface UseFormReturns<T extends defaultValues> {
getValue: () => T;
setValue: (name: keyof T, value: string | number) => void;
setValues: (values: Partial<T>) => void;
bindInput: (name: keyof T) => InputHTMLAttributes<InputElements>;
// 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<T extends defaultValues>({ initialValues }: Props<T>) {
const inputs = useRef<Partial<Record<keyof T, InputElements>>>({});
const values = useRef<T>({ ...initialValues } as T);
const inst = useRef<UseFormReturns<T>>();
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;