@connect-soft/form-generator 1.1.0-alpha2 → 1.1.0-alpha4

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.
package/README.md CHANGED
@@ -1,61 +1,519 @@
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
- **v2.0.0** - Complete rewrite with Radix UI + Tailwind CSS
5
+ [![Version](https://img.shields.io/npm/v/@connect-soft/form-generator)](https://www.npmjs.com/package/@connect-soft/form-generator)
6
+ [![License](https://img.shields.io/npm/l/@connect-soft/form-generator)](./LICENSE)
7
+
8
+ ---
6
9
 
7
10
  ## Features
8
11
 
9
- - Modern UI with Radix primitives + Tailwind CSS
10
- - 📦 50-60% smaller bundle (<80 KB gzipped)
11
- - 🎯 Full TypeScript type inference
12
- - 🔧 10+ field types with extensible API
13
- - Built-in accessibility
14
- - 🎨 Easy Tailwind customization
15
- - 🚀 Zero runtime CSS overhead
16
- - 🔄 v1→v2 migration 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
+ - **Layouts**: Support for sections and multi-column layouts
20
+ - **Lightweight**: No UI dependencies, minimal footprint
21
+ - **HTML Fallbacks**: Works out of the box with native HTML inputs
22
+
23
+ ---
17
24
 
18
25
  ## Installation
19
26
 
20
27
  ```bash
21
- pnpm add @connect-soft/form-generator react-hook-form zod
28
+ npm install @connect-soft/form-generator
22
29
  ```
23
30
 
31
+ ### Peer Dependencies
32
+
33
+ - `react` ^19.0.0
34
+ - `react-dom` ^19.0.0
35
+ - `zod` ^4.0.0
36
+
37
+ ---
38
+
24
39
  ## Quick Start
25
40
 
41
+ The library works immediately with HTML fallback components:
42
+
26
43
  ```typescript
27
44
  import { FormGenerator } from '@connect-soft/form-generator';
28
45
 
46
+ const fields = [
47
+ { type: 'text', name: 'email', label: 'Email', required: true },
48
+ { type: 'number', name: 'age', label: 'Age', min: 18, max: 120 },
49
+ { type: 'select', name: 'country', label: 'Country', options: [
50
+ { label: 'United States', value: 'us' },
51
+ { label: 'Germany', value: 'de' },
52
+ ]},
53
+ { type: 'checkbox', name: 'subscribe', label: 'Subscribe to newsletter' },
54
+ ] as const;
55
+
56
+ function MyForm() {
57
+ return (
58
+ <FormGenerator
59
+ fields={fields}
60
+ onSubmit={(values) => {
61
+ console.log(values); // Fully typed!
62
+ }}
63
+ />
64
+ );
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Registering Custom Components
71
+
72
+ Register your own UI components to replace the HTML fallbacks:
73
+
74
+ ```typescript
75
+ import { registerFields, registerFormComponents } from '@connect-soft/form-generator';
76
+ import { Input } from './ui/input';
77
+ import { Label } from './ui/label';
78
+ import { Checkbox } from './ui/checkbox';
79
+ import { Button } from './ui/button';
80
+
81
+ // Register field components
82
+ registerFields({
83
+ text: ({ field, formField }) => (
84
+ <Input
85
+ {...formField}
86
+ type={field.fieldType || 'text'}
87
+ placeholder={field.placeholder}
88
+ disabled={field.disabled}
89
+ />
90
+ ),
91
+ number: ({ field, formField }) => (
92
+ <Input
93
+ {...formField}
94
+ type="number"
95
+ min={field.min}
96
+ max={field.max}
97
+ />
98
+ ),
99
+ checkbox: {
100
+ component: ({ field, formField }) => (
101
+ <Checkbox
102
+ checked={formField.value}
103
+ onCheckedChange={formField.onChange}
104
+ disabled={field.disabled}
105
+ />
106
+ ),
107
+ options: {
108
+ className: 'flex items-center gap-2',
109
+ }
110
+ },
111
+ });
112
+
113
+ // Register form wrapper components
114
+ registerFormComponents({
115
+ FormItem: ({ children, className }) => <div className={className}>{children}</div>,
116
+ FormLabel: Label,
117
+ FormMessage: ({ children }) => <span className="text-red-500 text-sm">{children}</span>,
118
+ SubmitButton: Button,
119
+ });
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Field Types
125
+
126
+ Built-in HTML fallback types:
127
+
128
+ | Type | Description | Value Type |
129
+ |------|-------------|------------|
130
+ | `text` | Text input | `string` |
131
+ | `email` | Email input | `string` |
132
+ | `password` | Password input | `string` |
133
+ | `number` | Number input with min/max | `number` |
134
+ | `textarea` | Multi-line text | `string` |
135
+ | `checkbox` | Checkbox | `boolean` |
136
+ | `select` | Dropdown select | `string` |
137
+ | `radio` | Radio button group | `string` |
138
+ | `date` | Date input | `Date` |
139
+ | `time` | Time input | `string` |
140
+ | `file` | File input | `File` |
141
+ | `hidden` | Hidden input | `string` |
142
+
143
+ ### Adding Custom Field Types (TypeScript)
144
+
145
+ Extend the `FieldTypeRegistry` interface to add type checking for custom fields:
146
+
147
+ ```typescript
148
+ // types/form-generator.d.ts
149
+ import { CreateFieldType } from '@connect-soft/form-generator';
150
+
151
+ declare module '@connect-soft/form-generator' {
152
+ interface FieldTypeRegistry {
153
+ // Add your custom field types
154
+ 'color-picker': CreateFieldType<'color-picker', string, {
155
+ swatches?: string[];
156
+ showAlpha?: boolean;
157
+ }>;
158
+ 'rich-text': CreateFieldType<'rich-text', string, {
159
+ toolbar?: ('bold' | 'italic' | 'link')[];
160
+ maxLength?: number;
161
+ }>;
162
+ }
163
+ }
164
+ ```
165
+
166
+ Now TypeScript will recognize your custom field types:
167
+
168
+ ```typescript
169
+ const fields = [
170
+ { type: 'color-picker', name: 'theme', swatches: ['#fff', '#000'] }, // ✅ Valid
171
+ { type: 'unknown-type', name: 'test' }, // ❌ Type error
172
+ ] as const;
173
+ ```
174
+
175
+ Don't forget to register the component for your custom field:
176
+
177
+ ```typescript
178
+ import { registerField } from '@connect-soft/form-generator';
179
+ import { ColorPicker } from './components/ColorPicker';
180
+
181
+ registerField('color-picker', ({ field, formField }) => (
182
+ <ColorPicker
183
+ value={formField.value}
184
+ onChange={formField.onChange}
185
+ swatches={field.swatches}
186
+ showAlpha={field.showAlpha}
187
+ />
188
+ ));
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Custom Validation
194
+
195
+ Use Zod for field-level or form-level validation:
196
+
197
+ ```typescript
198
+ import { z } from 'zod';
199
+
200
+ // Field-level validation
29
201
  const fields = [
202
+ {
203
+ type: 'text',
204
+ name: 'username',
205
+ label: 'Username',
206
+ validation: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/),
207
+ },
30
208
  {
31
209
  type: 'text',
32
210
  name: 'email',
33
211
  label: 'Email',
34
- fieldType: 'email',
35
- required: true,
212
+ validation: z.string().email(),
36
213
  },
214
+ ] as const;
215
+
216
+ // Or use a full schema for type inference
217
+ const schema = z.object({
218
+ username: z.string().min(3),
219
+ email: z.string().email(),
220
+ });
221
+
222
+ <FormGenerator
223
+ fields={fields}
224
+ schema={schema}
225
+ onSubmit={(values) => {
226
+ // values is inferred from schema
227
+ }}
228
+ />
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Layouts
234
+
235
+ Organize fields with sections and columns:
236
+
237
+ ```typescript
238
+ const fields = [
37
239
  {
38
- type: 'number',
39
- name: 'age',
40
- label: 'Age',
41
- min: 18,
240
+ type: 'section',
241
+ title: 'Personal Information',
242
+ children: [
243
+ { type: 'text', name: 'firstName', label: 'First Name' },
244
+ { type: 'text', name: 'lastName', label: 'Last Name' },
245
+ ],
42
246
  },
247
+ {
248
+ type: 'columns',
249
+ columns: [
250
+ {
251
+ width: '1',
252
+ children: [
253
+ { type: 'text', name: 'city', label: 'City' },
254
+ ],
255
+ },
256
+ {
257
+ width: '1',
258
+ children: [
259
+ { type: 'text', name: 'zip', label: 'ZIP Code' },
260
+ ],
261
+ },
262
+ ],
263
+ },
264
+ ];
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Custom Layouts
270
+
271
+ For full control over form layout, pass a render function as `children`:
272
+
273
+ ```typescript
274
+ <FormGenerator
275
+ fields={[
276
+ { type: 'text', name: 'email', label: 'Email' },
277
+ { type: 'password', name: 'password', label: 'Password' },
278
+ ] as const}
279
+ title="Login"
280
+ onSubmit={handleSubmit}
281
+ >
282
+ {({ fields, buttons, title }) => (
283
+ <div className="login-form">
284
+ <h1>{title}</h1>
285
+ <div className="field-row">{fields.email}</div>
286
+ <div className="field-row">{fields.password}</div>
287
+ <div className="actions">{buttons.submit}</div>
288
+ </div>
289
+ )}
290
+ </FormGenerator>
291
+ ```
292
+
293
+ ### Render Props API
294
+
295
+ The render function receives:
296
+
297
+ | Property | Type | Description |
298
+ |----------|------|-------------|
299
+ | `fields` | `TemplateFields` | Pre-rendered fields (see below) |
300
+ | `layouts` | `TemplateLayouts` | Pre-rendered named layouts |
301
+ | `buttons` | `{ submit, reset? }` | Pre-rendered buttons |
302
+ | `title` | `string` | Form title prop |
303
+ | `description` | `string` | Form description prop |
304
+ | `form` | `UseFormReturn` | react-hook-form instance |
305
+ | `isSubmitting` | `boolean` | Form submission state |
306
+ | `isValid` | `boolean` | Form validity state |
307
+ | `isDirty` | `boolean` | Form dirty state |
308
+ | `renderField` | `function` | Manual field renderer |
309
+ | `renderLayout` | `function` | Manual layout renderer |
310
+
311
+ ### Fields Object
312
+
313
+ Access fields by name or use helper methods:
314
+
315
+ ```typescript
316
+ {({ fields }) => (
317
+ <div>
318
+ {/* Access individual fields */}
319
+ {fields.email}
320
+ {fields.password}
321
+
322
+ {/* Render all fields */}
323
+ {fields.all}
324
+
325
+ {/* Render only fields not yet accessed */}
326
+ {fields.remaining}
327
+
328
+ {/* Check if field exists */}
329
+ {fields.has('email') && fields.email}
330
+
331
+ {/* Get all field names */}
332
+ {fields.names.map(name => <div key={name}>{fields[name]}</div>)}
333
+
334
+ {/* Render specific fields */}
335
+ {fields.render('email', 'password')}
336
+ </div>
337
+ )}
338
+ ```
339
+
340
+ ### Mixed Layout Example
341
+
342
+ Highlight specific fields while rendering the rest normally:
343
+
344
+ ```typescript
345
+ <FormGenerator fields={fieldDefinitions} onSubmit={handleSubmit}>
346
+ {({ fields, buttons }) => (
347
+ <div>
348
+ <div className="highlighted">{fields.email}</div>
349
+ <div className="other-fields">{fields.remaining}</div>
350
+ {buttons.submit}
351
+ </div>
352
+ )}
353
+ </FormGenerator>
354
+ ```
355
+
356
+ ### Form State Access
357
+
358
+ Use form state for conditional rendering:
359
+
360
+ ```typescript
361
+ <FormGenerator fields={fieldDefinitions} onSubmit={handleSubmit}>
362
+ {({ fields, buttons, isSubmitting, isValid, isDirty }) => (
363
+ <div>
364
+ {fields.all}
365
+ <button type="submit" disabled={isSubmitting || !isValid}>
366
+ {isSubmitting ? 'Saving...' : 'Submit'}
367
+ </button>
368
+ {isDirty && <span>You have unsaved changes</span>}
369
+ </div>
370
+ )}
371
+ </FormGenerator>
372
+ ```
373
+
374
+ ---
375
+
376
+ ## TypeScript Type Inference
377
+
378
+ Get full type inference from field definitions:
379
+
380
+ ```typescript
381
+ const fields = [
382
+ { type: 'text', name: 'email', required: true },
383
+ { type: 'number', name: 'age', required: true },
384
+ { type: 'checkbox', name: 'terms' },
43
385
  ] as const;
44
386
 
45
- export const MyForm = () => (
46
- <FormGenerator
47
- fields={fields}
48
- onSubmit={(values) => {
49
- // values is fully typed!
50
- console.log(values);
51
- }}
52
- />
53
- );
387
+ <FormGenerator
388
+ fields={fields}
389
+ onSubmit={(values) => {
390
+ values.email; // string
391
+ values.age; // number
392
+ values.terms; // boolean | undefined
393
+ }}
394
+ />
395
+ ```
396
+
397
+ Or provide an explicit Zod schema:
398
+
399
+ ```typescript
400
+ const schema = z.object({
401
+ email: z.string().email(),
402
+ age: z.number().min(18),
403
+ terms: z.boolean(),
404
+ });
405
+
406
+ <FormGenerator
407
+ fields={fields}
408
+ schema={schema}
409
+ onSubmit={(values) => {
410
+ // values: { email: string; age: number; terms: boolean }
411
+ }}
412
+ />
54
413
  ```
55
414
 
56
- ## Documentation
415
+ ---
416
+
417
+ ## Imperative API (Ref)
418
+
419
+ Access form methods programmatically using a ref:
420
+
421
+ ```typescript
422
+ import { useRef } from 'react';
423
+ import { FormGenerator, FormGeneratorRef } from '@connect-soft/form-generator';
424
+
425
+ function MyForm() {
426
+ const formRef = useRef<FormGeneratorRef>(null);
427
+
428
+ const handleExternalSubmit = async () => {
429
+ await formRef.current?.submit();
430
+ };
431
+
432
+ const handleReset = () => {
433
+ formRef.current?.reset();
434
+ };
435
+
436
+ const handleSetValues = () => {
437
+ formRef.current?.setValues({
438
+ email: 'test@example.com',
439
+ age: 25,
440
+ });
441
+ };
442
+
443
+ return (
444
+ <>
445
+ <FormGenerator
446
+ ref={formRef}
447
+ fields={fields}
448
+ onSubmit={(values) => console.log(values)}
449
+ />
450
+ <button type="button" onClick={handleExternalSubmit}>Submit Externally</button>
451
+ <button type="button" onClick={handleReset}>Reset Form</button>
452
+ <button type="button" onClick={handleSetValues}>Set Values</button>
453
+ </>
454
+ );
455
+ }
456
+ ```
457
+
458
+ ### Available Ref Methods
459
+
460
+ | Method | Description |
461
+ |--------|-------------|
462
+ | `setValues(values)` | Set form values (partial update) |
463
+ | `getValues()` | Get current form values |
464
+ | `reset(values?)` | Reset to default or provided values |
465
+ | `submit()` | Programmatically submit the form |
466
+ | `clearErrors()` | Clear all validation errors |
467
+ | `setError(name, error)` | Set error for a specific field |
468
+ | `isValid()` | Check if form passes validation |
469
+ | `isDirty()` | Check if form has unsaved changes |
470
+ | `form` | Access underlying react-hook-form instance |
471
+
472
+ ---
473
+
474
+ ## API Reference
475
+
476
+ ### FormGenerator Props
477
+
478
+ | Prop | Type | Default | Description |
479
+ |------|------|---------|-------------|
480
+ | `fields` | `FormItem[]` | **required** | Array of field definitions |
481
+ | `onSubmit` | `(values) => void \| Promise<void>` | **required** | Form submission handler |
482
+ | `schema` | `ZodType` | - | Optional Zod schema for validation |
483
+ | `defaultValues` | `object` | `{}` | Initial form values |
484
+ | `className` | `string` | - | CSS class for form element |
485
+ | `submitText` | `string` | `'Submit'` | Submit button text |
486
+ | `disabled` | `boolean` | `false` | Disable entire form |
487
+ | `mode` | `'onChange' \| 'onBlur' \| 'onSubmit' \| 'onTouched' \| 'all'` | `'onChange'` | Validation trigger mode |
488
+ | `children` | `TemplateRenderFn` | - | Render function for custom layout |
489
+ | `title` | `string` | - | Form title (available in render props) |
490
+ | `description` | `string` | - | Form description (available in render props) |
491
+ | `showReset` | `boolean` | `false` | Include reset button in `buttons.reset` |
492
+ | `resetText` | `string` | `'Reset'` | Reset button text |
493
+
494
+ ### Field Base Properties
495
+
496
+ | Property | Type | Description |
497
+ |----------|------|-------------|
498
+ | `type` | `string` | Field type (text, number, select, etc.) |
499
+ | `name` | `string` | Field name (must be unique) |
500
+ | `label` | `string` | Field label |
501
+ | `description` | `string` | Helper text below field |
502
+ | `required` | `boolean` | Mark field as required |
503
+ | `disabled` | `boolean` | Disable field |
504
+ | `hidden` | `boolean` | Hide field |
505
+ | `defaultValue` | `any` | Default field value |
506
+ | `validation` | `ZodType` | Zod validation schema |
507
+ | `className` | `string` | CSS class for field wrapper |
508
+
509
+ ---
510
+
511
+ ## Links
512
+
513
+ - [GitLab Repository](https://gitlab.com/connect-soft/components/form-generator)
514
+ - [Issues](https://gitlab.com/connect-soft/components/form-generator/issues)
57
515
 
58
- See [main README](../../README.md) for full documentation.
516
+ ---
59
517
 
60
518
  ## License
61
519