@dmitryvim/form-builder 0.1.9 → 0.1.12

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.9",
6
+ "version": "0.1.12",
7
7
  "description": "A reusable JSON schema form builder library",
8
8
  "main": "dist/form-builder.js",
9
9
  "files": [
@@ -11,10 +11,8 @@
11
11
  "docs"
12
12
  ],
13
13
  "scripts": {
14
- "build": "mkdir -p dist && cp public/index.html dist/sample.html",
15
- "build:lib": "echo 'Library already built at dist/form-builder.js'",
16
- "dev": "serve public",
17
- "dev:sample": "serve dist --single",
14
+ "build": "mkdir -p dist && cp public/index.html dist/index.html && cp src/form-builder.js dist/form-builder.js && cp public/demo.js dist/demo.js && cp -r public/images dist/",
15
+ "dev": "npm run build && serve dist --single",
18
16
  "test": "jest",
19
17
  "format": "prettier --write ."
20
18
  },
package/dist/README.md DELETED
@@ -1,284 +0,0 @@
1
- # Form Builder Library
2
-
3
- A reusable JavaScript library for generating dynamic forms from JSON schemas.
4
-
5
- ## Quick Start
6
-
7
- ### 1. Include the Library
8
-
9
- ```html
10
- <script src="https://unpkg.com/@dmitryvim/form-builder@latest/dist/form-builder.js"></script>
11
- ```
12
-
13
- Or via npm:
14
- ```bash
15
- npm install @dmitryvim/form-builder
16
- ```
17
-
18
- ### 2. Basic Usage
19
-
20
- ```javascript
21
- // Define your schema
22
- const schema = {
23
- "version": "0.3",
24
- "title": "User Registration",
25
- "elements": [
26
- {
27
- "type": "text",
28
- "key": "name",
29
- "label": "Full Name",
30
- "required": true
31
- },
32
- {
33
- "type": "text",
34
- "key": "email",
35
- "label": "Email",
36
- "required": true
37
- }
38
- ]
39
- };
40
-
41
- // Get container element
42
- const container = document.getElementById('form-container');
43
-
44
- // Render the form
45
- const form = FormBuilder.renderForm(schema, container, {
46
- onSubmit: (data) => {
47
- console.log('Form submitted:', data);
48
- },
49
- onDraft: (data) => {
50
- console.log('Draft saved:', data);
51
- },
52
- onError: (errors) => {
53
- console.log('Validation errors:', errors);
54
- }
55
- });
56
- ```
57
-
58
- ## API Reference
59
-
60
- ### FormBuilder.renderForm(schema, container, options)
61
-
62
- Renders a form in the specified container.
63
-
64
- **Parameters:**
65
- - `schema` - JSON schema object (v0.3)
66
- - `container` - DOM element to render form in
67
- - `options` - Configuration object (optional)
68
-
69
- **Options:**
70
- - `prefill` - Object with prefilled values
71
- - `readonly` - Boolean, renders form in read-only mode (hides buttons)
72
- - `debug` - Boolean, enables debug logging to console
73
- - `onSubmit` - Callback for form submission `(data) => {}`
74
- - `onDraft` - Callback for draft saving `(data) => {}`
75
- - `onError` - Callback for validation errors `(errors) => {}`
76
- - `buttons` - Custom button text: `{ submit: "Start Workflow", draft: "Save Progress" }`
77
-
78
- **Important:** Upload handlers must return a **string** resourceId, not an object.
79
-
80
- ### FormBuilder.validateSchema(schema)
81
-
82
- Validates a JSON schema and returns array of errors.
83
-
84
- **Returns:** `string[]` - Array of error messages (empty if valid)
85
-
86
- ### FormBuilder.collectAndValidate(schema, formElement, skipValidation)
87
-
88
- ⚠️ **Direct API for advanced users only**
89
-
90
- Collects form data and validates it. Most users should use `onSubmit`/`onDraft` callbacks instead.
91
-
92
- **Parameters:**
93
- - `schema` - The form schema
94
- - `formElement` - The form DOM element
95
- - `skipValidation` - Boolean, skip validation (for drafts)
96
-
97
- **Returns:** `{ result: object, errors: string[] }`
98
-
99
- **Important:** This is the correct destructuring format - there is no `.valid` or `.data` property.
100
-
101
- ### FormBuilder.setUploadHandler(uploadFn)
102
-
103
- Sets custom file upload handler:
104
- ```javascript
105
- FormBuilder.setUploadHandler(async (file) => {
106
- // Upload file to your backend
107
- const response = await fetch('/upload', {
108
- method: 'POST',
109
- body: file
110
- });
111
- const result = await response.json();
112
- return result.resourceId; // Return resource ID
113
- });
114
- ```
115
-
116
- ### FormBuilder.setDownloadHandler(downloadFn)
117
-
118
- Sets custom file download handler:
119
- ```javascript
120
- FormBuilder.setDownloadHandler(async (resourceId, fileName) => {
121
- window.open(`/download/${resourceId}`, '_blank');
122
- });
123
- ```
124
-
125
- ## Supported Field Types
126
-
127
- - `text` - Single line text input
128
- - `textarea` - Multi-line text input
129
- - `number` - Numeric input with constraints
130
- - `select` - Dropdown selection
131
- - `file` - Single file upload
132
- - `files` - Multiple file upload
133
- - `group` - Nested objects with optional repeat and custom element titles
134
-
135
- ## Troubleshooting Common Issues
136
-
137
- ### ❌ Upload Handler Returns Object
138
- ```javascript
139
- // Wrong - causes "resourceId.slice is not a function"
140
- FormBuilder.setUploadHandler(async (file) => {
141
- const response = await uploadFile(file);
142
- return { reference: response.id, name: file.name }; // ❌ Object
143
- });
144
-
145
- // Correct - return string only
146
- FormBuilder.setUploadHandler(async (file) => {
147
- const response = await uploadFile(file);
148
- return response.id; // ✅ String resourceId
149
- });
150
- ```
151
-
152
- ### ❌ Wrong API Usage
153
- ```javascript
154
- // Wrong - no .valid or .data properties
155
- const result = FormBuilder.collectAndValidate(schema, form);
156
- if (result.valid) { // ❌ Property doesn't exist
157
- console.log(result.data); // ❌ Property doesn't exist
158
- }
159
-
160
- // Correct - use destructuring
161
- const { result, errors } = FormBuilder.collectAndValidate(schema, form);
162
- if (errors.length === 0) { // ✅ Check errors array
163
- console.log(result); // ✅ Data is in result
164
- }
165
- ```
166
-
167
- ### ❌ Group Elements Missing Elements Array
168
- ```javascript
169
- // Wrong - causes "group.elements must be array"
170
- {
171
- type: 'group',
172
- key: 'address',
173
- // Missing elements array ❌
174
- }
175
-
176
- // Correct - always include elements
177
- {
178
- type: 'group',
179
- key: 'address',
180
- label: 'Address Information',
181
- element_label: 'Address #$index', // ✅ Optional custom title
182
- elements: [ // ✅ Required array
183
- { type: 'text', key: 'street', label: 'Street' }
184
- ]
185
- }
186
- ```
187
-
188
- ### ❌ Readonly Mode Confusion
189
- ```javascript
190
- // This only hides the default buttons, fields remain editable
191
- FormBuilder.renderForm(schema, container, { readonly: true });
192
-
193
- // For true read-only, you need to disable inputs manually or use a different approach
194
- ```
195
-
196
- ## Complete Example
197
-
198
- ```javascript
199
- const schema = {
200
- "version": "0.3",
201
- "title": "Video Cover Generation",
202
- "elements": [
203
- {
204
- "type": "text",
205
- "key": "concept",
206
- "label": "Animation Concept (Optional)",
207
- "required": false,
208
- "maxLength": 100,
209
- "placeholder": "e.g., fun, elegant, dynamic, cozy..."
210
- },
211
- {
212
- "type": "group",
213
- "key": "slides_input",
214
- "label": "Video Slides",
215
- "element_label": "Slide $index", // 🆕 Custom title for each item
216
- "repeat": {
217
- "min": 1,
218
- "max": 10
219
- },
220
- "elements": [
221
- {
222
- "type": "file",
223
- "key": "main_image",
224
- "label": "Main Image",
225
- "required": true,
226
- "accept": {
227
- "extensions": ["png", "jpg", "jpeg", "webp"],
228
- "mime": ["image/png", "image/jpeg", "image/webp"]
229
- },
230
- "maxSizeMB": 25
231
- },
232
- {
233
- "type": "files",
234
- "key": "elements",
235
- "label": "Element Images (Optional)",
236
- "required": false,
237
- "accept": {
238
- "extensions": ["png", "jpg", "jpeg", "webp"],
239
- "mime": ["image/png", "image/jpeg", "image/webp"]
240
- },
241
- "minCount": 0,
242
- "maxCount": 10,
243
- "maxSizeMB": 10
244
- }
245
- ]
246
- }
247
- ]
248
- };
249
-
250
- // Configure file upload
251
- FormBuilder.setUploadHandler(async (file) => {
252
- const formData = new FormData();
253
- formData.append('file', file);
254
-
255
- const response = await fetch('/api/upload', {
256
- method: 'POST',
257
- body: formData
258
- });
259
-
260
- const result = await response.json();
261
- return result.resourceId;
262
- });
263
-
264
- // Render form
265
- FormBuilder.renderForm(schema, document.getElementById('form'), {
266
- onSubmit: async (data) => {
267
- const response = await fetch('/api/submit', {
268
- method: 'POST',
269
- headers: { 'Content-Type': 'application/json' },
270
- body: JSON.stringify(data)
271
- });
272
-
273
- if (response.ok) {
274
- alert('Form submitted successfully!');
275
- }
276
- }
277
- });
278
- ```
279
-
280
- ## Files
281
-
282
- - `form-builder.js` - Main library file
283
- - `sample.html` - Interactive demo page
284
- - Complete documentation at `/docs/`
package/dist/example.html DELETED
@@ -1,108 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Form Builder - Simple Example</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- </head>
9
- <body class="bg-gray-50 p-8">
10
- <div class="max-w-2xl mx-auto">
11
- <h1 class="text-3xl font-bold mb-8">Form Builder Library Example</h1>
12
-
13
- <div class="bg-white rounded-lg shadow p-6 mb-8">
14
- <h2 class="text-xl font-semibold mb-4">Generated Form</h2>
15
- <div id="form-container"></div>
16
- </div>
17
-
18
- <div class="bg-white rounded-lg shadow p-6">
19
- <h2 class="text-xl font-semibold mb-4">Form Output</h2>
20
- <pre id="output" class="bg-gray-100 p-4 rounded text-sm overflow-auto">Submit the form to see output...</pre>
21
- </div>
22
- </div>
23
-
24
- <script src="form-builder.js"></script>
25
- <script>
26
- // Example schema demonstrating element_label feature
27
- const schema = {
28
- "version": "0.3",
29
- "title": "Video Cover Generation",
30
- "elements": [
31
- {
32
- "type": "text",
33
- "key": "concept",
34
- "label": "Animation Concept (Optional)",
35
- "required": false,
36
- "maxLength": 100,
37
- "placeholder": "e.g., fun, elegant, dynamic, cozy..."
38
- },
39
- {
40
- "type": "group",
41
- "key": "slides_input",
42
- "label": "Video Slides",
43
- "element_label": "Slide $index",
44
- "repeat": {
45
- "min": 1,
46
- "max": 5
47
- },
48
- "elements": [
49
- {
50
- "type": "file",
51
- "key": "main_image",
52
- "label": "Main Image",
53
- "required": true,
54
- "accept": {
55
- "extensions": ["png", "jpg", "jpeg", "webp"],
56
- "mime": ["image/png", "image/jpeg", "image/webp"]
57
- },
58
- "maxSizeMB": 25
59
- },
60
- {
61
- "type": "files",
62
- "key": "elements",
63
- "label": "Element Images (Optional)",
64
- "required": false,
65
- "accept": {
66
- "extensions": ["png", "jpg", "jpeg", "webp"],
67
- "mime": ["image/png", "image/jpeg", "image/webp"]
68
- },
69
- "minCount": 0,
70
- "maxCount": 5,
71
- "maxSizeMB": 10
72
- }
73
- ]
74
- }
75
- ]
76
- };
77
-
78
- // Configure file upload simulation
79
- FormBuilder.setUploadHandler(async (file) => {
80
- // Simulate upload delay
81
- await new Promise(resolve => setTimeout(resolve, 1000));
82
-
83
- // Generate fake resource ID
84
- const resourceId = 'res_' + Math.random().toString(36).substr(2, 12);
85
- console.log(`File "${file.name}" uploaded with ID: ${resourceId}`);
86
- return resourceId;
87
- });
88
-
89
- // Render the form
90
- const container = document.getElementById('form-container');
91
- const output = document.getElementById('output');
92
-
93
- FormBuilder.renderForm(schema, container, {
94
- onSubmit: (data) => {
95
- output.textContent = JSON.stringify(data, null, 2);
96
- alert('Form submitted successfully! Check the output below.');
97
- },
98
- onDraft: (data) => {
99
- output.textContent = 'DRAFT:\n' + JSON.stringify(data, null, 2);
100
- console.log('Draft saved:', data);
101
- },
102
- onError: (errors) => {
103
- alert('Validation errors: ' + errors.join(', '));
104
- }
105
- });
106
- </script>
107
- </body>
108
- </html>