@classytic/formkit 1.0.0 → 1.0.2
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 +161 -273
- package/dist/index.d.cts +29 -6
- package/dist/index.d.ts +29 -6
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,273 +1,161 @@
|
|
|
1
|
-
# @classytic/formkit
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
import
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
{children}
|
|
163
|
-
</FormSystemProvider>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
**Props:**
|
|
167
|
-
- `components`: Object mapping field types to React components
|
|
168
|
-
- `layouts`: Object mapping layout types to React components
|
|
169
|
-
- `children`: React children
|
|
170
|
-
|
|
171
|
-
### `<FormGenerator>`
|
|
172
|
-
|
|
173
|
-
Renders forms from schemas.
|
|
174
|
-
|
|
175
|
-
```tsx
|
|
176
|
-
<FormGenerator schema={schema} control={control} disabled={false} variant="default" />
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
**Props:**
|
|
180
|
-
- `schema`: Form schema object
|
|
181
|
-
- `control?`: React Hook Form control (optional if inside FormProvider)
|
|
182
|
-
- `disabled?`: Global disabled state
|
|
183
|
-
- `variant?`: Component variant to use
|
|
184
|
-
|
|
185
|
-
### Type Exports
|
|
186
|
-
|
|
187
|
-
```tsx
|
|
188
|
-
import type {
|
|
189
|
-
FormSchema,
|
|
190
|
-
BaseField,
|
|
191
|
-
Section,
|
|
192
|
-
FieldComponentProps,
|
|
193
|
-
ComponentRegistry,
|
|
194
|
-
} from "@classytic/formkit";
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## 🎨 Advanced Usage
|
|
198
|
-
|
|
199
|
-
### Variants
|
|
200
|
-
|
|
201
|
-
Support multiple UI styles:
|
|
202
|
-
|
|
203
|
-
```tsx
|
|
204
|
-
const components = {
|
|
205
|
-
text: DefaultInput,
|
|
206
|
-
compact: {
|
|
207
|
-
text: CompactInput,
|
|
208
|
-
select: CompactSelect,
|
|
209
|
-
},
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
// Use compact variant
|
|
213
|
-
<FormGenerator schema={schema} variant="compact" />
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Conditional Fields
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
{
|
|
220
|
-
name: "vatNumber",
|
|
221
|
-
type: "text",
|
|
222
|
-
label: "VAT Number",
|
|
223
|
-
condition: (values) => values.country === "EU",
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Custom Renderers
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
{
|
|
231
|
-
title: "Custom Section",
|
|
232
|
-
render: ({ control, disabled }) => (
|
|
233
|
-
<div>Your custom JSX here</div>
|
|
234
|
-
),
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Full Width Fields
|
|
239
|
-
|
|
240
|
-
```tsx
|
|
241
|
-
{
|
|
242
|
-
name: "description",
|
|
243
|
-
type: "textarea",
|
|
244
|
-
label: "Description",
|
|
245
|
-
fullWidth: true, // Spans all columns
|
|
246
|
-
}
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## 🧪 Testing
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
npm test
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## 📄 License
|
|
256
|
-
|
|
257
|
-
MIT © [Classytic](https://github.com/classytic)
|
|
258
|
-
|
|
259
|
-
## 🤝 Contributing
|
|
260
|
-
|
|
261
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
262
|
-
|
|
263
|
-
## 🔗 Links
|
|
264
|
-
|
|
265
|
-
- [GitHub Repository](https://github.com/classytic/formkit)
|
|
266
|
-
- [Issue Tracker](https://github.com/classytic/formkit/issues)
|
|
267
|
-
- [npm Package](https://www.npmjs.com/package/@classytic/formkit)
|
|
268
|
-
|
|
269
|
-
## 🌟 Related Packages
|
|
270
|
-
|
|
271
|
-
- [@classytic/notifications](https://www.npmjs.com/package/@classytic/notifications) - Multi-channel notification system
|
|
272
|
-
- [@classytic/mongokit](https://www.npmjs.com/package/@classytic/mongokit) - Event-driven MongoDB repositories
|
|
273
|
-
|
|
1
|
+
# @classytic/formkit
|
|
2
|
+
|
|
3
|
+
Headless, type-safe form generation engine for React 18/19. Schema-driven with full TypeScript support.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@classytic/formkit)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @classytic/formkit react-hook-form
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start (Shadcn UI)
|
|
15
|
+
|
|
16
|
+
**Important:** You must use `Controller` from react-hook-form. Raw Shadcn components won't work.
|
|
17
|
+
|
|
18
|
+
### 1. Install Shadcn Components
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx shadcn@latest add input label select
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Create Form Component
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// components/form-input.tsx
|
|
28
|
+
import { Controller } from "react-hook-form";
|
|
29
|
+
import { Input } from "@/components/ui/input";
|
|
30
|
+
import { Label } from "@/components/ui/label";
|
|
31
|
+
|
|
32
|
+
export function FormInput({ control, name, label, placeholder, required, ...props }) {
|
|
33
|
+
return (
|
|
34
|
+
<Controller
|
|
35
|
+
name={name}
|
|
36
|
+
control={control}
|
|
37
|
+
render={({ field, fieldState }) => (
|
|
38
|
+
<div className="space-y-2">
|
|
39
|
+
{label && <Label>{label}{required && '*'}</Label>}
|
|
40
|
+
<Input {...field} placeholder={placeholder} />
|
|
41
|
+
{fieldState.error && <p className="text-sm text-red-500">{fieldState.error.message}</p>}
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 3. Create Adapter
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// lib/form-adapter.tsx
|
|
53
|
+
import { FormSystemProvider } from "@classytic/formkit";
|
|
54
|
+
import { FormInput } from "@/components/form-input";
|
|
55
|
+
|
|
56
|
+
const components = {
|
|
57
|
+
text: FormInput,
|
|
58
|
+
email: FormInput,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const layouts = {
|
|
62
|
+
section: ({ title, children }) => <div><h3>{title}</h3>{children}</div>,
|
|
63
|
+
grid: ({ children, cols = 1 }) => <div className={`grid grid-cols-${cols} gap-4`}>{children}</div>,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export function FormProvider({ children }) {
|
|
67
|
+
return <FormSystemProvider components={components} layouts={layouts}>{children}</FormSystemProvider>;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 4. Use in Your App
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { useForm } from "react-hook-form";
|
|
75
|
+
import { FormGenerator } from "@classytic/formkit";
|
|
76
|
+
import { FormProvider } from "./form-adapter";
|
|
77
|
+
|
|
78
|
+
export function MyForm() {
|
|
79
|
+
const form = useForm();
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<FormProvider>
|
|
83
|
+
<form onSubmit={form.handleSubmit(console.log)}>
|
|
84
|
+
<FormGenerator
|
|
85
|
+
schema={{
|
|
86
|
+
sections: [{
|
|
87
|
+
fields: [
|
|
88
|
+
{ name: "email", type: "email", label: "Email", required: true },
|
|
89
|
+
{ name: "password", type: "text", label: "Password" },
|
|
90
|
+
]
|
|
91
|
+
}]
|
|
92
|
+
}}
|
|
93
|
+
control={form.control}
|
|
94
|
+
/>
|
|
95
|
+
<button type="submit">Submit</button>
|
|
96
|
+
</form>
|
|
97
|
+
</FormProvider>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Complete Examples
|
|
103
|
+
|
|
104
|
+
See `example/shadcn/` directory for full working examples with:
|
|
105
|
+
- FormInput, FormSelect, FormCheckbox
|
|
106
|
+
- Validation with Zod
|
|
107
|
+
- Conditional fields
|
|
108
|
+
- Error handling
|
|
109
|
+
|
|
110
|
+
## Key Points
|
|
111
|
+
|
|
112
|
+
**You MUST use Controller:**
|
|
113
|
+
```tsx
|
|
114
|
+
import { Controller } from "react-hook-form";
|
|
115
|
+
|
|
116
|
+
<Controller
|
|
117
|
+
name={name}
|
|
118
|
+
control={control}
|
|
119
|
+
render={({ field, fieldState }) => (
|
|
120
|
+
<Input {...field} /> // ← Spread field
|
|
121
|
+
)}
|
|
122
|
+
/>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Component receives these props:**
|
|
126
|
+
```tsx
|
|
127
|
+
{
|
|
128
|
+
field: {...}, // Config object
|
|
129
|
+
control: {...}, // React Hook Form control
|
|
130
|
+
name: "email", // Plus all field props spread
|
|
131
|
+
label: "Email",
|
|
132
|
+
// ...
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## API
|
|
137
|
+
|
|
138
|
+
### FormGenerator
|
|
139
|
+
|
|
140
|
+
| Prop | Type | Required |
|
|
141
|
+
|------|------|----------|
|
|
142
|
+
| schema | FormSchema | Yes |
|
|
143
|
+
| control | Control | Yes |
|
|
144
|
+
| disabled | boolean | No |
|
|
145
|
+
| variant | string | No |
|
|
146
|
+
|
|
147
|
+
### Types
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import type { FormSchema, FieldComponentProps } from "@classytic/formkit";
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT © [Classytic](https://github.com/classytic)
|
|
156
|
+
|
|
157
|
+
## Links
|
|
158
|
+
|
|
159
|
+
- [GitHub](https://github.com/classytic/formkit)
|
|
160
|
+
- [Examples](https://github.com/classytic/formkit/tree/main/example/shadcn)
|
|
161
|
+
- [Issues](https://github.com/classytic/formkit/issues)
|
package/dist/index.d.cts
CHANGED
|
@@ -45,15 +45,38 @@ interface BaseField {
|
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Field component props
|
|
48
|
+
*
|
|
49
|
+
* IMPORTANT: Components receive both:
|
|
50
|
+
* 1. A `field` object with the complete field configuration
|
|
51
|
+
* 2. All field properties spread at the top level (via ...field)
|
|
52
|
+
*
|
|
53
|
+
* Example:
|
|
54
|
+
* ```tsx
|
|
55
|
+
* // Schema
|
|
56
|
+
* { name: "email", type: "email", label: "Email", placeholder: "user@example.com" }
|
|
57
|
+
*
|
|
58
|
+
* // Your component receives:
|
|
59
|
+
* {
|
|
60
|
+
* field: { name: "email", type: "email", label: "Email", placeholder: "..." },
|
|
61
|
+
* control: {...},
|
|
62
|
+
* disabled: false,
|
|
63
|
+
* variant: undefined,
|
|
64
|
+
* // PLUS all field props at top level:
|
|
65
|
+
* name: "email",
|
|
66
|
+
* type: "email",
|
|
67
|
+
* label: "Email",
|
|
68
|
+
* placeholder: "user@example.com"
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
48
71
|
*/
|
|
49
|
-
interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> {
|
|
50
|
-
/** Field configuration */
|
|
72
|
+
interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> extends BaseField {
|
|
73
|
+
/** Field configuration object (contains all field props) */
|
|
51
74
|
field: BaseField;
|
|
52
|
-
/** React Hook Form control */
|
|
53
|
-
control?: Control<TFieldValues>;
|
|
54
|
-
/** Whether field is disabled */
|
|
75
|
+
/** React Hook Form control (for Controller integration) */
|
|
76
|
+
control?: Control<TFieldValues> | Control<any>;
|
|
77
|
+
/** Whether field is globally disabled */
|
|
55
78
|
disabled?: boolean;
|
|
56
|
-
/**
|
|
79
|
+
/** Component variant (e.g., "compact", "default") */
|
|
57
80
|
variant?: Variant;
|
|
58
81
|
}
|
|
59
82
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -45,15 +45,38 @@ interface BaseField {
|
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Field component props
|
|
48
|
+
*
|
|
49
|
+
* IMPORTANT: Components receive both:
|
|
50
|
+
* 1. A `field` object with the complete field configuration
|
|
51
|
+
* 2. All field properties spread at the top level (via ...field)
|
|
52
|
+
*
|
|
53
|
+
* Example:
|
|
54
|
+
* ```tsx
|
|
55
|
+
* // Schema
|
|
56
|
+
* { name: "email", type: "email", label: "Email", placeholder: "user@example.com" }
|
|
57
|
+
*
|
|
58
|
+
* // Your component receives:
|
|
59
|
+
* {
|
|
60
|
+
* field: { name: "email", type: "email", label: "Email", placeholder: "..." },
|
|
61
|
+
* control: {...},
|
|
62
|
+
* disabled: false,
|
|
63
|
+
* variant: undefined,
|
|
64
|
+
* // PLUS all field props at top level:
|
|
65
|
+
* name: "email",
|
|
66
|
+
* type: "email",
|
|
67
|
+
* label: "Email",
|
|
68
|
+
* placeholder: "user@example.com"
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
48
71
|
*/
|
|
49
|
-
interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> {
|
|
50
|
-
/** Field configuration */
|
|
72
|
+
interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> extends BaseField {
|
|
73
|
+
/** Field configuration object (contains all field props) */
|
|
51
74
|
field: BaseField;
|
|
52
|
-
/** React Hook Form control */
|
|
53
|
-
control?: Control<TFieldValues>;
|
|
54
|
-
/** Whether field is disabled */
|
|
75
|
+
/** React Hook Form control (for Controller integration) */
|
|
76
|
+
control?: Control<TFieldValues> | Control<any>;
|
|
77
|
+
/** Whether field is globally disabled */
|
|
55
78
|
disabled?: boolean;
|
|
56
|
-
/**
|
|
79
|
+
/** Component variant (e.g., "compact", "default") */
|
|
57
80
|
variant?: Variant;
|
|
58
81
|
}
|
|
59
82
|
/**
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/formkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Headless, type-safe form generation engine for React. Schema-driven with full TypeScript support.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.
|
|
7
|
-
"module": "./dist/index.
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.
|
|
13
|
-
"require": "./dist/index.
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|