diff options
Diffstat (limited to 'packages/web-util/src/forms/forms.ts')
-rw-r--r-- | packages/web-util/src/forms/forms.ts | 144 |
1 files changed, 144 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..6bda2f674 --- /dev/null +++ b/packages/web-util/src/forms/forms.ts @@ -0,0 +1,144 @@ +import { h as create, Fragment, VNode } from "preact"; +import { Caption } from "./Caption.js"; +import { Group } from "./Group.js"; +import { InputAbsoluteTime } from "./InputAbsoluteTime.js"; +import { InputAmount } from "./InputAmount.js"; +import { InputArray } from "./InputArray.js"; +import { InputChoiceHorizontal } from "./InputChoiceHorizontal.js"; +import { InputChoiceStacked } from "./InputChoiceStacked.js"; +import { InputFile } from "./InputFile.js"; +import { InputInteger } from "./InputInteger.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"; + +/** + * 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]; + absoluteTime: 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]; +}; + +/** + * List all the form fields so typescript can type-check the form instance + */ +export type UIFormField = + | { 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: "absoluteTime"; + properties: FieldType["absoluteTime"]; + }; + +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 + absoluteTime: InputAbsoluteTime, + //@ts-ignore + choiceStacked: InputChoiceStacked, + //@ts-ignore + choiceHorizontal: InputChoiceHorizontal, + integer: InputInteger, + //@ts-ignore + selectOne: InputSelectOne, + //@ts-ignore + selectMultiple: InputSelectMultiple, + //@ts-ignore + toggle: InputToggle, + //@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.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>; +// }; + +/** + * 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(), +// }; +// } |