65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import { AbsoluteTime, TranslatedString } from "@gnu-taler/taler-util";
|
|
import { ComponentChildren, VNode, createContext, h } from "preact";
|
|
import { MutableRef, StateUpdater, useEffect, useRef } 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 Array<infer P>
|
|
? Partial<InputArrayFieldState<P>>
|
|
: T[field] extends object
|
|
? 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,
|
|
computeFormState,
|
|
}: {
|
|
initialValue?: Partial<T>;
|
|
onUpdate?: (v: Partial<T>) => void;
|
|
computeFormState?: (v: T) => FormState<T>;
|
|
children: ComponentChildren;
|
|
}): VNode {
|
|
const value = useRef(initialValue ?? {});
|
|
useEffect(() => {
|
|
return function onUnload() {
|
|
value.current = initialValue ?? {};
|
|
};
|
|
});
|
|
return (
|
|
<FormContext.Provider
|
|
value={{ initialValue, value, onUpdate, computeFormState }}
|
|
>
|
|
<form>{children}</form>
|
|
</FormContext.Provider>
|
|
);
|
|
}
|