form-hook-kit 1.2.0

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +753 -0
  3. package/dist/FormContext.d.ts +8 -0
  4. package/dist/FormContext.d.ts.map +1 -0
  5. package/dist/FormProvider.d.ts +33 -0
  6. package/dist/FormProvider.d.ts.map +1 -0
  7. package/dist/devtools/FormDevTools.d.ts +86 -0
  8. package/dist/devtools/FormDevTools.d.ts.map +1 -0
  9. package/dist/devtools/index.d.ts +3 -0
  10. package/dist/devtools/index.d.ts.map +1 -0
  11. package/dist/hooks/index.d.ts +4 -0
  12. package/dist/hooks/index.d.ts.map +1 -0
  13. package/dist/hooks/useForm.d.ts +30 -0
  14. package/dist/hooks/useForm.d.ts.map +1 -0
  15. package/dist/hooks/useFormField.d.ts +40 -0
  16. package/dist/hooks/useFormField.d.ts.map +1 -0
  17. package/dist/hooks/useFormPerformance.d.ts +57 -0
  18. package/dist/hooks/useFormPerformance.d.ts.map +1 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.esm.js +394 -0
  22. package/dist/index.esm.js.map +1 -0
  23. package/dist/index.js +408 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/types/index.d.ts +94 -0
  26. package/dist/types/index.d.ts.map +1 -0
  27. package/dist/utils/debounce.d.ts +6 -0
  28. package/dist/utils/debounce.d.ts.map +1 -0
  29. package/dist/utils/errors.d.ts +11 -0
  30. package/dist/utils/errors.d.ts.map +1 -0
  31. package/dist/utils/formActions.d.ts +57 -0
  32. package/dist/utils/formActions.d.ts.map +1 -0
  33. package/dist/utils/formReducer.d.ts +7 -0
  34. package/dist/utils/formReducer.d.ts.map +1 -0
  35. package/dist/utils/index.d.ts +7 -0
  36. package/dist/utils/index.d.ts.map +1 -0
  37. package/dist/utils/performance.d.ts +7 -0
  38. package/dist/utils/performance.d.ts.map +1 -0
  39. package/dist/utils/validation.d.ts +25 -0
  40. package/dist/utils/validation.d.ts.map +1 -0
  41. package/package.json +91 -0
package/README.md ADDED
@@ -0,0 +1,753 @@
1
+ # form-hook-kit
2
+
3
+ A lightweight, flexible form management library for React and React Native with a hooks-based API and Yup validation.
4
+
5
+ **Author:** bc-bane
6
+ **License:** MIT
7
+ **Platform tested:** React 18+ & React Native
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Type-safe** - Full TypeScript support with 100% type coverage
14
+ - **Cross-platform** - Works with React and React Native
15
+ - **React Native Compatible** - No native iOS/Android code - works with legacy architecture, new architecture, and Android 16KB page size
16
+ - **Validation** - Powered by Yup for robust schema validation
17
+ - **Hooks-based** - Modern React hooks API
18
+ - **Context-based** - Efficient state management with React Context
19
+ - **Performant** - Memoized functions, optional debounced validation, minimal re-renders
20
+ - **Developer Tools** - Built-in DevTools component for debugging (development only)
21
+ - **Flexible** - Works with any UI component library
22
+ - **Well-tested** - 100% test coverage
23
+ - **Production-ready** - Comprehensive documentation and examples
24
+
25
+ ---
26
+
27
+ ## Why form-hook-kit?
28
+
29
+ ### Comparison with Other Form Libraries
30
+
31
+ #### vs. Formik
32
+
33
+ **Key Differences:**
34
+ - **API Style** - form-hook-kit is hooks-only, Formik supports both hooks and render props
35
+ - **React Native** - Both support React Native with different approaches
36
+ - **Yup Integration** - Both have built-in Yup support
37
+ - **Community** - Formik has larger community and more plugins
38
+
39
+ **When to use Formik instead:**
40
+ - You need a battle-tested library with years of production use
41
+ - You want access to a larger ecosystem of community plugins
42
+ - Your project already uses Formik
43
+
44
+ #### vs. React Hook Form
45
+
46
+ **Key Differences:**
47
+ - **State Management** - form-hook-kit uses Context, React Hook Form uses refs
48
+ - **Input Style** - form-hook-kit uses controlled inputs, React Hook Form uses uncontrolled
49
+ - **Yup Integration** - form-hook-kit has built-in support, React Hook Form requires resolver
50
+ - **Performance** - React Hook Form may be faster for very large forms
51
+ - **Popularity** - React Hook Form has larger user base
52
+
53
+ **When to use React Hook Form instead:**
54
+ - You need uncontrolled inputs for maximum performance
55
+ - You prefer ref-based form tracking
56
+ - You have very large forms (100+ fields)
57
+
58
+ #### vs. Final Form
59
+
60
+ **Key Differences:**
61
+ - **API Style** - form-hook-kit is hooks-only, Final Form uses subscriptions
62
+ - **TypeScript** - form-hook-kit is TypeScript-first, Final Form has TypeScript support
63
+ - **React Version** - form-hook-kit requires React 16.8+, Final Form supports older versions
64
+ - **Maturity** - Final Form is more established
65
+
66
+ **When to use Final Form instead:**
67
+ - You need field-level subscriptions for complex performance optimization
68
+ - You're migrating from Redux Form
69
+ - You need to support older React versions
70
+
71
+ #### vs. Custom Solutions
72
+
73
+ **Advantages over rolling your own:**
74
+ - **Well-tested** - 100% test coverage with comprehensive test suite
75
+ - **Edge cases handled** - Validation, error handling, field refs all included
76
+ - **TypeScript support** - Full type safety out of the box
77
+ - **Ready to use** - No need to build and maintain form infrastructure
78
+ - **Documentation** - Complete docs and examples
79
+
80
+ ### Feature Comparison Table
81
+
82
+ | Feature | form-hook-kit | Formik | React Hook Form | Final Form |
83
+ |---------|-------------------|--------|-----------------|------------|
84
+ | React Native Support | ✓ Native | ✓ Supported | ✓ Supported | ✓ Supported |
85
+ | TypeScript | ✓ First-class | ✓ Supported | ✓ First-class | ✓ Supported |
86
+ | Yup Integration | ✓ Built-in | ✓ Built-in | Via resolver | Via plugin |
87
+ | API Style | Context + Hooks | Context + Hooks | Refs + Hooks | Subscriptions |
88
+ | Hooks-only API | ✓ Yes | Mixed | ✓ Yes | Mixed |
89
+ | Built-in Field Refs | ✓ Yes | ✓ Yes | ✓ Yes | ✓ Yes |
90
+ | Learning Curve | Low | Low-Medium | Medium | Medium-High |
91
+
92
+ ### When to Choose form-hook-kit
93
+
94
+ Choose `form-hook-kit` if you:
95
+ - Are building a React or React Native app
96
+ - Need React Native new architecture compatibility (no native code dependencies)
97
+ - Want a simple, hooks-based API
98
+ - Prefer context-based state management
99
+ - Need TypeScript support with 100% type coverage
100
+ - Use Yup for validation
101
+ - Want built-in Yup integration without extra packages
102
+ - Prefer controlled inputs over uncontrolled
103
+ - Need compatibility with Android 16KB page size
104
+
105
+ ---
106
+
107
+ ## Installation
108
+
109
+ ```bash
110
+ npm install form-hook-kit yup
111
+ # or
112
+ yarn add form-hook-kit yup
113
+ # or
114
+ pnpm add form-hook-kit yup
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Quick Start
120
+
121
+ ### Basic Example (React Web)
122
+
123
+ ```tsx
124
+ import React from 'react';
125
+ import * as yup from 'yup';
126
+ import {FormProvider, useForm, useFormField} from 'form-hook-kit';
127
+
128
+ // Define your validation schema
129
+ const schema = yup.object({
130
+ email: yup.string().email('Invalid email').required('Email is required'),
131
+ password: yup
132
+ .string()
133
+ .min(8, 'Password must be at least 8 characters')
134
+ .required('Password is required'),
135
+ });
136
+
137
+ // Create form fields
138
+ function EmailField() {
139
+ const {value, error, onChange, onBlur} = useFormField('email');
140
+
141
+ return (
142
+ <div>
143
+ <input
144
+ type="email"
145
+ value={value || ''}
146
+ onChange={onChange}
147
+ onBlur={onBlur}
148
+ placeholder="Email"
149
+ />
150
+ {error && <span className="error">{error}</span>}
151
+ </div>
152
+ );
153
+ }
154
+
155
+ function PasswordField() {
156
+ const {value, error, onChange, onBlur} = useFormField('password');
157
+
158
+ return (
159
+ <div>
160
+ <input
161
+ type="password"
162
+ value={value || ''}
163
+ onChange={onChange}
164
+ onBlur={onBlur}
165
+ placeholder="Password"
166
+ />
167
+ {error && <span className="error">{error}</span>}
168
+ </div>
169
+ );
170
+ }
171
+
172
+ // Create your form
173
+ function LoginForm() {
174
+ const {validateForm, values} = useForm();
175
+
176
+ const handleSubmit = (e: React.FormEvent) => {
177
+ e.preventDefault();
178
+ const errors = validateForm();
179
+
180
+ if (Object.values(errors).every(error => !error)) {
181
+ // Form is valid, submit it
182
+ console.log('Form submitted:', values);
183
+ }
184
+ };
185
+
186
+ return (
187
+ <form onSubmit={handleSubmit}>
188
+ <EmailField />
189
+ <PasswordField />
190
+ <button type="submit">Login</button>
191
+ </form>
192
+ );
193
+ }
194
+
195
+ // Wrap with FormProvider
196
+ export default function App() {
197
+ return (
198
+ <FormProvider
199
+ schema={schema}
200
+ initialValues={{email: '', password: ''}}
201
+ >
202
+ <LoginForm />
203
+ </FormProvider>
204
+ );
205
+ }
206
+ ```
207
+
208
+ ### React Native Example
209
+
210
+ > **Note:** form-hook-kit has **zero native dependencies** - it's pure JavaScript/TypeScript. This means it's fully compatible with:
211
+ > - ✅ React Native legacy architecture
212
+ > - ✅ React Native new architecture (Fabric & TurboModules)
213
+ > - ✅ Android 16KB page size requirement
214
+ > - ✅ Expo (including Expo Go)
215
+ >
216
+ > **📱 For detailed React Native usage and platform-specific features, see [REACT_NATIVE.md](REACT_NATIVE.md)**
217
+
218
+ ```tsx
219
+ import React from 'react';
220
+ import {View, TextInput, Text, Button} from 'react-native';
221
+ import * as yup from 'yup';
222
+ import {FormProvider, useFormField, useForm} from 'form-hook-kit';
223
+
224
+ const schema = yup.object({
225
+ username: yup.string().required('Username is required'),
226
+ email: yup.string().email('Invalid email').required('Email is required'),
227
+ });
228
+
229
+ function UsernameField() {
230
+ const {value, error, onChangeValue, onBlur, setRef} = useFormField('username');
231
+
232
+ return (
233
+ <View>
234
+ <TextInput
235
+ ref={setRef}
236
+ value={value || ''}
237
+ onChangeText={onChangeValue}
238
+ onBlur={onBlur}
239
+ placeholder="Username"
240
+ />
241
+ {error && <Text style={{color: 'red'}}>{error}</Text>}
242
+ </View>
243
+ );
244
+ }
245
+
246
+ function EmailField() {
247
+ const {value, error, onChangeValue, onBlur, setRef} = useFormField('email');
248
+
249
+ return (
250
+ <View>
251
+ <TextInput
252
+ ref={setRef}
253
+ value={value || ''}
254
+ onChangeText={onChangeValue}
255
+ onBlur={onBlur}
256
+ placeholder="Email"
257
+ keyboardType="email-address"
258
+ />
259
+ {error && <Text style={{color: 'red'}}>{error}</Text>}
260
+ </View>
261
+ );
262
+ }
263
+
264
+ function SignupForm() {
265
+ const {validateForm, values} = useForm();
266
+
267
+ const handleSubmit = () => {
268
+ const errors = validateForm();
269
+
270
+ if (Object.values(errors).every(error => !error)) {
271
+ console.log('Form submitted:', values);
272
+ }
273
+ };
274
+
275
+ return (
276
+ <View>
277
+ <UsernameField />
278
+ <EmailField />
279
+ <Button title="Sign Up" onPress={handleSubmit} />
280
+ </View>
281
+ );
282
+ }
283
+
284
+ export default function App() {
285
+ return (
286
+ <FormProvider
287
+ schema={schema}
288
+ initialValues={{username: '', email: ''}}
289
+ >
290
+ <SignupForm />
291
+ </FormProvider>
292
+ );
293
+ }
294
+ ```
295
+
296
+ ---
297
+
298
+ ## API Reference
299
+
300
+ For advanced usage including custom form implementations and direct access to utility functions, see [ADVANCED_USAGE.md](./ADVANCED_USAGE.md).
301
+
302
+ ### `FormProvider`
303
+
304
+ The main component that wraps your form and provides context.
305
+
306
+ **Props:**
307
+
308
+ - `schema` (required): Yup validation schema
309
+ - `initialValues` (optional): Initial form values (default: `{}`)
310
+ - `initialErrors` (optional): Initial error state (default: `{}`)
311
+ - `validationDebounce` (optional): Debounce validation in milliseconds for performance optimization (default: `0`)
312
+ - `children` (required): Form components
313
+
314
+ ```tsx
315
+ <FormProvider
316
+ schema={yupSchema}
317
+ initialValues={{email: '', password: ''}}
318
+ initialErrors={{}}
319
+ validationDebounce={300} // Optional: debounce validation for better performance
320
+ >
321
+ {children}
322
+ </FormProvider>
323
+ ```
324
+
325
+ ### `useForm()`
326
+
327
+ Hook to access the form context. Must be used within a `FormProvider`.
328
+
329
+ **Returns:**
330
+
331
+ - `values`: Object containing all form values
332
+ - `errors`: Object containing all form errors
333
+ - `fieldRefs`: Ref object for managing field focus
334
+ - `changeValue(params)`: Function to update a single field
335
+ - `changeValues(values)`: Function to update multiple fields
336
+ - `clearError(name)`: Function to clear error for a field
337
+ - `setError(params)`: Function to set error for a field
338
+ - `validateField(name, value?)`: Function to validate a single field
339
+ - `validateForm()`: Function to validate entire form
340
+
341
+ ```tsx
342
+ const {
343
+ values,
344
+ errors,
345
+ changeValue,
346
+ validateForm,
347
+ fieldRefs,
348
+ } = useForm();
349
+ ```
350
+
351
+ ### `useFormField(name)`
352
+
353
+ Convenient hook for managing a single form field. Provides pre-configured handlers.
354
+
355
+ **Parameters:**
356
+
357
+ - `name` (string): The field name
358
+
359
+ **Returns:**
360
+
361
+ - `value`: Current field value
362
+ - `error`: Current field error
363
+ - `name`: Field name
364
+ - `onChange`: Handler for React web inputs (e.target.value)
365
+ - `onChangeValue`: Handler for React Native or custom value changes
366
+ - `onBlur`: Handler for field blur (triggers validation)
367
+ - `onFocus`: Handler for field focus (clears errors)
368
+ - `setRef`: Function to set field ref for focus management
369
+
370
+ ```tsx
371
+ const {value, error, onChange, onBlur} = useFormField('email');
372
+ ```
373
+
374
+ ### `useFormPerformance()`
375
+
376
+ **NEW in v1.2.0** - Hook to monitor form performance metrics. Useful for debugging and optimization.
377
+
378
+ **Returns:**
379
+
380
+ - `renderCount`: Number of times the component has rendered
381
+ - `lastRenderTime`: Time taken for the last render (ms)
382
+ - `validationCount`: Number of validations performed
383
+ - `averageValidationTime`: Average validation time (ms)
384
+ - `fieldChangeCount`: Number of field changes
385
+
386
+ ```tsx
387
+ import {useFormPerformance} from 'form-hook-kit';
388
+
389
+ function MyForm() {
390
+ const metrics = useFormPerformance();
391
+
392
+ console.log('Renders:', metrics.renderCount);
393
+ console.log('Avg validation time:', metrics.averageValidationTime);
394
+
395
+ return <div>...</div>;
396
+ }
397
+ ```
398
+
399
+ ### `useValidationPerformance()`
400
+
401
+ **NEW in v1.2.0** - Hook to track validation performance with timing metrics.
402
+
403
+ ```tsx
404
+ import {useValidationPerformance} from 'form-hook-kit';
405
+
406
+ function MyForm() {
407
+ const {validateField, validateForm, metrics} = useValidationPerformance();
408
+
409
+ const handleSubmit = () => {
410
+ validateForm();
411
+ console.log('Validation took:', metrics.lastValidationTime, 'ms');
412
+ };
413
+
414
+ return <button onClick={handleSubmit}>Submit</button>;
415
+ }
416
+ ```
417
+
418
+ ### `FormDevTools`
419
+
420
+ **NEW in v1.2.0** - Cross-platform development tool for inspecting form state and performance.
421
+
422
+ **Platform Support:**
423
+ - **Web**: Visual UI panel (default)
424
+ - **React Native**: Console logging mode (works with React Native Debugger, Flipper, or Metro logs)
425
+
426
+ **Import from separate entry point:**
427
+
428
+ ```tsx
429
+ import {FormDevTools} from 'form-hook-kit/devtools';
430
+
431
+ // Web - shows UI panel
432
+ function WebForm() {
433
+ return (
434
+ <FormProvider schema={schema}>
435
+ <MyFormFields />
436
+ {process.env.NODE_ENV === 'development' && <FormDevTools />}
437
+ </FormProvider>
438
+ );
439
+ }
440
+
441
+ // React Native - logs to console
442
+ function MobileForm() {
443
+ return (
444
+ <FormProvider schema={schema}>
445
+ <MyFormFields />
446
+ {__DEV__ && <FormDevTools mode="console" autoLog />}
447
+ </FormProvider>
448
+ );
449
+ }
450
+ ```
451
+
452
+ **Props:**
453
+ - `mode?: 'ui' | 'console' | 'none'` - Display mode (auto-detects platform by default)
454
+ - `autoLog?: boolean` - Auto-log changes in console mode (default: `false`)
455
+ - `logPrefix?: string` - Custom log prefix (default: `'[FormDevTools]'`)
456
+ - `position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'` - UI panel position (default: `'bottom-right'`)
457
+ - `defaultOpen?: boolean` - UI panel open by default (default: `true`)
458
+
459
+ **Console Mode (React Native):**
460
+
461
+ When using `mode="console"`, you can manually inspect form state:
462
+
463
+ ```tsx
464
+ // In React Native Debugger or browser console:
465
+ global.formDevTools.logValues() // Log current values
466
+ global.formDevTools.logErrors() // Log current errors
467
+ global.formDevTools.logMetrics() // Log performance metrics
468
+ global.formDevTools.logAll() // Log everything
469
+ ```
470
+
471
+ **Props:**
472
+
473
+ - `position` (optional): `'top-left'` | `'top-right'` | `'bottom-left'` | `'bottom-right'` (default: `'bottom-right'`)
474
+ - `defaultOpen` (optional): Whether to show by default (default: `false`)
475
+
476
+ ---
477
+
478
+ ## Advanced Usage
479
+
480
+ ### Performance Optimization
481
+
482
+ **Debounced Validation:**
483
+
484
+ For forms with real-time validation, you can debounce validation to improve performance:
485
+
486
+ ```tsx
487
+ <FormProvider
488
+ schema={schema}
489
+ validationDebounce={300} // Wait 300ms after user stops typing
490
+ >
491
+ <MyForm />
492
+ </FormProvider>
493
+ ```
494
+
495
+ **Performance Monitoring:**
496
+
497
+ Track and optimize your form's performance:
498
+
499
+ ```tsx
500
+ import {useFormPerformance} from 'form-hook-kit';
501
+
502
+ function MyForm() {
503
+ const metrics = useFormPerformance();
504
+
505
+ // Log performance in development
506
+ useEffect(() => {
507
+ if (process.env.NODE_ENV === 'development') {
508
+ console.log('Form Performance:', metrics);
509
+ }
510
+ }, [metrics]);
511
+
512
+ return <div>...</div>;
513
+ }
514
+ ```
515
+
516
+ ### Custom Validation
517
+
518
+ ```tsx
519
+ import * as yup from 'yup';
520
+
521
+ const schema = yup.object({
522
+ password: yup.string().required('Password is required'),
523
+ confirmPassword: yup
524
+ .string()
525
+ .oneOf([yup.ref('password')], 'Passwords must match')
526
+ .required('Confirm password is required'),
527
+ });
528
+ ```
529
+
530
+ ### Manual Field Validation
531
+
532
+ ```tsx
533
+ function MyField() {
534
+ const {values, errors, changeValue, validateField} = useForm();
535
+
536
+ const handleChange = (value: string) => {
537
+ changeValue({name: 'email', value});
538
+ // Validate immediately on change
539
+ validateField('email', value);
540
+ };
541
+
542
+ return (
543
+ <input
544
+ value={values.email || ''}
545
+ onChange={(e) => handleChange(e.target.value)}
546
+ />
547
+ );
548
+ }
549
+ ```
550
+
551
+ ### Setting Errors Manually
552
+
553
+ ```tsx
554
+ function MyForm() {
555
+ const {setError, clearError} = useForm();
556
+
557
+ const handleCustomValidation = () => {
558
+ if (someCondition) {
559
+ setError({name: 'email', error: 'Custom error message'});
560
+ } else {
561
+ clearError('email');
562
+ }
563
+ };
564
+
565
+ return (
566
+ // ...
567
+ );
568
+ }
569
+ ```
570
+
571
+ ### Focus Management (React Native)
572
+
573
+ ```tsx
574
+ function MyForm() {
575
+ const {fieldRefs} = useForm();
576
+
577
+ const focusNextField = () => {
578
+ // Focus the email field
579
+ fieldRefs.current.email?.focus();
580
+ };
581
+
582
+ return (
583
+ <View>
584
+ <TextInput
585
+ ref={(ref) => (fieldRefs.current.username = ref)}
586
+ onSubmitEditing={() => fieldRefs.current.email?.focus()}
587
+ returnKeyType="next"
588
+ />
589
+ <TextInput
590
+ ref={(ref) => (fieldRefs.current.email = ref)}
591
+ returnKeyType="done"
592
+ />
593
+ </View>
594
+ );
595
+ }
596
+ ```
597
+
598
+ ### Updating Multiple Values
599
+
600
+ ```tsx
601
+ function MyForm() {
602
+ const {changeValues} = useForm();
603
+
604
+ const resetForm = () => {
605
+ changeValues({
606
+ email: '',
607
+ password: '',
608
+ username: '',
609
+ });
610
+ };
611
+
612
+ return (
613
+ <button onClick={resetForm}>Reset</button>
614
+ );
615
+ }
616
+ ```
617
+
618
+ ### Custom Formatters
619
+
620
+ ```tsx
621
+ function PhoneField() {
622
+ const {value, error, onChangeValue, onBlur} = useFormField('phone');
623
+
624
+ const formatPhone = (text: string) => {
625
+ // Remove non-digits
626
+ const digits = text.replace(/\D/g, '');
627
+ // Format as (XXX) XXX-XXXX
628
+ if (digits.length <= 3) return digits;
629
+ if (digits.length <= 6) return `(${digits.slice(0, 3)}) ${digits.slice(3)}`;
630
+ return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6, 10)}`;
631
+ };
632
+
633
+ return (
634
+ <input
635
+ value={value || ''}
636
+ onChange={(e) => onChangeValue(formatPhone(e.target.value))}
637
+ onBlur={onBlur}
638
+ />
639
+ );
640
+ }
641
+ ```
642
+
643
+ ---
644
+
645
+ ## TypeScript Support
646
+
647
+ Full TypeScript support with type inference:
648
+
649
+ ```tsx
650
+ import {FormProvider, useForm, useFormField} from 'form-hook-kit';
651
+ import * as yup from 'yup';
652
+
653
+ interface FormValues {
654
+ email: string;
655
+ password: string;
656
+ }
657
+
658
+ const schema = yup.object({
659
+ email: yup.string().email().required(),
660
+ password: yup.string().min(8).required(),
661
+ });
662
+
663
+ function MyForm() {
664
+ const {values, errors} = useForm();
665
+ // values and errors are properly typed based on schema
666
+ }
667
+ ```
668
+
669
+ ---
670
+
671
+ ## Testing
672
+
673
+ Example test using React Testing Library:
674
+
675
+ ```tsx
676
+ import {render, screen, fireEvent} from '@testing-library/react';
677
+ import * as yup from 'yup';
678
+ import {FormProvider, useForm} from 'form-hook-kit';
679
+
680
+ const schema = yup.object({
681
+ email: yup.string().email().required(),
682
+ });
683
+
684
+ test('validates email field', async () => {
685
+ function TestForm() {
686
+ const {values, errors, changeValue, validateField} = useForm();
687
+
688
+ return (
689
+ <div>
690
+ <input
691
+ data-testid="email"
692
+ value={values.email || ''}
693
+ onChange={(e) => changeValue({name: 'email', value: e.target.value})}
694
+ onBlur={() => validateField('email')}
695
+ />
696
+ {errors.email && <span data-testid="error">{errors.email}</span>}
697
+ </div>
698
+ );
699
+ }
700
+
701
+ render(
702
+ <FormProvider schema={schema} initialValues={{email: ''}}>
703
+ <TestForm />
704
+ </FormProvider>
705
+ );
706
+
707
+ const input = screen.getByTestId('email');
708
+ fireEvent.change(input, {target: {value: 'invalid'}});
709
+ fireEvent.blur(input);
710
+
711
+ expect(await screen.findByTestId('error')).toBeInTheDocument();
712
+ });
713
+ ```
714
+
715
+ ---
716
+
717
+ ## Performance Tips
718
+
719
+ 1. **Memoize handlers**: Use `useCallback` for event handlers if needed
720
+ 2. **Split forms**: Break large forms into smaller sub-forms
721
+ 3. **Lazy validation**: Validate on blur instead of on every keystroke
722
+ 4. **Schema optimization**: Keep Yup schemas simple and efficient
723
+
724
+ ---
725
+
726
+ ## Troubleshooting
727
+
728
+ | Issue | Solution |
729
+ |-------|----------|
730
+ | Validation not working | Ensure your Yup schema is properly defined and passed to FormProvider |
731
+ | Field not updating | Check that you're using the correct field name and onChange handler |
732
+ | TypeScript errors | Make sure your form values interface matches your Yup schema |
733
+ | React Native TextInput issues | Use `onChangeText` with `onChangeValue` instead of `onChange` |
734
+
735
+ ---
736
+
737
+ ## Contributing
738
+
739
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
740
+
741
+ ---
742
+
743
+ ## License
744
+
745
+ MIT License - see [LICENSE](LICENSE) file for details
746
+
747
+ ---
748
+
749
+ ## Credits
750
+
751
+ **Author:** bc-bane
752
+ Built for production use in React and React Native applications.
753
+ Designed to be simple, performant, and flexible.