Skip to content

Commit

Permalink
Merge pull request #65 from tyghaykal/main
Browse files Browse the repository at this point in the history
feat(autoform): add default value on array, set value 0 to show on form input
  • Loading branch information
vantezzen authored Mar 21, 2024
2 parents a24db0b + 678aabf commit ccde9f2
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 7 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ const formSchema = z.object({
});
```
If you want to set default value of date, convert it to Date first using `new Date(val)`.
#### Sub-objects
You can nest objects to create accordion sections.
Expand Down Expand Up @@ -371,6 +373,33 @@ const formSchema = z.object({
Arrays are not supported as the root element of the form schema.
You also can set default value of an array using .default(), but please makesure the array element has same structure with the schema.
```tsx
const formSchema = z.object({
guestListName: z.string(),
invitedGuests: z
.array(
// Define the fields for each item
z.object({
name: z.string(),
age: z.coerce.number(),
})
)
.describe("Guests invited to the party")
.default([
{
name: "John",
age: 24,
},
{
name: "Jane",
age: 20,
},
]),
});
```
### Field configuration
As zod doesn't allow adding other properties to the schema, you can use the `fieldConfig` prop to add additional configuration for the UI of each field.
Expand Down
22 changes: 20 additions & 2 deletions src/components/ui/auto-form/fields/array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ import * as z from "zod";
import { beautifyObjectName } from "../utils";
import AutoFormObject from "./object";

function isZodArray(
item: z.ZodArray<any> | z.ZodDefault<any>,
): item is z.ZodArray<any> {
return item instanceof z.ZodArray;
}

function isZodDefault(
item: z.ZodArray<any> | z.ZodDefault<any>,
): item is z.ZodDefault<any> {
return item instanceof z.ZodDefault;
}

export default function AutoFormArray({
name,
item,
Expand All @@ -19,7 +31,7 @@ export default function AutoFormArray({
fieldConfig,
}: {
name: string;
item: z.ZodArray<any>;
item: z.ZodArray<any> | z.ZodDefault<any>;
form: ReturnType<typeof useForm>;
path?: string[];
fieldConfig?: any;
Expand All @@ -30,6 +42,12 @@ export default function AutoFormArray({
});
const title = item._def.description ?? beautifyObjectName(name);

const itemDefType = isZodArray(item)
? item._def.type
: isZodDefault(item)
? item._def.innerType._def.type
: null;

return (
<AccordionItem value={name} className="border-none">
<AccordionTrigger>{title}</AccordionTrigger>
Expand All @@ -39,7 +57,7 @@ export default function AutoFormArray({
return (
<div className="mt-4 flex flex-col" key={`${key}`}>
<AutoFormObject
schema={item._def.type as z.ZodObject<any, any>}
schema={itemDefType as z.ZodObject<any, any>}
form={form}
fieldConfig={fieldConfig}
path={[...path, index.toString()]}
Expand Down
30 changes: 29 additions & 1 deletion src/components/ui/auto-form/tests/basics.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AutoForm from "../index";
import { z } from "zod";
import AutoForm from "../index";

describe("<AutoForm />", () => {
it("renders fields", () => {
Expand Down Expand Up @@ -194,4 +194,32 @@ describe("<AutoForm />", () => {

cy.get("p").contains("Your username here");
});

it("can set default values on array", () => {
const formSchema = z.object({
arr: z.array(z.object({ name: z.string(), age: z.number() })).default([
{ name: "Haykal", age: 21 },
{ name: "John", age: 20 },
]),
});

cy.mount(<AutoForm formSchema={formSchema} />);

//get button with text Arr
cy.get("button").contains("Arr").click();
cy.get("input[name='arr.0.name']").should("have.value", "Haykal");
cy.get("input[name='arr.0.age']").should("have.value", "21");
cy.get("input[name='arr.1.name']").should("have.value", "John");
cy.get("input[name='arr.1.age']").should("have.value", "20");
});

it("can set default value of number to 0", () => {
const formSchema = z.object({
number: z.number().default(0),
});

cy.mount(<AutoForm formSchema={formSchema} />);

cy.get("input[name='number']").should("have.value", "0");
});
});
5 changes: 4 additions & 1 deletion src/components/ui/auto-form/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ export function getDefaultValues<Schema extends z.ZodObject<any, any>>(
}
} else {
let defaultValue = getDefaultValueInZodStack(item);
if (!defaultValue && fieldConfig?.[key]?.inputProps) {
if (
(defaultValue === null || defaultValue === "") &&
fieldConfig?.[key]?.inputProps
) {
defaultValue = (fieldConfig?.[key]?.inputProps as unknown as any)
.defaultValue;
}
Expand Down
6 changes: 3 additions & 3 deletions src/examples/Array.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Json from "@/components/ui/json";
import { useState } from "react";
import * as z from "zod";
import AutoForm, { AutoFormSubmit } from "../components/ui/auto-form";
import {
Expand All @@ -7,8 +9,6 @@ import {
CardHeader,
CardTitle,
} from "../components/ui/card";
import { useState } from "react";
import Json from "@/components/ui/json";

const formSchema = z.object({
guestListName: z.string(),
Expand All @@ -17,7 +17,7 @@ const formSchema = z.object({
z.object({
name: z.string(),
age: z.coerce.number(),
}),
})
)
.describe("Guests invited to the party"),
});
Expand Down

0 comments on commit ccde9f2

Please sign in to comment.