diff options
Diffstat (limited to 'packages/web-util/src/forms/FormProvider.tsx')
-rw-r--r-- | packages/web-util/src/forms/FormProvider.tsx | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/packages/web-util/src/forms/FormProvider.tsx b/packages/web-util/src/forms/FormProvider.tsx new file mode 100644 index 000000000..3da2a4f07 --- /dev/null +++ b/packages/web-util/src/forms/FormProvider.tsx @@ -0,0 +1,99 @@ +import { + AbsoluteTime, + AmountJson, + TranslatedString, +} from "@gnu-taler/taler-util"; +import { ComponentChildren, VNode, createContext, h } from "preact"; +import { + MutableRef, + StateUpdater, + useEffect, + useRef, + useState, +} from "preact/hooks"; + +export interface FormType<T> { + value: MutableRef<Partial<T>>; + initialValue?: Partial<T>; + onUpdate?: StateUpdater<T>; + computeFormState?: (v: T) => FormState<T>; +} + +//@ts-ignore +export const FormContext = createContext<FormType<any>>({}); + +export type FormState<T> = { + [field in keyof T]?: T[field] extends AbsoluteTime + ? Partial<InputFieldState> + : T[field] extends AmountJson + ? Partial<InputFieldState> + : T[field] extends Array<infer P> + ? Partial<InputArrayFieldState<P>> + : T[field] extends (object | undefined) + ? FormState<T[field]> + : Partial<InputFieldState>; +}; + +export interface InputFieldState { + /* should show the error */ + error?: TranslatedString; + /* should not allow to edit */ + readonly: boolean; + /* should show as disable */ + disabled: boolean; + /* should not show */ + hidden: boolean; +} + +export interface InputArrayFieldState<T> extends InputFieldState { + elements: FormState<T>[]; +} + +export function FormProvider<T>({ + children, + initialValue, + onUpdate: notify, + onSubmit, + computeFormState, +}: { + initialValue?: Partial<T>; + onUpdate?: (v: Partial<T>) => void; + onSubmit?: (v: Partial<T>, s: FormState<T> | undefined) => void; + computeFormState?: (v: Partial<T>) => FormState<T>; + children: ComponentChildren; +}): VNode { + // const value = useRef(initialValue ?? {}); + // useEffect(() => { + // return function onUnload() { + // value.current = initialValue ?? {}; + // }; + // }); + // const onUpdate = notify + const [state, setState] = useState<Partial<T>>(initialValue ?? {}); + const value = { current: state }; + // console.log("RENDER", initialValue, value); + const onUpdate = (v: typeof state) => { + // console.log("updated"); + setState(v); + if (notify) notify(v); + }; + return ( + <FormContext.Provider + value={{ initialValue, value, onUpdate, computeFormState }} + > + <form + onSubmit={(e) => { + e.preventDefault(); + //@ts-ignore + if (onSubmit) + onSubmit( + value.current, + !computeFormState ? undefined : computeFormState(value.current), + ); + }} + > + {children} + </form> + </FormContext.Provider> + ); +} |