aboutsummaryrefslogtreecommitdiff
path: root/packages/web-util/src/forms/FormProvider.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-12-31 15:25:03 -0300
committerSebastian <sebasjm@gmail.com>2023-12-31 15:25:03 -0300
commit5ed54d872a70c2ba3c0a727d99093335e03f7a77 (patch)
tree14ab4c3cedcff72f738f86b6c87b877c1a868697 /packages/web-util/src/forms/FormProvider.tsx
parent6dd7cfa1ecd3ab95e4ab50e144762e5dceb03328 (diff)
downloadwallet-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.tsx93
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) => {