@delightui/components 0.1.162-alpha.4 → 0.1.162

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/cjs/components/atoms/Checkbox/Checkbox.d.ts +1 -1
  2. package/dist/cjs/components/atoms/Checkbox/Checkbox.presenter.d.ts +1 -1
  3. package/dist/cjs/components/atoms/CheckboxItem/CheckboxItem.d.ts +1 -1
  4. package/dist/cjs/components/atoms/CheckboxItem/CheckboxItem.presenter.d.ts +2 -2
  5. package/dist/cjs/components/atoms/CustomToggle/CustomToggle.d.ts +1 -1
  6. package/dist/cjs/components/atoms/Input/Input.d.ts +1 -1
  7. package/dist/cjs/components/atoms/Input/Input.presenter.d.ts +2 -2
  8. package/dist/cjs/components/atoms/Password/Password.presenter.d.ts +2 -2
  9. package/dist/cjs/components/atoms/RadioButton/RadioButton.d.ts +1 -1
  10. package/dist/cjs/components/atoms/RadioButtonItem/RadioButtonItem.d.ts +1 -1
  11. package/dist/cjs/components/atoms/RadioButtonItem/RadioButtonItem.presenter.d.ts +2 -2
  12. package/dist/cjs/components/atoms/TextArea/TextArea.d.ts +1 -1
  13. package/dist/cjs/components/atoms/TextArea/TextArea.presenter.d.ts +1 -1
  14. package/dist/cjs/components/atoms/Toggle/Toggle.d.ts +1 -1
  15. package/dist/cjs/components/atoms/Toggle/Toggle.presenter.d.ts +2 -2
  16. package/dist/cjs/components/atoms/ToggleButton/ToggleButton.d.ts +1 -1
  17. package/dist/cjs/components/molecules/FormField/FormField.d.ts +2 -28
  18. package/dist/cjs/components/molecules/FormField/FormField.presenter.d.ts +8 -17
  19. package/dist/cjs/components/molecules/FormField/FormField.types.d.ts +52 -115
  20. package/dist/cjs/components/molecules/FormField/FormField.utils.d.ts +11 -8
  21. package/dist/cjs/components/molecules/FormField/index.d.ts +2 -1
  22. package/dist/cjs/components/molecules/Search/Search.d.ts +1 -1
  23. package/dist/cjs/components/molecules/Search/Search.presenter.d.ts +2 -2
  24. package/dist/cjs/components/molecules/Select/Select.presenter.d.ts +4 -4
  25. package/dist/cjs/components/organisms/Form/DropzoneFormExample.d.ts +6 -0
  26. package/dist/cjs/components/organisms/Form/Form.d.ts +1 -22
  27. package/dist/cjs/components/organisms/Form/Form.types.d.ts +93 -64
  28. package/dist/cjs/components/organisms/Form/Form.utils.d.ts +2 -0
  29. package/dist/cjs/components/organisms/Form/FormContext.d.ts +5 -0
  30. package/dist/cjs/components/organisms/Form/UpdatedFormExample.d.ts +23 -0
  31. package/dist/cjs/components/organisms/Form/{examples/UseFormExample.d.ts → UseFormExample.d.ts} +3 -0
  32. package/dist/cjs/components/organisms/Form/index.d.ts +4 -7
  33. package/dist/cjs/components/organisms/Form/useForm.d.ts +50 -0
  34. package/dist/cjs/library.js +3 -3
  35. package/dist/cjs/library.js.map +1 -1
  36. package/dist/esm/components/atoms/Checkbox/Checkbox.d.ts +1 -1
  37. package/dist/esm/components/atoms/Checkbox/Checkbox.presenter.d.ts +1 -1
  38. package/dist/esm/components/atoms/CheckboxItem/CheckboxItem.d.ts +1 -1
  39. package/dist/esm/components/atoms/CheckboxItem/CheckboxItem.presenter.d.ts +2 -2
  40. package/dist/esm/components/atoms/CustomToggle/CustomToggle.d.ts +1 -1
  41. package/dist/esm/components/atoms/Input/Input.d.ts +1 -1
  42. package/dist/esm/components/atoms/Input/Input.presenter.d.ts +2 -2
  43. package/dist/esm/components/atoms/Password/Password.presenter.d.ts +2 -2
  44. package/dist/esm/components/atoms/RadioButton/RadioButton.d.ts +1 -1
  45. package/dist/esm/components/atoms/RadioButtonItem/RadioButtonItem.d.ts +1 -1
  46. package/dist/esm/components/atoms/RadioButtonItem/RadioButtonItem.presenter.d.ts +2 -2
  47. package/dist/esm/components/atoms/TextArea/TextArea.d.ts +1 -1
  48. package/dist/esm/components/atoms/TextArea/TextArea.presenter.d.ts +1 -1
  49. package/dist/esm/components/atoms/Toggle/Toggle.d.ts +1 -1
  50. package/dist/esm/components/atoms/Toggle/Toggle.presenter.d.ts +2 -2
  51. package/dist/esm/components/atoms/ToggleButton/ToggleButton.d.ts +1 -1
  52. package/dist/esm/components/molecules/FormField/FormField.d.ts +2 -28
  53. package/dist/esm/components/molecules/FormField/FormField.presenter.d.ts +8 -17
  54. package/dist/esm/components/molecules/FormField/FormField.types.d.ts +52 -115
  55. package/dist/esm/components/molecules/FormField/FormField.utils.d.ts +11 -8
  56. package/dist/esm/components/molecules/FormField/index.d.ts +2 -1
  57. package/dist/esm/components/molecules/Search/Search.d.ts +1 -1
  58. package/dist/esm/components/molecules/Search/Search.presenter.d.ts +2 -2
  59. package/dist/esm/components/molecules/Select/Select.presenter.d.ts +4 -4
  60. package/dist/esm/components/organisms/Form/DropzoneFormExample.d.ts +6 -0
  61. package/dist/esm/components/organisms/Form/Form.d.ts +1 -22
  62. package/dist/esm/components/organisms/Form/Form.types.d.ts +93 -64
  63. package/dist/esm/components/organisms/Form/Form.utils.d.ts +2 -0
  64. package/dist/esm/components/organisms/Form/FormContext.d.ts +5 -0
  65. package/dist/esm/components/organisms/Form/UpdatedFormExample.d.ts +23 -0
  66. package/dist/esm/components/organisms/Form/{examples/UseFormExample.d.ts → UseFormExample.d.ts} +3 -0
  67. package/dist/esm/components/organisms/Form/index.d.ts +4 -7
  68. package/dist/esm/components/organisms/Form/useForm.d.ts +50 -0
  69. package/dist/esm/library.js +3 -3
  70. package/dist/esm/library.js.map +1 -1
  71. package/dist/index.d.ts +232 -270
  72. package/docs/components/molecules/FormField.md +34 -129
  73. package/docs/components/organisms/Form.md +162 -858
  74. package/package.json +1 -4
  75. package/dist/cjs/components/molecules/FormField/useSafeController.d.ts +0 -14
  76. package/dist/cjs/components/molecules/FormField/useSafeFormContext.d.ts +0 -8
  77. package/dist/cjs/components/organisms/Form/Form.presenter.d.ts +0 -290
  78. package/dist/cjs/components/organisms/Form/examples/DropzoneFormExample.d.ts +0 -6
  79. package/dist/cjs/components/organisms/Form/examples/UpdatedFormExample.d.ts +0 -2
  80. package/dist/cjs/components/organisms/Form/useAutosave.d.ts +0 -10
  81. package/dist/esm/components/molecules/FormField/useSafeController.d.ts +0 -14
  82. package/dist/esm/components/molecules/FormField/useSafeFormContext.d.ts +0 -8
  83. package/dist/esm/components/organisms/Form/Form.presenter.d.ts +0 -290
  84. package/dist/esm/components/organisms/Form/examples/DropzoneFormExample.d.ts +0 -6
  85. package/dist/esm/components/organisms/Form/examples/UpdatedFormExample.d.ts +0 -2
  86. package/dist/esm/components/organisms/Form/useAutosave.d.ts +0 -10
  87. package/docs/FORM_MIGRATION_GUIDE.md +0 -631
  88. /package/dist/cjs/components/organisms/Form/{examples/AutosaveFormExample.d.ts → AutosaveFormExample.d.ts} +0 -0
  89. /package/dist/esm/components/organisms/Form/{examples/AutosaveFormExample.d.ts → AutosaveFormExample.d.ts} +0 -0
@@ -1,631 +0,0 @@
1
- # Form & FormField Migration Guide
2
-
3
- ## Overview
4
-
5
- The Form and FormField components have been rewritten on top of **React Hook Form** (RHF) to provide better performance, TypeScript support, and a more modern API. This guide will help you migrate from the old custom form implementation to the new RHF-based implementation.
6
-
7
- ---
8
-
9
- ## Quick Reference: Props Comparison
10
-
11
- ### Form Component
12
-
13
- | OLD Prop | NEW Prop | Status | Migration Notes |
14
- |----------|----------|--------|-----------------|
15
- | `formState?: T` | `defaultValues?: object` | 🔴 **BREAKING** | Renamed. Use for initial uncontrolled form values |
16
- | `onFormStateChange?: (state, setError) => void` | ❌ Removed | 🔴 **BREAKING** | Use RHF's `watch()` or `useWatch()` hooks instead |
17
- | `formValidator?: (state, setError) => boolean` | ❌ Removed | 🔴 **BREAKING** | Use field-level validation or RHF's `resolver` |
18
- | `onSubmit?: (values, setError) => void` | `onSubmit?: (values) => void \| Promise<void>` | 🔴 **BREAKING** | No `setError` callback - use RHF hooks instead |
19
- | `validateOnChange?: boolean` | `mode?: 'onSubmit' \| 'onChange' \| 'onBlur' \| ...` | 🔴 **BREAKING** | More flexible validation modes |
20
- | `formRef?: Ref<HTMLFormElement>` | `formRef?: Ref<HTMLFormElement>` | ✅ **SAME** | Unchanged |
21
- | `children?: ReactNode` | `children: ReactNode` | ✅ **SAME** | Now required |
22
- | ❌ N/A | `autosave?: boolean` | 🟢 **NEW** | Enable autosave functionality |
23
- | ❌ N/A | `autosaveDelayMs?: number` | 🟢 **NEW** | Autosave debounce delay |
24
- | ❌ N/A | `formOptions?: UseFormProps` | 🟢 **NEW** | Pass additional RHF options |
25
- | ❌ N/A | `className?: string` | 🟢 **NEW** | Form CSS class |
26
- | ❌ N/A | `style?: CSSProperties` | 🟢 **NEW** | Form inline styles |
27
-
28
- ### FormField Component
29
-
30
- | OLD Prop | NEW Prop | Status | Migration Notes |
31
- |----------|----------|--------|-----------------|
32
- | `name: string` | `name: TName` (type-safe) | 🟡 **ENHANCED** | Now type-checked against form values |
33
- | `label?: string` | `label?: string` | ✅ **SAME** | Unchanged |
34
- | `children: ReactNode` | `children: ReactNode` | ✅ **SAME** | Unchanged |
35
- | `message?: string` | `message?: string` | ✅ **SAME** | Info message |
36
- | `hasMessage?: boolean` | ❌ Removed | 🔴 **BREAKING** | No longer needed |
37
- | `infoIcon?: ReactNode` | `infoIcon?: ReactNode` | ✅ **SAME** | Unchanged |
38
- | `required?: boolean` | `required?: boolean` | ✅ **SAME** | Unchanged |
39
- | `validate?: (setError, value?) => boolean` | `validate?: (value) => string \| undefined` | 🔴 **BREAKING** | Return error message instead of calling setError |
40
- | ❌ N/A | `asyncValidate?: (value) => Promise<string \| undefined>` | 🟢 **NEW** | Async validation support |
41
- | `disabled?: boolean` | `disabled?: boolean` | ✅ **SAME** | Unchanged |
42
- | `invalid?: boolean` | `invalid?: boolean` | ✅ **SAME** | External invalid state |
43
- | `id?: string` | `id?: string` | ✅ **SAME** | Unchanged |
44
- | ❌ N/A | `displayName?: string` | 🟢 **NEW** | Custom name for error messages |
45
- | ❌ N/A | `defaultValue?: TValue` | 🟢 **NEW** | Field-level default value |
46
- | ❌ N/A | `value?: TValue` | 🟢 **NEW** | Standalone mode: controlled value |
47
- | ❌ N/A | `onChange?: (value) => void` | 🟢 **NEW** | Standalone mode: onChange handler |
48
- | ❌ N/A | `error?: string` | 🟢 **NEW** | Standalone mode: external error |
49
-
50
- ---
51
-
52
- ## Breaking Changes
53
-
54
- ### 1. FormProvider Component Removed
55
-
56
- **OLD:**
57
- ```tsx
58
- <FormProvider formState={formState} onFormStateChange={handleChange} onSubmit={handleSubmit}>
59
- <Form>
60
- <FormField name="email" required>
61
- <Input />
62
- </FormField>
63
- </Form>
64
- </FormProvider>
65
- ```
66
-
67
- **NEW:**
68
- ```tsx
69
- <Form defaultValues={formState} onSubmit={handleSubmit}>
70
- <FormField name="email" required>
71
- <Input />
72
- </FormField>
73
- </Form>
74
- ```
75
-
76
- ### 2. Props Renamed: `formState` → `defaultValues`
77
-
78
- **OLD:**
79
- ```tsx
80
- <FormProvider formState={{ email: '', name: '' }}>
81
- <Form>{/* ... */}</Form>
82
- </FormProvider>
83
- ```
84
-
85
- **NEW:**
86
- ```tsx
87
- <Form defaultValues={{ email: '', name: '' }}>
88
- {/* ... */}
89
- </Form>
90
- ```
91
-
92
- ### 3. `onSubmit` Signature Changed
93
-
94
- **OLD:**
95
- ```tsx
96
- const handleSubmit = (values, setError) => {
97
- if (!validateEmail(values.email)) {
98
- setError('email', 'Invalid email');
99
- return;
100
- }
101
- // Submit logic
102
- };
103
- ```
104
-
105
- **NEW:**
106
- ```tsx
107
- import { useFormContext } from 'react-hook-form';
108
-
109
- const handleSubmit = async (values) => {
110
- // For setting errors, use RHF hooks in a component
111
- // or handle validation in field-level validators
112
- try {
113
- await submitToAPI(values);
114
- } catch (error) {
115
- // Use setError from useFormContext if needed
116
- }
117
- };
118
- ```
119
-
120
- **Setting Errors in NEW Version:**
121
- ```tsx
122
- // Create a component that can access form context
123
- function MyFormContent() {
124
- const { setError } = useFormContext();
125
-
126
- const handleAPIError = (fieldName, message) => {
127
- setError(fieldName, { message });
128
- };
129
-
130
- return (
131
- <FormField name="email" required>
132
- <Input />
133
- </FormField>
134
- );
135
- }
136
-
137
- function MyForm() {
138
- const handleSubmit = async (values) => {
139
- // Handle submission
140
- };
141
-
142
- return (
143
- <Form defaultValues={{ email: '' }} onSubmit={handleSubmit}>
144
- <MyFormContent />
145
- </Form>
146
- );
147
- }
148
- ```
149
-
150
- ### 4. Validation Function Signature Changed
151
-
152
- **OLD:**
153
- ```tsx
154
- const validatePassword = (setError, value) => {
155
- if (!value) {
156
- setError('Password is required');
157
- return false;
158
- }
159
- if (value.length < 8) {
160
- setError('Password must be at least 8 characters');
161
- return false;
162
- }
163
- return true;
164
- };
165
-
166
- <FormField name="password" validate={validatePassword}>
167
- <Input inputType="Password" />
168
- </FormField>
169
- ```
170
-
171
- **NEW:**
172
- ```tsx
173
- const validatePassword = (value: string) => {
174
- if (!value) {
175
- return 'Password is required';
176
- }
177
- if (value.length < 8) {
178
- return 'Password must be at least 8 characters';
179
- }
180
- return undefined; // Valid
181
- };
182
-
183
- <FormField name="password" validate={validatePassword}>
184
- <Input inputType="Password" />
185
- </FormField>
186
- ```
187
-
188
- ### 5. `onFormStateChange` Removed
189
-
190
- **OLD:**
191
- ```tsx
192
- const handleStateChange = (state, setError) => {
193
- console.log('Form changed:', state);
194
- // Validate on change
195
- if (state.email && !validateEmail(state.email)) {
196
- setError('email', 'Invalid email');
197
- }
198
- };
199
-
200
- <FormProvider
201
- formState={formState}
202
- onFormStateChange={handleStateChange}
203
- >
204
- <Form>{/* ... */}</Form>
205
- </FormProvider>
206
- ```
207
-
208
- **NEW:**
209
- ```tsx
210
- import { useWatch } from 'react-hook-form';
211
-
212
- function FormContent() {
213
- const formValues = useWatch(); // Watch all fields
214
- // Or watch specific field: const email = useWatch({ name: 'email' });
215
-
216
- useEffect(() => {
217
- console.log('Form changed:', formValues);
218
- }, [formValues]);
219
-
220
- return (
221
- <>
222
- <FormField name="email" required>
223
- <Input />
224
- </FormField>
225
- {/* ... */}
226
- </>
227
- );
228
- }
229
-
230
- function MyForm() {
231
- return (
232
- <Form defaultValues={{ email: '' }}>
233
- <FormContent />
234
- </Form>
235
- );
236
- }
237
- ```
238
-
239
- ### 6. `validateOnChange` → `mode`
240
-
241
- **OLD:**
242
- ```tsx
243
- <FormProvider validateOnChange={true}>
244
- <Form>{/* ... */}</Form>
245
- </FormProvider>
246
- ```
247
-
248
- **NEW:**
249
- ```tsx
250
- <Form mode="onChange">
251
- {/* ... */}
252
- </Form>
253
- ```
254
-
255
- **Available modes:**
256
- - `"onSubmit"` (default) - Validate on submit
257
- - `"onChange"` - Validate on every change
258
- - `"onBlur"` - Validate on blur
259
- - `"onTouched"` - Validate after first blur, then on change
260
- - `"all"` - Validate on change, blur, and submit
261
-
262
- ### 7. `formValidator` Removed
263
-
264
- **OLD:**
265
- ```tsx
266
- const formValidator = (state, setError) => {
267
- let isValid = true;
268
- if (state.password !== state.confirmPassword) {
269
- setError('confirmPassword', 'Passwords do not match');
270
- isValid = false;
271
- }
272
- return isValid;
273
- };
274
-
275
- <FormProvider formValidator={formValidator}>
276
- <Form>{/* ... */}</Form>
277
- </FormProvider>
278
- ```
279
-
280
- **NEW (Option 1 - Field-level validation):**
281
- ```tsx
282
- <FormField
283
- name="confirmPassword"
284
- validate={(value) => {
285
- const password = /* get password value using useWatch */;
286
- if (value !== password) {
287
- return 'Passwords do not match';
288
- }
289
- return undefined;
290
- }}
291
- >
292
- <Input inputType="Password" />
293
- </FormField>
294
- ```
295
-
296
- **NEW (Option 2 - RHF Resolver):**
297
- ```tsx
298
- import { zodResolver } from '@hookform/resolvers/zod';
299
- import * as z from 'zod';
300
-
301
- const schema = z.object({
302
- password: z.string().min(8),
303
- confirmPassword: z.string()
304
- }).refine(data => data.password === data.confirmPassword, {
305
- message: "Passwords do not match",
306
- path: ["confirmPassword"]
307
- });
308
-
309
- <Form
310
- formOptions={{ resolver: zodResolver(schema) }}
311
- defaultValues={{ password: '', confirmPassword: '' }}
312
- >
313
- {/* ... */}
314
- </Form>
315
- ```
316
-
317
- ### 8. `hasMessage` Prop Removed
318
-
319
- **OLD:**
320
- ```tsx
321
- <FormField name="email" hasMessage={true} message="Invalid email">
322
- <Input />
323
- </FormField>
324
- ```
325
-
326
- **NEW:**
327
- ```tsx
328
- <FormField name="email" message="Invalid email">
329
- <Input />
330
- </FormField>
331
- ```
332
-
333
- ---
334
-
335
- ## New Features
336
-
337
- ### 1. Autosave Support
338
-
339
- ```tsx
340
- <Form
341
- defaultValues={{ title: '', content: '' }}
342
- onSubmit={handleAutosave}
343
- autosave={true}
344
- autosaveDelayMs={2000} // Wait 2s after user stops typing
345
- >
346
- <FormField name="title" label="Title">
347
- <Input />
348
- </FormField>
349
- <FormField name="content" label="Content">
350
- <TextArea rows={10} />
351
- </FormField>
352
- </Form>
353
- ```
354
-
355
- ### 2. Async Validation
356
-
357
- ```tsx
358
- const validateUsername = async (value: string) => {
359
- const response = await fetch(`/api/check-username?username=${value}`);
360
- const { available } = await response.json();
361
- if (!available) {
362
- return 'Username is already taken';
363
- }
364
- return undefined;
365
- };
366
-
367
- <FormField
368
- name="username"
369
- label="Username"
370
- asyncValidate={validateUsername}
371
- >
372
- <Input />
373
- </FormField>
374
- ```
375
-
376
- ### 3. Standalone FormField (No Form Required)
377
-
378
- ```tsx
379
- function StandaloneExample() {
380
- const [email, setEmail] = useState('');
381
- const [error, setError] = useState('');
382
-
383
- const validateEmail = (value: string) => {
384
- if (!value.includes('@')) {
385
- return 'Invalid email';
386
- }
387
- return undefined;
388
- };
389
-
390
- return (
391
- <FormField
392
- name="email"
393
- label="Email"
394
- value={email}
395
- onChange={setEmail}
396
- error={error}
397
- validate={(value) => {
398
- const error = validateEmail(value);
399
- setError(error || '');
400
- return error;
401
- }}
402
- >
403
- <Input />
404
- </FormField>
405
- );
406
- }
407
- ```
408
-
409
- ### 4. Full TypeScript Type Safety
410
-
411
- ```tsx
412
- interface MyFormValues {
413
- email: string;
414
- age: number;
415
- newsletter: boolean;
416
- }
417
-
418
- function TypeSafeForm() {
419
- const handleSubmit = (values: MyFormValues) => {
420
- // values is fully typed!
421
- console.log(values.email); // ✅ TypeScript knows this is a string
422
- };
423
-
424
- return (
425
- <Form<MyFormValues>
426
- defaultValues={{ email: '', age: 0, newsletter: false }}
427
- onSubmit={handleSubmit}
428
- >
429
- {/* TypeScript will validate field names */}
430
- <FormField<MyFormValues> name="email" label="Email">
431
- <Input />
432
- </FormField>
433
-
434
- {/* This would cause a TypeScript error: */}
435
- {/* <FormField name="invalidField"> */}
436
- </Form>
437
- );
438
- }
439
- ```
440
-
441
- ### 5. Access to React Hook Form Methods
442
-
443
- ```tsx
444
- import { useFormContext } from 'react-hook-form';
445
-
446
- function FormActions() {
447
- const { reset, setValue, getValues, formState } = useFormContext();
448
-
449
- return (
450
- <div>
451
- <Button onClick={() => reset()}>Reset Form</Button>
452
- <Button onClick={() => setValue('email', 'test@example.com')}>
453
- Prefill Email
454
- </Button>
455
- <Text>Form is {formState.isDirty ? 'modified' : 'pristine'}</Text>
456
- </div>
457
- );
458
- }
459
-
460
- function MyForm() {
461
- return (
462
- <Form defaultValues={{ email: '' }}>
463
- <FormField name="email" label="Email">
464
- <Input />
465
- </FormField>
466
- <FormActions />
467
- </Form>
468
- );
469
- }
470
- ```
471
-
472
- ---
473
-
474
- ## Migration Checklist
475
-
476
- - [ ] Replace `FormProvider` wrapper with direct `<Form>` usage
477
- - [ ] Rename `formState` prop to `defaultValues`
478
- - [ ] Update `onSubmit` handlers to remove `setError` parameter
479
- - [ ] Convert validation functions to return error strings instead of calling `setError`
480
- - [ ] Replace `onFormStateChange` with `useWatch()` or `useFormContext()`
481
- - [ ] Change `validateOnChange` to `mode="onChange"`
482
- - [ ] Remove `formValidator` and use field-level validation or RHF resolver
483
- - [ ] Remove `hasMessage` prop from FormField components
484
- - [ ] Update TypeScript types to use new form value types
485
- - [ ] Test all form validation flows
486
- - [ ] Test form submission and error handling
487
- - [ ] Consider using new features: autosave, async validation, standalone mode
488
-
489
- ---
490
-
491
- ## Common Migration Patterns
492
-
493
- ### Pattern 1: Simple Contact Form
494
-
495
- **OLD:**
496
- ```tsx
497
- function ContactForm() {
498
- const [formState, setFormState] = useState({ name: '', email: '', message: '' });
499
-
500
- const handleSubmit = (values, setError) => {
501
- if (!values.email.includes('@')) {
502
- setError('email', 'Invalid email');
503
- return;
504
- }
505
- console.log('Submitted:', values);
506
- };
507
-
508
- return (
509
- <FormProvider formState={formState} onSubmit={handleSubmit}>
510
- <Form>
511
- <FormField name="name" label="Name" required><Input /></FormField>
512
- <FormField name="email" label="Email" required><Input /></FormField>
513
- <FormField name="message" label="Message"><TextArea /></FormField>
514
- <Button actionType="submit">Send</Button>
515
- </Form>
516
- </FormProvider>
517
- );
518
- }
519
- ```
520
-
521
- **NEW:**
522
- ```tsx
523
- function ContactForm() {
524
- const handleSubmit = (values: { name: string; email: string; message: string }) => {
525
- console.log('Submitted:', values);
526
- };
527
-
528
- const validateEmail = (value: string) => {
529
- if (!value.includes('@')) return 'Invalid email';
530
- return undefined;
531
- };
532
-
533
- return (
534
- <Form
535
- defaultValues={{ name: '', email: '', message: '' }}
536
- onSubmit={handleSubmit}
537
- >
538
- <FormField name="name" label="Name" required><Input /></FormField>
539
- <FormField name="email" label="Email" required validate={validateEmail}>
540
- <Input />
541
- </FormField>
542
- <FormField name="message" label="Message"><TextArea /></FormField>
543
- <Button actionType="submit">Send</Button>
544
- </Form>
545
- );
546
- }
547
- ```
548
-
549
- ### Pattern 2: Form with Dynamic Validation
550
-
551
- **OLD:**
552
- ```tsx
553
- function SignupForm() {
554
- const formValidator = (state, setError) => {
555
- if (state.password !== state.confirmPassword) {
556
- setError('confirmPassword', 'Passwords must match');
557
- return false;
558
- }
559
- return true;
560
- };
561
-
562
- return (
563
- <FormProvider formValidator={formValidator}>
564
- <Form>
565
- <FormField name="password" label="Password" required>
566
- <Input inputType="Password" />
567
- </FormField>
568
- <FormField name="confirmPassword" label="Confirm" required>
569
- <Input inputType="Password" />
570
- </FormField>
571
- <Button actionType="submit">Sign Up</Button>
572
- </Form>
573
- </FormProvider>
574
- );
575
- }
576
- ```
577
-
578
- **NEW:**
579
- ```tsx
580
- import { useWatch, useFormContext } from 'react-hook-form';
581
-
582
- function ConfirmPasswordField() {
583
- const password = useWatch({ name: 'password' });
584
-
585
- const validateConfirm = (value: string) => {
586
- if (value !== password) return 'Passwords must match';
587
- return undefined;
588
- };
589
-
590
- return (
591
- <FormField
592
- name="confirmPassword"
593
- label="Confirm"
594
- required
595
- validate={validateConfirm}
596
- >
597
- <Input inputType="Password" />
598
- </FormField>
599
- );
600
- }
601
-
602
- function SignupForm() {
603
- return (
604
- <Form defaultValues={{ password: '', confirmPassword: '' }}>
605
- <FormField name="password" label="Password" required>
606
- <Input inputType="Password" />
607
- </FormField>
608
- <ConfirmPasswordField />
609
- <Button actionType="submit">Sign Up</Button>
610
- </Form>
611
- );
612
- }
613
- ```
614
-
615
- ---
616
-
617
- ## Resources
618
-
619
- - [React Hook Form Documentation](https://react-hook-form.com/)
620
- - [React Hook Form API Reference](https://react-hook-form.com/api)
621
- - [Migration Examples in Codebase](./components/organisms/Form/examples/)
622
-
623
- ---
624
-
625
- ## Need Help?
626
-
627
- If you encounter issues during migration:
628
-
629
- 1. Check the [Form examples](../src/components/organisms/Form/examples/) in the codebase
630
- 2. Review the [React Hook Form docs](https://react-hook-form.com/)
631
- 3. Reach out to the team for assistance