1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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, FormState } 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(),
};
}
|