Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(frontend)!: Auto Form - reduce re-render components #475

Merged
merged 9 commits into from
Sep 1, 2024
1 change: 0 additions & 1 deletion apps/backend/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ type Mutation {
admin__core_languages__delete(code: String!): String!
admin__core_languages__download(code: String!, plugins: [String!]!): String!
admin__core_languages__edit(allow_in_input: Boolean!, default: Boolean!, enabled: Boolean!, id: Int!, locale: String!, name: String!, time_24: Boolean!, timezone: String!): ShowCoreLanguages!
admin__core_languages__update(code: String!, file: Upload!): String!
admin__core_main_settings__edit(site_copyright: [TextLanguageInput!]!, site_description: [TextLanguageInput!]!, site_name: String!, site_short_name: String!): EditAdminSettingsObj!
admin__core_manifest_metadata__edit(background_color: String!, display: String!, start_url: String!, theme_color: String!): ShowAdminManifestMetadataObj!
admin__core_members__create(email: String!, name: String!, password: String!): SignUpCoreSessionsObj!
Expand Down
183 changes: 105 additions & 78 deletions apps/docs/content/docs/ui/forms/auto-form.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ title: Auto Form
description: Automatically generate form fields based on a schema.
---

Component created based on [Auto Form by vantezzen](https://github.com/vantezzen/auto-form).

## Support Fileds

- [Color Picker](/docs/ui/forms/color-picker)
Expand All @@ -17,7 +15,7 @@ Component created based on [Auto Form by vantezzen](https://github.com/vantezzen
- [Switch](/docs/ui/forms/switch)
- [Text Language Input](/docs/ui/forms/text-language-input)
- [Icon Picker](/docs/ui/forms/icon-picker)
- [Tags Input](/docs/ui/forms/tags-input)
- [Tag Input](/docs/ui/forms/tag-input)
- [Combobox](/docs/ui/forms/combobox)
- [Date Picker](/docs/ui/forms/date-picker)

Expand Down Expand Up @@ -56,57 +54,80 @@ const formSchema = z.object({
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
name: {
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
},
}}
]}
/>
```

## Zod Configuration

### Validators

Our component is smart and well integrated with Zod, so you can use all the validators that Zod provides. For exampele if you use `zod.string().min(8)`, the input will automatically have a minlength="8" attribute.
## Component Props

Validation methods not supported by HTML will automatically be checked when the form is submitted.
Each field has a set of props with `Props` surfix that can be passed to the component. For example, for the `AutoFormInput` component, you can pass the `AutoFormInputProps` props using the `componentProps` prop.

### Descriptions

You can add a description to your schema fields by using the `description` method.
```tsx
import {
AutoFormInput,
AutoFormInputProps,
} from 'vitnode-frontend/components/auto-form/fields/input';

```ts
const formSchema = z.object({
username: z.string().describe('Your username'),
});
<AutoForm
formSchema={formSchema}
fields={[
{
id: 'username',
component: AutoFormInput,
componentProps: {
type: 'password',
} as AutoFormInputProps,
},
]}
/>;
```

or using the `description` method in the `fieldConfig` object.
<Callout title="Avoid function for component argument!" type="error">
Do not use function for component argument like this:

```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
name: {
fieldType: AutoFormInput
description: 'Test description',
fields={[
{
id: 'username',
component: props => <AutoFormInput {...props} />, // [!code highlight]
},
}}
]}
/>
```

You can also use the `description` as function to get the current value of the field.
This will cause the component to re-render on every change.

</Callout>

## Zod Configuration

### Validators

Our component is smart and well integrated with Zod, so you can use all the validators that Zod provides. For exampele if you use `zod.string().min(8)`, the input will automatically have a minlength="8" attribute.

Validation methods not supported by HTML will automatically be checked when the form is submitted.

### Descriptions

You can add a description to your field by passing the `description` prop.

```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
name: {
fieldType: AutoFormInput
description: value => `The current value is ${value}`,
fields={[
{
id: 'username',
component: AutoFormInput,
description: 'Test description', // [!code highlight]
},
}}
]}
/>
```

Expand Down Expand Up @@ -137,12 +158,13 @@ You can set a label for a field by using the `label` method.
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
label: 'Your username',
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
label: 'Your username', // [!code highlight]
},
}}
]}
/>
```

Expand Down Expand Up @@ -210,31 +232,31 @@ const formSchema = z.object({
/>
```

### Render Parent

You can render the parent object by using the `renderParent` prop.

Avaliable props:
### Child Component

- `children`: The children of the parent object.
- `field`: The field object `ControllerRenderProps` from `react-hook-form`.
If you want to render something below the field, you can use the `childComponent` prop.

```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
start_url: {
label: t('start_url.label'),
description: t('start_url.desc'),
fieldType: props => <AutoFormInput className="w-64" {...props} />,
renderParent: ({ children, field }: FieldRenderParentProps) => (
<div className="flex flex-wrap items-center gap-1">
<span>Something</span>
{children} // Here is the input
</div>
),
fields={[
{
id: 'name',
label: t('sign_up.form.name.label'),
description: t('sign_up.form.name.desc'),
component: AutoFormInput,
childComponent: ({ field }) => {
const value: string = field.value ?? '';
if (!value.length) return null;

return (
<span className="text-muted-foreground mt-1 block max-w-md truncate text-sm">
{value}
</span>
);
},
},
}}
]}
/>
```

Expand All @@ -245,11 +267,12 @@ You can use the `onSubmit` prop to get the form data.
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
},
}}
]}
onSubmit={data => {
console.log(data);
}}
Expand All @@ -261,15 +284,17 @@ You can get access to the `form` from `react-hook-form` by using the `form` prop
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
},
}}
]}
onSubmit={(data, form) => {
console.log(data);
form.setError("username", { type: "manual", message: "This is an error" });
form.setError('username', { type: 'manual', message: 'This is an error' });
}}
/>
```

You can also move `onSubmit` to a separate function.
Expand Down Expand Up @@ -315,11 +340,12 @@ Component has a submit button by default with the text `Save` include translatio
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
},
}}
]}
submitButton={props => (
<Button {...props} className="w-full">
{t('sign_in.form.submit')}
Expand All @@ -337,16 +363,17 @@ You can change the theme of the form by using the `theme` prop and passing `hori
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
username: {
fieldType: AutoFormInput,
fields={[
{
id: 'username',
component: AutoFormInput,
},
}}
]}
theme="horizontal" // [!code highlight]
/>
```

### Get Values from Form
## Get Values from Form

You can get the values from the form by using the `onValuesChange` prop.

Expand All @@ -371,7 +398,7 @@ For example if `provider` is not `smtp`, the field `smtp` will be hidden.
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{}}
fields={[]}
dependencies={[
{
sourceField: 'provider',
Expand All @@ -390,7 +417,7 @@ For example if `provider` is `resend`, the field `resend_key` will be required.
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{}}
fields={[]}
dependencies={[
{
sourceField: 'email.provider',
Expand All @@ -409,7 +436,7 @@ For example if `provider` is not `smtp`, the field `smtp` will be disabled.
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{}}
fields={[]}
dependencies={[
{
sourceField: 'email.provider',
Expand All @@ -428,7 +455,7 @@ For example if `vegetarian` checkbox hides the `Beef Wellington` option from `me
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{}}
fields={[]}
dependencies={[
{
sourceField: 'vegetarian',
Expand Down
10 changes: 5 additions & 5 deletions apps/docs/content/docs/ui/forms/checkbox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ const formSchema = z.object({
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
allow_files: {
label: 'Allow Files',
fieldType: AutoFormCheckbox, // [!code highlight]
fields={[
{
id: 'allow_files',
component: AutoFormCheckbox, // [!code highlight]
},
}}
]}
/>
```

Expand Down
10 changes: 5 additions & 5 deletions apps/docs/content/docs/ui/forms/color-picker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ const formSchema = z.object({
```tsx
<AutoForm
formSchema={formSchema}
fieldConfig={{
color_primary: {
label: 'Color picker',
fieldType: AutoFormColor, // [!code highlight]
fields={[
{
id: 'color_primary',
component: AutoFormColor, // [!code highlight]
},
}}
]}
/>
```

Expand Down
Loading
Loading