@connect-soft/form-generator 1.0.0 → 1.1.0-alpha10

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 (34) hide show
  1. package/README.md +956 -188
  2. package/dist/index.js +4400 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +4329 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/dist/types/components/form/array-field-renderer.d.ts +39 -0
  7. package/dist/types/components/form/array-field-renderer.d.ts.map +1 -0
  8. package/dist/types/components/form/create-template-fields.d.ts +3 -0
  9. package/dist/types/components/form/create-template-fields.d.ts.map +1 -0
  10. package/dist/types/components/form/field-renderer.d.ts +7 -0
  11. package/dist/types/components/form/field-renderer.d.ts.map +1 -0
  12. package/dist/types/components/form/fields-context.d.ts +26 -0
  13. package/dist/types/components/form/fields-context.d.ts.map +1 -0
  14. package/dist/types/components/form/form-generator-typed.d.ts +47 -0
  15. package/dist/types/components/form/form-generator-typed.d.ts.map +1 -0
  16. package/dist/types/components/form/form-generator.d.ts +51 -0
  17. package/dist/types/components/form/form-generator.d.ts.map +1 -0
  18. package/dist/types/components/form/form-utils.d.ts +47 -0
  19. package/dist/types/components/form/form-utils.d.ts.map +1 -0
  20. package/dist/types/components/form/index.d.ts +7 -0
  21. package/dist/types/components/form/index.d.ts.map +1 -0
  22. package/dist/types/index.d.ts +22 -0
  23. package/dist/types/index.d.ts.map +1 -0
  24. package/dist/types/lib/field-registry.d.ts +74 -0
  25. package/dist/types/lib/field-registry.d.ts.map +1 -0
  26. package/dist/types/lib/field-types.d.ts +151 -0
  27. package/dist/types/lib/field-types.d.ts.map +1 -0
  28. package/dist/types/lib/index.d.ts +7 -0
  29. package/dist/types/lib/index.d.ts.map +1 -0
  30. package/dist/types/lib/template-types.d.ts +55 -0
  31. package/dist/types/lib/template-types.d.ts.map +1 -0
  32. package/dist/types/setupTests.d.ts +2 -0
  33. package/dist/types/setupTests.d.ts.map +1 -0
  34. package/package.json +40 -131
package/README.md CHANGED
@@ -1,33 +1,32 @@
1
1
  # @connect-soft/form-generator
2
2
 
3
- > Type-safe form generator with Radix UI, Tailwind CSS, and react-hook-form
3
+ > Headless, type-safe form generator with react-hook-form and Zod validation
4
4
 
5
5
  [![Version](https://img.shields.io/npm/v/@connect-soft/form-generator)](https://www.npmjs.com/package/@connect-soft/form-generator)
6
6
  [![License](https://img.shields.io/npm/l/@connect-soft/form-generator)](./LICENSE)
7
- [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@connect-soft/form-generator)](https://bundlephobia.com/package/@connect-soft/form-generator)
8
-
9
- **v2.0.0** - Complete rewrite with Radix UI + Tailwind CSS
10
- **50-60% smaller bundle** | **No runtime CSS overhead** | **Modern, accessible UI**
11
7
 
12
8
  ---
13
9
 
14
10
  ## Features
15
11
 
16
- **Modern UI Stack**: Radix UI primitives + Tailwind CSS (shadcn/ui approach)
17
- 📦 **Lightweight**: <80 KB gzipped (50-60% reduction from v1)
18
- 🎯 **Type-Safe**: Full TypeScript inference for form values
19
- 🔧 **Flexible**: 10+ field types with extensible API
20
- **Accessible**: Built on Radix UI's accessible primitives
21
- 🎨 **Customizable**: Easy styling with Tailwind classes
22
- 🚀 **Performance**: No runtime CSS-in-JS, field-level subscriptions
23
- 🔄 **Backward Compatible**: v1→v2 adapter included
12
+ - **Headless**: Bring your own UI components (Radix, MUI, Chakra, or plain HTML)
13
+ - **Type-Safe**: Full TypeScript inference for form values and field types
14
+ - **Field Type Checking**: Compile-time validation of `field.type` with autocomplete
15
+ - **Extensible Types**: Add custom field types via module augmentation
16
+ - **Imperative API**: Control form via ref (`setValues`, `reset`, `submit`, etc.)
17
+ - **Flexible**: Register custom field components with a simple API
18
+ - **Validation**: Built-in Zod validation support
19
+ - **Array Fields**: Repeatable field groups with `useFieldArray` integration
20
+ - **Custom Layouts**: Full control over form layout via render props
21
+ - **Lightweight**: No UI dependencies, minimal footprint
22
+ - **HTML Fallbacks**: Works out of the box with native HTML inputs
24
23
 
25
24
  ---
26
25
 
27
26
  ## Installation
28
27
 
29
28
  ```bash
30
- npm install @connect-soft/form-generator react-hook-form zod
29
+ npm install @connect-soft/form-generator
31
30
  ```
32
31
 
33
32
  ### Peer Dependencies
@@ -36,74 +35,23 @@ npm install @connect-soft/form-generator react-hook-form zod
36
35
  - `react-dom` ^19.0.0
37
36
  - `zod` ^4.0.0
38
37
 
39
- ### Tailwind CSS Setup
40
-
41
- This library requires Tailwind CSS. If you don't have it set up:
42
-
43
- ```bash
44
- npm install -D tailwindcss postcss autoprefixer
45
- npx tailwindcss init -p
46
- ```
47
-
48
- **tailwind.config.js:**
49
- ```javascript
50
- module.exports = {
51
- content: [
52
- './src/**/*.{js,ts,jsx,tsx}',
53
- './node_modules/@connect-soft/form-generator/dist/**/*.{js,mjs}',
54
- ],
55
- theme: {
56
- extend: {
57
- // Your custom theme
58
- },
59
- },
60
- plugins: [],
61
- };
62
- ```
63
-
64
- **Import the styles in your main file:**
65
- ```typescript
66
- import '@connect-soft/form-generator/dist/styles.css';
67
- ```
68
-
69
38
  ---
70
39
 
71
40
  ## Quick Start
72
41
 
42
+ The library works immediately with HTML fallback components:
43
+
73
44
  ```typescript
74
- import { FormGenerator, Field } from '@connect-soft/form-generator';
45
+ import { FormGenerator } from '@connect-soft/form-generator';
75
46
 
76
- const fields: Field[] = [
77
- {
78
- type: 'text',
79
- name: 'email',
80
- label: 'Email',
81
- fieldType: 'email',
82
- required: true,
83
- placeholder: 'Enter your email',
84
- },
85
- {
86
- type: 'number',
87
- name: 'age',
88
- label: 'Age',
89
- min: 18,
90
- max: 120,
91
- },
92
- {
93
- type: 'select',
94
- name: 'country',
95
- label: 'Country',
96
- options: [
97
- { label: 'United States', value: 'us' },
98
- { label: 'United Kingdom', value: 'uk' },
99
- { label: 'Germany', value: 'de' },
100
- ],
101
- },
102
- {
103
- type: 'checkbox',
104
- name: 'subscribe',
105
- label: 'Subscribe to newsletter',
106
- },
47
+ const fields = [
48
+ { type: 'text', name: 'email', label: 'Email', required: true },
49
+ { type: 'number', name: 'age', label: 'Age', min: 18, max: 120 },
50
+ { type: 'select', name: 'country', label: 'Country', options: [
51
+ { label: 'United States', value: 'us' },
52
+ { label: 'Germany', value: 'de' },
53
+ ]},
54
+ { type: 'checkbox', name: 'subscribe', label: 'Subscribe to newsletter' },
107
55
  ] as const;
108
56
 
109
57
  function MyForm() {
@@ -111,13 +59,8 @@ function MyForm() {
111
59
  <FormGenerator
112
60
  fields={fields}
113
61
  onSubmit={(values) => {
114
- // ✅ values is fully typed!
115
- console.log(values.email); // string
116
- console.log(values.age); // number
117
- console.log(values.country); // string
118
- console.log(values.subscribe);// boolean
62
+ console.log(values); // Fully typed!
119
63
  }}
120
- submitText="Create Account"
121
64
  />
122
65
  );
123
66
  }
@@ -125,77 +68,250 @@ function MyForm() {
125
68
 
126
69
  ---
127
70
 
71
+ ## Registering Custom Components
72
+
73
+ Register your own UI components to replace the HTML fallbacks. Field components are fully responsible for rendering their own label, description, and error messages:
74
+
75
+ ```typescript
76
+ import { registerFields, registerFormComponent } from '@connect-soft/form-generator';
77
+ import { Input } from './ui/input';
78
+ import { Label } from './ui/label';
79
+ import { Checkbox } from './ui/checkbox';
80
+ import { Button } from './ui/button';
81
+
82
+ // Register field components - they handle their own rendering
83
+ registerFields({
84
+ text: ({ field, formField, fieldState }) => (
85
+ <div className="form-field">
86
+ {field.label && <Label>{field.label}{field.required && ' *'}</Label>}
87
+ <Input
88
+ {...formField}
89
+ type={field.fieldType || 'text'}
90
+ placeholder={field.placeholder}
91
+ disabled={field.disabled}
92
+ />
93
+ {field.description && <p className="text-sm text-muted">{field.description}</p>}
94
+ {fieldState.error && <span className="text-red-500 text-sm">{fieldState.error.message}</span>}
95
+ </div>
96
+ ),
97
+ number: ({ field, formField, fieldState }) => (
98
+ <div className="form-field">
99
+ {field.label && <Label>{field.label}</Label>}
100
+ <Input
101
+ {...formField}
102
+ type="number"
103
+ min={field.min}
104
+ max={field.max}
105
+ />
106
+ {fieldState.error && <span className="text-red-500 text-sm">{fieldState.error.message}</span>}
107
+ </div>
108
+ ),
109
+ checkbox: ({ field, formField }) => (
110
+ <div className="flex items-center gap-2">
111
+ <Checkbox
112
+ checked={formField.value}
113
+ onCheckedChange={formField.onChange}
114
+ disabled={field.disabled}
115
+ />
116
+ {field.label && <Label>{field.label}</Label>}
117
+ </div>
118
+ ),
119
+ });
120
+
121
+ // Register the submit button component
122
+ registerFormComponent('SubmitButton', Button);
123
+
124
+ // Optional: Register field wrappers for custom styling
125
+ registerFormComponent('FieldWrapper', ({ children, name, type, className }) => (
126
+ <div className={`field-wrapper field-${type}`} data-field={name}>
127
+ {children}
128
+ </div>
129
+ ));
130
+
131
+ registerFormComponent('FieldsWrapper', ({ children }) => (
132
+ <div className="form-fields">
133
+ {children}
134
+ </div>
135
+ ));
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Field Wrappers
141
+
142
+ Customize how fields are wrapped without modifying individual field components:
143
+
144
+ ### FieldWrapper
145
+
146
+ Wraps each individual field. Receives the field's `name`, `type`, and `className`:
147
+
148
+ ```typescript
149
+ registerFormComponent('FieldWrapper', ({ children, name, type, className }) => (
150
+ <div className={`form-group ${className || ''}`} data-field-type={type}>
151
+ {children}
152
+ </div>
153
+ ));
154
+ ```
155
+
156
+ ### FieldsWrapper
157
+
158
+ Wraps all fields together (excludes the submit button). Useful for grid layouts:
159
+
160
+ ```typescript
161
+ registerFormComponent('FieldsWrapper', ({ children, className }) => (
162
+ <div className={`grid grid-cols-2 gap-4 ${className || ''}`}>
163
+ {children}
164
+ </div>
165
+ ));
166
+ ```
167
+
168
+ Both default to `React.Fragment`, adding zero DOM overhead when not customized.
169
+
170
+ ---
171
+
128
172
  ## Field Types
129
173
 
174
+ Built-in HTML fallback types:
175
+
130
176
  | Type | Description | Value Type |
131
177
  |------|-------------|------------|
132
- | `text` | Text input (email, password, url, tel) | `string` |
133
- | `textarea` | Multi-line text input | `string` |
134
- | `number` | Number input with min/max/step | `number` |
135
- | `checkbox` | Checkbox input | `boolean` |
136
- | `switch` | Toggle switch | `boolean` |
178
+ | `text` | Text input | `string` |
179
+ | `email` | Email input | `string` |
180
+ | `password` | Password input | `string` |
181
+ | `number` | Number input with min/max | `number` |
182
+ | `textarea` | Multi-line text | `string` |
183
+ | `checkbox` | Checkbox | `boolean` |
137
184
  | `select` | Dropdown select | `string` |
138
185
  | `radio` | Radio button group | `string` |
139
- | `date` | Date picker (react-day-picker) | `Date` |
140
- | `dateRange` | Date range picker | `{from: Date, to?: Date}` |
141
- | `time` | Time picker (HH:mm) | `string` |
186
+ | `date` | Date input | `Date` |
187
+ | `time` | Time input | `string` |
188
+ | `file` | File input | `File` |
189
+ | `hidden` | Hidden input | `string` |
142
190
 
143
- ---
191
+ ### Adding Custom Field Types (TypeScript)
144
192
 
145
- ## Advanced Components
193
+ Extend the `FieldTypeRegistry` interface to add type checking for custom fields:
146
194
 
147
- ### MultiSelect
195
+ ```typescript
196
+ // types/form-generator.d.ts
197
+ import { CreateFieldType } from '@connect-soft/form-generator';
198
+
199
+ declare module '@connect-soft/form-generator' {
200
+ interface FieldTypeRegistry {
201
+ // Add your custom field types
202
+ 'color-picker': CreateFieldType<'color-picker', string, {
203
+ swatches?: string[];
204
+ showAlpha?: boolean;
205
+ }>;
206
+ 'rich-text': CreateFieldType<'rich-text', string, {
207
+ toolbar?: ('bold' | 'italic' | 'link')[];
208
+ maxLength?: number;
209
+ }>;
210
+ }
211
+ }
212
+ ```
213
+
214
+ Now TypeScript will recognize your custom field types:
148
215
 
149
216
  ```typescript
150
- import { MultiSelect } from '@connect-soft/form-generator/advanced';
217
+ const fields = [
218
+ { type: 'color-picker', name: 'theme', swatches: ['#fff', '#000'] }, // ✅ Valid
219
+ { type: 'unknown-type', name: 'test' }, // ❌ Type error
220
+ ] as const;
221
+ ```
151
222
 
152
- <MultiSelect
153
- options={[
154
- { label: 'React', value: 'react' },
155
- { label: 'Vue', value: 'vue' },
156
- { label: 'Angular', value: 'angular' },
157
- ]}
158
- value={selected}
159
- onChange={setSelected}
160
- placeholder="Select frameworks..."
161
- />
223
+ Then register the component for your custom field:
224
+
225
+ ```typescript
226
+ import { registerField } from '@connect-soft/form-generator';
227
+ import { ColorPicker } from './components/ColorPicker';
228
+
229
+ // Type-safe: 'color-picker' must exist in FieldTypeRegistry
230
+ registerField('color-picker', ({ field, formField }) => (
231
+ <ColorPicker
232
+ value={formField.value}
233
+ onChange={formField.onChange}
234
+ swatches={field.swatches}
235
+ showAlpha={field.showAlpha}
236
+ />
237
+ ));
238
+
239
+ // ❌ TypeScript error: 'unknown-type' is not in FieldTypeRegistry
240
+ // registerField('unknown-type', MyComponent);
162
241
  ```
163
242
 
164
- ### ColorPicker
243
+ > **Note:** Both `registerField` and `registerFields` enforce that field types must be defined in `FieldTypeRegistry`. This ensures type safety between your type definitions and runtime registrations.
244
+
245
+ ### Field Type Validation Helpers
246
+
247
+ Use helper functions for strict type checking without `as const`:
165
248
 
166
249
  ```typescript
167
- import { ColorPicker } from '@connect-soft/form-generator/advanced';
250
+ import { createField, createArrayField, strictFields } from '@connect-soft/form-generator';
168
251
 
169
- <ColorPicker
170
- value={color}
171
- onChange={setColor}
172
- />
252
+ // Create a single field with full type checking
253
+ const emailField = createField({
254
+ type: 'email',
255
+ name: 'email',
256
+ label: 'Email',
257
+ placeholder: 'Enter your email' // TypeScript knows this is valid for email
258
+ });
259
+
260
+ // Create an array field
261
+ const contacts = createArrayField({
262
+ name: 'contacts',
263
+ fields: [
264
+ { type: 'text', name: 'name', label: 'Name' },
265
+ { type: 'email', name: 'email', label: 'Email' }
266
+ ],
267
+ minItems: 1,
268
+ maxItems: 5
269
+ });
270
+
271
+ // Create an array of fields with type checking
272
+ const fields = strictFields([
273
+ { type: 'text', name: 'username', label: 'Username' },
274
+ { type: 'email', name: 'email', label: 'Email' },
275
+ // { type: 'unknown', name: 'bad' } // TypeScript error!
276
+ ]);
173
277
  ```
174
278
 
175
- ### TransferList
279
+ ### Runtime Field Type Validation
280
+
281
+ Enable runtime validation to catch unregistered field types during development:
176
282
 
177
283
  ```typescript
178
- import { TransferList } from '@connect-soft/form-generator/advanced';
179
-
180
- <TransferList
181
- options={allOptions}
182
- value={selectedValues}
183
- onChange={setSelectedValues}
184
- leftTitle="Available"
185
- rightTitle="Selected"
186
- searchable={true}
284
+ // Warn in console for unregistered types (recommended for development)
285
+ <FormGenerator
286
+ fields={fields}
287
+ onSubmit={handleSubmit}
288
+ validateTypes
187
289
  />
290
+
291
+ // Throw an error for unregistered types
292
+ <FormGenerator
293
+ fields={fields}
294
+ onSubmit={handleSubmit}
295
+ validateTypes={{ throwOnError: true }}
296
+ />
297
+
298
+ // Manual validation
299
+ import { validateFieldTypes, getRegisteredFieldTypes } from '@connect-soft/form-generator';
300
+
301
+ const registeredTypes = getRegisteredFieldTypes();
302
+ validateFieldTypes(fields, registeredTypes, { throwOnError: true });
188
303
  ```
189
304
 
190
305
  ---
191
306
 
192
307
  ## Custom Validation
193
308
 
194
- Use Zod for schema validation:
309
+ Use Zod for field-level or form-level validation:
195
310
 
196
311
  ```typescript
197
312
  import { z } from 'zod';
198
313
 
314
+ // Field-level validation
199
315
  const fields = [
200
316
  {
201
317
  type: 'text',
@@ -207,104 +323,727 @@ const fields = [
207
323
  type: 'text',
208
324
  name: 'email',
209
325
  label: 'Email',
210
- fieldType: 'email',
211
- validation: z.string().email().endsWith('@company.com'),
326
+ validation: z.string().email(),
212
327
  },
328
+ ] as const;
329
+
330
+ // Or use a full schema for type inference
331
+ const schema = z.object({
332
+ username: z.string().min(3),
333
+ email: z.string().email(),
334
+ });
335
+
336
+ <FormGenerator
337
+ fields={fields}
338
+ schema={schema}
339
+ onSubmit={(values) => {
340
+ // values is inferred from schema
341
+ }}
342
+ />
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Array Fields
348
+
349
+ Create repeatable field groups with `useFieldArray` integration:
350
+
351
+ ```typescript
352
+ const fields = [
353
+ { type: 'text', name: 'name', label: 'Name' },
213
354
  {
214
- type: 'number',
215
- name: 'age',
216
- label: 'Age',
217
- validation: z.number().min(18).max(120),
355
+ type: 'array',
356
+ name: 'contacts',
357
+ label: 'Contacts',
358
+ fields: [
359
+ { type: 'text', name: 'email', label: 'Email' },
360
+ { type: 'text', name: 'phone', label: 'Phone' },
361
+ ],
362
+ minItems: 1,
363
+ maxItems: 5,
218
364
  },
219
365
  ] as const;
220
366
  ```
221
367
 
368
+ ### Default Array Rendering
369
+
370
+ Array fields render automatically with add/remove functionality:
371
+
372
+ ```typescript
373
+ <FormGenerator
374
+ fields={fields}
375
+ onSubmit={(values) => {
376
+ console.log(values.contacts); // Array<{ email: string, phone: string }>
377
+ }}
378
+ />
379
+ ```
380
+
381
+ ### Custom Array Rendering with useArrayField
382
+
383
+ For full control, use the `useArrayField` hook in a custom layout:
384
+
385
+ ```typescript
386
+ import { FormGenerator, useArrayField } from '@connect-soft/form-generator';
387
+
388
+ <FormGenerator fields={fields} onSubmit={handleSubmit}>
389
+ {({ fields, arrays, buttons }) => {
390
+ const contacts = useArrayField(arrays.contacts.field);
391
+
392
+ return (
393
+ <div>
394
+ {fields.name}
395
+
396
+ <h3>Contacts</h3>
397
+ {contacts.items.map(({ id, index, remove, fields: itemFields }) => (
398
+ <div key={id} className="contact-row">
399
+ {itemFields.email}
400
+ {itemFields.phone}
401
+ {contacts.canRemove && (
402
+ <button type="button" onClick={remove}>Remove</button>
403
+ )}
404
+ </div>
405
+ ))}
406
+
407
+ {contacts.canAppend && (
408
+ <button type="button" onClick={contacts.append}>
409
+ Add Contact
410
+ </button>
411
+ )}
412
+
413
+ {buttons.submit}
414
+ </div>
415
+ );
416
+ }}
417
+ </FormGenerator>
418
+ ```
419
+
420
+ ### useArrayField Return Values
421
+
422
+ | Property | Type | Description |
423
+ |----------|------|-------------|
424
+ | `items` | `Array<{ id, index }>` | Array items with unique ids |
425
+ | `append` | `() => void` | Add new empty item |
426
+ | `appendWith` | `(values) => void` | Add item with values |
427
+ | `prepend` | `() => void` | Add item at beginning |
428
+ | `remove` | `(index) => void` | Remove item at index |
429
+ | `move` | `(from, to) => void` | Move item |
430
+ | `swap` | `(a, b) => void` | Swap two items |
431
+ | `insert` | `(index, values?) => void` | Insert at index |
432
+ | `canAppend` | `boolean` | Can add more items (respects maxItems) |
433
+ | `canRemove` | `boolean` | Can remove items (respects minItems) |
434
+ | `renderField` | `(index, name) => ReactElement` | Render single field |
435
+ | `renderItem` | `(index) => Record<string, ReactElement>` | Render all fields for item |
436
+
222
437
  ---
223
438
 
224
- ## Styling
439
+ ## Custom Layouts
225
440
 
226
- ### Using Tailwind Classes
441
+ For full control over form layout, pass a render function as `children`:
227
442
 
228
443
  ```typescript
229
- {
230
- type: 'text',
231
- name: 'email',
232
- className: 'bg-blue-50 border-blue-300 focus:ring-blue-500',
444
+ <FormGenerator
445
+ fields={[
446
+ { type: 'text', name: 'email', label: 'Email' },
447
+ { type: 'password', name: 'password', label: 'Password' },
448
+ ] as const}
449
+ title="Login"
450
+ onSubmit={handleSubmit}
451
+ >
452
+ {({ fields, buttons, title }) => (
453
+ <div className="login-form">
454
+ <h1>{title}</h1>
455
+ <div className="field-row">{fields.email}</div>
456
+ <div className="field-row">{fields.password}</div>
457
+ <div className="actions">{buttons.submit}</div>
458
+ </div>
459
+ )}
460
+ </FormGenerator>
461
+ ```
462
+
463
+ ### Render Props API
464
+
465
+ The render function receives:
466
+
467
+ | Property | Type | Description |
468
+ |----------|------|-------------|
469
+ | `fields` | `TemplateFields` | Pre-rendered fields (see below) |
470
+ | `arrays` | `Record<string, TemplateArrayField>` | Array field definitions (use with `useArrayField`) |
471
+ | `buttons` | `{ submit, reset? }` | Pre-rendered buttons |
472
+ | `title` | `string` | Form title prop |
473
+ | `description` | `string` | Form description prop |
474
+ | `form` | `UseFormReturn` | react-hook-form instance |
475
+ | `isSubmitting` | `boolean` | Form submission state |
476
+ | `isValid` | `boolean` | Form validity state |
477
+ | `isDirty` | `boolean` | Form dirty state |
478
+ | `renderField` | `function` | Manual field renderer |
479
+ | `FieldWrapper` | `ComponentType` | Registered FieldWrapper component |
480
+ | `FieldsWrapper` | `ComponentType` | Registered FieldsWrapper component |
481
+
482
+ ### Fields Object
483
+
484
+ Access fields by name or use helper methods:
485
+
486
+ ```typescript
487
+ {({ fields }) => (
488
+ <div>
489
+ {/* Access individual fields */}
490
+ {fields.email}
491
+ {fields.password}
492
+
493
+ {/* Render all fields */}
494
+ {fields.all}
495
+
496
+ {/* Render only fields not yet accessed */}
497
+ {fields.remaining}
498
+
499
+ {/* Check if field exists */}
500
+ {fields.has('email') && fields.email}
501
+
502
+ {/* Get all field names */}
503
+ {fields.names.map(name => <div key={name}>{fields[name]}</div>)}
504
+
505
+ {/* Render specific fields */}
506
+ {fields.render('email', 'password')}
507
+ </div>
508
+ )}
509
+ ```
510
+
511
+ ### Mixed Layout Example
512
+
513
+ Highlight specific fields while rendering the rest normally:
514
+
515
+ ```typescript
516
+ <FormGenerator fields={fieldDefinitions} onSubmit={handleSubmit}>
517
+ {({ fields, buttons }) => (
518
+ <div>
519
+ <div className="highlighted">{fields.email}</div>
520
+ <div className="other-fields">{fields.remaining}</div>
521
+ {buttons.submit}
522
+ </div>
523
+ )}
524
+ </FormGenerator>
525
+ ```
526
+
527
+ ### Form State Access
528
+
529
+ Use form state for conditional rendering:
530
+
531
+ ```typescript
532
+ <FormGenerator fields={fieldDefinitions} onSubmit={handleSubmit}>
533
+ {({ fields, buttons, isSubmitting, isValid, isDirty }) => (
534
+ <div>
535
+ {fields.all}
536
+ <button type="submit" disabled={isSubmitting || !isValid}>
537
+ {isSubmitting ? 'Saving...' : 'Submit'}
538
+ </button>
539
+ {isDirty && <span>You have unsaved changes</span>}
540
+ </div>
541
+ )}
542
+ </FormGenerator>
543
+ ```
544
+
545
+ ---
546
+
547
+ ## Raw Field Props with useFieldProps
548
+
549
+ For complete control over field rendering, use the `useFieldProps` hook to get raw form binding props. This is useful when you want to create custom field components without registering them globally.
550
+
551
+ ```typescript
552
+ import { FormGenerator, useFieldProps } from '@connect-soft/form-generator';
553
+
554
+ const fields = [
555
+ { type: 'text', name: 'email', label: 'Email', required: true },
556
+ { type: 'password', name: 'password', label: 'Password' },
557
+ ] as const;
558
+
559
+ // Custom component using the hook
560
+ function CustomEmailField() {
561
+ const { value, onChange, onBlur, ref, field, fieldState } = useFieldProps<string>('email');
562
+
563
+ return (
564
+ <div className="my-custom-field">
565
+ <label>{field.label}{field.required && ' *'}</label>
566
+ <input
567
+ ref={ref}
568
+ type="email"
569
+ value={value ?? ''}
570
+ onChange={(e) => onChange(e.target.value)}
571
+ onBlur={onBlur}
572
+ placeholder={field.placeholder}
573
+ />
574
+ {fieldState.error && (
575
+ <span className="error">{fieldState.error.message}</span>
576
+ )}
577
+ </div>
578
+ );
233
579
  }
580
+
581
+ // Use in FormGenerator with custom layout
582
+ <FormGenerator fields={fields} onSubmit={handleSubmit}>
583
+ {({ fields, buttons }) => (
584
+ <div>
585
+ <CustomEmailField />
586
+ {fields.password} {/* Mix with pre-rendered fields */}
587
+ {buttons.submit}
588
+ </div>
589
+ )}
590
+ </FormGenerator>
234
591
  ```
235
592
 
236
- ### Form-Level Styling
593
+ ### useFieldProps Return Value
594
+
595
+ | Property | Type | Description |
596
+ |----------|------|-------------|
597
+ | `name` | `string` | Field name (with any prefix applied) |
598
+ | `value` | `TValue` | Current field value |
599
+ | `onChange` | `(value: TValue) => void` | Change handler |
600
+ | `onBlur` | `() => void` | Blur handler |
601
+ | `ref` | `Ref<any>` | Ref to attach to input element |
602
+ | `field` | `BaseField` | Full field definition (type, label, required, etc.) |
603
+ | `fieldState` | `FieldState` | Validation state (see below) |
604
+
605
+ ### FieldState Properties
606
+
607
+ | Property | Type | Description |
608
+ |----------|------|-------------|
609
+ | `invalid` | `boolean` | Whether the field has validation errors |
610
+ | `error` | `{ type: string; message?: string }` | Error details if invalid |
611
+ | `isDirty` | `boolean` | Whether the value has changed from default |
612
+ | `isTouched` | `boolean` | Whether the field has been focused and blurred |
613
+
614
+ ### When to Use useFieldProps vs Registered Components
615
+
616
+ | Use Case | Approach |
617
+ |----------|----------|
618
+ | Reusable field component across forms | Register with `registerField` |
619
+ | One-off custom field in a specific form | Use `useFieldProps` |
620
+ | Need full control over a single field | Use `useFieldProps` |
621
+ | Consistent field styling across app | Register with `registerField` |
622
+
623
+ ### Example: Complete Custom Form
237
624
 
238
625
  ```typescript
239
- <FormGenerator
626
+ import { FormGenerator, useFieldProps } from '@connect-soft/form-generator';
627
+
628
+ const fields = [
629
+ { type: 'text', name: 'firstName', label: 'First Name', required: true },
630
+ { type: 'text', name: 'lastName', label: 'Last Name', required: true },
631
+ { type: 'email', name: 'email', label: 'Email', required: true },
632
+ ] as const;
633
+
634
+ function NameFields() {
635
+ const firstName = useFieldProps<string>('firstName');
636
+ const lastName = useFieldProps<string>('lastName');
637
+
638
+ return (
639
+ <div className="name-row">
640
+ <div className="field">
641
+ <label>{firstName.field.label}</label>
642
+ <input
643
+ ref={firstName.ref}
644
+ value={firstName.value ?? ''}
645
+ onChange={(e) => firstName.onChange(e.target.value)}
646
+ onBlur={firstName.onBlur}
647
+ />
648
+ {firstName.fieldState.error && (
649
+ <span className="error">{firstName.fieldState.error.message}</span>
650
+ )}
651
+ </div>
652
+ <div className="field">
653
+ <label>{lastName.field.label}</label>
654
+ <input
655
+ ref={lastName.ref}
656
+ value={lastName.value ?? ''}
657
+ onChange={(e) => lastName.onChange(e.target.value)}
658
+ onBlur={lastName.onBlur}
659
+ />
660
+ {lastName.fieldState.error && (
661
+ <span className="error">{lastName.fieldState.error.message}</span>
662
+ )}
663
+ </div>
664
+ </div>
665
+ );
666
+ }
667
+
668
+ function MyForm() {
669
+ return (
670
+ <FormGenerator fields={fields} onSubmit={handleSubmit}>
671
+ {({ fields, buttons, isSubmitting }) => (
672
+ <div className="custom-form">
673
+ <NameFields />
674
+ {fields.email}
675
+ <button type="submit" disabled={isSubmitting}>
676
+ {isSubmitting ? 'Submitting...' : 'Submit'}
677
+ </button>
678
+ </div>
679
+ )}
680
+ </FormGenerator>
681
+ );
682
+ }
683
+ ```
684
+
685
+ ---
686
+
687
+ ## Type-Safe Forms with StrictFormGenerator
688
+
689
+ For maximum type safety, use `StrictFormGenerator` which requires a Zod schema. This ensures field names match your schema and provides fully typed form values.
690
+
691
+ ```typescript
692
+ import { StrictFormGenerator } from '@connect-soft/form-generator';
693
+ import { z } from 'zod';
694
+
695
+ const userSchema = z.object({
696
+ email: z.string().email('Invalid email'),
697
+ password: z.string().min(8, 'Password must be at least 8 characters'),
698
+ age: z.number().min(18, 'Must be 18 or older'),
699
+ });
700
+
701
+ <StrictFormGenerator
702
+ schema={userSchema}
703
+ fields={[
704
+ { type: 'email', name: 'email', label: 'Email' }, // name must be keyof schema
705
+ { type: 'password', name: 'password', label: 'Password' },
706
+ { type: 'number', name: 'age', label: 'Age' },
707
+ // { type: 'text', name: 'invalid' } // TypeScript error: 'invalid' not in schema
708
+ ]}
709
+ onSubmit={(values) => {
710
+ // values: { email: string; password: string; age: number }
711
+ console.log(values.email); // Fully typed!
712
+ }}
713
+ />
714
+ ```
715
+
716
+ ### Typed Field Helpers
717
+
718
+ Use helper functions for even stricter type checking:
719
+
720
+ ```typescript
721
+ import { StrictFormGenerator, createFieldFactory } from '@connect-soft/form-generator';
722
+ import { z } from 'zod';
723
+
724
+ const loginSchema = z.object({
725
+ email: z.string().email(),
726
+ password: z.string(),
727
+ rememberMe: z.boolean(),
728
+ });
729
+
730
+ // Create a typed field factory from schema
731
+ const defineField = createFieldFactory(loginSchema);
732
+
733
+ // Each field is validated against the schema
734
+ const fields = [
735
+ defineField({ type: 'email', name: 'email', label: 'Email' }),
736
+ defineField({ type: 'password', name: 'password', label: 'Password' }),
737
+ defineField({ type: 'checkbox', name: 'rememberMe', label: 'Remember Me' }),
738
+ ];
739
+
740
+ <StrictFormGenerator
741
+ schema={loginSchema}
240
742
  fields={fields}
241
743
  onSubmit={handleSubmit}
242
- className="max-w-md mx-auto p-6 bg-white rounded-lg shadow"
243
744
  />
244
745
  ```
245
746
 
246
- ### Custom Theme
747
+ ### StrictFormGenerator vs FormGenerator
247
748
 
248
- Override CSS variables in your global CSS:
749
+ | Feature | FormGenerator | StrictFormGenerator |
750
+ |---------|---------------|---------------------|
751
+ | Schema | No (infers from fields) | Required (Zod) |
752
+ | Field name checking | Inferred from fields | Enforced at compile-time |
753
+ | Type inference | From field definitions | From Zod schema |
754
+ | Constraint detection | No | Yes (automatic) |
755
+ | Use case | Quick prototyping | Production apps |
249
756
 
250
- ```css
251
- :root {
252
- --primary: 220 90% 56%;
253
- --primary-foreground: 0 0% 100%;
254
- --radius: 0.5rem;
255
- }
757
+ ### Automatic Schema Constraint Detection
758
+
759
+ `StrictFormGenerator` automatically extracts constraints from your Zod schema and propagates them to field components. This means you don't need to duplicate constraints in both your schema and field definitions.
760
+
761
+ #### Supported Constraints
762
+
763
+ **Number fields** (`z.number()`):
764
+ | Zod Method | Field Property | Example |
765
+ |------------|----------------|---------|
766
+ | `.min(n)` | `min` | `z.number().min(0)` → `{ min: 0 }` |
767
+ | `.max(n)` | `max` | `z.number().max(100)` → `{ max: 100 }` |
768
+ | `.int()` | `step: 1` | `z.number().int()` → `{ step: 1 }` |
769
+ | `.multipleOf(n)` | `step` | `z.number().multipleOf(0.01)` → `{ step: 0.01 }` |
770
+ | `.positive()` | `min` | `z.number().positive()` → `{ min: 0 }` (exclusive) |
771
+ | `.nonnegative()` | `min: 0` | `z.number().nonnegative()` → `{ min: 0 }` |
772
+
773
+ **String fields** (`z.string()`):
774
+ | Zod Method | Field Property | Example |
775
+ |------------|----------------|---------|
776
+ | `.min(n)` | `minLength` | `z.string().min(3)` → `{ minLength: 3 }` |
777
+ | `.max(n)` | `maxLength` | `z.string().max(100)` → `{ maxLength: 100 }` |
778
+ | `.length(n)` | `minLength` + `maxLength` | `z.string().length(6)` → `{ minLength: 6, maxLength: 6 }` |
779
+ | `.regex(pattern)` | `pattern` | `z.string().regex(/^[A-Z]+$/)` → `{ pattern: '^[A-Z]+$' }` |
780
+
781
+ **Date fields** (`z.date()`):
782
+ | Zod Method | Field Property | Example |
783
+ |------------|----------------|---------|
784
+ | `.min(date)` | `min` (ISO string) | `z.date().min(new Date('2020-01-01'))` → `{ min: '2020-01-01' }` |
785
+ | `.max(date)` | `max` (ISO string) | `z.date().max(new Date('2030-12-31'))` → `{ max: '2030-12-31' }` |
786
+
787
+ #### Example
788
+
789
+ ```typescript
790
+ import { StrictFormGenerator } from '@connect-soft/form-generator';
791
+ import { z } from 'zod';
792
+
793
+ const userSchema = z.object({
794
+ username: z.string().min(3).max(20).regex(/^[a-z0-9_]+$/),
795
+ age: z.number().int().min(18).max(120),
796
+ price: z.number().multipleOf(0.01).min(0),
797
+ birthDate: z.date().min(new Date('1900-01-01')).max(new Date()),
798
+ });
799
+
800
+ // No need to specify min/max/minLength/maxLength in fields!
801
+ // They are automatically extracted from the schema
802
+ <StrictFormGenerator
803
+ schema={userSchema}
804
+ fields={[
805
+ { type: 'text', name: 'username', label: 'Username' },
806
+ { type: 'number', name: 'age', label: 'Age' },
807
+ { type: 'number', name: 'price', label: 'Price' },
808
+ { type: 'date', name: 'birthDate', label: 'Birth Date' },
809
+ ]}
810
+ onSubmit={handleSubmit}
811
+ />
812
+
813
+ // Field components receive:
814
+ // username: { minLength: 3, maxLength: 20, pattern: '^[a-z0-9_]+$', required: true }
815
+ // age: { min: 18, max: 120, step: 1, required: true }
816
+ // price: { min: 0, step: 0.01, required: true }
817
+ // birthDate: { min: '1900-01-01', max: '2026-02-02', required: true }
256
818
  ```
257
819
 
820
+ #### Using Constraints in Field Components
821
+
822
+ Your registered field components can use these constraints directly:
823
+
824
+ ```typescript
825
+ registerField('number', ({ field, formField, fieldState }) => (
826
+ <div>
827
+ <label>{field.label}</label>
828
+ <input
829
+ type="number"
830
+ {...formField}
831
+ min={field.min}
832
+ max={field.max}
833
+ step={field.step}
834
+ />
835
+ {fieldState.error && <span>{fieldState.error.message}</span>}
836
+ </div>
837
+ ));
838
+
839
+ registerField('text', ({ field, formField, fieldState }) => (
840
+ <div>
841
+ <label>{field.label}</label>
842
+ <input
843
+ type="text"
844
+ {...formField}
845
+ minLength={field.minLength}
846
+ maxLength={field.maxLength}
847
+ pattern={field.pattern}
848
+ />
849
+ {fieldState.error && <span>{fieldState.error.message}</span>}
850
+ </div>
851
+ ));
852
+ ```
853
+
854
+ #### Manual Constraint Merging
855
+
856
+ You can also manually merge constraints using the utility functions:
857
+
858
+ ```typescript
859
+ import { mergeSchemaConstraints, analyzeSchema } from '@connect-soft/form-generator';
860
+
861
+ const schema = z.object({
862
+ age: z.number().min(0).max(120),
863
+ name: z.string().min(1).max(100),
864
+ });
865
+
866
+ // Analyze schema to get field info
867
+ const fieldInfo = analyzeSchema(schema);
868
+ // => [
869
+ // { name: 'age', type: 'number', required: true, min: 0, max: 120 },
870
+ // { name: 'name', type: 'string', required: true, minLength: 1, maxLength: 100 }
871
+ // ]
872
+
873
+ // Or merge constraints into existing fields
874
+ const fields = [
875
+ { type: 'number', name: 'age', label: 'Age' },
876
+ { type: 'text', name: 'name', label: 'Name' },
877
+ ];
878
+
879
+ const fieldsWithConstraints = mergeSchemaConstraints(schema, fields);
880
+ // => [
881
+ // { type: 'number', name: 'age', label: 'Age', required: true, min: 0, max: 120 },
882
+ // { type: 'text', name: 'name', label: 'Name', required: true, minLength: 1, maxLength: 100 }
883
+ // ]
884
+ ```
885
+
886
+ ### Available Helpers
887
+
888
+ | Helper | Description |
889
+ |--------|-------------|
890
+ | `createFieldFactory(schema)` | Create a field factory for a schema |
891
+ | `typedField<typeof schema>()` | Create a single typed field |
892
+ | `typedFields<typeof schema>([...])` | Create an array of typed fields |
893
+
258
894
  ---
259
895
 
260
896
  ## TypeScript Type Inference
261
897
 
262
- The library provides full type inference for form values:
898
+ Get full type inference from field definitions:
263
899
 
264
900
  ```typescript
265
901
  const fields = [
266
- { type: 'text', name: 'email', fieldType: 'email' },
267
- { type: 'number', name: 'age' },
902
+ { type: 'text', name: 'email', required: true },
903
+ { type: 'number', name: 'age', required: true },
268
904
  { type: 'checkbox', name: 'terms' },
269
- { type: 'date', name: 'birthdate' },
270
905
  ] as const;
271
906
 
272
907
  <FormGenerator
273
908
  fields={fields}
274
909
  onSubmit={(values) => {
275
- // ✅ Fully typed!
276
- values.email; // string
277
- values.age; // number
278
- values.terms; // boolean
279
- values.birthdate; // Date
910
+ values.email; // string
911
+ values.age; // number
912
+ values.terms; // boolean | undefined
913
+ }}
914
+ />
915
+ ```
916
+
917
+ Or provide an explicit Zod schema:
918
+
919
+ ```typescript
920
+ const schema = z.object({
921
+ email: z.string().email(),
922
+ age: z.number().min(18),
923
+ terms: z.boolean(),
924
+ });
925
+
926
+ <FormGenerator
927
+ fields={fields}
928
+ schema={schema}
929
+ onSubmit={(values) => {
930
+ // values: { email: string; age: number; terms: boolean }
280
931
  }}
281
932
  />
282
933
  ```
283
934
 
284
935
  ---
285
936
 
286
- ## Migration from v1.x
937
+ ## Imperative API (Ref)
938
+
939
+ Access form methods programmatically using a ref:
940
+
941
+ ```typescript
942
+ import { useRef } from 'react';
943
+ import { FormGenerator, FormGeneratorRef } from '@connect-soft/form-generator';
944
+
945
+ function MyForm() {
946
+ const formRef = useRef<FormGeneratorRef>(null);
947
+
948
+ const handleExternalSubmit = async () => {
949
+ await formRef.current?.submit();
950
+ };
951
+
952
+ const handleReset = () => {
953
+ formRef.current?.reset();
954
+ };
955
+
956
+ const handleSetValues = () => {
957
+ formRef.current?.setValues({
958
+ email: 'test@example.com',
959
+ age: 25,
960
+ });
961
+ };
962
+
963
+ return (
964
+ <>
965
+ <FormGenerator
966
+ ref={formRef}
967
+ fields={fields}
968
+ onSubmit={(values) => console.log(values)}
969
+ />
970
+ <button type="button" onClick={handleExternalSubmit}>Submit Externally</button>
971
+ <button type="button" onClick={handleReset}>Reset Form</button>
972
+ <button type="button" onClick={handleSetValues}>Set Values</button>
973
+ </>
974
+ );
975
+ }
976
+ ```
977
+
978
+ ### Available Ref Methods
287
979
 
288
- Migrating from `@connect-soft/mui-hook-form` v1.x? See the [MIGRATION.md](./MIGRATION.md) guide.
980
+ | Method | Description |
981
+ |--------|-------------|
982
+ | `setValues(values)` | Set form values (partial update) |
983
+ | `getValues()` | Get current form values |
984
+ | `reset(values?)` | Reset to default or provided values |
985
+ | `submit()` | Programmatically submit the form |
986
+ | `clearErrors()` | Clear all validation errors |
987
+ | `setError(name, error)` | Set error for a specific field |
988
+ | `isValid()` | Check if form passes validation |
989
+ | `isDirty()` | Check if form has unsaved changes |
990
+ | `form` | Access underlying react-hook-form instance |
289
991
 
290
- ### Quick Migration with Adapter
992
+ ### Watching Form Values
993
+
994
+ Detect when field values change from the parent component:
291
995
 
292
996
  ```typescript
293
- import { FormGenerator } from '@connect-soft/form-generator';
294
- import { adaptV1FieldsToV2 } from '@connect-soft/form-generator/adapters';
997
+ import { useRef, useEffect } from 'react';
998
+ import { FormGenerator, FormGeneratorRef } from '@connect-soft/form-generator';
295
999
 
296
- // Your existing v1 fields
297
- const v1Fields = [
298
- {
299
- type: 'textField',
300
- props: { name: 'email', label: 'Email', required: true },
301
- },
302
- ];
1000
+ function MyForm() {
1001
+ const formRef = useRef<FormGeneratorRef>(null);
1002
+
1003
+ useEffect(() => {
1004
+ // Watch all fields for changes
1005
+ const subscription = formRef.current?.form.watch((values, { name, type }) => {
1006
+ console.log('Changed field:', name);
1007
+ console.log('New values:', values);
1008
+ });
303
1009
 
304
- // Auto-convert to v2
305
- const v2Fields = adaptV1FieldsToV2(v1Fields);
1010
+ return () => subscription?.unsubscribe();
1011
+ }, []);
306
1012
 
307
- <FormGenerator fields={v2Fields} onSubmit={handleSubmit} />
1013
+ return (
1014
+ <FormGenerator
1015
+ ref={formRef}
1016
+ fields={fields}
1017
+ onSubmit={handleSubmit}
1018
+ />
1019
+ );
1020
+ }
1021
+ ```
1022
+
1023
+ Or use `useWatch` inside a custom layout:
1024
+
1025
+ ```typescript
1026
+ import { FormGenerator, useWatch } from '@connect-soft/form-generator';
1027
+
1028
+ function ValueWatcher() {
1029
+ const email = useWatch({ name: 'email' }); // Watch specific field
1030
+
1031
+ useEffect(() => {
1032
+ console.log('Email changed:', email);
1033
+ }, [email]);
1034
+
1035
+ return null;
1036
+ }
1037
+
1038
+ <FormGenerator fields={fields} onSubmit={handleSubmit}>
1039
+ {({ fields, buttons }) => (
1040
+ <>
1041
+ {fields.all}
1042
+ <ValueWatcher />
1043
+ {buttons.submit}
1044
+ </>
1045
+ )}
1046
+ </FormGenerator>
308
1047
  ```
309
1048
 
310
1049
  ---
@@ -315,14 +1054,20 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
315
1054
 
316
1055
  | Prop | Type | Default | Description |
317
1056
  |------|------|---------|-------------|
318
- | `fields` | `Field[]` | **required** | Array of field definitions |
1057
+ | `fields` | `FormItem[]` | **required** | Array of field definitions |
319
1058
  | `onSubmit` | `(values) => void \| Promise<void>` | **required** | Form submission handler |
320
- | `defaultValues` | `Partial<InferFormValues<TFields>>` | `{}` | Initial form values |
321
- | `className` | `string` | - | Tailwind classes for form container |
1059
+ | `schema` | `ZodType` | - | Optional Zod schema for validation |
1060
+ | `defaultValues` | `object` | `{}` | Initial form values |
1061
+ | `className` | `string` | - | CSS class for form element |
322
1062
  | `submitText` | `string` | `'Submit'` | Submit button text |
323
- | `submitButtonVariant` | `'default' \| 'destructive' \| 'outline' \| 'secondary' \| 'ghost' \| 'link'` | `'default'` | Submit button style |
324
1063
  | `disabled` | `boolean` | `false` | Disable entire form |
325
1064
  | `mode` | `'onChange' \| 'onBlur' \| 'onSubmit' \| 'onTouched' \| 'all'` | `'onChange'` | Validation trigger mode |
1065
+ | `children` | `TemplateRenderFn` | - | Render function for custom layout |
1066
+ | `title` | `string` | - | Form title (available in render props) |
1067
+ | `description` | `string` | - | Form description (available in render props) |
1068
+ | `showReset` | `boolean` | `false` | Include reset button in `buttons.reset` |
1069
+ | `resetText` | `string` | `'Reset'` | Reset button text |
1070
+ | `validateTypes` | `boolean \| ValidateTypesOptions` | `false` | Runtime validation of field types |
326
1071
 
327
1072
  ### Field Base Properties
328
1073
 
@@ -337,13 +1082,50 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
337
1082
  | `hidden` | `boolean` | Hide field |
338
1083
  | `defaultValue` | `any` | Default field value |
339
1084
  | `validation` | `ZodType` | Zod validation schema |
340
- | `className` | `string` | Tailwind classes for field |
1085
+ | `className` | `string` | CSS class for field wrapper |
1086
+
1087
+ ### Field Type-Specific Properties
1088
+
1089
+ **Text fields** (`text`, `email`, `password`, `tel`, `url`, `search`):
1090
+ | Property | Type | Description |
1091
+ |----------|------|-------------|
1092
+ | `placeholder` | `string` | Placeholder text |
1093
+ | `minLength` | `number` | Minimum character length |
1094
+ | `maxLength` | `number` | Maximum character length |
1095
+ | `pattern` | `string` | HTML5 validation pattern |
1096
+
1097
+ **Number fields** (`number`, `range`):
1098
+ | Property | Type | Description |
1099
+ |----------|------|-------------|
1100
+ | `placeholder` | `string` | Placeholder text |
1101
+ | `min` | `number` | Minimum value |
1102
+ | `max` | `number` | Maximum value |
1103
+ | `step` | `number` | Step increment |
1104
+
1105
+ **Date fields** (`date`, `datetime`, `datetime-local`):
1106
+ | Property | Type | Description |
1107
+ |----------|------|-------------|
1108
+ | `min` | `string` | Minimum date (ISO format: YYYY-MM-DD) |
1109
+ | `max` | `string` | Maximum date (ISO format: YYYY-MM-DD) |
1110
+
1111
+ ### Schema Analysis Utilities
1112
+
1113
+ | Function | Description |
1114
+ |----------|-------------|
1115
+ | `analyzeSchema(schema)` | Extract detailed field info from Zod schema |
1116
+ | `mergeSchemaConstraints(schema, fields)` | Merge schema constraints into field definitions |
1117
+ | `mergeSchemaRequirements(schema, fields)` | Merge only required status (legacy) |
1118
+ | `getNumberConstraints(schema)` | Extract min/max/step from number schema |
1119
+ | `getStringConstraints(schema)` | Extract minLength/maxLength/pattern from string schema |
1120
+ | `getDateConstraints(schema)` | Extract min/max dates from date schema |
1121
+ | `isSchemaRequired(schema)` | Check if schema field is required |
1122
+ | `unwrapSchema(schema)` | Unwrap optional/nullable wrappers |
1123
+ | `getSchemaTypeName(schema)` | Get base type name (string, number, etc.) |
341
1124
 
342
1125
  ---
343
1126
 
344
1127
  ## Links
345
1128
 
346
- - [Migration Guide](./MIGRATION.md)
347
1129
  - [GitLab Repository](https://gitlab.com/connect-soft/components/form-generator)
348
1130
  - [Issues](https://gitlab.com/connect-soft/components/form-generator/issues)
349
1131
 
@@ -352,17 +1134,3 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
352
1134
  ## License
353
1135
 
354
1136
  ISC © Connect Soft
355
-
356
- ---
357
-
358
- ## Acknowledgments
359
-
360
- Built with:
361
- - [Radix UI](https://www.radix-ui.com/) - Accessible UI primitives
362
- - [Tailwind CSS](https://tailwindcss.com/) - Utility-first CSS framework
363
- - [react-hook-form](https://react-hook-form.com/) - Performant form library
364
- - [Zod](https://zod.dev/) - TypeScript-first schema validation
365
- - [react-day-picker](https://react-day-picker.js.org/) - Flexible date picker
366
- - [lucide-react](https://lucide.dev/) - Beautiful icons
367
-
368
- Inspired by [shadcn/ui](https://ui.shadcn.com/) component architecture.