11"use client" ;
22
3+ import { useForm } from "@tanstack/react-form" ;
34import {
45 useMutation ,
56 useQueryClient ,
@@ -11,27 +12,19 @@ import { CreatePostSchema } from "@acme/db/schema";
1112import { cn } from "@acme/ui" ;
1213import { Button } from "@acme/ui/button" ;
1314import {
14- Form ,
15- FormControl ,
16- FormField ,
17- FormItem ,
18- FormMessage ,
19- useForm ,
20- } from "@acme/ui/form" ;
15+ Field ,
16+ FieldContent ,
17+ FieldError ,
18+ FieldGroup ,
19+ FieldLabel ,
20+ } from "@acme/ui/field" ;
2121import { Input } from "@acme/ui/input" ;
2222import { toast } from "@acme/ui/toast" ;
2323
2424import { useTRPC } from "~/trpc/react" ;
2525
2626export function CreatePostForm ( ) {
2727 const trpc = useTRPC ( ) ;
28- const form = useForm ( {
29- schema : CreatePostSchema ,
30- defaultValues : {
31- content : "" ,
32- title : "" ,
33- } ,
34- } ) ;
3528
3629 const queryClient = useQueryClient ( ) ;
3730 const createPost = useMutation (
@@ -50,41 +43,77 @@ export function CreatePostForm() {
5043 } ) ,
5144 ) ;
5245
46+ const form = useForm ( {
47+ defaultValues : {
48+ content : "" ,
49+ title : "" ,
50+ } ,
51+ validators : {
52+ onSubmit : CreatePostSchema ,
53+ } ,
54+ onSubmit : ( data ) => createPost . mutate ( data . value ) ,
55+ } ) ;
56+
5357 return (
54- < Form { ... form } >
55- < form
56- className = "flex w-full max-w-2xl flex-col gap-4"
57- onSubmit = { form . handleSubmit ( ( data ) => {
58- createPost . mutate ( data ) ;
59- } ) }
60- >
61- < FormField
62- control = { form . control }
58+ < form
59+ className = "w-full max-w-2xl"
60+ onSubmit = { ( event ) => {
61+ event . preventDefault ( ) ;
62+ void form . handleSubmit ( ) ;
63+ } }
64+ >
65+ < FieldGroup >
66+ < form . Field
6367 name = "title"
64- render = { ( { field } ) => (
65- < FormItem >
66- < FormControl >
67- < Input { ...field } placeholder = "Title" />
68- </ FormControl >
69- < FormMessage />
70- </ FormItem >
71- ) }
68+ children = { ( field ) => {
69+ const isInvalid =
70+ field . state . meta . isTouched && ! field . state . meta . isValid ;
71+ return (
72+ < Field data-invalid = { isInvalid } >
73+ < FieldContent >
74+ < FieldLabel htmlFor = { field . name } > Bug Title</ FieldLabel >
75+ </ FieldContent >
76+ < Input
77+ id = { field . name }
78+ name = { field . name }
79+ value = { field . state . value }
80+ onBlur = { field . handleBlur }
81+ onChange = { ( e ) => field . handleChange ( e . target . value ) }
82+ aria-invalid = { isInvalid }
83+ placeholder = "Title"
84+ />
85+ { isInvalid && < FieldError errors = { field . state . meta . errors } /> }
86+ </ Field >
87+ ) ;
88+ } }
7289 />
73- < FormField
74- control = { form . control }
90+ < form . Field
7591 name = "content"
76- render = { ( { field } ) => (
77- < FormItem >
78- < FormControl >
79- < Input { ...field } placeholder = "Content" />
80- </ FormControl >
81- < FormMessage />
82- </ FormItem >
83- ) }
92+ children = { ( field ) => {
93+ const isInvalid =
94+ field . state . meta . isTouched && ! field . state . meta . isValid ;
95+ return (
96+ < Field data-invalid = { isInvalid } >
97+ < FieldContent >
98+ < FieldLabel htmlFor = { field . name } > Content</ FieldLabel >
99+ </ FieldContent >
100+ < Input
101+ id = { field . name }
102+ name = { field . name }
103+ value = { field . state . value }
104+ onBlur = { field . handleBlur }
105+ onChange = { ( e ) => field . handleChange ( e . target . value ) }
106+ aria-invalid = { isInvalid }
107+ placeholder = "Content"
108+ />
109+ { isInvalid && < FieldError errors = { field . state . meta . errors } /> }
110+ </ Field >
111+ ) ;
112+ } }
84113 />
85- < Button > Create </ Button >
86- </ form >
87- </ Form >
114+ </ FieldGroup >
115+ < Button type = "submit" > Create </ Button >
116+ </ form >
88117 ) ;
89118}
90119
0 commit comments