design system token v0.1
This commit is contained in:
211
stories/Form/Form.stories.tsx
Normal file
211
stories/Form/Form.stories.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import React from 'react'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
|
||||
import {
|
||||
Form,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
const meta = {
|
||||
title: 'Form/Form',
|
||||
component: Form,
|
||||
tags: ['autodocs'],
|
||||
parameters: { layout: 'centered' },
|
||||
} satisfies Meta<typeof Form>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
const profileSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.min(2, { message: 'Username must be at least 2 characters.' })
|
||||
.max(30, { message: 'Username must not be longer than 30 characters.' }),
|
||||
email: z.string().email({ message: 'Please enter a valid email address.' }),
|
||||
})
|
||||
|
||||
type ProfileValues = z.infer<typeof profileSchema>
|
||||
|
||||
function ProfileForm() {
|
||||
const form = useForm<ProfileValues>({
|
||||
resolver: zodResolver(profileSchema),
|
||||
defaultValues: {
|
||||
username: '',
|
||||
email: '',
|
||||
},
|
||||
})
|
||||
|
||||
function onSubmit(data: ProfileValues) {
|
||||
alert(JSON.stringify(data, null, 2))
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="w-100 space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="johndoe" {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
This is your public display name.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" placeholder="john@example.com" {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
We will never share your email with anyone.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit">Submit</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export const Default: Story = {
|
||||
render: () => <ProfileForm />,
|
||||
}
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.string().email({ message: 'Invalid email address.' }),
|
||||
password: z
|
||||
.string()
|
||||
.min(8, { message: 'Password must be at least 8 characters.' }),
|
||||
})
|
||||
|
||||
type LoginValues = z.infer<typeof loginSchema>
|
||||
|
||||
function LoginForm() {
|
||||
const form = useForm<LoginValues>({
|
||||
resolver: zodResolver(loginSchema),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
},
|
||||
})
|
||||
|
||||
function onSubmit(data: LoginValues) {
|
||||
alert(JSON.stringify(data, null, 2))
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="w-100 space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" placeholder="you@example.com" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Enter password" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full">
|
||||
Sign in
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export const Login: Story = {
|
||||
render: () => <LoginForm />,
|
||||
}
|
||||
|
||||
function PrefilledErrorForm() {
|
||||
const form = useForm<ProfileValues>({
|
||||
resolver: zodResolver(profileSchema),
|
||||
defaultValues: {
|
||||
username: 'a',
|
||||
email: 'not-an-email',
|
||||
},
|
||||
})
|
||||
|
||||
// Trigger validation on mount
|
||||
React.useEffect(() => {
|
||||
form.trigger()
|
||||
}, [form])
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form className="w-100 space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit">Submit</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export const WithErrors: Story = {
|
||||
render: () => <PrefilledErrorForm />,
|
||||
}
|
||||
Reference in New Issue
Block a user