import React, { ReactNode } from "react"; import BaseField, { IProps as IBaseFieldProps } from "./BaseField"; export type IBaseField = BaseField; export type IFormContext = { setField: (name: string, field: IBaseField) => void; unSetField: (name: string) => void; onFieldChange: (name: string, field: IBaseField) => void; }; type IFields = { [key: string]: IBaseField; }; type IState = {}; export type IProps = { onFieldChange?: (name: string, field: IBaseField) => void; onSubmit?: ( e: React.FormEvent | null, values: { [key: string]: string }, ) => void; className?: string; children?: ReactNode; }; export const FormContext = React.createContext({ setField: () => {}, unSetField: () => {}, onFieldChange: () => {} }); export default class Form extends React.Component { protected fields: IFields = {}; private formRef: React.RefObject; constructor(props: IProps) { super(props); this.state = {}; this.setField = this.setField.bind(this); this.unSetField = this.unSetField.bind(this); this.onFieldChange = this.onFieldChange.bind(this); this.onSubmit = this.onSubmit.bind(this); this.formRef = React.createRef(); } public override render() { return (
{this.props.children}
); } public async onSubmit(e: React.FormEvent | null) { e?.preventDefault(); const allChildren = this.getAllChildrenFields(e); const elementsValues = allChildren .filter((e) => { return e.getAttribute("type") !== "radio" && e.getAttribute("type") !== "checkbox"; }) .reduce((obj, element) => ({ ...obj, [element.getAttribute("name") ?? ""]: (element as any).value }), {}); const radioInputs = allChildren.filter((e) => e.getAttribute("type") === "radio").filter((e) => (e as any).checked); const radioInputsValues = radioInputs.reduce( (obj, element) => ({ ...obj, [element.getAttribute("name") ?? ""]: (element as any).value }), {}, ); const checkBoxesInput = allChildren.filter((e) => e.getAttribute("type") === "checkbox").filter((e) => (e as any).checked); const checkBoxesValues = checkBoxesInput.reduce((obj, element) => { const inputName = element.getAttribute("name") ?? ""; const inputValue = (element as any).value as string; const newValue = ((obj as any)[inputName] as string[]) ?? []; newValue.push(inputValue); return { ...obj, [inputName]: newValue, }; }, {}); const allInputs = { ...elementsValues, ...radioInputsValues, ...checkBoxesValues, }; // Deleting empty input delete (allInputs as any)[""]; if (this.props.onSubmit) { this.props.onSubmit(e, allInputs); } return { values: elementsValues }; } protected setField(name: string, field: IBaseField) { this.fields[name] = field; } protected unSetField(name: string) { delete this.fields[name]; } protected async onFieldChange(name: string, field: IBaseField) { if (this.props.onFieldChange) { this.props.onFieldChange(name, field); } } private getAllChildrenFields(e: React.FormEvent | null): Element[] { return Array.from(((e?.target as HTMLFormElement) ?? this.formRef.current).elements); } }