Skip to content

Commit 55aa9b5

Browse files
Merge pull request #84 from elek-io/fix-collection-field-definition
Fix collection field definition
2 parents 6e3dc92 + b9ee408 commit 55aa9b5

47 files changed

Lines changed: 2955 additions & 2327 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/extensions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"recommendations": ["dbaeumer.vscode-eslint"]
2+
"recommendations": ["dbaeumer.vscode-eslint", "bradlc.vscode-tailwindcss"]
33
}

.vscode/settings.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
"**/routeTree.gen.ts": true
1010
},
1111
"editor.formatOnSave": true,
12-
"editor.defaultFormatter": "esbenp.prettier-vscode",
12+
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
1313
"editor.codeActionsOnSave": {
14-
"source.organizeImports": "explicit",
15-
"source.sortMembers": "explicit"
14+
"source.fixAll.eslint": "always"
1615
},
1716
"typescript.tsdk": "./node_modules/typescript/lib"
1817
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Dynamic form field generation
2+
Handling predefined forms that stay the same is straight forward. We simply use the correct input component and attach it to the forms field. But when it comes to user defined forms it gets tricky. We want to be able to define a form field in a way that it can be rendered dynamically. This means we need to define what type of input it is, what label and description it has, if it is required and so on. This is done using field definitions. A field definition is simply a JSON object that contains all the necessary information to render a form field.
3+
4+
When a user creates a Collection he can define those field definitions. When the form is rendered we loop over the field definitions and render the corresponding input component based on what is defined in the field definition. This way we can create forms dynamically based on user defined field definitions.
5+
6+
## Component overview
7+
The following components are used:
8+
- The [`Input`](/src/renderer/src/components/ui/input.tsx), [`Textarea`](/src/renderer/src/components/ui/textarea.tsx), [`Switch`](/src/renderer/src/components/ui/switch.tsx), [`Slider`](/src/renderer/src/components/ui/slider.tsx) and [`Select`](/src/renderer/src/components/ui/select.tsx) are basic HTML inputs with added styling and [Radix UI primitives](https://www.radix-ui.com/primitives) for accessibility.
9+
- The components [`FormInputField`, `FormTextareaField`, `FormRangeField` and others](/src/renderer/src/components/ui/form.tsx) wrap the corresponding basic HTML component and transform the value the user put in (e.g. in case of an Input of type "number" to a number) before handing it back to the attached forms field. This is done because the inputs value internally is always a string. But this does become a problem when the form requires the type to be a number. It also returns null instead of an empty string if the user does not put in a value since a form can allow for strings with a minimum lenght and null but an empty string should fail the validation.
10+
- The [`FormComponentFromFieldDefinition`](/src/renderer/src/components/ui/form.tsx) simply takes a fieldDefinition and renders a component based on it.
11+
- The [`FormComponentFromFieldDefinitionTranslatable`](/src/renderer/src/components/ui/form.tsx) extends the FormComponentFromFieldDefinition. If there are multiple supported languages, it renders a button next to the field that opens a dialog where translations for all supported languages can be entered.
12+
- Finally, the [`FormFieldFromDefinition`](/src/renderer/src/components/ui/form.tsx) wraps the FormComponentFromFieldDefinitionTranslatable in a FormItem and adds a label, description and validation message. This is the component that should be used when rendering a form field based on a field definition.
13+
14+
## Validating generated forms
15+
All validation of user input is done using [Zod](https://zod.dev/). elek.io Core provides [predefined Zod schemas for all supported field types](https://github.com/elek-io/core/blob/main/src/schema/fieldSchema.ts). When a user creates a Collection and defines field definitions, elek.io Core can generate a Zod schema for the Values based on the field definitions with [`getValueSchemaFromFieldDefinition` as well as full schema generation for creating and updating Entries `getCreateEntrySchemaFromFieldDefinitions` and `getUpdateEntrySchemaFromFieldDefinitions`](https://github.com/elek-io/core/blob/main/src/schema/schemaFromFieldDefinition.ts). This schema can then be used in conjunction with the [React Hook Form Zod resolver](https://react-hook-form.com/get-started#SchemaValidation) to validate the user input before the form is submitted and provide feedback to the user if the input is invalid.

0 commit comments

Comments
 (0)