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

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,33 +1,31 @@
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
+ - **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
24
22
 
25
23
  ---
26
24
 
27
25
  ## Installation
28
26
 
29
27
  ```bash
30
- npm install @connect-soft/form-generator react-hook-form zod
28
+ npm install @connect-soft/form-generator
31
29
  ```
32
30
 
33
31
  ### Peer Dependencies
@@ -36,74 +34,23 @@ npm install @connect-soft/form-generator react-hook-form zod
36
34
  - `react-dom` ^19.0.0
37
35
  - `zod` ^4.0.0
38
36
 
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
37
  ---
70
38
 
71
39
  ## Quick Start
72
40
 
41
+ The library works immediately with HTML fallback components:
42
+
73
43
  ```typescript
74
- import { FormGenerator, Field } from '@connect-soft/form-generator';
44
+ import { FormGenerator } from '@connect-soft/form-generator';
75
45
 
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
- },
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' },
107
54
  ] as const;
108
55
 
109
56
  function MyForm() {
@@ -111,13 +58,8 @@ function MyForm() {
111
58
  <FormGenerator
112
59
  fields={fields}
113
60
  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
61
+ console.log(values); // Fully typed!
119
62
  }}
120
- submitText="Create Account"
121
63
  />
122
64
  );
123
65
  }
@@ -125,77 +67,137 @@ function MyForm() {
125
67
 
126
68
  ---
127
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
+
128
124
  ## Field Types
129
125
 
126
+ Built-in HTML fallback types:
127
+
130
128
  | Type | Description | Value Type |
131
129
  |------|-------------|------------|
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` |
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` |
137
136
  | `select` | Dropdown select | `string` |
138
137
  | `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` |
138
+ | `date` | Date input | `Date` |
139
+ | `time` | Time input | `string` |
140
+ | `file` | File input | `File` |
141
+ | `hidden` | Hidden input | `string` |
142
142
 
143
- ---
143
+ ### Adding Custom Field Types (TypeScript)
144
144
 
145
- ## Advanced Components
146
-
147
- ### MultiSelect
145
+ Extend the `FieldTypeRegistry` interface to add type checking for custom fields:
148
146
 
149
147
  ```typescript
150
- import { MultiSelect } from '@connect-soft/form-generator/advanced';
151
-
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
- />
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
+ }
162
164
  ```
163
165
 
164
- ### ColorPicker
166
+ Now TypeScript will recognize your custom field types:
165
167
 
166
168
  ```typescript
167
- import { ColorPicker } from '@connect-soft/form-generator/advanced';
168
-
169
- <ColorPicker
170
- value={color}
171
- onChange={setColor}
172
- />
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
173
  ```
174
174
 
175
- ### TransferList
175
+ Don't forget to register the component for your custom field:
176
176
 
177
177
  ```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}
187
- />
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
+ ));
188
189
  ```
189
190
 
190
191
  ---
191
192
 
192
193
  ## Custom Validation
193
194
 
194
- Use Zod for schema validation:
195
+ Use Zod for field-level or form-level validation:
195
196
 
196
197
  ```typescript
197
198
  import { z } from 'zod';
198
199
 
200
+ // Field-level validation
199
201
  const fields = [
200
202
  {
201
203
  type: 'text',
@@ -207,106 +209,159 @@ const fields = [
207
209
  type: 'text',
208
210
  name: 'email',
209
211
  label: 'Email',
210
- fieldType: 'email',
211
- validation: z.string().email().endsWith('@company.com'),
212
- },
213
- {
214
- type: 'number',
215
- name: 'age',
216
- label: 'Age',
217
- validation: z.number().min(18).max(120),
212
+ validation: z.string().email(),
218
213
  },
219
214
  ] as const;
220
- ```
221
215
 
222
- ---
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
+ });
223
221
 
224
- ## Styling
225
-
226
- ### Using Tailwind Classes
227
-
228
- ```typescript
229
- {
230
- type: 'text',
231
- name: 'email',
232
- className: 'bg-blue-50 border-blue-300 focus:ring-blue-500',
233
- }
234
- ```
235
-
236
- ### Form-Level Styling
237
-
238
- ```typescript
239
222
  <FormGenerator
240
223
  fields={fields}
241
- onSubmit={handleSubmit}
242
- className="max-w-md mx-auto p-6 bg-white rounded-lg shadow"
224
+ schema={schema}
225
+ onSubmit={(values) => {
226
+ // values is inferred from schema
227
+ }}
243
228
  />
244
229
  ```
245
230
 
246
- ### Custom Theme
231
+ ---
247
232
 
248
- Override CSS variables in your global CSS:
233
+ ## Layouts
249
234
 
250
- ```css
251
- :root {
252
- --primary: 220 90% 56%;
253
- --primary-foreground: 0 0% 100%;
254
- --radius: 0.5rem;
255
- }
235
+ Organize fields with sections and columns:
236
+
237
+ ```typescript
238
+ const fields = [
239
+ {
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
+ ],
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
+ ];
256
265
  ```
257
266
 
258
267
  ---
259
268
 
260
269
  ## TypeScript Type Inference
261
270
 
262
- The library provides full type inference for form values:
271
+ Get full type inference from field definitions:
263
272
 
264
273
  ```typescript
265
274
  const fields = [
266
- { type: 'text', name: 'email', fieldType: 'email' },
267
- { type: 'number', name: 'age' },
275
+ { type: 'text', name: 'email', required: true },
276
+ { type: 'number', name: 'age', required: true },
268
277
  { type: 'checkbox', name: 'terms' },
269
- { type: 'date', name: 'birthdate' },
270
278
  ] as const;
271
279
 
272
280
  <FormGenerator
273
281
  fields={fields}
274
282
  onSubmit={(values) => {
275
- // ✅ Fully typed!
276
- values.email; // string
277
- values.age; // number
278
- values.terms; // boolean
279
- values.birthdate; // Date
283
+ values.email; // string
284
+ values.age; // number
285
+ values.terms; // boolean | undefined
280
286
  }}
281
287
  />
282
288
  ```
283
289
 
284
- ---
290
+ Or provide an explicit Zod schema:
291
+
292
+ ```typescript
293
+ const schema = z.object({
294
+ email: z.string().email(),
295
+ age: z.number().min(18),
296
+ terms: z.boolean(),
297
+ });
285
298
 
286
- ## Migration from v1.x
299
+ <FormGenerator
300
+ fields={fields}
301
+ schema={schema}
302
+ onSubmit={(values) => {
303
+ // values: { email: string; age: number; terms: boolean }
304
+ }}
305
+ />
306
+ ```
287
307
 
288
- Migrating from `@connect-soft/mui-hook-form` v1.x? See the [MIGRATION.md](./MIGRATION.md) guide.
308
+ ---
289
309
 
290
- ### Quick Migration with Adapter
310
+ ## Imperative API (Ref)
311
+
312
+ Access form methods programmatically using a ref:
291
313
 
292
314
  ```typescript
293
- import { FormGenerator } from '@connect-soft/form-generator';
294
- import { adaptV1FieldsToV2 } from '@connect-soft/form-generator/adapters';
315
+ import { useRef } from 'react';
316
+ import { FormGenerator, FormGeneratorRef } from '@connect-soft/form-generator';
295
317
 
296
- // Your existing v1 fields
297
- const v1Fields = [
298
- {
299
- type: 'textField',
300
- props: { name: 'email', label: 'Email', required: true },
301
- },
302
- ];
318
+ function MyForm() {
319
+ const formRef = useRef<FormGeneratorRef>(null);
303
320
 
304
- // Auto-convert to v2
305
- const v2Fields = adaptV1FieldsToV2(v1Fields);
321
+ const handleExternalSubmit = async () => {
322
+ await formRef.current?.submit();
323
+ };
306
324
 
307
- <FormGenerator fields={v2Fields} onSubmit={handleSubmit} />
325
+ const handleReset = () => {
326
+ formRef.current?.reset();
327
+ };
328
+
329
+ const handleSetValues = () => {
330
+ formRef.current?.setValues({
331
+ email: 'test@example.com',
332
+ age: 25,
333
+ });
334
+ };
335
+
336
+ return (
337
+ <>
338
+ <FormGenerator
339
+ ref={formRef}
340
+ fields={fields}
341
+ onSubmit={(values) => console.log(values)}
342
+ />
343
+ <button type="button" onClick={handleExternalSubmit}>Submit Externally</button>
344
+ <button type="button" onClick={handleReset}>Reset Form</button>
345
+ <button type="button" onClick={handleSetValues}>Set Values</button>
346
+ </>
347
+ );
348
+ }
308
349
  ```
309
350
 
351
+ ### Available Ref Methods
352
+
353
+ | Method | Description |
354
+ |--------|-------------|
355
+ | `setValues(values)` | Set form values (partial update) |
356
+ | `getValues()` | Get current form values |
357
+ | `reset(values?)` | Reset to default or provided values |
358
+ | `submit()` | Programmatically submit the form |
359
+ | `clearErrors()` | Clear all validation errors |
360
+ | `setError(name, error)` | Set error for a specific field |
361
+ | `isValid()` | Check if form passes validation |
362
+ | `isDirty()` | Check if form has unsaved changes |
363
+ | `form` | Access underlying react-hook-form instance |
364
+
310
365
  ---
311
366
 
312
367
  ## API Reference
@@ -315,12 +370,12 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
315
370
 
316
371
  | Prop | Type | Default | Description |
317
372
  |------|------|---------|-------------|
318
- | `fields` | `Field[]` | **required** | Array of field definitions |
373
+ | `fields` | `FormItem[]` | **required** | Array of field definitions |
319
374
  | `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 |
375
+ | `schema` | `ZodType` | - | Optional Zod schema for validation |
376
+ | `defaultValues` | `object` | `{}` | Initial form values |
377
+ | `className` | `string` | - | CSS class for form element |
322
378
  | `submitText` | `string` | `'Submit'` | Submit button text |
323
- | `submitButtonVariant` | `'default' \| 'destructive' \| 'outline' \| 'secondary' \| 'ghost' \| 'link'` | `'default'` | Submit button style |
324
379
  | `disabled` | `boolean` | `false` | Disable entire form |
325
380
  | `mode` | `'onChange' \| 'onBlur' \| 'onSubmit' \| 'onTouched' \| 'all'` | `'onChange'` | Validation trigger mode |
326
381
 
@@ -337,13 +392,12 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
337
392
  | `hidden` | `boolean` | Hide field |
338
393
  | `defaultValue` | `any` | Default field value |
339
394
  | `validation` | `ZodType` | Zod validation schema |
340
- | `className` | `string` | Tailwind classes for field |
395
+ | `className` | `string` | CSS class for field wrapper |
341
396
 
342
397
  ---
343
398
 
344
399
  ## Links
345
400
 
346
- - [Migration Guide](./MIGRATION.md)
347
401
  - [GitLab Repository](https://gitlab.com/connect-soft/components/form-generator)
348
402
  - [Issues](https://gitlab.com/connect-soft/components/form-generator/issues)
349
403
 
@@ -352,17 +406,3 @@ const v2Fields = adaptV1FieldsToV2(v1Fields);
352
406
  ## License
353
407
 
354
408
  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.