docs: add form example for checkbox input and datepicker

This commit is contained in:
sadeghbarati 2023-10-02 15:36:35 +03:30
parent 854cb8f20c
commit 5868374679
27 changed files with 667 additions and 17 deletions

View File

@ -30,6 +30,16 @@ import { Checkbox } from '@/components/ui/checkbox'
## Examples
### With text
<ComponentPreview name="CheckboxWithText" />
### Disabled
<ComponentPreview name="CheckboxDisabled" />
<ComponentPreview name="CheckboxDisabled" />
### Form
<ComponentPreview name="CheckboxFormSingle" />
<ComponentPreview name="CheckboxFormMultiple" />

View File

@ -58,10 +58,12 @@ const date = ref<Date>()
### Date Range Picker
<ComponentPreview name="DatePickerWithRange" />
<ComponentPreview name="DatePickerWithRange" />
### Date Picker
<ComponentPreview name="DatePickerDemo" />
<ComponentPreview name="DatePickerDemo" />
### Form
<ComponentPreview name="DatePickerForm" />

View File

@ -50,13 +50,13 @@ The `<Form />` component is a wrapper around the `vee-validate` library. It prov
</Form>
```
## Examples
## Example
<TabPreview name="Component" :names="['Component', 'Native']">
<template #Component>
#### Input Component
#### `Input` Component
```vue
<FormField v-slot="{ componentField }">
@ -75,7 +75,7 @@ The `<Form />` component is a wrapper around the `vee-validate` library. It prov
<template #Native>
#### Native input element
#### native `input` element
```vue
<FormField v-slot="{ field }">
@ -312,7 +312,20 @@ That's it. You now have a fully accessible form that is type-safe with client-si
<ComponentPreview
name="InputForm"
className="[&_[role=tablist]]:hidden [&>div>div:first-child]:hidden"
class="[&_[role=tablist]]:hidden [&>div>div:first-child]:hidden"
/>
</Steps>
## Examples
See the following links for more examples on how to use the `vee-validate` features with other components:
- [Checkbox](/docs/components/checkbox#form)
- [Date Picker](/docs/components/date-picker#form)
- [Input](/docs/components/input#form)
- [Radio Group](/docs/components/radio-group#form)
- [Select](/docs/components/select#form)
- [Switch](/docs/components/switch#form)
- [Textarea](/docs/components/textarea#form)
- [Combobox](/docs/components/combobox#form)

View File

@ -41,4 +41,28 @@ import { Input } from '@/components/ui/input'
<template>
<Input />
</template>
```
```
### Default
<ComponentPreview name="InputDemo" class="[&_input]:max-w-xs" />
### File
<ComponentPreview name="InputFile" class="[&_input]:max-w-xs" />
### Disabled
<ComponentPreview name="InputDisabled" class="[&_input]:max-w-xs" />
### With Label
<ComponentPreview name="InputWithLabel" class="[&_input]:max-w-xs" />
### With Button
<ComponentPreview name="InputWithButton" class="[&_input]:max-w-xs" />
### Form
<ComponentPreview name="InputForm" />

View File

@ -85,7 +85,9 @@ const onSubmit = handleSubmit((values) => {
<Checkbox
:checked="value.includes(item.id)"
@update:checked="(checked) => {
handleChange(checked ? [...value, item.id] : value.filter(id => id !== item.id))
if (Array.isArray(value)) {
handleChange(checked ? [...value, item.id] : value.filter(id => id !== item.id))
}
}"
/>
</FormControl>

View File

@ -6,7 +6,7 @@ import { Checkbox } from '@/lib/registry/default/ui/checkbox'
<div class="flex items-center space-x-2">
<Checkbox id="terms" />
<label
htmlFor="terms"
for="terms"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions

View File

@ -0,0 +1,102 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
const items = [
{
id: 'recents',
label: 'Recents',
},
{
id: 'home',
label: 'Home',
},
{
id: 'applications',
label: 'Applications',
},
{
id: 'desktop',
label: 'Desktop',
},
{
id: 'downloads',
label: 'Downloads',
},
{
id: 'documents',
label: 'Documents',
},
] as const
const formSchema = toTypedSchema(z.object({
items: z.array(z.string()).refine(value => value.some(item => item), {
message: 'You have to select at least one item.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
items: ['recents', 'home'],
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form @submit="onSubmit">
<FormField name="items">
<FormItem>
<div class="mb-4">
<FormLabel class="text-base">
Sidebar
</FormLabel>
<FormDescription>
Select the items you want to display in the sidebar.
</FormDescription>
</div>
<FormField v-for="item in items" v-slot="{ value, handleChange }" :key="item.id" name="items">
<FormItem :key="item.id" class="flex flex-row items-start space-x-3 space-y-0">
<FormControl>
<Checkbox
:checked="value.includes(item.id)"
@update:checked="(checked) => {
if (Array.isArray(value)) {
handleChange(checked ? [...value, item.id] : value.filter(id => id !== item.id))
}
}"
/>
</FormControl>
<FormLabel class="font-normal">
{{ item.label }}
</FormLabel>
</FormItem>
</FormField>
<FormMessage />
</FormItem>
</FormField>
<div class="flex justify-start mt-4">
<Button type="submit">
Submit
</Button>
</div>
</form>
</template>

View File

@ -0,0 +1,54 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
const formSchema = toTypedSchema(z.object({
mobile: z.boolean().default(false).optional(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
mobile: true,
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-6" @submit="onSubmit">
<FormField v-slot="{ value, handleChange }" name="mobile">
<FormItem class="flex flex-row items-start gap-x-3 space-y-0 rounded-md border p-4">
<FormControl>
<Checkbox :checked="value" @update:checked="handleChange" />
</FormControl>
<div class="space-y-1 leading-none">
<FormLabel>Use different settings for my mobile devices</FormLabel>
<FormDescription>
You can manage your mobile notifications in the
<a href="/examples/forms">mobile settings</a> page.
</FormDescription>
<FormMessage />
</div>
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
</script>
<template>
<div class="items-top flex gap-x-2">
<Checkbox id="terms1" />
<div class="grid gap-1.5 leading-none">
<label
for="terms1"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
<p class="text-sm text-muted-foreground">
You agree to our Terms of Service and Privacy Policy.
</p>
</div>
</div>
</template>

View File

@ -0,0 +1,74 @@
<script setup lang="ts">
import { format } from 'date-fns'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/default/ui/popover'
const formSchema = toTypedSchema(z.object({
dob: z.date({
required_error: 'A date of birth is required.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField, value }" name="dob">
<FormItem class="flex flex-col">
<FormLabel>Date of birth</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline" :class="cn(
'w-[240px] ps-3 text-start font-normal',
!value && 'text-muted-foreground',
)"
>
<span>{{ value ? format(value, "PPP") : "Pick a date" }}</span>
<CalendarIcon class="ms-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent class="p-0">
<Calendar v-bind="componentField" />
</PopoverContent>
</Popover>
<FormDescription>
Your date of birth is used to calculate your age.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,7 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/default/ui/input'
</script>
<template>
<Input disabled type="email" placeholder="Email" />
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/default/ui/input'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<div class="grid w-full max-w-sm items-center gap-1.5">
<Label for="picture">Picture</Label>
<Input id="picture" type="file" />
</div>
</template>

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/default/ui/input'
import { Button } from '@/lib/registry/default/ui/button'
</script>
<template>
<div class="flex w-full max-w-sm items-center gap-1.5">
<Input id="email" type="email" placeholder="Email" />
<Button type="submit">
Subscribe
</Button>
</div>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/default/ui/input'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<div class="grid w-full max-w-sm items-center gap-1.5">
<Label for="email">Email</Label>
<Input id="email" type="email" placeholder="Email" />
</div>
</template>

View File

@ -6,7 +6,7 @@ import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
<div class="flex items-center space-x-2">
<Checkbox id="terms" />
<label
htmlFor="terms"
for="terms"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions

View File

@ -0,0 +1,15 @@
<script setup lang="ts">
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
</script>
<template>
<div class="items-top flex space-x-2">
<Checkbox id="terms1" disabled />
<label
for="terms2"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
</div>
</template>

View File

@ -0,0 +1,102 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
const items = [
{
id: 'recents',
label: 'Recents',
},
{
id: 'home',
label: 'Home',
},
{
id: 'applications',
label: 'Applications',
},
{
id: 'desktop',
label: 'Desktop',
},
{
id: 'downloads',
label: 'Downloads',
},
{
id: 'documents',
label: 'Documents',
},
] as const
const formSchema = toTypedSchema(z.object({
items: z.array(z.string()).refine(value => value.some(item => item), {
message: 'You have to select at least one item.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
items: ['recents', 'home'],
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form @submit="onSubmit">
<FormField name="items">
<FormItem>
<div class="mb-4">
<FormLabel class="text-base">
Sidebar
</FormLabel>
<FormDescription>
Select the items you want to display in the sidebar.
</FormDescription>
</div>
<FormField v-for="item in items" v-slot="{ value, handleChange }" :key="item.id" name="items">
<FormItem :key="item.id" class="flex flex-row items-start space-x-3 space-y-0">
<FormControl>
<Checkbox
:checked="value.includes(item.id)"
@update:checked="(checked) => {
if (Array.isArray(value)) {
handleChange(checked ? [...value, item.id] : value.filter(id => id !== item.id))
}
}"
/>
</FormControl>
<FormLabel class="font-normal">
{{ item.label }}
</FormLabel>
</FormItem>
</FormField>
<FormMessage />
</FormItem>
</FormField>
<div class="flex justify-start mt-4">
<Button type="submit">
Submit
</Button>
</div>
</form>
</template>

View File

@ -0,0 +1,54 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
const formSchema = toTypedSchema(z.object({
mobile: z.boolean().default(false).optional(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
mobile: true,
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-6" @submit="onSubmit">
<FormField v-slot="{ value, handleChange }" name="mobile">
<FormItem class="flex flex-row items-start gap-x-3 space-y-0 rounded-md border p-4 shadow">
<FormControl>
<Checkbox :checked="value" @update:checked="handleChange" />
</FormControl>
<div class="space-y-1 leading-none">
<FormLabel>Use different settings for my mobile devices</FormLabel>
<FormDescription>
You can manage your mobile notifications in the
<a href="/examples/forms">mobile settings</a> page.
</FormDescription>
<FormMessage />
</div>
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
</script>
<template>
<div class="items-top flex gap-x-2">
<Checkbox id="terms1" />
<div class="grid gap-1.5 leading-none">
<label
for="terms1"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
<p class="text-sm text-muted-foreground">
You agree to our Terms of Service and Privacy Policy.
</p>
</div>
</div>
</template>

View File

@ -3,19 +3,19 @@ import { ref } from 'vue'
import { CaretSortIcon, CheckIcon } from '@radix-icons/vue'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from '@/lib/registry/default/ui/command'
} from '@/lib/registry/new-york/ui/command'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/default/ui/popover'
} from '@/lib/registry/new-york/ui/popover'
const frameworks = [
{ value: 'next.js', label: 'Next.js' },

View File

@ -0,0 +1,74 @@
<script setup lang="ts">
import { format } from 'date-fns'
import { CalendarIcon } from '@radix-icons/vue'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/new-york/ui/popover'
const formSchema = toTypedSchema(z.object({
dob: z.date({
required_error: 'A date of birth is required.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField, value }" name="dob">
<FormItem class="flex flex-col">
<FormLabel>Date of birth</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline" :class="cn(
'w-[240px] ps-3 text-start font-normal',
!value && 'text-muted-foreground',
)"
>
<span>{{ value ? format(value, "PPP") : "Pick a date" }}</span>
<CalendarIcon class="ms-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent class="p-0">
<Calendar v-bind="componentField" />
</PopoverContent>
</Popover>
<FormDescription>
Your date of birth is used to calculate your age.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</Form>
</template>

View File

@ -0,0 +1,7 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/new-york/ui/input'
</script>
<template>
<Input disabled type="email" placeholder="Email" />
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/new-york/ui/input'
import { Label } from '@/lib/registry/new-york/ui/label'
</script>
<template>
<div class="grid w-full max-w-sm items-center gap-1.5">
<Label for="picture">Picture</Label>
<Input id="picture" type="file" />
</div>
</template>

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/new-york/ui/input'
import { Button } from '@/lib/registry/new-york/ui/button'
</script>
<template>
<div class="flex w-full max-w-sm items-center gap-1.5">
<Input id="email" type="email" placeholder="Email" />
<Button type="submit">
Subscribe
</Button>
</div>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Input } from '@/lib/registry/new-york/ui/input'
import { Label } from '@/lib/registry/new-york/ui/label'
</script>
<template>
<div class="grid w-full max-w-sm items-center gap-1.5">
<Label for="email">Email</Label>
<Input id="email" type="email" placeholder="Email" />
</div>
</template>

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
const props = defineProps<AlertDialogActionProps>()
</script>

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/lib/registry/default/ui/button'
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
const props = defineProps<AlertDialogCancelProps>()
</script>