@dmitryvim/form-builder 0.1.34 → 0.1.37

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/dist/demo.js CHANGED
@@ -215,7 +215,7 @@ const EXAMPLE_SCHEMA = {
215
215
  label: "Session ID",
216
216
  description: "Hidden session identifier for tracking purposes",
217
217
  hidden: true,
218
- default: "session_" + Math.random().toString(36).substr(2, 9),
218
+ default: `session_${Math.random().toString(36).substr(2, 9)}`,
219
219
  },
220
220
  ],
221
221
  };
@@ -373,6 +373,10 @@ const el = {
373
373
  copyDataBtn: document.getElementById("copyDataBtn"),
374
374
  downloadDataBtn: document.getElementById("downloadDataBtn"),
375
375
  dataErrors: document.getElementById("dataErrors"),
376
+ actionsTextarea: document.getElementById("actionsTextarea"),
377
+ formatActionsBtn: document.getElementById("formatActionsBtn"),
378
+ clearActionsBtn: document.getElementById("clearActionsBtn"),
379
+ actionsErrors: document.getElementById("actionsErrors"),
376
380
  };
377
381
 
378
382
  // Utility functions
@@ -406,6 +410,44 @@ function downloadFile(filename, content) {
406
410
  URL.revokeObjectURL(url);
407
411
  }
408
412
 
413
+ // Parse and validate external actions
414
+ function parseActions(actionsText) {
415
+ if (!actionsText || actionsText.trim() === "") {
416
+ return [];
417
+ }
418
+
419
+ try {
420
+ const actions = JSON.parse(actionsText);
421
+
422
+ if (!Array.isArray(actions)) {
423
+ throw new Error("Actions must be an array");
424
+ }
425
+
426
+ // Validate each action
427
+ for (let i = 0; i < actions.length; i++) {
428
+ const action = actions[i];
429
+ if (!action || typeof action !== "object") {
430
+ throw new Error(`Action at index ${i} must be an object`);
431
+ }
432
+ if (!action.related_field || typeof action.related_field !== "string") {
433
+ throw new Error(
434
+ `Action at index ${i} missing valid 'related_field' property`,
435
+ );
436
+ }
437
+ if (!action.value || typeof action.value !== "string") {
438
+ throw new Error(`Action at index ${i} missing valid 'value' property`);
439
+ }
440
+ if (!action.label || typeof action.label !== "string") {
441
+ throw new Error(`Action at index ${i} missing valid 'label' property`);
442
+ }
443
+ }
444
+
445
+ return actions;
446
+ } catch (error) {
447
+ throw new Error(`Actions JSON error: ${error.message}`);
448
+ }
449
+ }
450
+
409
451
  // Configure FormBuilder with in-memory handlers
410
452
  function setupFormBuilder() {
411
453
  // Set form container
@@ -438,17 +480,44 @@ function setupFormBuilder() {
438
480
  });
439
481
 
440
482
  // Action handler - display message when action button is clicked
441
- FormBuilder.setActionHandler((value) => {
442
- // Use cached action map for O(1) lookup instead of re-parsing schema
443
- const actionLabel = actionLabelMap.get(value) || value; // fallback to value
483
+ // Updated to support both old system (1 param) and new system (2 params)
484
+ FormBuilder.setActionHandler((relatedFieldOrValue, value) => {
485
+ let actionLabel, actionValue, relatedField;
486
+
487
+ // Determine if this is the old system (1 param) or new system (2 params)
488
+ if (arguments.length === 1) {
489
+ // Old system: only value parameter
490
+ actionValue = relatedFieldOrValue;
491
+ actionLabel = actionLabelMap.get(actionValue) || actionValue;
492
+ relatedField = null;
493
+ } else {
494
+ // New system: related_field and value parameters
495
+ relatedField = relatedFieldOrValue;
496
+ actionValue = value;
497
+ actionLabel = `Action for ${relatedField}`;
498
+ }
444
499
 
445
- console.log("Action clicked:", { label: actionLabel, value });
500
+ console.log("Action clicked:", {
501
+ label: actionLabel,
502
+ value: actionValue,
503
+ relatedField,
504
+ system: arguments.length === 1 ? "schema-based" : "external",
505
+ });
446
506
 
447
507
  // Show message to user (compatible with all environments)
448
508
  if (typeof window !== "undefined" && window.alert) {
449
- window.alert(`${actionLabel} clicked: ${value}`);
509
+ if (relatedField) {
510
+ window.alert(
511
+ `External Action: "${actionLabel}" clicked for field "${relatedField}" with value: ${actionValue}`,
512
+ );
513
+ } else {
514
+ window.alert(`Schema Action: "${actionLabel}" clicked: ${actionValue}`);
515
+ }
450
516
  } else {
451
- console.log(`Demo action: ${actionLabel} clicked: ${value}`);
517
+ console.log(
518
+ `Demo action: ${actionLabel} clicked: ${actionValue}`,
519
+ relatedField ? ` for field: ${relatedField}` : "",
520
+ );
452
521
  }
453
522
  });
454
523
 
@@ -461,6 +530,7 @@ function setupFormBuilder() {
461
530
  function applyCurrentSchema() {
462
531
  clearError(el.schemaErrors);
463
532
  clearError(el.formErrors);
533
+ clearError(el.actionsErrors);
464
534
 
465
535
  try {
466
536
  const schema = JSON.parse(el.schemaInput.value);
@@ -474,6 +544,15 @@ function applyCurrentSchema() {
474
544
  return false;
475
545
  }
476
546
 
547
+ // Parse external actions
548
+ let externalActions = [];
549
+ try {
550
+ externalActions = parseActions(el.actionsTextarea.value);
551
+ } catch (error) {
552
+ showError(el.actionsErrors, error.message);
553
+ return false;
554
+ }
555
+
477
556
  // Build action value -> label map for efficient lookup
478
557
  actionLabelMap = buildActionLabelMap(schema);
479
558
 
@@ -492,10 +571,12 @@ function applyCurrentSchema() {
492
571
  // Ignore errors when getting current data
493
572
  }
494
573
 
495
- // Render form with current data
496
- FormBuilder.renderForm(schema, currentData);
574
+ // Render form with current data and external actions
575
+ FormBuilder.renderForm(schema, currentData, externalActions);
497
576
 
498
577
  console.log(`Form rendered in ${isReadOnly ? "readonly" : "edit"} mode`);
578
+ console.log(`External actions:`, externalActions);
579
+
499
580
  return true;
500
581
  } catch (e) {
501
582
  showError(el.schemaErrors, `JSON parse error: ${e.message}`);
@@ -513,7 +594,9 @@ el.resetSchemaBtn.addEventListener("click", () => {
513
594
  clearError(el.schemaErrors);
514
595
  clearError(el.formErrors);
515
596
  clearError(el.dataErrors);
597
+ clearError(el.actionsErrors);
516
598
  el.dataTextarea.value = "";
599
+ el.actionsTextarea.value = "";
517
600
 
518
601
  // Clear file storage
519
602
  fileStorage.clear();
@@ -618,6 +701,15 @@ el.prefillBtn.addEventListener("click", () => {
618
701
  const prefillData = JSON.parse(el.dataTextarea.value || "{}");
619
702
  const currentSchema = JSON.parse(el.schemaInput.value);
620
703
 
704
+ // Parse external actions
705
+ let externalActions = [];
706
+ try {
707
+ externalActions = parseActions(el.actionsTextarea.value);
708
+ } catch (error) {
709
+ showError(el.actionsErrors, error.message);
710
+ return;
711
+ }
712
+
621
713
  // Convert enhanced data back to raw format for prefilling
622
714
  const processedData = JSON.parse(JSON.stringify(prefillData));
623
715
 
@@ -658,9 +750,10 @@ el.prefillBtn.addEventListener("click", () => {
658
750
  const isReadOnly = el.readOnlyToggle.checked;
659
751
  FormBuilder.setMode(isReadOnly ? "readonly" : "edit");
660
752
 
661
- FormBuilder.renderForm(currentSchema, processedData);
753
+ FormBuilder.renderForm(currentSchema, processedData, externalActions);
662
754
  console.log("Form prefilled with data");
663
755
  console.log("Processed prefill data:", processedData);
756
+ console.log("External actions:", externalActions);
664
757
  } catch (e) {
665
758
  showError(el.dataErrors, `JSON parse error: ${e.message}`);
666
759
  console.error("Prefill error:", e);
@@ -685,6 +778,51 @@ el.downloadDataBtn.addEventListener("click", () => {
685
778
  console.log("Data downloaded");
686
779
  });
687
780
 
781
+ // Actions management handlers
782
+ el.formatActionsBtn.addEventListener("click", () => {
783
+ try {
784
+ const actions = parseActions(el.actionsTextarea.value);
785
+ el.actionsTextarea.value = pretty(actions);
786
+ clearError(el.actionsErrors);
787
+ console.log("Actions formatted");
788
+ } catch (e) {
789
+ showError(el.actionsErrors, e.message);
790
+ console.error("Format actions error:", e);
791
+ }
792
+ });
793
+
794
+ el.clearActionsBtn.addEventListener("click", () => {
795
+ el.actionsTextarea.value = "";
796
+ clearError(el.actionsErrors);
797
+ // Re-apply schema to remove external actions from the form
798
+ applyCurrentSchema();
799
+ console.log("Actions cleared");
800
+ });
801
+
802
+ // Example external actions for demonstration
803
+ const EXAMPLE_ACTIONS = [
804
+ {
805
+ related_field: "title[0]",
806
+ value: "generate-title",
807
+ label: "🤖 Generate Title",
808
+ },
809
+ {
810
+ related_field: "description",
811
+ value: "improve-description",
812
+ label: "✨ Improve Description",
813
+ },
814
+ {
815
+ related_field: "slides[0].title",
816
+ value: "optimize-slide-title",
817
+ label: "🎯 Optimize Slide Title",
818
+ },
819
+ {
820
+ related_field: "cover",
821
+ value: "analyze-image",
822
+ label: "🔍 Analyze Image",
823
+ },
824
+ ];
825
+
688
826
  // Initialize demo application
689
827
  function initDemo() {
690
828
  // Set up FormBuilder
@@ -693,6 +831,9 @@ function initDemo() {
693
831
  // Initialize with example schema
694
832
  el.schemaInput.value = pretty(EXAMPLE_SCHEMA);
695
833
 
834
+ // Initialize with example actions
835
+ el.actionsTextarea.value = pretty(EXAMPLE_ACTIONS);
836
+
696
837
  // Apply initial schema
697
838
  applyCurrentSchema();
698
839
 
@@ -4,28 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <title>Form Builder - Element Types Documentation</title>
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <!-- Development only - replace with local Tailwind build for production -->
8
- <script>
9
- if (
10
- location.hostname === "localhost" ||
11
- location.hostname === "127.0.0.1" ||
12
- location.protocol === "file:"
13
- ) {
14
- // Development environment - load Tailwind CDN
15
- const script = document.createElement("script");
16
- script.src = "https://cdn.tailwindcss.com";
17
- document.head.appendChild(script);
18
- } else {
19
- // Production environment - load local CSS (implement local build)
20
- console.warn(
21
- "Production mode: Please implement local Tailwind CSS build",
22
- );
23
- const link = document.createElement("link");
24
- link.rel = "stylesheet";
25
- link.href = "./tailwind.min.css"; // Local build file
26
- document.head.appendChild(link);
27
- }
28
- </script>
7
+ <script src="https://cdn.tailwindcss.com"></script>
29
8
  <script>
30
9
  tailwind.config = {
31
10
  darkMode: "media",
package/dist/elements.js CHANGED
@@ -12,7 +12,7 @@ function initializeFormBuilder() {
12
12
  const fileUrl = URL.createObjectURL(file);
13
13
 
14
14
  fileStorage.set(resourceId, {
15
- file: file,
15
+ file,
16
16
  url: fileUrl,
17
17
  name: file.name,
18
18
  type: file.type,