@connect-soft/form-generator 1.1.0-alpha4 → 1.1.0-alpha6
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 +117 -59
- package/dist/index.js +339 -453
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +339 -450
- package/dist/index.mjs.map +1 -1
- package/dist/types/components/form/array-field-renderer.d.ts +39 -0
- package/dist/types/components/form/array-field-renderer.d.ts.map +1 -0
- package/dist/types/components/form/create-template-fields.d.ts +1 -2
- package/dist/types/components/form/create-template-fields.d.ts.map +1 -1
- package/dist/types/components/form/field-renderer.d.ts +1 -6
- package/dist/types/components/form/field-renderer.d.ts.map +1 -1
- package/dist/types/components/form/form-generator.d.ts.map +1 -1
- package/dist/types/components/form/form-utils.d.ts +3 -9
- package/dist/types/components/form/form-utils.d.ts.map +1 -1
- package/dist/types/components/form/index.d.ts +4 -2
- package/dist/types/components/form/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/field-registry.d.ts +1 -53
- package/dist/types/lib/field-registry.d.ts.map +1 -1
- package/dist/types/lib/field-types.d.ts +18 -30
- package/dist/types/lib/field-types.d.ts.map +1 -1
- package/dist/types/lib/index.d.ts +3 -5
- package/dist/types/lib/index.d.ts.map +1 -1
- package/dist/types/lib/template-types.d.ts +14 -16
- package/dist/types/lib/template-types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
- **Imperative API**: Control form via ref (`setValues`, `reset`, `submit`, etc.)
|
|
17
17
|
- **Flexible**: Register custom field components with a simple API
|
|
18
18
|
- **Validation**: Built-in Zod validation support
|
|
19
|
-
- **
|
|
19
|
+
- **Array Fields**: Repeatable field groups with `useFieldArray` integration
|
|
20
|
+
- **Custom Layouts**: Full control over form layout via render props
|
|
20
21
|
- **Lightweight**: No UI dependencies, minimal footprint
|
|
21
22
|
- **HTML Fallbacks**: Works out of the box with native HTML inputs
|
|
22
23
|
|
|
@@ -69,54 +70,56 @@ function MyForm() {
|
|
|
69
70
|
|
|
70
71
|
## Registering Custom Components
|
|
71
72
|
|
|
72
|
-
Register your own UI components to replace the HTML fallbacks:
|
|
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:
|
|
73
74
|
|
|
74
75
|
```typescript
|
|
75
|
-
import { registerFields,
|
|
76
|
+
import { registerFields, registerFormComponent } from '@connect-soft/form-generator';
|
|
76
77
|
import { Input } from './ui/input';
|
|
77
78
|
import { Label } from './ui/label';
|
|
78
79
|
import { Checkbox } from './ui/checkbox';
|
|
79
80
|
import { Button } from './ui/button';
|
|
80
81
|
|
|
81
|
-
// Register field components
|
|
82
|
+
// Register field components - they handle their own rendering
|
|
82
83
|
registerFields({
|
|
83
|
-
text: ({ field, formField }) => (
|
|
84
|
-
<
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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>
|
|
90
96
|
),
|
|
91
|
-
number: ({ field, formField }) => (
|
|
92
|
-
<
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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>
|
|
98
108
|
),
|
|
99
|
-
checkbox: {
|
|
100
|
-
|
|
109
|
+
checkbox: ({ field, formField }) => (
|
|
110
|
+
<div className="flex items-center gap-2">
|
|
101
111
|
<Checkbox
|
|
102
112
|
checked={formField.value}
|
|
103
113
|
onCheckedChange={formField.onChange}
|
|
104
114
|
disabled={field.disabled}
|
|
105
115
|
/>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
},
|
|
116
|
+
{field.label && <Label>{field.label}</Label>}
|
|
117
|
+
</div>
|
|
118
|
+
),
|
|
111
119
|
});
|
|
112
120
|
|
|
113
|
-
// Register
|
|
114
|
-
|
|
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
|
-
});
|
|
121
|
+
// Register the submit button component
|
|
122
|
+
registerFormComponent('SubmitButton', Button);
|
|
120
123
|
```
|
|
121
124
|
|
|
122
125
|
---
|
|
@@ -230,40 +233,96 @@ const schema = z.object({
|
|
|
230
233
|
|
|
231
234
|
---
|
|
232
235
|
|
|
233
|
-
##
|
|
236
|
+
## Array Fields
|
|
234
237
|
|
|
235
|
-
|
|
238
|
+
Create repeatable field groups with `useFieldArray` integration:
|
|
236
239
|
|
|
237
240
|
```typescript
|
|
238
241
|
const fields = [
|
|
242
|
+
{ type: 'text', name: 'name', label: 'Name' },
|
|
239
243
|
{
|
|
240
|
-
type: '
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
{ type: 'text', 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
|
-
},
|
|
244
|
+
type: 'array',
|
|
245
|
+
name: 'contacts',
|
|
246
|
+
label: 'Contacts',
|
|
247
|
+
fields: [
|
|
248
|
+
{ type: 'text', name: 'email', label: 'Email' },
|
|
249
|
+
{ type: 'text', name: 'phone', label: 'Phone' },
|
|
262
250
|
],
|
|
251
|
+
minItems: 1,
|
|
252
|
+
maxItems: 5,
|
|
263
253
|
},
|
|
264
|
-
];
|
|
254
|
+
] as const;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Default Array Rendering
|
|
258
|
+
|
|
259
|
+
Array fields render automatically with add/remove functionality:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
<FormGenerator
|
|
263
|
+
fields={fields}
|
|
264
|
+
onSubmit={(values) => {
|
|
265
|
+
console.log(values.contacts); // Array<{ email: string, phone: string }>
|
|
266
|
+
}}
|
|
267
|
+
/>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Custom Array Rendering with useArrayField
|
|
271
|
+
|
|
272
|
+
For full control, use the `useArrayField` hook in a custom layout:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { FormGenerator, useArrayField } from '@connect-soft/form-generator';
|
|
276
|
+
|
|
277
|
+
<FormGenerator fields={fields} onSubmit={handleSubmit}>
|
|
278
|
+
{({ fields, arrays, buttons }) => {
|
|
279
|
+
const contacts = useArrayField(arrays.contacts.field);
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<div>
|
|
283
|
+
{fields.name}
|
|
284
|
+
|
|
285
|
+
<h3>Contacts</h3>
|
|
286
|
+
{contacts.items.map(({ id, index, remove, fields: itemFields }) => (
|
|
287
|
+
<div key={id} className="contact-row">
|
|
288
|
+
{itemFields.email}
|
|
289
|
+
{itemFields.phone}
|
|
290
|
+
{contacts.canRemove && (
|
|
291
|
+
<button type="button" onClick={remove}>Remove</button>
|
|
292
|
+
)}
|
|
293
|
+
</div>
|
|
294
|
+
))}
|
|
295
|
+
|
|
296
|
+
{contacts.canAppend && (
|
|
297
|
+
<button type="button" onClick={contacts.append}>
|
|
298
|
+
Add Contact
|
|
299
|
+
</button>
|
|
300
|
+
)}
|
|
301
|
+
|
|
302
|
+
{buttons.submit}
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}}
|
|
306
|
+
</FormGenerator>
|
|
265
307
|
```
|
|
266
308
|
|
|
309
|
+
### useArrayField Return Values
|
|
310
|
+
|
|
311
|
+
| Property | Type | Description |
|
|
312
|
+
|----------|------|-------------|
|
|
313
|
+
| `items` | `Array<{ id, index }>` | Array items with unique ids |
|
|
314
|
+
| `append` | `() => void` | Add new empty item |
|
|
315
|
+
| `appendWith` | `(values) => void` | Add item with values |
|
|
316
|
+
| `prepend` | `() => void` | Add item at beginning |
|
|
317
|
+
| `remove` | `(index) => void` | Remove item at index |
|
|
318
|
+
| `move` | `(from, to) => void` | Move item |
|
|
319
|
+
| `swap` | `(a, b) => void` | Swap two items |
|
|
320
|
+
| `insert` | `(index, values?) => void` | Insert at index |
|
|
321
|
+
| `canAppend` | `boolean` | Can add more items (respects maxItems) |
|
|
322
|
+
| `canRemove` | `boolean` | Can remove items (respects minItems) |
|
|
323
|
+
| `renderField` | `(index, name) => ReactElement` | Render single field |
|
|
324
|
+
| `renderItem` | `(index) => Record<string, ReactElement>` | Render all fields for item |
|
|
325
|
+
|
|
267
326
|
---
|
|
268
327
|
|
|
269
328
|
## Custom Layouts
|
|
@@ -297,7 +356,7 @@ The render function receives:
|
|
|
297
356
|
| Property | Type | Description |
|
|
298
357
|
|----------|------|-------------|
|
|
299
358
|
| `fields` | `TemplateFields` | Pre-rendered fields (see below) |
|
|
300
|
-
| `
|
|
359
|
+
| `arrays` | `Record<string, TemplateArrayField>` | Array field definitions (use with `useArrayField`) |
|
|
301
360
|
| `buttons` | `{ submit, reset? }` | Pre-rendered buttons |
|
|
302
361
|
| `title` | `string` | Form title prop |
|
|
303
362
|
| `description` | `string` | Form description prop |
|
|
@@ -306,7 +365,6 @@ The render function receives:
|
|
|
306
365
|
| `isValid` | `boolean` | Form validity state |
|
|
307
366
|
| `isDirty` | `boolean` | Form dirty state |
|
|
308
367
|
| `renderField` | `function` | Manual field renderer |
|
|
309
|
-
| `renderLayout` | `function` | Manual layout renderer |
|
|
310
368
|
|
|
311
369
|
### Fields Object
|
|
312
370
|
|