From d03067db67e51b46a5f653f1d1ee270b9fa70535 Mon Sep 17 00:00:00 2001 From: Sadegh Barati Date: Fri, 6 Oct 2023 07:34:38 +0330 Subject: [PATCH] feat: add `vee-validate` (#85) * feat: add `vee-validate` * chore: update * chore: update `AccountForm` example - add `FormDescription` component - include `src` in tsconfig * refactor: use radix-vue `Slot` component * chore: refresh lockfile * chore: update `ProfileForm.vue` and `AccountForm` fix vee-validate initialValues on components with `componentField` slotProp * chore: update `AppearanceForm.vue` update pnpm and some deps -_- * refactor: update - add new-york style - off eslint import/first rule - use `useId` from radix-vue * fix: class-name -> class * refactor: simplify validation for `Command` component * fix: v-bind="field" -> v-bind="componentField" * fix: useAttrs to prevent class duplication * docs: add `form.md` - change TabPreview.vue to showcase way of using vee-validate * docs: add form example for `checkbox` `input` and `datepicker` * docs: add `combobox`, `datepicker`, `radio-group`, `select`, `switch` and `textarea` form and some other exmaples * chore: typo, update `zod`, `vite`, and `@vitejs/plugin-vue` --- .eslintrc.cjs | 1 + .../theme/components/TabPreview.vue | 25 +- apps/www/.vitepress/theme/config/docs.ts | 13 +- apps/www/package.json | 20 +- .../src/content/docs/components/checkbox.md | 12 +- .../src/content/docs/components/combobox.md | 18 +- .../content/docs/components/date-picker.md | 12 +- apps/www/src/content/docs/components/form.md | 331 +++ apps/www/src/content/docs/components/input.md | 26 +- .../content/docs/components/radio-group.md | 8 +- .../www/src/content/docs/components/select.md | 6 + .../www/src/content/docs/components/switch.md | 8 +- .../src/content/docs/components/textarea.md | 28 +- .../examples/forms/components/AccountForm.vue | 207 +- .../forms/components/AppearanceForm.vue | 242 +- .../examples/forms/components/DisplayForm.vue | 83 +- .../forms/components/NotificationsForm.vue | 275 +- .../examples/forms/components/ProfileForm.vue | 201 +- .../lib/registry/default/example/CardChat.vue | 6 +- .../default/example/Cards/DataTable.vue | 2 +- .../registry/default/example/CheckboxDemo.vue | 2 +- .../default/example/CheckboxFormMultiple.vue | 102 + .../default/example/CheckboxFormSingle.vue | 54 + .../default/example/CheckboxWithText.vue | 20 + .../default/example/ComboboxDropdownMenu.vue | 108 + .../registry/default/example/ComboboxForm.vue | 112 + .../default/example/ComboboxPopover.vue | 118 + .../default/example/DatePickerForm.vue | 74 + .../default/example/DatePickerWithPresets.vue | 73 + .../default/example/InputDisabled.vue | 7 + .../registry/default/example/InputFile.vue | 11 + .../registry/default/example/InputForm.vue | 48 + .../default/example/InputWithButton.vue | 13 + .../default/example/InputWithLabel.vue | 11 + .../default/example/RadioGroupForm.vue | 76 + .../registry/default/example/SelectForm.vue | 79 + .../registry/default/example/SwitchForm.vue | 85 + .../registry/default/example/TableDemo.vue | 4 +- .../default/example/TextareaDisabled.vue | 7 + .../registry/default/example/TextareaForm.vue | 59 + .../default/example/TextareaWithButton.vue | 11 + .../default/example/TextareaWithLabel.vue | 11 + .../default/example/TextareaWithText.vue | 14 + .../registry/default/ui/form/FormControl.vue | 16 + .../default/ui/form/FormDescription.vue | 22 + .../lib/registry/default/ui/form/FormItem.vue | 27 + .../registry/default/ui/form/FormLabel.vue | 28 + .../registry/default/ui/form/FormMessage.vue | 16 + .../src/lib/registry/default/ui/form/index.ts | 6 + .../registry/default/ui/form/useFormField.ts | 30 + .../new-york/example/Cards/DataTable.vue | 2 +- .../new-york/example/CheckboxDemo.vue | 2 +- .../new-york/example/CheckboxDisabled.vue | 15 + .../new-york/example/CheckboxFormMultiple.vue | 102 + .../new-york/example/CheckboxFormSingle.vue | 54 + .../new-york/example/CheckboxWithText.vue | 20 + .../new-york/example/ComboboxDemo.vue | 6 +- .../new-york/example/ComboboxDropdownMenu.vue | 104 + .../new-york/example/ComboboxForm.vue | 115 + .../new-york/example/ComboboxPopover.vue | 94 + .../new-york/example/DatePickerForm.vue | 74 + .../example/DatePickerWithPresets.vue | 73 + .../new-york/example/InputDisabled.vue | 7 + .../registry/new-york/example/InputFile.vue | 11 + .../registry/new-york/example/InputForm.vue | 48 + .../new-york/example/InputWithButton.vue | 13 + .../new-york/example/InputWithLabel.vue | 11 + .../new-york/example/RadioGroupForm.vue | 76 + .../registry/new-york/example/SelectForm.vue | 79 + .../registry/new-york/example/SwitchForm.vue | 85 + .../registry/new-york/example/TableDemo.vue | 4 +- .../new-york/example/TextareaDisabled.vue | 7 + .../new-york/example/TextareaForm.vue | 59 + .../new-york/example/TextareaWithButton.vue | 11 + .../new-york/example/TextareaWithLabel.vue | 11 + .../new-york/example/TextareaWithText.vue | 14 + .../ui/alert-dialog/AlertDialogAction.vue | 2 +- .../ui/alert-dialog/AlertDialogCancel.vue | 2 +- .../registry/new-york/ui/form/FormControl.vue | 16 + .../new-york/ui/form/FormDescription.vue | 15 + .../registry/new-york/ui/form/FormItem.vue | 21 + .../registry/new-york/ui/form/FormLabel.vue | 22 + .../registry/new-york/ui/form/FormMessage.vue | 16 + .../lib/registry/new-york/ui/form/index.ts | 6 + .../registry/new-york/ui/form/useFormField.ts | 30 + apps/www/tsconfig.json | 28 +- package.json | 10 +- pnpm-lock.yaml | 2233 +++++++++-------- 88 files changed, 4688 insertions(+), 1578 deletions(-) create mode 100644 apps/www/src/content/docs/components/form.md create mode 100644 apps/www/src/lib/registry/default/example/CheckboxFormMultiple.vue create mode 100644 apps/www/src/lib/registry/default/example/CheckboxFormSingle.vue create mode 100644 apps/www/src/lib/registry/default/example/CheckboxWithText.vue create mode 100644 apps/www/src/lib/registry/default/example/ComboboxDropdownMenu.vue create mode 100644 apps/www/src/lib/registry/default/example/ComboboxForm.vue create mode 100644 apps/www/src/lib/registry/default/example/ComboboxPopover.vue create mode 100644 apps/www/src/lib/registry/default/example/DatePickerForm.vue create mode 100644 apps/www/src/lib/registry/default/example/DatePickerWithPresets.vue create mode 100644 apps/www/src/lib/registry/default/example/InputDisabled.vue create mode 100644 apps/www/src/lib/registry/default/example/InputFile.vue create mode 100644 apps/www/src/lib/registry/default/example/InputForm.vue create mode 100644 apps/www/src/lib/registry/default/example/InputWithButton.vue create mode 100644 apps/www/src/lib/registry/default/example/InputWithLabel.vue create mode 100644 apps/www/src/lib/registry/default/example/RadioGroupForm.vue create mode 100644 apps/www/src/lib/registry/default/example/SelectForm.vue create mode 100644 apps/www/src/lib/registry/default/example/SwitchForm.vue create mode 100644 apps/www/src/lib/registry/default/example/TextareaDisabled.vue create mode 100644 apps/www/src/lib/registry/default/example/TextareaForm.vue create mode 100644 apps/www/src/lib/registry/default/example/TextareaWithButton.vue create mode 100644 apps/www/src/lib/registry/default/example/TextareaWithLabel.vue create mode 100644 apps/www/src/lib/registry/default/example/TextareaWithText.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/FormControl.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/FormDescription.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/FormItem.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/FormLabel.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/FormMessage.vue create mode 100644 apps/www/src/lib/registry/default/ui/form/index.ts create mode 100644 apps/www/src/lib/registry/default/ui/form/useFormField.ts create mode 100644 apps/www/src/lib/registry/new-york/example/CheckboxDisabled.vue create mode 100644 apps/www/src/lib/registry/new-york/example/CheckboxFormMultiple.vue create mode 100644 apps/www/src/lib/registry/new-york/example/CheckboxFormSingle.vue create mode 100644 apps/www/src/lib/registry/new-york/example/CheckboxWithText.vue create mode 100644 apps/www/src/lib/registry/new-york/example/ComboboxDropdownMenu.vue create mode 100644 apps/www/src/lib/registry/new-york/example/ComboboxForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/ComboboxPopover.vue create mode 100644 apps/www/src/lib/registry/new-york/example/DatePickerForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/DatePickerWithPresets.vue create mode 100644 apps/www/src/lib/registry/new-york/example/InputDisabled.vue create mode 100644 apps/www/src/lib/registry/new-york/example/InputFile.vue create mode 100644 apps/www/src/lib/registry/new-york/example/InputForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/InputWithButton.vue create mode 100644 apps/www/src/lib/registry/new-york/example/InputWithLabel.vue create mode 100644 apps/www/src/lib/registry/new-york/example/RadioGroupForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/SelectForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/SwitchForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/TextareaDisabled.vue create mode 100644 apps/www/src/lib/registry/new-york/example/TextareaForm.vue create mode 100644 apps/www/src/lib/registry/new-york/example/TextareaWithButton.vue create mode 100644 apps/www/src/lib/registry/new-york/example/TextareaWithLabel.vue create mode 100644 apps/www/src/lib/registry/new-york/example/TextareaWithText.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/FormControl.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/FormDescription.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/FormItem.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/FormLabel.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/FormMessage.vue create mode 100644 apps/www/src/lib/registry/new-york/ui/form/index.ts create mode 100644 apps/www/src/lib/registry/new-york/ui/form/useFormField.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9caef3c08..db30a80c9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,5 +12,6 @@ module.exports = { 'no-console': 'warn', 'no-tabs': 'off', 'no-invalid-character': 'off', + 'import/first': 'off', }, } diff --git a/apps/www/.vitepress/theme/components/TabPreview.vue b/apps/www/.vitepress/theme/components/TabPreview.vue index 025e1c34c..46bb64eeb 100644 --- a/apps/www/.vitepress/theme/components/TabPreview.vue +++ b/apps/www/.vitepress/theme/components/TabPreview.vue @@ -3,10 +3,14 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default const props = withDefaults(defineProps<{ name: string + names?: string[] align?: 'center' | 'start' | 'end' sfcTsCode?: string sfcTsHtml?: string -}>(), { align: 'center' }) +}>(), { + align: 'center', + names: () => ['CLI', 'Manual'], +}) ``` - \ No newline at end of file +## Examples + +### Combobox + + + +### Popover + + + +### Dropdown menu + + + +### Form + + diff --git a/apps/www/src/content/docs/components/date-picker.md b/apps/www/src/content/docs/components/date-picker.md index 4acfd90bb..43aef1494 100644 --- a/apps/www/src/content/docs/components/date-picker.md +++ b/apps/www/src/content/docs/components/date-picker.md @@ -56,12 +56,18 @@ const date = ref() ## Examples +### Date Picker + + + ### Date Range Picker - + +### With Presets -### Date Picker + +### Form - \ No newline at end of file + diff --git a/apps/www/src/content/docs/components/form.md b/apps/www/src/content/docs/components/form.md new file mode 100644 index 000000000..4721788bc --- /dev/null +++ b/apps/www/src/content/docs/components/form.md @@ -0,0 +1,331 @@ +--- +title: VeeValidate +description: Building forms with VeeValidate and Zod. +--- + +Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex. + +Well-designed HTML forms are: + +- Well-structured and semantically correct. +- Easy to use and navigate (keyboard). +- Accessible with ARIA attributes and proper labels. +- Has support for client and server side validation. +- Well-styled and consistent with the rest of the application. + +In this guide, we will take a look at building forms with [`vee-validate`](https://vee-validate.logaretm.com/v4/) and [`zod`](https://zod.dev). We're going to use a `` component to compose accessible forms using Radix Vue components. + + +## Features + +The `
` component is a wrapper around the `vee-validate` library. It provides a few things: + + +- Composable components for building forms. +- A `` component for building controlled form fields. +- Form validation using `zod`. +- Applies the correct `aria` attributes to form fields based on states, handle unqiue IDs +- Built to work with all Radix Vue components. +- Bring your own schema library. We use `zod` but you can use any other supported schema validation you want, like [`yup`](https://github.com/jquense/yup) or [`valibot`](https://valibot.dev/). +- **You have full control over the markup and styling.** + +[`vee-validate`](https://vee-validate.logaretm.com/v4/) makes use of two flavors to add validation to your forms. +- Composition API +- Higher-order components (HOC) + +## Anatomy + +```vue + + + + + + + + + + + + +``` + +## Example + + + + + + + + +## Installation + + + + + + + +## Usage + + + +### Create a form schema + +Define the shape of your form using a Zod schema. You can read more about using Zod in the [Zod documentation](https://zod.dev). + +Use `@vee-validate/zod` to integrate Zod schema validation with `vee-validate` + +`toTypedSchema` also makes the form values and submitted values typed automatically and caters for both input and output types of that schema. + +```vue showLineNumbers {2-3,5-7} + +``` + + +### Define a form + +Use the `useForm` composable from `vee-validate` or use `
` component to create a from. + + + + + + + + +### Build your form + +Based on last step we can either use `` component or `useForm` composable +`useForm` is recommended cause values are typed automatically + +```vue showLineNumbers {2} + + + +``` + +### Done + +That's it. You now have a fully accessible form that is type-safe with client-side validation. + + + + + +## 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) diff --git a/apps/www/src/content/docs/components/input.md b/apps/www/src/content/docs/components/input.md index bfa96c759..6c1206760 100644 --- a/apps/www/src/content/docs/components/input.md +++ b/apps/www/src/content/docs/components/input.md @@ -41,4 +41,28 @@ import { Input } from '@/components/ui/input' -``` \ No newline at end of file +``` + +### Default + + + +### File + + + +### Disabled + + + +### With Label + + + +### With Button + + + +### Form + + diff --git a/apps/www/src/content/docs/components/radio-group.md b/apps/www/src/content/docs/components/radio-group.md index a2b9a7624..d7db0bc93 100644 --- a/apps/www/src/content/docs/components/radio-group.md +++ b/apps/www/src/content/docs/components/radio-group.md @@ -34,4 +34,10 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' -``` \ No newline at end of file +``` + +## Examples + +### Form + + diff --git a/apps/www/src/content/docs/components/select.md b/apps/www/src/content/docs/components/select.md index d653bf0ae..caae327d8 100644 --- a/apps/www/src/content/docs/components/select.md +++ b/apps/www/src/content/docs/components/select.md @@ -46,3 +46,9 @@ import { ``` + +## Examples + +### Form + + diff --git a/apps/www/src/content/docs/components/switch.md b/apps/www/src/content/docs/components/switch.md index ccb8c1add..a359a4df9 100644 --- a/apps/www/src/content/docs/components/switch.md +++ b/apps/www/src/content/docs/components/switch.md @@ -47,4 +47,10 @@ import { Switch } from '@/components/ui/switch' -``` \ No newline at end of file +``` + +## Examples + +### Form + + diff --git a/apps/www/src/content/docs/components/textarea.md b/apps/www/src/content/docs/components/textarea.md index 39229b036..24b31da8c 100644 --- a/apps/www/src/content/docs/components/textarea.md +++ b/apps/www/src/content/docs/components/textarea.md @@ -45,4 +45,30 @@ import { Textarea } from '@/components/ui/textarea'