Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.18.3
version: 11.1.3

- name: Install Node.js
uses: actions/setup-node@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bump_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.18.3
version: 11.1.3

- name: Install Node.js
uses: actions/setup-node@v4
Expand Down
8 changes: 4 additions & 4 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
},
"dependencies": {
"@hono/zod-openapi": "^1.3.0",
"@hono/zod-validator": "^0.7.6",
"@hono/zod-validator": "^0.8.0",
"@vitnode/core": "workspace:*",
"drizzle-kit": "^0.31.10",
"drizzle-orm": "^0.45.2",
"hono": "^4.12.16",
"hono": "^4.12.21",
"next-intl": "^4.11.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
Expand All @@ -36,9 +36,9 @@
"@vitnode/nodemailer": "workspace:*",
"dotenv": "^17.4.2",
"eslint": "^10.2.1",
"react-email": "^6.0.5",
"react-email": "^6.1.5",
"tsc-alias": "^1.8.16",
"tsx": "^4.21.0",
"tsx": "^4.22.3",
"typescript": "^6.0.3"
}
}
9 changes: 9 additions & 0 deletions apps/api/src/locales/@vitnode/core/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
{
"core": {
"global": {
"close": "Close",
"confirm": "Confirm",
"previous": "Previous",
"next": "Next",
"current_page": "Current page",
"go_to_page": "Go to page",
"previous_page": "Previous page",
"next_page": "Next page",
"remove": "Remove",
"editor": {
"undo": "Undo",
"redo": "Redo",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/components.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"style": "radix-vega",
"rsc": true,
"tsx": true,
"tailwind": {
Expand Down
26 changes: 13 additions & 13 deletions apps/docs/content/docs/dev/email/components/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ description: A button or link component for emails.

## Preview

import { ImgDocs } from '@/components/fumadocs/img';
import buttonPreviewImg from './button-preview.png';
import { ImgDocs } from "@/components/fumadocs/img";
import buttonPreviewImg from "./button-preview.png";

<ImgDocs src={buttonPreviewImg} alt="Buttons Preview" />

## Usage

```ts
import { EmailButton } from '@vitnode/core/emails/ui/button';
import { EmailButton } from "@vitnode/core/emails/ui/button";
```

```tsx
Expand All @@ -22,24 +22,24 @@ import { EmailButton } from '@vitnode/core/emails/ui/button';

## Props

import { TypeTable } from 'fumadocs-ui/components/type-table';
import { TypeTable } from "fumadocs-ui/components/type-table";

<TypeTable
type={{
variant: {
description: 'The variant of the button.',
type: 'default | secondary | outline | ghost | link | destructive | destructiveGhost',
default: 'default',
description: "The variant of the button.",
type: "default | secondary | outline | ghost | link | destructive | destructiveGhost",
default: "default",
},
size: {
description: 'The size of the button.',
type: 'default | sm | lg',
default: 'default',
description: "The size of the button.",
type: "default | sm | lg",
default: "default",
},
href: {
description: 'The URL the button links to.',
type: 'string',
default: '',
description: "The URL the button links to.",
type: "string",
default: "",
},
}}
/>
142 changes: 139 additions & 3 deletions apps/docs/content/docs/ui/auto-form.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import { AutoFormCheckbox } from "@vitnode/core/components/form/fields/checkbox"
import { AutoFormInput } from "@vitnode/core/components/form/fields/input";
import { AutoFormSelect } from "@vitnode/core/components/form/fields/select";
import { AutoFormTextarea } from "@vitnode/core/components/form/fields/textarea";
import { AutoFormArray } from "@vitnode/core/components/form/fields/array";
import { InputGroupAddon } from "@vitnode/core/components/ui/input-group";
import { Search } from "lucide-react";
import { z } from "zod";
```

Expand All @@ -25,10 +28,19 @@ const formSchema = z.object({
.email("Please enter a valid email address")
.describe("We'll use this email to contact you. (from zod schema)"),
user_type: z.enum(["admin", "editor", "viewer"]),
links: z
.array(
z.object({
title: z.string().min(1, "Title is required"),
url: z.string().url(),
}),
)
.optional(),
accept_terms: z.boolean().refine(val => val, {
message: "You must accept the terms and conditions",
}),
description: z.string().min(10, "Description must be at least 10 characters"),
search: z.string().optional(),
});
```

Expand Down Expand Up @@ -64,6 +76,29 @@ const formSchema = z.object({
/>
),
},
{
id: "links",
component: props => (
<AutoFormArray
{...props}
label="Profile Links"
fields={[
{
id: "title",
component: subProps => (
<AutoFormInput {...subProps} label="Title" />
),
},
{
id: "url",
component: subProps => (
<AutoFormInput {...subProps} label="URL" />
),
},
]}
/>
),
},
{
id: "accept_terms",
component: props => (
Expand All @@ -84,6 +119,17 @@ const formSchema = z.object({
/>
),
},
{
id: "search",
component: props => (
<AutoFormInput {...props} placeholder="Search..." label="Search">
<InputGroupAddon>
<Search />
</InputGroupAddon>
<InputGroupAddon align="inline-end">12 results</InputGroupAddon>
</AutoFormInput>
),
},
]}
formSchema={formSchema}
/>
Expand Down Expand Up @@ -166,6 +212,57 @@ const formSchema = z.object({
});
```

### Arrays

You can create dynamic list of fields using `AutoFormArray` component working with `z.array(z.object(...))` schema:

```ts
const formSchema = z.object({
guests: z
.array(
z.object({
name: z.string(),
email: z.string().email(),
}),
)
.min(1),
});
```

```tsx
{
id: "guests",
component: props => (
<AutoFormArray
{...props}
label="Guests"
fields={[
{ id: "name", component: p => <AutoFormInput {...p} label="Name" /> },
{ id: "email", component: p => <AutoFormInput {...p} label="Email" /> },
]}
/>
)
}
```

You can customize the wrapper, items layout, and Add/Remove buttons logic through `className`, `addButtonLabel` props:

```tsx
{
id: "guests",
component: props => (
<AutoFormArray
{...props}
label="Guests"
fields={[
{ id: "name", className: "flex-1", component: p => <AutoFormInput {...p} label="Name" /> },
{ id: "email", component: p => <AutoFormInput {...p} label="Email" /> },
]}
/>
)
}
```

### Advanced Validation

Auto Form supports all Zod validators:
Expand All @@ -186,9 +283,48 @@ const formSchema = z.object({

## Custom Fields

<Callout type="warn" title="This documentation is under construction! 🚧">
We're working hard to bring you the best documentation experience.
</Callout>
Because Auto Form fields are controlled entirely by the `component` property function, creating a custom field component is just a matter of rendering your own UI using the provided props. The props passed to the `component` function contain the field properties managed by `react-hook-form` along with Zod validation details.

Here is an example of creating a custom color picker input:

```ts
const formSchema = z.object({
custom_color: z
.string()
.default("#000000")
.describe("Pick your favorite color."),
});
```

```tsx
<AutoForm
formSchema={formSchema}
fields={[
{
id: "custom_color",
component: props => (
<div className="flex w-full flex-col gap-3">
<div className="text-sm leading-none font-medium">
Custom Color Picker
</div>
<input
{...props.field}
value={(props.field.value as string) ?? "#000000"}
className="h-10 w-24 cursor-pointer rounded-md border p-1"
type="color"
/>
{props.description && (
<div className="text-muted-foreground text-sm">
{props.description}
</div>
)}
</div>
),
},
]}
onSubmit={values => console.log(values)}
/>
```

## Form Submission

Expand Down
18 changes: 9 additions & 9 deletions apps/docs/content/docs/ui/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ description: A button component for triggering actions in your application.
## Usage

```ts
import { Home } from 'lucide-react';
import { Button } from '@vitnode/core/components/ui/button';
import { Home } from "lucide-react";
import { Button } from "@vitnode/core/components/ui/button";
```

```tsx
Expand All @@ -23,19 +23,19 @@ import { Button } from '@vitnode/core/components/ui/button';

## Props

import { TypeTable } from 'fumadocs-ui/components/type-table';
import { TypeTable } from "fumadocs-ui/components/type-table";

<TypeTable
type={{
variant: {
description: 'The variant of the button.',
type: 'default | secondary | outline | ghost | link | destructive| destructiveGhost',
default: 'default',
description: "The variant of the button.",
type: "default | secondary | outline | ghost | link | destructive",
default: "default",
},
size: {
description: 'The size of the button.',
type: 'default | sm | lg | icon',
default: 'default',
description: "The size of the button.",
type: "default | sm | lg | icon",
default: "default",
},
}}
/>
Loading
Loading