diff options
author | Sebastian <sebasjm@gmail.com> | 2023-09-20 15:16:28 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-09-25 14:50:39 -0300 |
commit | fdbe623e1060efc4b074d213a96e8f5a2ab7498b (patch) | |
tree | 6bbe00f6f36f1910ea99180a6e0d5c53aeb9f34f /packages/web-util/src/forms/forms.ts | |
parent | a5406c5a5dc437e036168eb068db11d88e05bb0f (diff) | |
download | wallet-core-fdbe623e1060efc4b074d213a96e8f5a2ab7498b.tar.xz |
more ui stuff, moved forms to util
Diffstat (limited to 'packages/web-util/src/forms/forms.ts')
-rw-r--r-- | packages/web-util/src/forms/forms.ts | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/packages/web-util/src/forms/forms.ts b/packages/web-util/src/forms/forms.ts new file mode 100644 index 000000000..2c90a69ed --- /dev/null +++ b/packages/web-util/src/forms/forms.ts @@ -0,0 +1,135 @@ +import { TranslatedString } from "@gnu-taler/taler-util"; +import { InputText } from "./InputText.js"; +import { InputDate } from "./InputDate.js"; +import { InputInteger } from "./InputInteger.js"; +import { h as create, Fragment, VNode } from "preact"; +import { InputChoiceStacked } from "./InputChoiceStacked.js"; +import { InputArray } from "./InputArray.js"; +import { InputSelectMultiple } from "./InputSelectMultiple.js"; +import { InputTextArea } from "./InputTextArea.js"; +import { InputFile } from "./InputFile.js"; +import { Caption } from "./Caption.js"; +import { Group } from "./Group.js"; +import { InputSelectOne } from "./InputSelectOne.js"; +import { FormProvider } from "./FormProvider.js"; +import { InputLine } from "./InputLine.js"; +import { InputAmount } from "./InputAmount.js"; +import { InputChoiceHorizontal } from "./InputChoiceHorizontal.js"; + +export type DoubleColumnForm = Array<DoubleColumnFormSection | undefined>; + +export type DoubleColumnFormSection = { + title: TranslatedString; + description?: TranslatedString; + fields: UIFormField[]; +}; + +/** + * Constrain the type with the ui props + */ +type FieldType<T extends object = any, K extends keyof T = any> = { + group: Parameters<typeof Group>[0]; + caption: Parameters<typeof Caption>[0]; + array: Parameters<typeof InputArray<T, K>>[0]; + file: Parameters<typeof InputFile<T, K>>[0]; + selectOne: Parameters<typeof InputSelectOne<T, K>>[0]; + selectMultiple: Parameters<typeof InputSelectMultiple<T, K>>[0]; + text: Parameters<typeof InputText<T, K>>[0]; + textArea: Parameters<typeof InputTextArea<T, K>>[0]; + choiceStacked: Parameters<typeof InputChoiceStacked<T, K>>[0]; + choiceHorizontal: Parameters<typeof InputChoiceHorizontal<T, K>>[0]; + date: Parameters<typeof InputDate<T, K>>[0]; + integer: Parameters<typeof InputInteger<T, K>>[0]; + amount: Parameters<typeof InputAmount<T, K>>[0]; +}; + +/** + * List all the form fields so typescript can type-check the form instance + */ +export type UIFormField = + | { type: "group"; props: FieldType["group"] } + | { type: "caption"; props: FieldType["caption"] } + | { type: "array"; props: FieldType["array"] } + | { type: "file"; props: FieldType["file"] } + | { type: "amount"; props: FieldType["amount"] } + | { type: "selectOne"; props: FieldType["selectOne"] } + | { type: "selectMultiple"; props: FieldType["selectMultiple"] } + | { type: "text"; props: FieldType["text"] } + | { type: "textArea"; props: FieldType["textArea"] } + | { type: "choiceStacked"; props: FieldType["choiceStacked"] } + | { type: "choiceHorizontal"; props: FieldType["choiceHorizontal"] } + | { type: "integer"; props: FieldType["integer"] } + | { type: "date"; props: FieldType["date"] }; + +type FieldComponentFunction<key extends keyof FieldType> = ( + props: FieldType[key], +) => VNode; + +type UIFormFieldMap = { + [key in keyof FieldType]: FieldComponentFunction<key>; +}; + +/** + * Maps input type with component implementation + */ +const UIFormConfiguration: UIFormFieldMap = { + group: Group, + caption: Caption, + //@ts-ignore + array: InputArray, + text: InputText, + //@ts-ignore + file: InputFile, + textArea: InputTextArea, + //@ts-ignore + date: InputDate, + //@ts-ignore + choiceStacked: InputChoiceStacked, + //@ts-ignore + choiceHorizontal: InputChoiceHorizontal, + integer: InputInteger, + //@ts-ignore + selectOne: InputSelectOne, + //@ts-ignore + selectMultiple: InputSelectMultiple, + //@ts-ignore + amount: InputAmount, +}; + +export function RenderAllFieldsByUiConfig({ + fields, +}: { + fields: UIFormField[]; +}): VNode { + return create( + Fragment, + {}, + fields.map((field, i) => { + const Component = UIFormConfiguration[ + field.type + ] as FieldComponentFunction<any>; + return Component(field.props); + }), + ); +} + +type FormSet<T extends object> = { + Provider: typeof FormProvider<T>; + InputLine: <K extends keyof T>() => typeof InputLine<T, K>; + InputChoiceHorizontal: <K extends keyof T>() => typeof InputChoiceHorizontal< + T, + K + >; +}; +export function createNewForm<T extends object>() { + const res: FormSet<T> = { + Provider: FormProvider, + InputLine: () => InputLine, + InputChoiceHorizontal: () => InputChoiceHorizontal, + }; + return { + Provider: res.Provider, + InputLine: res.InputLine(), + InputChoiceHorizontal: res.InputChoiceHorizontal(), + }; +} |