import { observable } from "mobx"; import React, { useCallback, useMemo } from "react"; import { Button, Column } from "../../design"; import { emptyValue, ObservedInputElement, Type, TypeProps, Value, } from "./InputElement"; /** * Form schema */ export type FormTemplate = Record; /** * Generate value object from form schema */ export type MapFormToValues = { [Property in keyof T]: Value; }; /** * Generate data object from form schema */ type MapFormToData = { [Property in keyof T]: TypeProps; }; /** * Form props */ export interface Props { /** * Form schema */ schema: T; /** * Props required for rendering form elements */ data: MapFormToData; /** * Handle changes to the data */ onChange?: (data: MapFormToValues, key: keyof T) => void; /** * Handle form submission */ onSubmit?: (data: MapFormToValues) => void; /** * Provide an observable object of values */ observed?: MapFormToValues; /** * Provide default values for keys */ defaults?: Partial>; /** * Submit button properties */ submitBtn?: Omit, "type">; /** * Whether all elements are disabled */ disabled?: boolean; } /** * Get initial values to use for the form data * @param schema Schema to use * @param defaults Defaults to apply * @returns Initial values */ export function getInitialValues( schema: T, defaults?: Partial>, ) { const values: Partial> = {}; Object.keys(schema).forEach( (key) => (values[key as keyof typeof values] = defaults?.[key] ?? emptyValue(schema[key])), ); return values as MapFormToValues; } /** * Dynamic Form component */ export function Form({ schema, data, disabled, onChange, onSubmit, observed, defaults, submitBtn, }: Props) { const keys = useMemo(() => Object.keys(schema), []); const values = observed ?? observable(getInitialValues(schema, defaults)); const submit = useCallback((ev: React.FormEvent) => { ev.preventDefault(); onSubmit?.(values); }, []); return (
{keys.map((key) => ( values[key] as Value } onChange={(value) => { values[key as keyof typeof values] = value; onChange?.(values, key); }} {...data[key]} /> ))} {submitBtn && (