summaryrefslogtreecommitdiff
path: root/packages/exchange-backoffice-ui/src/forms/useField.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/exchange-backoffice-ui/src/forms/useField.ts')
-rw-r--r--packages/exchange-backoffice-ui/src/forms/useField.ts72
1 files changed, 72 insertions, 0 deletions
diff --git a/packages/exchange-backoffice-ui/src/forms/useField.ts b/packages/exchange-backoffice-ui/src/forms/useField.ts
new file mode 100644
index 000000000..6f7b84112
--- /dev/null
+++ b/packages/exchange-backoffice-ui/src/forms/useField.ts
@@ -0,0 +1,72 @@
+import { TargetedEvent, useContext, useState } from "preact/compat";
+import { FormContext, InputFieldState } from "./FormProvider.js";
+
+export interface InputFieldHandler<Type> {
+ value: Type;
+ onChange: (s: Type) => void;
+ state: InputFieldState;
+ isDirty: boolean;
+}
+
+export function useField<T>(name: keyof T): InputFieldHandler<T[keyof T]> {
+ const {
+ initialValue,
+ value: formValue,
+ computeFormState,
+ onUpdate,
+ } = useContext(FormContext);
+ type P = typeof name;
+ type V = T[P];
+ const [isDirty, setDirty] = useState(false);
+ const formState = computeFormState ? computeFormState(formValue) : {};
+
+ const fieldValue = readField(formValue, String(name)) as V;
+ const fieldState = readField<Partial<InputFieldState>>(
+ formState,
+ String(name),
+ );
+
+ //default state
+ const state: InputFieldState = {
+ disabled: fieldState?.disabled ?? false,
+ readonly: fieldState?.readonly ?? false,
+ hidden: fieldState?.hidden ?? false,
+ error: fieldState?.error,
+ };
+
+ function onChange(value: V): void {
+ setDirty(true);
+ return onUpdate((prev: any) => {
+ return setValueDeeper(prev, String(name).split("."), value);
+ });
+ }
+
+ return {
+ value: fieldValue,
+ onChange,
+ isDirty,
+ state,
+ };
+}
+
+/**
+ * read the field of an object an support accessing it using '.'
+ *
+ * @param object
+ * @param name
+ * @returns
+ */
+function readField<T>(object: any, name: string): T | undefined {
+ return name
+ .split(".")
+ .reduce((prev, current) => prev && prev[current], object);
+}
+
+function setValueDeeper(object: any, names: string[], value: any): any {
+ if (names.length === 0) return value;
+ const [head, ...rest] = names;
+ if (object === undefined) {
+ return { [head]: setValueDeeper({}, rest, value) };
+ }
+ return { ...object, [head]: setValueDeeper(object[head] ?? {}, rest, value) };
+}