@dmitryvim/form-builder 0.1.29 → 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
@@ -39,10 +39,11 @@ npm install @dmitryvim/form-builder
39
39
 
40
40
  - **🎯 Schema-driven forms**: JSON Schema v0.3 → Interactive forms with live preview
41
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
42
+ - **✅ Real-time validation**: Client-side validation with visual feedback and error display
43
43
  - **🌍 Internationalization**: Built-in English/Russian support with extensible translation system
44
44
  - **🎨 Rich field types**: Text, textarea, number, select, file, files, and nested groups
45
45
  - **👁️ Read-only mode**: Display form data without editing capabilities
46
+ - **🔘 Action buttons**: Configurable buttons in readonly mode for custom interactions
46
47
  - **💾 Draft saving**: Save incomplete forms without validation
47
48
  - **🔧 Framework agnostic**: Works with any web stack (React, Vue, Angular, vanilla JS)
48
49
  - **📦 Zero dependencies**: Self-contained HTML/CSS/JavaScript
@@ -51,6 +52,7 @@ npm install @dmitryvim/form-builder
51
52
  ## Quick Examples
52
53
 
53
54
  ### Simple Contact Form
55
+
54
56
  ```json
55
57
  {
56
58
  "version": "0.3",
@@ -87,7 +89,8 @@ npm install @dmitryvim/form-builder
87
89
  }
88
90
  ```
89
91
 
90
- ### Advanced Product Form with Groups
92
+ ### Advanced Product Form with Actions
93
+
91
94
  ```json
92
95
  {
93
96
  "version": "0.3",
@@ -100,7 +103,12 @@ npm install @dmitryvim/form-builder
100
103
  "required": true,
101
104
  "accept": {
102
105
  "extensions": ["jpg", "png", "webp"]
103
- }
106
+ },
107
+ "actions": [
108
+ { "value": "enhance", "label": "Enhance Quality" },
109
+ { "value": "crop", "label": "Auto Crop" },
110
+ { "value": "retry", "label": "Try Again" }
111
+ ]
104
112
  },
105
113
  {
106
114
  "type": "group",
@@ -129,24 +137,30 @@ npm install @dmitryvim/form-builder
129
137
  ## Integration Methods
130
138
 
131
139
  ### 1. NPM Package (Recommended)
140
+
132
141
  ```bash
133
142
  npm install @dmitryvim/form-builder
134
143
  ```
135
144
 
136
145
  ```javascript
137
146
  // ES6 imports
138
- import FormBuilder from '@dmitryvim/form-builder';
147
+ import FormBuilder from "@dmitryvim/form-builder";
139
148
 
140
149
  // Configure and use
141
- FormBuilder.setFormRoot(document.getElementById('form-container'));
150
+ FormBuilder.setFormRoot(document.getElementById("form-container"));
142
151
  FormBuilder.setUploadHandler(async (file) => {
143
152
  // Your upload logic - return resource ID
144
- return 'resource-123';
153
+ return "resource-123";
154
+ });
155
+ FormBuilder.setActionHandler((value) => {
156
+ // Handle action button clicks
157
+ console.log("Action clicked:", value);
145
158
  });
146
159
  FormBuilder.renderForm(schema, prefillData);
147
160
  ```
148
161
 
149
162
  ### 2. CDN Integration
163
+
150
164
  ```html
151
165
  <!-- Direct script include (npm CDN) -->
152
166
  <script src="https://cdn.jsdelivr.net/npm/@dmitryvim/form-builder@latest/dist/form-builder.js"></script>
@@ -160,11 +174,15 @@ FormBuilder.renderForm(schema, prefillData);
160
174
  <!-- Embed complete demo -->
161
175
  <iframe
162
176
  src="https://picaz-form-builder.website.yandexcloud.net/form-builder/latest/index.html"
163
- width="100%" height="600px" frameborder="0">
177
+ width="100%"
178
+ height="600px"
179
+ frameborder="0"
180
+ >
164
181
  </iframe>
165
182
  ```
166
183
 
167
184
  ### 3. Self-Hosted Deployment
185
+
168
186
  Download and serve the `dist/` folder contents.
169
187
 
170
188
  See [Integration Guide](docs/integration.md) for detailed setup instructions.
@@ -172,6 +190,7 @@ See [Integration Guide](docs/integration.md) for detailed setup instructions.
172
190
  ## Complete Feature Set
173
191
 
174
192
  ### Field Types
193
+
175
194
  - **Text**: Single-line with pattern validation, length limits
176
195
  - **Textarea**: Multi-line with configurable rows
177
196
  - **Number**: Numeric input with min/max/step/decimals
@@ -181,6 +200,7 @@ See [Integration Guide](docs/integration.md) for detailed setup instructions.
181
200
  - **Group**: Nested objects with repeatable array support
182
201
 
183
202
  ### File Handling
203
+
184
204
  - **Supported formats**: Images (jpg, png, gif, webp), Videos (mp4, webm, mov), Documents (pdf, docx, etc.)
185
205
  - **Preview system**: Thumbnails for images, video players, document icons
186
206
  - **Drag-and-drop**: Visual feedback and multi-file support
@@ -188,12 +208,14 @@ See [Integration Guide](docs/integration.md) for detailed setup instructions.
188
208
  - **Resource management**: Metadata tracking and automatic cleanup
189
209
 
190
210
  ### Validation & UX
211
+
191
212
  - **Real-time validation**: As-you-type with visual feedback
192
213
  - **Schema validation**: Comprehensive error reporting
193
214
  - **Internationalization**: English/Russian built-in, extensible
194
215
  - **Tooltips**: Field descriptions and hints
195
216
  - **Responsive design**: Mobile-friendly interface
196
217
  - **Read-only mode**: Display data without editing
218
+ - **Action buttons**: Custom buttons in readonly mode with configurable handlers
197
219
 
198
220
  ## Documentation
199
221
 
@@ -209,6 +231,7 @@ See [Integration Guide](docs/integration.md) for detailed setup instructions.
209
231
  **Version Index**: [https://picaz-form-builder.website.yandexcloud.net/index.html](https://picaz-form-builder.website.yandexcloud.net/index.html)
210
232
 
211
233
  Features a 3-column interface:
234
+
212
235
  - **Schema Editor**: Edit JSON schema with validation
213
236
  - **Live Preview**: See form render in real-time
214
237
  - **Data Output**: View/export form data as JSON
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.29",
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",