import { useContext } from "preact/compat"; import { FieldUIOptions, FormContext } from "./FormProvider.js"; import { TranslatedString } from "@gnu-taler/taler-util"; export interface InputFieldHandler { value: Type; onChange: (s: Type) => void; state: FieldUIOptions; error?: TranslatedString | undefined; } /** * @depreacted removing this so we don't depend on context to create a form * @param name * @returns */ export function useField( name: K, ): InputFieldHandler | undefined { const ctx = useContext(FormContext); if (!ctx) { //no context, can't be used return undefined; } const { value: formValue, computeFormState, onUpdate: notifyUpdate, readOnly: readOnlyForm, } = ctx type P = typeof name; type V = T[P]; const formState = computeFormState ? computeFormState(formValue.current) : {}; const fieldValue = readField(formValue.current, String(name)) as V; const fieldState = readField>(formState, String(name)) ?? {}; //compute default state const state = { disabled: readOnlyForm ? true : (fieldState.disabled ?? false), hidden: fieldState.hidden ?? false, help: fieldState.help, elements: "elements" in fieldState ? fieldState.elements ?? [] : [], }; function onChange(value: V): void { // setCurrentValue(value); formValue.current = setValueDeeper( formValue.current, String(name).split("."), value, ); if (notifyUpdate) { notifyUpdate(formValue.current); } } return { value: fieldValue, onChange, state, }; } /** * read the field of an object an support accessing it using '.' * * @param object * @param name * @returns */ function readField( object: any, name: string, ): T | undefined { return name.split(".").reduce((prev, current) => { return prev ? prev[current] : undefined; }, 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) }; }