@dmitryvim/form-builder 0.1.28 → 0.1.31

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  JSON Schema → Dynamic Forms → Structured Output
4
4
 
5
- A reusable, zero-dependency form generation library that converts JSON schemas into dynamic, interactive forms with real-time validation and file upload support.
5
+ A comprehensive, zero-dependency form generation library that converts JSON Schema v0.3 into dynamic, interactive HTML forms with advanced file handling, real-time validation, internationalization, and extensive field type support.
6
6
 
7
7
  ## Live Demo
8
8
 
@@ -37,15 +37,21 @@ npm install @dmitryvim/form-builder
37
37
 
38
38
  ## Core Features
39
39
 
40
- - **Schema-driven forms**: JSON Schema v0.3 → Interactive forms
41
- - **File uploads**: Built-in support with configurable handlers
42
- - **Real-time validation**: Client-side validation with error display
43
- - **Framework agnostic**: Works with any web stack
44
- - **Zero dependencies**: Self-contained HTML/CSS/JavaScript
45
- - **Read-only mode**: Display form data without editing
46
- - **Draft saving**: Save incomplete forms without validation
40
+ - **🎯 Schema-driven forms**: JSON Schema v0.3 → Interactive forms with live preview
41
+ - **📁 Advanced file handling**: Images, videos, documents with drag-and-drop and grid preview
42
+ - **✅ Real-time validation**: Client-side validation with visual feedback and error display
43
+ - **🌍 Internationalization**: Built-in English/Russian support with extensible translation system
44
+ - **🎨 Rich field types**: Text, textarea, number, select, file, files, and nested groups
45
+ - **👁️ Read-only mode**: Display form data without editing capabilities
46
+ - **🔘 Action buttons**: Configurable buttons in readonly mode for custom interactions
47
+ - **💾 Draft saving**: Save incomplete forms without validation
48
+ - **🔧 Framework agnostic**: Works with any web stack (React, Vue, Angular, vanilla JS)
49
+ - **📦 Zero dependencies**: Self-contained HTML/CSS/JavaScript
50
+ - **📱 Responsive design**: Mobile-friendly with Tailwind CSS styling
47
51
 
48
- ## Basic Example
52
+ ## Quick Examples
53
+
54
+ ### Simple Contact Form
49
55
 
50
56
  ```json
51
57
  {
@@ -56,36 +62,186 @@ npm install @dmitryvim/form-builder
56
62
  "type": "text",
57
63
  "key": "name",
58
64
  "label": "Full Name",
59
- "required": true
65
+ "required": true,
66
+ "minLength": 2,
67
+ "maxLength": 50
68
+ },
69
+ {
70
+ "type": "textarea",
71
+ "key": "message",
72
+ "label": "Message",
73
+ "placeholder": "Your message here...",
74
+ "required": true,
75
+ "rows": 4
60
76
  },
61
77
  {
62
78
  "type": "files",
63
79
  "key": "attachments",
64
80
  "label": "Attachments",
81
+ "description": "Upload supporting documents or images",
65
82
  "maxCount": 3,
83
+ "maxSizeMB": 10,
66
84
  "accept": {
67
- "extensions": ["pdf", "jpg", "png"]
85
+ "extensions": ["pdf", "jpg", "png", "docx"]
68
86
  }
69
87
  }
70
88
  ]
71
89
  }
72
90
  ```
73
91
 
74
- ## Integration Options
92
+ ### Advanced Product Form with Actions
75
93
 
76
- - **CDN**: Direct iframe embedding
77
- - **NPM**: Import as module
78
- - **Direct**: Self-hosted deployment
94
+ ```json
95
+ {
96
+ "version": "0.3",
97
+ "title": "Product Registration",
98
+ "elements": [
99
+ {
100
+ "type": "file",
101
+ "key": "mainImage",
102
+ "label": "Product Image",
103
+ "required": true,
104
+ "accept": {
105
+ "extensions": ["jpg", "png", "webp"]
106
+ },
107
+ "actions": [
108
+ { "value": "enhance", "label": "Enhance Quality" },
109
+ { "value": "crop", "label": "Auto Crop" },
110
+ { "value": "retry", "label": "Try Again" }
111
+ ]
112
+ },
113
+ {
114
+ "type": "group",
115
+ "key": "specifications",
116
+ "label": "Product Specifications",
117
+ "repeat": { "min": 1, "max": 10 },
118
+ "elements": [
119
+ {
120
+ "type": "text",
121
+ "key": "name",
122
+ "label": "Specification Name",
123
+ "required": true
124
+ },
125
+ {
126
+ "type": "text",
127
+ "key": "value",
128
+ "label": "Value",
129
+ "required": true
130
+ }
131
+ ]
132
+ }
133
+ ]
134
+ }
135
+ ```
136
+
137
+ ## Integration Methods
138
+
139
+ ### 1. NPM Package (Recommended)
140
+
141
+ ```bash
142
+ npm install @dmitryvim/form-builder
143
+ ```
144
+
145
+ ```javascript
146
+ // ES6 imports
147
+ import FormBuilder from "@dmitryvim/form-builder";
148
+
149
+ // Configure and use
150
+ FormBuilder.setFormRoot(document.getElementById("form-container"));
151
+ FormBuilder.setUploadHandler(async (file) => {
152
+ // Your upload logic - return resource ID
153
+ return "resource-123";
154
+ });
155
+ FormBuilder.setActionHandler((value) => {
156
+ // Handle action button clicks
157
+ console.log("Action clicked:", value);
158
+ });
159
+ FormBuilder.renderForm(schema, prefillData);
160
+ ```
161
+
162
+ ### 2. CDN Integration
79
163
 
80
- See [Integration Guide](docs/integration.md) for complete setup instructions.
164
+ ```html
165
+ <!-- Direct script include (npm CDN) -->
166
+ <script src="https://cdn.jsdelivr.net/npm/@dmitryvim/form-builder@latest/dist/form-builder.js"></script>
167
+ <script>
168
+ window.FormBuilder.renderForm(schema);
169
+ </script>
170
+
171
+ <!-- Or use our S3 CDN -->
172
+ <script src="https://picaz-form-builder.website.yandexcloud.net/form-builder/latest/form-builder.js"></script>
173
+
174
+ <!-- Embed complete demo -->
175
+ <iframe
176
+ src="https://picaz-form-builder.website.yandexcloud.net/form-builder/latest/index.html"
177
+ width="100%"
178
+ height="600px"
179
+ frameborder="0"
180
+ >
181
+ </iframe>
182
+ ```
183
+
184
+ ### 3. Self-Hosted Deployment
185
+
186
+ Download and serve the `dist/` folder contents.
187
+
188
+ See [Integration Guide](docs/integration.md) for detailed setup instructions.
189
+
190
+ ## Complete Feature Set
191
+
192
+ ### Field Types
193
+
194
+ - **Text**: Single-line with pattern validation, length limits
195
+ - **Textarea**: Multi-line with configurable rows
196
+ - **Number**: Numeric input with min/max/step/decimals
197
+ - **Select**: Dropdown with options and default values
198
+ - **File**: Single file upload with preview and type restrictions
199
+ - **Files**: Multiple file upload with grid layout and drag-and-drop
200
+ - **Group**: Nested objects with repeatable array support
201
+
202
+ ### File Handling
203
+
204
+ - **Supported formats**: Images (jpg, png, gif, webp), Videos (mp4, webm, mov), Documents (pdf, docx, etc.)
205
+ - **Preview system**: Thumbnails for images, video players, document icons
206
+ - **Drag-and-drop**: Visual feedback and multi-file support
207
+ - **Validation**: File size, type, and count restrictions
208
+ - **Resource management**: Metadata tracking and automatic cleanup
209
+
210
+ ### Validation & UX
211
+
212
+ - **Real-time validation**: As-you-type with visual feedback
213
+ - **Schema validation**: Comprehensive error reporting
214
+ - **Internationalization**: English/Russian built-in, extensible
215
+ - **Tooltips**: Field descriptions and hints
216
+ - **Responsive design**: Mobile-friendly interface
217
+ - **Read-only mode**: Display data without editing
218
+ - **Action buttons**: Custom buttons in readonly mode with configurable handlers
81
219
 
82
220
  ## Documentation
83
221
 
84
- - [Integration Guide](docs/integration.md) - How to use and integrate
85
- - [Schema Reference](docs/schema.md) - Complete schema documentation
86
- - [Requirements](docs/requirements.md) - Product and business requirements
87
- - [Development Guide](development.md) - Development and testing
222
+ - [Integration Guide](docs/integration.md) - Complete setup and usage
223
+ - [Schema Reference](docs/schema.md) - Field types and validation rules
224
+ - [API Documentation](docs/api.md) - Method reference and examples
225
+ - [Development Guide](CLAUDE.md) - Architecture and development workflow
226
+
227
+ ## Live Demo
228
+
229
+ **Try it now**: [https://picaz-form-builder.website.yandexcloud.net/form-builder/latest/index.html](https://picaz-form-builder.website.yandexcloud.net/form-builder/latest/index.html)
230
+
231
+ **Version Index**: [https://picaz-form-builder.website.yandexcloud.net/index.html](https://picaz-form-builder.website.yandexcloud.net/index.html)
232
+
233
+ Features a 3-column interface:
234
+
235
+ - **Schema Editor**: Edit JSON schema with validation
236
+ - **Live Preview**: See form render in real-time
237
+ - **Data Output**: View/export form data as JSON
238
+
239
+ ## Support & Contributing
88
240
 
89
- ## License
241
+ - **GitHub**: [picazru/form-builder](https://github.com/picazru/form-builder)
242
+ - **NPM Package**: [@dmitryvim/form-builder](https://www.npmjs.com/package/@dmitryvim/form-builder)
243
+ - **CDN**: [picaz-form-builder.website.yandexcloud.net](https://picaz-form-builder.website.yandexcloud.net/)
244
+ - **Version**: 0.1.28
245
+ - **License**: MIT - see [LICENSE](LICENSE) file
90
246
 
91
- MIT - see [LICENSE](LICENSE) file.
247
+ Built with ❤️ for the web development community.
package/dist/demo.js CHANGED
@@ -18,6 +18,11 @@ const EXAMPLE_SCHEMA = {
18
18
  mime: ["image/png", "image/jpeg", "image/gif"],
19
19
  },
20
20
  maxSizeMB: 10,
21
+ actions: [
22
+ { value: "cover1.retry", label: "А давай ещё разок" },
23
+ { value: "cover1.enhance", label: "Улучшить качество" },
24
+ { value: "cover1.crop", label: "Обрезать изображение" },
25
+ ],
21
26
  },
22
27
  {
23
28
  type: "files",
@@ -241,6 +246,39 @@ class InMemoryFileStorage {
241
246
  // Initialize file storage
242
247
  const fileStorage = new InMemoryFileStorage();
243
248
 
249
+ // Cache for action value -> label mapping for efficient lookup
250
+ let actionLabelMap = new Map();
251
+
252
+ // Build action value -> label mapping from schema for efficient lookup
253
+ function buildActionLabelMap(schema) {
254
+ const map = new Map();
255
+
256
+ function processElements(elements) {
257
+ if (!Array.isArray(elements)) return;
258
+
259
+ for (const element of elements) {
260
+ if (element.actions && Array.isArray(element.actions)) {
261
+ for (const action of element.actions) {
262
+ if (action.value && action.label) {
263
+ map.set(action.value, action.label);
264
+ }
265
+ }
266
+ }
267
+
268
+ // Process nested group elements
269
+ if (element.elements && Array.isArray(element.elements)) {
270
+ processElements(element.elements);
271
+ }
272
+ }
273
+ }
274
+
275
+ if (schema && schema.elements) {
276
+ processElements(schema.elements);
277
+ }
278
+
279
+ return map;
280
+ }
281
+
244
282
  // DOM element references
245
283
  const el = {
246
284
  schemaInput: document.getElementById("schemaInput"),
@@ -322,7 +360,24 @@ function setupFormBuilder() {
322
360
  return thumbnailUrl;
323
361
  });
324
362
 
325
- console.log("FormBuilder configured with in-memory file handlers");
363
+ // Action handler - display message when action button is clicked
364
+ FormBuilder.setActionHandler((value) => {
365
+ // Use cached action map for O(1) lookup instead of re-parsing schema
366
+ const actionLabel = actionLabelMap.get(value) || value; // fallback to value
367
+
368
+ console.log("Action clicked:", { label: actionLabel, value });
369
+
370
+ // Show message to user (compatible with all environments)
371
+ if (typeof window !== "undefined" && window.alert) {
372
+ window.alert(`${actionLabel} clicked: ${value}`);
373
+ } else {
374
+ console.log(`Demo action: ${actionLabel} clicked: ${value}`);
375
+ }
376
+ });
377
+
378
+ console.log(
379
+ "FormBuilder configured with in-memory file handlers and action handler",
380
+ );
326
381
  }
327
382
 
328
383
  // Schema management functions
@@ -342,6 +397,9 @@ function applyCurrentSchema() {
342
397
  return false;
343
398
  }
344
399
 
400
+ // Build action value -> label map for efficient lookup
401
+ actionLabelMap = buildActionLabelMap(schema);
402
+
345
403
  // Set mode based on toggle
346
404
  const isReadOnly = el.readOnlyToggle.checked;
347
405
  FormBuilder.setMode(isReadOnly ? "readonly" : "edit");
@@ -11,6 +11,8 @@ const state = {
11
11
  downloadFile: null,
12
12
  getThumbnail: null,
13
13
  getDownloadUrl: null,
14
+ // Action handler
15
+ actionHandler: null,
14
16
  // Default implementations
15
17
  enableFilePreview: true,
16
18
  maxPreviewSize: "200px",
@@ -242,6 +244,43 @@ function renderElement(element, ctx) {
242
244
  }
243
245
  }
244
246
 
247
+ // Add action buttons in readonly mode
248
+ if (
249
+ state.config.readonly &&
250
+ element.actions &&
251
+ Array.isArray(element.actions) &&
252
+ element.actions.length > 0
253
+ ) {
254
+ const actionsContainer = document.createElement("div");
255
+ actionsContainer.className = "mt-3 flex flex-wrap gap-2";
256
+
257
+ element.actions.forEach((action) => {
258
+ if (action.value && action.label) {
259
+ const actionBtn = document.createElement("button");
260
+ actionBtn.type = "button";
261
+ actionBtn.className =
262
+ "px-3 py-1.5 text-sm bg-blue-50 border border-blue-200 text-blue-700 rounded-lg hover:bg-blue-100 transition-colors";
263
+ actionBtn.textContent = action.label;
264
+
265
+ actionBtn.addEventListener("click", (e) => {
266
+ e.preventDefault();
267
+ e.stopPropagation();
268
+
269
+ if (
270
+ state.config.actionHandler &&
271
+ typeof state.config.actionHandler === "function"
272
+ ) {
273
+ state.config.actionHandler(action.value);
274
+ }
275
+ });
276
+
277
+ actionsContainer.appendChild(actionBtn);
278
+ }
279
+ });
280
+
281
+ wrapper.appendChild(actionsContainer);
282
+ }
283
+
245
284
  return wrapper;
246
285
  }
247
286
 
@@ -1817,6 +1856,10 @@ function setThumbnailHandler(thumbnailFn) {
1817
1856
  state.config.getThumbnail = thumbnailFn;
1818
1857
  }
1819
1858
 
1859
+ function setActionHandler(actionFn) {
1860
+ state.config.actionHandler = actionFn;
1861
+ }
1862
+
1820
1863
  function setMode(mode) {
1821
1864
  state.config.readonly = mode === "readonly";
1822
1865
  }
@@ -1879,6 +1922,7 @@ const formBuilderAPI = {
1879
1922
  setUploadHandler,
1880
1923
  setDownloadHandler,
1881
1924
  setThumbnailHandler,
1925
+ setActionHandler,
1882
1926
  setMode,
1883
1927
  setLocale,
1884
1928
  getFormData,
@@ -1903,6 +1947,7 @@ export {
1903
1947
  setUploadHandler,
1904
1948
  setDownloadHandler,
1905
1949
  setThumbnailHandler,
1950
+ setActionHandler,
1906
1951
  setMode,
1907
1952
  setLocale,
1908
1953
  getFormData,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.28",
6
+ "version": "0.1.31",
7
7
  "description": "A reusable JSON schema form builder library",
8
8
  "main": "dist/form-builder.js",
9
9
  "module": "dist/form-builder.js",