import * as React from "react"; import { Form, FormContext, IFormProps, ParentFormContext } from "./form"; import { FormBinder } from "./formBinders"; import { IDataBinder } from "./formCore"; import { FormBinderKey, IArrayProp, IObjectProp, PropType, toDataPath } from "./propertyPathBuilder"; export interface IUseParentForm { bind: FormBinder DataForm: React.FunctionComponent<{}> } export function createFormContext() { return { Form: (props: { initialData: TDataBinder, withoutClone?: boolean, children: (value: IUseFormProps) => React.ReactNode }) => { const { initialData, withoutClone, children } = props const { DataForm, ...rest } = useForm(initialData, withoutClone) return ( {children(rest)} ) }, ChildForm: (props: { children: (value: IUseFormProps) => React.ReactNode }) => { const ctx = React.useContext(FormContext) if (!ctx) { return null } return ( {props.children({ bind: new FormBinder(), dataBinder: ctx && ctx.dataBinder, notifyChange: ctx.notifyChange })} ) }, } } type IHookFormProps = Pick> & { onDataChanged?: (data?: T) => void } export interface IUseFormProps { dataBinder: IDataBinder bind: FormBinder notifyChange: () => void } export interface IUseForm extends IUseFormProps { DataForm: React.FunctionComponent> context: UseFormContext } export class UseFormContext { useForm(dataName: (builder: PropType) => IObjectProp): IUseParentForm useForm(dataName: (builder: PropType) => IArrayProp): IUseParentForm useForm>(dataName: TKey): IUseParentForm useForm(): IUseParentForm useForm(dataPath?: FormBinderKey): IUseParentForm { return { DataForm: ParentFormContext, bind: new FormBinder(toDataPath(dataPath)) } } } export function useForm(initialData: T, withoutClone: boolean = false): IUseForm { const [__, dispatch] = React.useReducer>(state => !state, false); const dataBinder = React.useMemo(() => { return withoutClone ? Form.jsonDataBinder(initialData) : Form.jsonDataBinderWithClone(initialData) }, [initialData, withoutClone]) const bind = React.useMemo(() => { return new FormBinder() }, []) const context = React.useMemo(() => { return new UseFormContext() }, []) const onDataBinderChange = React.useCallback(() => dispatch(0), [dispatch]); const DataForm = React.useCallback>>(p => { return
}, [dataBinder, onDataBinderChange]) return { dataBinder, bind, DataForm, context, notifyChange: onDataBinderChange } }