@dmitryvim/form-builder 0.1.42 → 0.2.1

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.
Files changed (35) hide show
  1. package/README.md +260 -22
  2. package/dist/browser/formbuilder.min.js +184 -0
  3. package/dist/browser/formbuilder.v0.2.1.min.js +184 -0
  4. package/dist/cjs/index.cjs +3652 -0
  5. package/dist/cjs/index.cjs.map +1 -0
  6. package/dist/esm/index.js +3603 -0
  7. package/dist/esm/index.js.map +1 -0
  8. package/dist/form-builder.js +154 -3369
  9. package/dist/types/components/container.d.ts +15 -0
  10. package/dist/types/components/file.d.ts +26 -0
  11. package/dist/types/components/group.d.ts +24 -0
  12. package/dist/types/components/index.d.ts +11 -0
  13. package/dist/types/components/number.d.ts +11 -0
  14. package/dist/types/components/registry.d.ts +15 -0
  15. package/dist/types/components/select.d.ts +11 -0
  16. package/dist/types/components/text.d.ts +11 -0
  17. package/dist/types/components/textarea.d.ts +11 -0
  18. package/dist/types/index.d.ts +33 -0
  19. package/dist/types/instance/FormBuilderInstance.d.ts +134 -0
  20. package/dist/types/instance/state.d.ts +13 -0
  21. package/dist/types/styles/theme.d.ts +63 -0
  22. package/dist/types/types/component-operations.d.ts +45 -0
  23. package/dist/types/types/config.d.ts +47 -0
  24. package/dist/types/types/index.d.ts +4 -0
  25. package/dist/types/types/schema.d.ts +115 -0
  26. package/dist/types/types/state.d.ts +11 -0
  27. package/dist/types/utils/helpers.d.ts +4 -0
  28. package/dist/types/utils/styles.d.ts +21 -0
  29. package/dist/types/utils/translation.d.ts +8 -0
  30. package/dist/types/utils/validation.d.ts +2 -0
  31. package/package.json +32 -15
  32. package/dist/demo.js +0 -861
  33. package/dist/elements.html +0 -1130
  34. package/dist/elements.js +0 -488
  35. package/dist/index.html +0 -315
package/README.md CHANGED
@@ -35,6 +35,22 @@ Try it now: **[https://picazru.github.io/form-builder/dist/index.html](https://p
35
35
  npm install @dmitryvim/form-builder
36
36
  ```
37
37
 
38
+ ### TypeScript Setup
39
+
40
+ This package ships with complete TypeScript definitions. Ensure your `tsconfig.json` is configured for modern module resolution:
41
+
42
+ ```json
43
+ {
44
+ "compilerOptions": {
45
+ "moduleResolution": "NodeNext", // or "Bundler" for Vite/Webpack
46
+ "esModuleInterop": true,
47
+ "skipLibCheck": false
48
+ }
49
+ }
50
+ ```
51
+
52
+ **No need for custom `.d.ts` files** - types are auto-resolved from the package at `dist/types/index.d.ts`.
53
+
38
54
  ## Core Features
39
55
 
40
56
  - **🎯 Schema-driven forms**: JSON Schema v0.3 → Interactive forms with live preview
@@ -48,6 +64,16 @@ npm install @dmitryvim/form-builder
48
64
  - **🔧 Framework agnostic**: Works with any web stack (React, Vue, Angular, vanilla JS)
49
65
  - **📦 Zero dependencies**: Self-contained HTML/CSS/JavaScript
50
66
  - **📱 Responsive design**: Mobile-friendly with Tailwind CSS styling
67
+ - **🏗️ Instance-based architecture**: Multiple independent forms with isolated state
68
+
69
+ ### New in v0.2.0
70
+
71
+ - **🔄 onChange Events**: Real-time change notifications with debouncing (eliminates polling)
72
+ - **🎨 CSS Theming**: 43 configurable theme properties (no `!important` overrides)
73
+ - **📝 Partial Updates**: Update fields without re-rendering (`setFormData`, `updateField`)
74
+ - **⚡ Async Thumbnails**: Dynamic thumbnail loading with async-only `getThumbnail`
75
+
76
+ **Impact**: Eliminates ~280+ lines of workaround code for Klein integration
51
77
 
52
78
  ## Quick Examples
53
79
 
@@ -144,24 +170,52 @@ npm install @dmitryvim/form-builder
144
170
 
145
171
  ```javascript
146
172
  // 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, key, relatedField) => {
156
- // Handle action button clicks
157
- console.log("Action clicked:", { value, key, relatedField });
158
- if (relatedField) {
159
- // Field-level action
160
- } else {
161
- // Form-level action
173
+ import { createFormBuilder } from "@dmitryvim/form-builder";
174
+
175
+ // Create form instance with v0.3.0 features
176
+ const formBuilder = createFormBuilder({
177
+ uploadFile: async (file) => {
178
+ // Your upload logic - return resource ID
179
+ return "resource-123";
180
+ },
181
+ downloadFile: (resourceId, fileName) => {
182
+ // Handle file download
183
+ window.open(`/api/files/${resourceId}`, '_blank');
184
+ },
185
+ getThumbnail: async (resourceId) => {
186
+ // v0.2.0: Async-only thumbnail loading
187
+ const url = await fetchThumbnailUrl(resourceId);
188
+ return url;
189
+ },
190
+ actionHandler: (value, key, field) => {
191
+ // Handle action button clicks
192
+ console.log("Action clicked:", { value, key, field });
193
+ },
194
+ // v0.2.0: Real-time change events
195
+ onChange: (formData) => {
196
+ console.log("Form changed:", formData);
197
+ if (formData.valid) autoSave(formData.data);
198
+ },
199
+ // v0.2.0: CSS theming
200
+ theme: {
201
+ primaryColor: '#0066cc',
202
+ borderRadius: '4px',
162
203
  }
163
204
  });
164
- FormBuilder.renderForm(schema, prefillData);
205
+
206
+ // Render form
207
+ const rootElement = document.getElementById("form-container");
208
+ formBuilder.renderForm(rootElement, schema, prefillData);
209
+
210
+ // Get form data
211
+ const result = formBuilder.getFormData();
212
+ if (result.valid) {
213
+ console.log("Form data:", result.data);
214
+ }
215
+
216
+ // v0.2.0: Update fields without re-rendering
217
+ formBuilder.updateField('email', 'newemail@example.com');
218
+ formBuilder.setFormData({ name: 'John', email: 'john@example.com' });
165
219
  ```
166
220
 
167
221
  ### 2. CDN Integration
@@ -170,7 +224,15 @@ FormBuilder.renderForm(schema, prefillData);
170
224
  <!-- Direct script include (npm CDN) -->
171
225
  <script src="https://cdn.jsdelivr.net/npm/@dmitryvim/form-builder@latest/dist/form-builder.js"></script>
172
226
  <script>
173
- window.FormBuilder.renderForm(schema);
227
+ const { createFormBuilder } = window.FormBuilder;
228
+
229
+ const formBuilder = createFormBuilder({
230
+ uploadFile: async (file) => "resource-id",
231
+ downloadFile: (resourceId) => { /* download */ }
232
+ });
233
+
234
+ const rootElement = document.getElementById("form-container");
235
+ formBuilder.renderForm(rootElement, schema);
174
236
  </script>
175
237
 
176
238
  <!-- Or use our S3 CDN -->
@@ -222,12 +284,188 @@ See [Integration Guide](docs/integration.md) for detailed setup instructions.
222
284
  - **Read-only mode**: Display data without editing
223
285
  - **Action buttons**: Custom buttons in readonly mode with configurable handlers
224
286
 
287
+ ## API Reference
288
+
289
+ ### Core Methods
290
+
291
+ ```typescript
292
+ import { createFormBuilder } from '@dmitryvim/form-builder';
293
+
294
+ // Create form instance
295
+ const form = createFormBuilder({
296
+ // Required handlers
297
+ uploadFile: async (file: File) => string, // Upload file, return resource ID
298
+ downloadFile: (resourceId: string, fileName: string) => void,
299
+
300
+ // Optional handlers
301
+ getThumbnail?: async (resourceId: string) => string | null, // v0.2.0: Async-only, for preview thumbnails
302
+ getDownloadUrl?: (resourceId: string) => string | null, // Optional: URL for downloading full file
303
+ actionHandler?: (value: any, key: string, field: any) => void,
304
+
305
+ // v0.2.0: onChange events
306
+ onChange?: (formData: FormResult) => void,
307
+ onFieldChange?: (fieldPath: string, value: any, formData: FormResult) => void,
308
+ debounceMs?: number, // Default: 300ms
309
+
310
+ // v0.2.0: CSS theming
311
+ theme?: {
312
+ primaryColor?: string,
313
+ borderRadius?: string,
314
+ fontSize?: string,
315
+ fontFamily?: string,
316
+ // ... 39 more theme properties
317
+ }
318
+ });
319
+
320
+ // Render form
321
+ form.renderForm(rootElement, schema, prefillData);
322
+
323
+ // Get form data
324
+ const result = form.getFormData(); // { valid, errors, data }
325
+
326
+ // v0.2.0: Update data without re-rendering
327
+ form.setFormData({ name: 'John', email: 'john@example.com' });
328
+ form.updateField('email', 'newemail@example.com');
329
+ form.updateField('address.city', 'New York'); // Nested paths
330
+
331
+ // Switch modes
332
+ form.setMode('readonly'); // or 'edit'
333
+
334
+ // Cleanup
335
+ form.destroy();
336
+ ```
337
+
338
+ ### Migration from v0.1.x
339
+
340
+ **Breaking Changes in v0.2.0:**
341
+
342
+ 1. **Instance-Only API** - Global static methods removed
343
+ ```typescript
344
+ // OLD (v0.1.x)
345
+ FormBuilder.configure({ uploadFile: async (file) => "id" });
346
+ FormBuilder.renderForm(root, schema);
347
+
348
+ // NEW (v0.2.0)
349
+ const form = createFormBuilder({ uploadFile: async (file) => "id" });
350
+ form.renderForm(root, schema);
351
+ ```
352
+
353
+ 2. **Async getThumbnail** - Must return Promise
354
+ ```typescript
355
+ // OLD (v0.1.x)
356
+ getThumbnail: (resourceId) => `/thumbs/${resourceId}.jpg`
357
+
358
+ // NEW (v0.2.0)
359
+ getThumbnail: async (resourceId) => `/thumbs/${resourceId}.jpg`
360
+ ```
361
+
362
+ See [CHANGELOG.md](CHANGELOG.md) for complete migration details.
363
+
364
+ ### Theming
365
+
366
+ Customize appearance with 43 theme properties:
367
+
368
+ ```typescript
369
+ const form = createFormBuilder({
370
+ theme: {
371
+ // Colors
372
+ primaryColor: '#0066cc',
373
+ borderColor: '#e0e0e0',
374
+ errorColor: '#d32f2f',
375
+
376
+ // Typography
377
+ fontSize: '16px',
378
+ fontFamily: '"Roboto", sans-serif',
379
+
380
+ // Spacing
381
+ borderRadius: '4px',
382
+ inputPaddingX: '12px',
383
+
384
+ // Buttons
385
+ buttonBgColor: '#0066cc',
386
+ buttonTextColor: '#ffffff',
387
+ }
388
+ });
389
+ ```
390
+
391
+ **Most Common Properties:**
392
+ - `primaryColor` - Primary brand color
393
+ - `borderRadius` - Border radius for inputs/buttons
394
+ - `fontSize` - Base font size
395
+ - `fontFamily` - Font family
396
+ - `borderColor` - Input border color
397
+
398
+ No `!important` overrides needed. See [CHANGELOG.md](CHANGELOG.md) for all 43 properties.
399
+
400
+ ### File Handling
401
+
402
+ The form builder provides flexible file handling with separate hooks for uploads, downloads, and previews:
403
+
404
+ ```typescript
405
+ const form = createFormBuilder({
406
+ // Required: Upload handler
407
+ uploadFile: async (file) => {
408
+ const formData = new FormData();
409
+ formData.append('file', file);
410
+ const response = await fetch('/api/upload', {
411
+ method: 'POST',
412
+ body: formData
413
+ });
414
+ const data = await response.json();
415
+ return data.resourceId; // Return unique resource ID
416
+ },
417
+
418
+ // Required: Download handler
419
+ downloadFile: (resourceId, fileName) => {
420
+ // Option 1: Direct download
421
+ window.open(`/api/files/${resourceId}/download`, '_blank');
422
+
423
+ // Option 2: Programmatic download
424
+ fetch(`/api/files/${resourceId}/download`)
425
+ .then(response => response.blob())
426
+ .then(blob => {
427
+ const url = URL.createObjectURL(blob);
428
+ const a = document.createElement('a');
429
+ a.href = url;
430
+ a.download = fileName;
431
+ a.click();
432
+ URL.revokeObjectURL(url);
433
+ });
434
+ },
435
+
436
+ // Optional: Thumbnail URLs for preview (async-only in v0.2.0)
437
+ getThumbnail: async (resourceId) => {
438
+ const response = await fetch(`/api/files/${resourceId}/thumbnail`);
439
+ const data = await response.json();
440
+ return data.thumbnailUrl; // Return URL or null
441
+ },
442
+
443
+ // Optional: Full file download URL (used instead of getThumbnail for downloads)
444
+ getDownloadUrl: (resourceId) => {
445
+ return `/api/files/${resourceId}/download`;
446
+ }
447
+ });
448
+ ```
449
+
450
+ **Handler Priority for Downloads:**
451
+
452
+ When a user clicks the download button in readonly mode, the form builder uses this priority:
453
+
454
+ 1. **`getDownloadUrl`** - If provided, this URL is used for downloads
455
+ 2. **`getThumbnail`** - If `getDownloadUrl` is not provided, falls back to thumbnail URL
456
+ 3. **`downloadFile`** - If neither URL hook is provided, calls the download handler
457
+
458
+ **Use Cases:**
459
+
460
+ - **Separate thumbnail and download URLs**: Provide both `getThumbnail` (for optimized previews) and `getDownloadUrl` (for full files)
461
+ - **Same URL for both**: Provide only `getThumbnail` if thumbnail URL is also the download URL
462
+ - **Programmatic download**: Provide only `downloadFile` for custom download logic
463
+
225
464
  ## Documentation
226
465
 
227
- - [Integration Guide](docs/integration.md) - Complete setup and usage
228
- - [Schema Reference](docs/schema.md) - Field types and validation rules
229
- - [API Documentation](docs/api.md) - Method reference and examples
230
- - [Development Guide](CLAUDE.md) - Architecture and development workflow
466
+ - **API Reference** - See above for core methods and theming
467
+ - **Development Guide** - [CLAUDE.md](CLAUDE.md) for architecture and workflow
468
+ - **Changelog** - [CHANGELOG.md](CHANGELOG.md) for version history and migration
231
469
 
232
470
  ## Live Demo
233
471
 
@@ -246,7 +484,7 @@ Features a 3-column interface:
246
484
  - **GitHub**: [picazru/form-builder](https://github.com/picazru/form-builder)
247
485
  - **NPM Package**: [@dmitryvim/form-builder](https://www.npmjs.com/package/@dmitryvim/form-builder)
248
486
  - **CDN**: [picaz-form-builder.website.yandexcloud.net](https://picaz-form-builder.website.yandexcloud.net/)
249
- - **Version**: 0.1.28
487
+ - **Version**: 0.2.0 (Unreleased - Breaking Changes + New Features)
250
488
  - **License**: MIT - see [LICENSE](LICENSE) file
251
489
 
252
490
  Built with ❤️ for the web development community.