diff options
author | Sebastian <sebasjm@gmail.com> | 2023-12-31 15:25:03 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-12-31 15:25:03 -0300 |
commit | 5ed54d872a70c2ba3c0a727d99093335e03f7a77 (patch) | |
tree | 14ab4c3cedcff72f738f86b6c87b877c1a868697 /packages/web-util/src/forms/FormProvider.tsx | |
parent | 6dd7cfa1ecd3ab95e4ab50e144762e5dceb03328 (diff) | |
download | wallet-core-5ed54d872a70c2ba3c0a727d99093335e03f7a77.tar.xz |
updat web utils
Diffstat (limited to 'packages/web-util/src/forms/FormProvider.tsx')
-rw-r--r-- | packages/web-util/src/forms/FormProvider.tsx | 93 |
1 files changed, 67 insertions, 26 deletions
diff --git a/packages/web-util/src/forms/FormProvider.tsx b/packages/web-util/src/forms/FormProvider.tsx index 3da2a4f07..b9f9f7832 100644 --- a/packages/web-util/src/forms/FormProvider.tsx +++ b/packages/web-util/src/forms/FormProvider.tsx @@ -7,14 +7,13 @@ import { ComponentChildren, VNode, createContext, h } from "preact"; import { MutableRef, StateUpdater, - useEffect, - useRef, - useState, + useState } from "preact/hooks"; -export interface FormType<T> { +export interface FormType<T extends object> { value: MutableRef<Partial<T>>; initialValue?: Partial<T>; + readOnly?: boolean; onUpdate?: StateUpdater<T>; computeFormState?: (v: T) => FormState<T>; } @@ -22,18 +21,31 @@ export interface FormType<T> { //@ts-ignore export const FormContext = createContext<FormType<any>>({}); -export type FormState<T> = { +/** + * Map of {[field]:BehaviorResult} + * for every field of type + * - any native (string, number, etc...) + * - absoluteTime + * - amountJson + * + * except for: + * - object => recurse into + * - array => behavior result and element field + */ +export type FormState<T extends object | undefined> = { [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>; + ? BehaviorResult + : T[field] extends AmountJson + ? BehaviorResult + : T[field] extends Array<infer P extends object> + ? InputArrayFieldState<P> + : T[field] extends (object | undefined) + ? FormState<T[field]> + : BehaviorResult; }; +export type BehaviorResult = Partial<InputFieldState> & FieldUIOptions + export interface InputFieldState { /* should show the error */ error?: TranslatedString; @@ -45,41 +57,70 @@ export interface InputFieldState { hidden: boolean; } -export interface InputArrayFieldState<T> extends InputFieldState { - elements: FormState<T>[]; +export interface IconAddon { + type: "icon"; + icon: VNode; +} +export interface ButtonAddon { + type: "button"; + onClick: () => void; + children: ComponentChildren; +} +export interface TextAddon { + type: "text"; + text: TranslatedString; } +export type Addon = IconAddon | ButtonAddon | TextAddon; -export function FormProvider<T>({ +export interface StringConverter<T> { + toStringUI: (v?: T) => string; + fromStringUI: (v?: string) => T; +} + +type FieldUIOptions = { + placeholder?: TranslatedString; + tooltip?: TranslatedString; + help?: TranslatedString; + required?: boolean; +} + +export interface UIFormProps<T extends object, K extends keyof T> extends FieldUIOptions { + name: K; + label: TranslatedString; + before?: Addon; + after?: Addon; + converter?: StringConverter<T[K]>; +} + +export interface InputArrayFieldState<P extends object> extends BehaviorResult { + elements?: FormState<P>[]; +} + +export function FormProvider<T extends object>({ children, initialValue, onUpdate: notify, onSubmit, computeFormState, + readOnly, }: { initialValue?: Partial<T>; onUpdate?: (v: Partial<T>) => void; onSubmit?: (v: Partial<T>, s: FormState<T> | undefined) => void; computeFormState?: (v: Partial<T>) => FormState<T>; + readOnly?: boolean; 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 }} + value={{ initialValue, value, onUpdate, computeFormState, readOnly }} > <form onSubmit={(e) => { |