diff options
Diffstat (limited to 'packages/web-util/src/forms/forms.ts')
-rw-r--r-- | packages/web-util/src/forms/forms.ts | 304 |
1 files changed, 271 insertions, 33 deletions
diff --git a/packages/web-util/src/forms/forms.ts b/packages/web-util/src/forms/forms.ts index 3b8620bfb..4c5050830 100644 --- a/packages/web-util/src/forms/forms.ts +++ b/packages/web-util/src/forms/forms.ts @@ -1,6 +1,5 @@ import { h as create, Fragment, VNode } from "preact"; import { Caption } from "./Caption.js"; -import { FormProvider } from "./FormProvider.js"; import { Group } from "./Group.js"; import { InputAbsoluteTime } from "./InputAbsoluteTime.js"; import { InputAmount } from "./InputAmount.js"; @@ -9,13 +8,15 @@ import { InputChoiceHorizontal } from "./InputChoiceHorizontal.js"; import { InputChoiceStacked } from "./InputChoiceStacked.js"; import { InputFile } from "./InputFile.js"; import { InputInteger } from "./InputInteger.js"; -import { InputLine } from "./InputLine.js"; import { InputSelectMultiple } from "./InputSelectMultiple.js"; import { InputSelectOne } from "./InputSelectOne.js"; import { InputText } from "./InputText.js"; import { InputTextArea } from "./InputTextArea.js"; import { InputToggle } from "./InputToggle.js"; - +import { Addon, StringConverter, UIFieldHandler } from "./FormProvider.js"; +import { InternationalizationAPI, UIFieldElementDescription } from "../index.browser.js"; +import { assertUnreachable, TranslatedString } from "@gnu-taler/taler-util"; +import {UIFormFieldBaseConfig, UIFormElementConfig} from "./ui-form.js"; /** * Constrain the type with the ui props */ @@ -30,7 +31,7 @@ type FieldType<T extends object = any, K extends keyof T = any> = { textArea: Parameters<typeof InputTextArea<T, K>>[0]; choiceStacked: Parameters<typeof InputChoiceStacked<T, K>>[0]; choiceHorizontal: Parameters<typeof InputChoiceHorizontal<T, K>>[0]; - absoluteTime: Parameters<typeof InputAbsoluteTime<T, K>>[0]; + absoluteTimeText: Parameters<typeof InputAbsoluteTime<T, K>>[0]; integer: Parameters<typeof InputInteger<T, K>>[0]; toggle: Parameters<typeof InputToggle<T, K>>[0]; amount: Parameters<typeof InputAmount<T, K>>[0]; @@ -40,20 +41,32 @@ type FieldType<T extends object = any, K extends keyof T = any> = { * 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: "toggle"; props: FieldType["toggle"] } - | { type: "absoluteTime"; props: FieldType["absoluteTime"] }; + | { type: "group"; properties: FieldType["group"] } + | { type: "caption"; properties: FieldType["caption"] } + | { type: "array"; properties: FieldType["array"] } + | { type: "file"; properties: FieldType["file"] } + | { type: "amount"; properties: FieldType["amount"] } + | { type: "selectOne"; properties: FieldType["selectOne"] } + | { + type: "selectMultiple"; + properties: FieldType["selectMultiple"]; + } + | { type: "text"; properties: FieldType["text"] } + | { type: "textArea"; properties: FieldType["textArea"] } + | { + type: "choiceStacked"; + properties: FieldType["choiceStacked"]; + } + | { + type: "choiceHorizontal"; + properties: FieldType["choiceHorizontal"]; + } + | { type: "integer"; properties: FieldType["integer"] } + | { type: "toggle"; properties: FieldType["toggle"] } + | { + type: "absoluteTimeText"; + properties: FieldType["absoluteTimeText"]; + }; type FieldComponentFunction<key extends keyof FieldType> = ( props: FieldType[key], @@ -76,7 +89,7 @@ const UIFormConfiguration: UIFormFieldMap = { file: InputFile, textArea: InputTextArea, //@ts-ignore - absoluteTime: InputAbsoluteTime, + absoluteTimeText: InputAbsoluteTime, //@ts-ignore choiceStacked: InputChoiceStacked, //@ts-ignore @@ -104,31 +117,256 @@ export function RenderAllFieldsByUiConfig({ const Component = UIFormConfiguration[ field.type ] as FieldComponentFunction<any>; - return Component(field.props); + return Component(field.properties); }), ); } -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>; -}; +// 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>; +// }; /** * Helper function that created a typed object. + * + * @returns + */ +// 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(), +// }; +// } + +/** + * convert field configuration to render function * + * @param i18n_ + * @param fieldConfig + * @param form * @returns */ -export function createNewForm<T extends object>() { - const res: FormSet<T> = { - Provider: FormProvider, - InputLine: () => InputLine, - InputChoiceHorizontal: () => InputChoiceHorizontal, +export function convertUiField( + i18n_: InternationalizationAPI, + fieldConfig: UIFormElementConfig[], + form: object, + getConverterById: GetConverterById, +): UIFormField[] { + return fieldConfig.map((config) => { + // NON input fields + switch (config.type) { + case "caption": { + const resp: UIFormField = { + type: config.type, + properties: converBaseFieldsProps(i18n_, config), + }; + return resp; + } + case "group": { + const resp: UIFormField = { + type: config.type, + properties: { + ...converBaseFieldsProps(i18n_, config), + fields: convertUiField(i18n_, config.fields, form, getConverterById), + }, + }; + return resp; + } + } + // Input Fields + switch (config.type) { + case "array": { + return { + type: "array", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + labelField: config.labelFieldId, + fields: convertUiField(i18n_, config.fields, form, getConverterById), + }, + } as UIFormField; + } + case "absoluteTimeText": { + return { + type: "absoluteTimeText", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + }, + } as UIFormField; + } + case "amount": { + return { + type: "amount", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + currency: config.currency, + }, + } as UIFormField; + } + case "choiceHorizontal": { + return { + type: "choiceHorizontal", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + choices: config.choices, + }, + } as UIFormField; + } + case "choiceStacked": { + return { + type: "choiceStacked", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + choices: config.choices, + + }, + }as UIFormField; + } + case "file":{ + return { + type: "file", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + accept: config.accept, + maxBites: config.maxBytes, + }, + } as UIFormField; + } + case "integer":{ + return { + type: "integer", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + }, + } as UIFormField; + } + case "selectMultiple":{ + return { + type: "selectMultiple", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + choices: config.choices, + }, + } as UIFormField; + } + case "selectOne": { + return { + type: "selectOne", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + choices: config.choices, + }, + } as UIFormField; + } + case "text": { + return { + type: "text", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + }, + } as UIFormField; + } + case "textArea": { + return { + type: "text", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + }, + } as UIFormField; + } + case "toggle": { + return { + type: "toggle", + properties: { + ...converBaseFieldsProps(i18n_, config), + ...converInputFieldsProps(form, config, getConverterById), + }, + } as UIFormField; + } + default: { + assertUnreachable(config); + } + } + }); +} + + + +function getAddonById(_id: string | undefined): Addon { + return undefined!; +} + + +type GetConverterById = ( + id: string | undefined, + config: unknown, +) => StringConverter<unknown>; + + +function converInputFieldsProps( + form: object, + p: UIFormFieldBaseConfig, + getConverterById: GetConverterById, +) { + return { + converter: getConverterById(p.converterId, p), + handler: getValueDeeper2(form, p.id.split(".")), + name: p.name, + required: p.required, + disabled: p.disabled, + help: p.help, + placeholder: p.placeholder, + tooltip: p.tooltip, + label: p.label as TranslatedString, }; +} + +function converBaseFieldsProps( + i18n_: InternationalizationAPI, + p: UIFieldElementDescription, +) { return { - Provider: res.Provider, - InputLine: res.InputLine(), - InputChoiceHorizontal: res.InputChoiceHorizontal(), + after: getAddonById(p.addonAfterId), + before: getAddonById(p.addonBeforeId), + hidden: p.hidden, + name: p.name, + help: i18n_.str`${p.help}`, + label: i18n_.str`${p.label}`, + tooltip: i18n_.str`${p.tooltip}`, }; } + +export function getValueDeeper2( + object: Record<string, any>, + names: string[], +): UIFieldHandler { + if (names.length === 0) return object as UIFieldHandler; + const [head, ...rest] = names; + if (!head) { + return getValueDeeper2(object, rest); + } + if (object === undefined) { + throw Error("handler not found"); + } + return getValueDeeper2(object[head], rest); +} + + |