@unvired/turboforms-embed-sdk 1.0.22 → 1.0.29

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
@@ -251,7 +251,9 @@ document.addEventListener('deviceready', function() {
251
251
  | `GET_ATTACHMENT` | Attachment request |
252
252
  | `ERROR` | Error occurred |
253
253
 
254
- ## ✅ Button Visibility & Enablement
254
+ ## ✅ Button Visibility & Enablement (Normal Forms)
255
+
256
+ The following rules apply to standard (non-wizard) forms:
255
257
 
256
258
  | privateExternal | Permission | Main Toolbar Button | More Options (Dropdown) | Enable / Disable Rule |
257
259
  | ------------------ | --------------- | -------------------------- | ------------------------------- | -------------------------------------------------- |
@@ -261,6 +263,18 @@ document.addEventListener('deviceready', function() {
261
263
  | **true (Private)** | `writesingle` | **Complete** (`submitBtn`) | **Save** (`saveOption`) | Complete enabled **ONLY when form is 100% filled** |
262
264
  | **Any** | `read` | None | None | N/A (Read-only mode) |
263
265
 
266
+ ## 🧙 Wizard Form Navigation & Visibility
267
+
268
+ For Wizard forms, the standard action buttons are managed per-page to prioritize navigation:
269
+
270
+ | Page Status | Action Buttons (Save/Complete) | Navigation Buttons | Action Menu (More Options) |
271
+ | :--- | :--- | :--- | :--- |
272
+ | **Intermediate Steps** | **Hidden** | **Previous**, **Next** | **Help** / **Comments** (if enabled) |
273
+ | **Final Step** | **Visible** (Follows standard rules above) | **Previous** | **All Actions** (Follows standard rules above) |
274
+
275
+ * **Intermediate Steps**: To ensure a clean experience, the SDK automatically hides all final submission actions (buttons, icons, and "More" dropdown items) until the user reaches the end of the wizard.
276
+ * **Final Step**: Once the user reaches the last page, the standard logic defined in the table above is applied. The **Next** button is replaced by the appropriate **Save** or **Complete** action based on permissions and form state.
277
+
264
278
  ## 🧭 “More Options” Dropdown Logic
265
279
 
266
280
  ### ▶ **Complete appears in More Options**
@@ -56365,6 +56365,11 @@ class SignatureComponent extends InputComponentForSignature {
56365
56365
  }
56366
56366
  if (this.refs.clicktoSign) {
56367
56367
  this.refs.clicktoSign.disabled = true;
56368
+ this.refs.clicktoSign.style.pointerEvents = 'none';
56369
+ this.refs.clicktoSign.style.display = 'none';
56370
+
56371
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
56372
+ if(clickBox) clickBox.style.display = 'none';
56368
56373
  }
56369
56374
  if (this.refs.signatureImage && this.dataValue) {
56370
56375
  this.refs.signatureImage.setAttribute('src', this.dataValue);
@@ -56376,6 +56381,12 @@ class SignatureComponent extends InputComponentForSignature {
56376
56381
  }
56377
56382
  if (this.refs.clicktoSign) {
56378
56383
  this.refs.clicktoSign.disabled = false;
56384
+ this.refs.clicktoSign.style.pointerEvents = 'auto';
56385
+ if (this.component.isEnableClicktoSign) {
56386
+ this.refs.clicktoSign.style.display = 'inline-flex';
56387
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
56388
+ if(clickBox) clickBox.style.display = '';
56389
+ }
56379
56390
  }
56380
56391
  }
56381
56392
  }
@@ -56447,6 +56458,11 @@ class SignatureComponent extends InputComponentForSignature {
56447
56458
  this.refs.refresh.classList.add('disabled');
56448
56459
  if (this.refs.clicktoSign) {
56449
56460
  this.refs.clicktoSign.disabled = true;
56461
+ this.refs.clicktoSign.style.pointerEvents = 'none';
56462
+ this.refs.clicktoSign.style.display = 'none';
56463
+
56464
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
56465
+ if(clickBox) clickBox.style.display = 'none';
56450
56466
  }
56451
56467
  }
56452
56468
 
@@ -58954,16 +58970,13 @@ function showDynamicModal(
58954
58970
  .custom-modal.show, .custom-modal-backdrop.show {
58955
58971
  display: flex;
58956
58972
  }
58957
- /* Center the dialog using translate which behaves consistently across browsers */
58973
+ /* Flexbox on the parent handles centering */
58958
58974
  .custom-modal-dialog {
58959
58975
  width: 100%;
58960
58976
  max-width: 500px;
58961
- margin: 0; /* reset; we position via transform */
58977
+ margin: auto;
58962
58978
  box-sizing: border-box;
58963
58979
  position: relative;
58964
- top: 50%;
58965
- left: 50%;
58966
- transform: translate(-50%, -50%);
58967
58980
  }
58968
58981
  .custom-modal-content {
58969
58982
  background: #fff;
@@ -59015,9 +59028,7 @@ function showDynamicModal(
59015
59028
  @media (max-width: 600px) {
59016
59029
  .custom-modal-dialog {
59017
59030
  max-width: 95vw;
59018
- /* On small screens prefer slightly higher vertical position so header isn't cut off */
59019
- top: 40%;
59020
- transform: translate(-50%, -40%);
59031
+ margin: 1rem auto;
59021
59032
  }
59022
59033
  .custom-modal-content {
59023
59034
  border-radius: 0.15rem;
@@ -59996,7 +60007,7 @@ async function renderRNform(
59996
60007
  }
59997
60008
 
59998
60009
  // Hide FormIO submit button component and wizard buttons in readOnly mode
59999
- if (mode == "readOnly") {
60010
+ if (mode == "readOnly" || permission == "read") {
60000
60011
  const submitComponents = document.querySelectorAll(
60001
60012
  ".formio-component-submit"
60002
60013
  );
@@ -60004,6 +60015,18 @@ async function renderRNform(
60004
60015
  component.style.display = "none";
60005
60016
  });
60006
60017
 
60018
+ // Disable signature pads robustly via CSS
60019
+ if (!document.getElementById("readonly-signature-style")) {
60020
+ const style = document.createElement("style");
60021
+ style.id = "readonly-signature-style";
60022
+ style.innerHTML = `
60023
+ .formio-component-signature { pointer-events: none !important; }
60024
+ .formio-component-signature [ref="clicktoSign"],
60025
+ .formio-component-signature .click-to-sign-box { display: none !important; }
60026
+ `;
60027
+ document.head.appendChild(style);
60028
+ }
60029
+
60007
60030
  // Hide wizard navigation buttons
60008
60031
  const wizardNextBtns = document.querySelectorAll(
60009
60032
  ".btn-wizard-nav-next"
@@ -60687,7 +60710,7 @@ window.CommentOnBack = CommentOnBack;
60687
60710
 
60688
60711
 
60689
60712
  <div id="sticky-footer">
60690
- <div class="build-version">SDK v1.0.22</div>
60713
+ <div class="build-version">SDK v1.0.29</div>
60691
60714
  <div class="relative-position">
60692
60715
  <button id="unvired-more-btn" class="ui button primary dataGrid-addRow" onclick="toggleTooltip()">
60693
60716
  <i class="icon options"></i>
@@ -43,11 +43,18 @@ function attachMasterDataToForm(obj, masterdataResults, key = "dataSrc", type =
43
43
  attachMasterDataToForm(obj[k], masterdataResults, key, type, true);
44
44
  } else if (k === key && obj[k] === type) {
45
45
  if (Array.isArray(masterdataResults)) {
46
- obj.masterdata = masterdataResults.flatMap(
47
- (md) => md.submissionData || []
48
- );
46
+ let matchedData = [];
47
+ if (obj.selMasterdataId) {
48
+ const match = masterdataResults.find((md) => md.masterdataId === obj.selMasterdataId);
49
+ if (match && match.submissionData) {
50
+ matchedData = match.submissionData;
51
+ }
52
+ } else {
53
+ matchedData = masterdataResults.flatMap((md) => md.submissionData || []);
54
+ }
55
+ obj.masterdata = matchedData.map((item) => item && item.data !== void 0 ? item : { data: item });
49
56
  } else if (masterdataResults && Array.isArray(masterdataResults.submissionData)) {
50
- obj.masterdata = masterdataResults.submissionData;
57
+ obj.masterdata = masterdataResults.submissionData.map((item) => item && item.data !== void 0 ? item : { data: item });
51
58
  } else {
52
59
  obj.masterdata = [];
53
60
  }
@@ -939,6 +946,8 @@ async function loadUnviredForms({
939
946
  const template = formJson;
940
947
  const nestedFormArrTemp = options.nestedFormData || [];
941
948
  const masterDataArrTemp = options.masterData || [];
949
+ console.log("[SDK:3] Debug - options.masterData received:", options.masterData);
950
+ console.log("[SDK:3] Debug - masterDataArrTemp evaluated to:", masterDataArrTemp);
942
951
  const nestedFormError = validateNestedForms(formJson, nestedFormArrTemp);
943
952
  if (nestedFormError) {
944
953
  console.error("[SDK] \u274C Step 3: Nested form validation failed", nestedFormError);
@@ -27823,6 +27832,7 @@ select.ui.dropdown {
27823
27832
  height: 100%;
27824
27833
  background: rgba(255, 255, 255, 0.95);
27825
27834
  backdrop-filter: blur(10px);
27835
+ -webkit-backdrop-filter: blur(10px);
27826
27836
  display: flex;
27827
27837
  flex-direction: column;
27828
27838
  justify-content: center;
@@ -27842,15 +27852,23 @@ select.ui.dropdown {
27842
27852
  border: 4px solid #e0e0e0;
27843
27853
  border-top: 4px solid #0077b6;
27844
27854
  border-radius: 50%;
27855
+ -webkit-animation: sdk-spin 1s linear infinite;
27845
27856
  animation: sdk-spin 1s linear infinite;
27846
27857
  margin-bottom: 20px;
27858
+ -webkit-transform: translateZ(0);
27859
+ transform: translateZ(0);
27860
+ will-change: transform;
27847
27861
  }
27848
27862
  .sdk-loader-text {
27849
27863
  color: #0077b6;
27850
27864
  font-size: 1.1rem;
27851
27865
  font-weight: 500;
27852
27866
  letter-spacing: 0.5px;
27867
+ -webkit-animation: sdk-pulse 1.5s ease-in-out infinite;
27853
27868
  animation: sdk-pulse 1.5s ease-in-out infinite;
27869
+ -webkit-transform: translateZ(0);
27870
+ transform: translateZ(0);
27871
+ will-change: opacity;
27854
27872
  }
27855
27873
  .sdk-loader-subtext {
27856
27874
  color: #666;
@@ -27858,10 +27876,18 @@ select.ui.dropdown {
27858
27876
  margin-top: 8px;
27859
27877
  opacity: 0.7;
27860
27878
  }
27879
+ @-webkit-keyframes sdk-spin {
27880
+ 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
27881
+ 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
27882
+ }
27861
27883
  @keyframes sdk-spin {
27862
27884
  0% { transform: rotate(0deg); }
27863
27885
  100% { transform: rotate(360deg); }
27864
27886
  }
27887
+ @-webkit-keyframes sdk-pulse {
27888
+ 0%, 100% { opacity: 1; }
27889
+ 50% { opacity: 0.5; }
27890
+ }
27865
27891
  @keyframes sdk-pulse {
27866
27892
  0%, 100% { opacity: 1; }
27867
27893
  50% { opacity: 0.5; }
@@ -27922,14 +27948,20 @@ select.ui.dropdown {
27922
27948
  <div id="formio-cmt" style="margin-bottom: 20px;"></div>
27923
27949
  </div>
27924
27950
  <div id="sticky-footer">
27925
- <div class="build-version">SDK v1.0.22</div>
27951
+ <div class="build-version">SDK v1.0.29</div>
27926
27952
  <button class="ui button primary dataGrid-addRow" id="saveBtn" disabled="true" onclick="FormOnSave()">
27927
27953
  <i class="icon save large"></i>Save
27928
27954
  </button>
27955
+ <button class="ui button secondary dataGrid-addRow" id="prevBtn" style="display:none" onclick="FormOnPrevious()">
27956
+ <i class="icon arrow left"></i>Previous
27957
+ </button>
27958
+ <button class="ui button primary dataGrid-addRow" id="nextBtn" style="display:none" onclick="FormOnNext()">
27959
+ Next<i class="icon arrow right"></i>
27960
+ </button>
27929
27961
  <button class="ui button primary dataGrid-addRow" id="submitBtn" style="display:none" onclick="FormOnSubmit()">
27930
27962
  <i class="icon save large"></i>Submit
27931
27963
  </button>
27932
-
27964
+
27933
27965
  <!-- Quick Action Buttons -->
27934
27966
  <div id="quick-actions" style="display: flex; align-items: center;">
27935
27967
  <i id="quickCompleteBtn" class="icon clipboard check large" style="display:none; cursor: pointer; margin: 0 10px;" onclick="FormOnSubmit()" title="Complete"></i>
@@ -28078,6 +28110,16 @@ select.ui.dropdown {
28078
28110
  window.formOnSubmitFunction();
28079
28111
  }
28080
28112
  };
28113
+ window.FormOnNext = window.FormOnNext || function() {
28114
+ if (typeof window.formOnNextFunction === "function") {
28115
+ window.formOnNextFunction();
28116
+ }
28117
+ };
28118
+ window.FormOnPrevious = window.FormOnPrevious || function() {
28119
+ if (typeof window.formOnPreviousFunction === "function") {
28120
+ window.formOnPreviousFunction();
28121
+ }
28122
+ };
28081
28123
  const scriptContents = `
28082
28124
  // Global variable initialization
28083
28125
  window.form = window.form || {};
@@ -63598,6 +63640,11 @@ class SignatureComponent extends InputComponentForSignature {
63598
63640
  }
63599
63641
  if (this.refs.clicktoSign) {
63600
63642
  this.refs.clicktoSign.disabled = true;
63643
+ this.refs.clicktoSign.style.pointerEvents = 'none';
63644
+ this.refs.clicktoSign.style.display = 'none';
63645
+
63646
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
63647
+ if(clickBox) clickBox.style.display = 'none';
63601
63648
  }
63602
63649
  if (this.refs.signatureImage && this.dataValue) {
63603
63650
  this.refs.signatureImage.setAttribute('src', this.dataValue);
@@ -63609,6 +63656,12 @@ class SignatureComponent extends InputComponentForSignature {
63609
63656
  }
63610
63657
  if (this.refs.clicktoSign) {
63611
63658
  this.refs.clicktoSign.disabled = false;
63659
+ this.refs.clicktoSign.style.pointerEvents = 'auto';
63660
+ if (this.component.isEnableClicktoSign) {
63661
+ this.refs.clicktoSign.style.display = 'inline-flex';
63662
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
63663
+ if(clickBox) clickBox.style.display = '';
63664
+ }
63612
63665
  }
63613
63666
  }
63614
63667
  }
@@ -63680,6 +63733,11 @@ class SignatureComponent extends InputComponentForSignature {
63680
63733
  this.refs.refresh.classList.add('disabled');
63681
63734
  if (this.refs.clicktoSign) {
63682
63735
  this.refs.clicktoSign.disabled = true;
63736
+ this.refs.clicktoSign.style.pointerEvents = 'none';
63737
+ this.refs.clicktoSign.style.display = 'none';
63738
+
63739
+ const clickBox = this.refs.clicktoSign.closest('.click-to-sign-box');
63740
+ if(clickBox) clickBox.style.display = 'none';
63683
63741
  }
63684
63742
  }
63685
63743
 
@@ -66192,16 +66250,13 @@ function showDynamicModal(
66192
66250
  .custom-modal.show, .custom-modal-backdrop.show {
66193
66251
  display: flex;
66194
66252
  }
66195
- /* Center the dialog using translate which behaves consistently across browsers */
66253
+ /* Flexbox on the parent handles centering */
66196
66254
  .custom-modal-dialog {
66197
66255
  width: 100%;
66198
66256
  max-width: 500px;
66199
- margin: 0; /* reset; we position via transform */
66257
+ margin: auto;
66200
66258
  box-sizing: border-box;
66201
66259
  position: relative;
66202
- top: 50%;
66203
- left: 50%;
66204
- transform: translate(-50%, -50%);
66205
66260
  }
66206
66261
  .custom-modal-content {
66207
66262
  background: #fff;
@@ -66253,9 +66308,7 @@ function showDynamicModal(
66253
66308
  @media (max-width: 600px) {
66254
66309
  .custom-modal-dialog {
66255
66310
  max-width: 95vw;
66256
- /* On small screens prefer slightly higher vertical position so header isn't cut off */
66257
- top: 40%;
66258
- transform: translate(-50%, -40%);
66311
+ margin: 1rem auto;
66259
66312
  }
66260
66313
  .custom-modal-content {
66261
66314
  border-radius: 0.15rem;
@@ -66567,6 +66620,8 @@ function FormOnBackNavigation() {
66567
66620
  function initialButtonSetup(privateExternal, permission) {
66568
66621
  const saveBtn = document.getElementById("saveBtn");
66569
66622
  const submitBtn = document.getElementById("submitBtn");
66623
+ const prevBtn = document.getElementById("prevBtn");
66624
+ const nextBtn = document.getElementById("nextBtn");
66570
66625
  const completeOption = document.getElementById("completeOption");
66571
66626
  const saveOption = document.getElementById("saveOption");
66572
66627
  const completeDivider = document.getElementById("completeDivider");
@@ -66672,6 +66727,7 @@ function initialButtonSetup(privateExternal, permission) {
66672
66727
  }
66673
66728
  }
66674
66729
 
66730
+
66675
66731
  function onChangeButtonSetup(
66676
66732
  completionPercentage,
66677
66733
  formData,
@@ -66680,6 +66736,8 @@ function onChangeButtonSetup(
66680
66736
  ) {
66681
66737
  const saveBtn = document.getElementById("saveBtn");
66682
66738
  const submitBtn = document.getElementById("submitBtn");
66739
+ const prevBtn = document.getElementById("prevBtn");
66740
+ const nextBtn = document.getElementById("nextBtn");
66683
66741
  if (!saveBtn || !submitBtn) return;
66684
66742
 
66685
66743
  const isPrivate = privateExternal === true || privateExternal === "true";
@@ -67042,6 +67100,11 @@ async function loadRNform(
67042
67100
  .then(() => {
67043
67101
  console.log("[FormIO] \u{1F680} formReady.then() triggered");
67044
67102
 
67103
+ // Handle Navigation and Button Hiding (Wizard-specific logic separated)
67104
+ if (typeof window.initializeWizardLogic === "function") {
67105
+ window.initializeWizardLogic(formObj, privateExternal, permission);
67106
+ }
67107
+
67045
67108
  if (formPreviousData) {
67046
67109
  console.log("[FormIO] \u{1F4E6} Previous form data found:", formPreviousData);
67047
67110
 
@@ -67063,7 +67126,7 @@ async function loadRNform(
67063
67126
  console.log("[FormIO] \u2705 Progress calculation completed");
67064
67127
 
67065
67128
  // Hide FormIO submit button component and wizard buttons in readOnly mode
67066
- if (mode == "readOnly") {
67129
+ if (mode == "readOnly" || permission == "read") {
67067
67130
  console.log("[FormIO] \u{1F512} ReadOnly mode detected");
67068
67131
 
67069
67132
  const submitComponents = document.querySelectorAll(
@@ -67078,41 +67141,17 @@ async function loadRNform(
67078
67141
  console.log(\`[FormIO] Hidden submit component \${index + 1}\`);
67079
67142
  });
67080
67143
 
67081
- const wizardNextBtns = document.querySelectorAll(
67082
- ".btn-wizard-nav-next"
67083
- );
67084
- console.log(
67085
- \`[FormIO] Found \${wizardNextBtns.length} wizard next buttons\`
67086
- );
67087
-
67088
- wizardNextBtns.forEach((btn, index) => {
67089
- btn.style.display = "none";
67090
- console.log(\`[FormIO] Hidden wizard next button \${index + 1}\`);
67091
- });
67092
-
67093
- const wizardSubmitBtns = document.querySelectorAll(
67094
- ".btn-wizard-nav-submit"
67095
- );
67096
- console.log(
67097
- \`[FormIO] Found \${wizardSubmitBtns.length} wizard submit buttons\`
67098
- );
67099
-
67100
- wizardSubmitBtns.forEach((btn, index) => {
67101
- btn.style.display = "none";
67102
- console.log(\`[FormIO] Hidden wizard submit button \${index + 1}\`);
67103
- });
67104
-
67105
- const wizardPrevBtns = document.querySelectorAll(
67106
- ".btn-wizard-nav-previous"
67107
- );
67108
- console.log(
67109
- \`[FormIO] Found \${wizardPrevBtns.length} wizard previous buttons\`
67110
- );
67111
-
67112
- wizardPrevBtns.forEach((btn, index) => {
67113
- btn.style.display = "none";
67114
- console.log(\`[FormIO] Hidden wizard previous button \${index + 1}\`);
67115
- });
67144
+ // Disable signature components robustly via CSS
67145
+ if (!document.getElementById("readonly-signature-style")) {
67146
+ const style = document.createElement("style");
67147
+ style.id = "readonly-signature-style";
67148
+ style.innerHTML = \`
67149
+ .formio-component-signature { pointer-events: none !important; }
67150
+ .formio-component-signature [ref="clicktoSign"],
67151
+ .formio-component-signature .click-to-sign-box { display: none !important; }
67152
+ \`;
67153
+ document.head.appendChild(style);
67154
+ }
67116
67155
  } else {
67117
67156
  console.log("[FormIO] \u{1F513} Editable mode detected");
67118
67157
  }
@@ -67257,6 +67296,11 @@ function buildMandatoryFieldsCache() {
67257
67296
  cacheMandatoryFields(comp.components, fieldPath);
67258
67297
  }
67259
67298
 
67299
+ // Nested forms
67300
+ if (comp.type === 'form' && comp.subForm && Array.isArray(comp.subForm.components)) {
67301
+ cacheMandatoryFields(comp.subForm.components, fieldPath ? \`\${fieldPath}.data\` : 'data');
67302
+ }
67303
+
67260
67304
  // Columns component handles children differently in instances?
67261
67305
  // Usually comp.columns is an array of objects which contain .components (instances)
67262
67306
  if (Array.isArray(comp.columns)) {
@@ -67290,13 +67334,16 @@ function buildMandatoryFieldsCache() {
67290
67334
  return cache;
67291
67335
  }
67292
67336
 
67293
- function executeProgressCalculation(privateExternal, permission) {
67337
+ window.executeProgressCalculation = function(privateExternal, permission) {
67294
67338
  if (!formObj) return;
67295
67339
 
67296
67340
  const data = formObj.data || {};
67297
67341
  const dataHash = JSON.stringify(data);
67342
+ const isWizard = formObj && !!formObj.wizard;
67298
67343
 
67299
- if (dataHash === lastDataHash) return;
67344
+ // For wizards, we must always proceed even if data is same,
67345
+ // because button visibility depends on the current page.
67346
+ if (!isWizard && dataHash === lastDataHash) return;
67300
67347
  lastDataHash = dataHash;
67301
67348
 
67302
67349
  const mandatoryFields = buildMandatoryFieldsCache();
@@ -67398,6 +67445,11 @@ function executeProgressCalculation(privateExternal, permission) {
67398
67445
  permission
67399
67446
  );
67400
67447
 
67448
+ // After setting up standard button visibility, override with wizard rules if applicable
67449
+ if (typeof window.updateWizardNav === "function") {
67450
+ window.updateWizardNav(formObj);
67451
+ }
67452
+
67401
67453
  // Update progress bar
67402
67454
  const progressBar = document.getElementById("progress-bar");
67403
67455
  if (progressBar) {
@@ -67678,6 +67730,12 @@ function FormOnSave() {
67678
67730
  }
67679
67731
 
67680
67732
  function FormOnBack() {
67733
+ // Do not ask for confirmation in read-only mode
67734
+ if (formObj && formObj.options && formObj.options.readOnly) {
67735
+ FormOnBackNavigation();
67736
+ return;
67737
+ }
67738
+
67681
67739
  let currentData;
67682
67740
  try {
67683
67741
  currentData = formObj ? formObj.getValue().data : null;
@@ -67685,10 +67743,10 @@ function FormOnBack() {
67685
67743
  currentData = null;
67686
67744
  }
67687
67745
 
67688
- const hasChanges =
67746
+ const noChanges =
67689
67747
  JSON.stringify(currentData) === JSON.stringify(initialFormData);
67690
67748
 
67691
- if (hasChanges) {
67749
+ if (noChanges) {
67692
67750
  FormOnBackNavigation();
67693
67751
  } else {
67694
67752
  showDynamicModal(
@@ -67740,18 +67798,19 @@ window.checkMoreButtonVisibility = function () {
67740
67798
  // For documentsOption, its display is managed by logic.
67741
67799
  // For comments/help, they are often just static items toggled.
67742
67800
 
67743
- const isVisible = (el) => el && el.style.display !== "none";
67744
-
67745
- // Assuming options.showComments/Help also imply the item SHOULD be visible if logic permits
67746
- // But logic might hide them. The 'isVisible' check handles dynamic logic.
67747
- // But for comments/help, they might be hidden initially.
67801
+ const isVisible = (el, optionKey) => {
67802
+ if (!el) return false;
67803
+ // If it's a static item like Help or Comments, check the options as well
67804
+ if (optionKey && options[optionKey] === true) return true;
67805
+ return el.style.display !== "none";
67806
+ };
67748
67807
 
67749
67808
  const hasVisibleItems =
67750
67809
  isVisible(completeOption) ||
67751
67810
  isVisible(saveOption) ||
67752
67811
  isVisible(documentsOption) ||
67753
- isVisible(commentsItem) ||
67754
- isVisible(helpItem); // Simplified: check actual DOM state
67812
+ isVisible(commentsItem, "showComments") ||
67813
+ isVisible(helpItem, "showHelp"); // Simplified: check actual DOM state + options
67755
67814
 
67756
67815
  // If ANY item is visible, show the button. Otherwise hide.
67757
67816
  if (hasVisibleItems) {
@@ -67769,6 +67828,28 @@ window.FormOnSave = FormOnSave;
67769
67828
  window.FormOnBack = FormOnBack;
67770
67829
  window.setImageData = setImageData;
67771
67830
  window.FormOnSubmit = FormOnSubmit;
67831
+ window.FormOnNext = function () {
67832
+ if (formObj && typeof formObj.nextPage === "function") {
67833
+ formObj.nextPage().then(() => {
67834
+ if (typeof window.updateWizardNav === "function") {
67835
+ window.updateWizardNav(formObj);
67836
+ }
67837
+ });
67838
+ }
67839
+ };
67840
+
67841
+ window.FormOnPrevious = function () {
67842
+ if (formObj && typeof formObj.prevPage === "function") {
67843
+ formObj.prevPage().then(() => {
67844
+ if (typeof window.updateWizardNav === "function") {
67845
+ window.updateWizardNav(formObj);
67846
+ }
67847
+ });
67848
+ }
67849
+ };
67850
+
67851
+ window.formOnSubmitFunction = FormOnSubmit;
67852
+
67772
67853
  window.resetFormCache = resetFormCache;
67773
67854
 
67774
67855
  // Notify that loadRNform is ready (for event-based coordination)
@@ -67778,6 +67859,174 @@ document.dispatchEvent(new CustomEvent('LoadRNformReady'));
67778
67859
 
67779
67860
  // === SCRIPT_SEPARATOR ===
67780
67861
 
67862
+ (function(){
67863
+ /**
67864
+ * Wizard Navigation Logic for Unvired Forms
67865
+ * This file handles all logic specific to Form.io wizard forms,
67866
+ * including navigation button visibility and event handling.
67867
+ */
67868
+
67869
+ /**
67870
+ * Updates the visibility of navigation buttons (Next, Previous, Submit)
67871
+ * based on the current wizard page and form type.
67872
+ *
67873
+ * @param {Object} formObj - The Form.io form instance
67874
+ */
67875
+ function updateWizardNav(formObj) {
67876
+ if (!formObj) return;
67877
+
67878
+ // 1. Hide default navigation and buttons (Next, Previous, Cancel, Submit)
67879
+ // This ensures that we only use our own footer buttons
67880
+ const selectorsToHide = [
67881
+ '.formio-component-wizard_nav',
67882
+ '.btn-wizard-nav-next',
67883
+ '.btn-wizard-nav-previous',
67884
+ '.btn-wizard-nav-cancel',
67885
+ '.btn-wizard-nav-submit'
67886
+ ];
67887
+
67888
+ selectorsToHide.forEach(selector => {
67889
+ const elements = formObj.element.querySelectorAll(selector);
67890
+ elements.forEach(el => {
67891
+ el.style.display = "none";
67892
+ });
67893
+ });
67894
+
67895
+ // 2. Hide components from JSON that match navigation actions
67896
+ if (typeof formObj.eachComponent === 'function') {
67897
+ formObj.eachComponent((component) => {
67898
+ if (component.type === 'button') {
67899
+ const action = (component.component.action || '').toLowerCase();
67900
+ const label = (component.component.label || '').toLowerCase();
67901
+
67902
+ if (action === 'next' || action === 'previous' || action === 'cancel' ||
67903
+ label === 'next' || label === 'previous' || label === 'cancel') {
67904
+ // Hide both the component instance and its DOM element
67905
+ component.visible = false;
67906
+ if (component.element) {
67907
+ component.element.style.display = 'none';
67908
+ }
67909
+ }
67910
+ }
67911
+ });
67912
+ }
67913
+
67914
+ // 3. Handle Footer Navigation Toggling (Only for Wizards)
67915
+ if (!formObj.wizard) return;
67916
+
67917
+ const prevBtn = document.getElementById("prevBtn");
67918
+ const nextBtn = document.getElementById("nextBtn");
67919
+ const submitBtn = document.getElementById("submitBtn");
67920
+ const saveBtn = document.getElementById("saveBtn");
67921
+
67922
+ const currentPage = formObj.page || 0;
67923
+ const numPages = (formObj.pages && formObj.pages.length) || 0;
67924
+ const isLastPage = (currentPage >= numPages - 1);
67925
+
67926
+ console.log(\`[WizardLogic] \u{1F9ED} Page: \${currentPage + 1}/\${numPages}, isLastPage: \${isLastPage}\`);
67927
+
67928
+ if (prevBtn) {
67929
+ prevBtn.style.display = currentPage > 0 ? "inline-block" : "none";
67930
+ }
67931
+
67932
+ if (nextBtn) {
67933
+ nextBtn.style.display = currentPage < numPages - 1 ? "inline-block" : "none";
67934
+ }
67935
+
67936
+ // If it's a wizard, we only want the save and submit buttons on the last page.
67937
+ // If it's NOT the last page, we force hide them.
67938
+ // If it IS the last page, we let the normal logic (onChangeButtonSetup) decide.
67939
+ if (!isLastPage) {
67940
+ console.log("[WizardLogic] \u{1F512} Intermediate page: Hiding save/complete actions");
67941
+ if (submitBtn) submitBtn.style.display = "none";
67942
+ if (saveBtn) saveBtn.style.display = "none";
67943
+
67944
+ // Hide dropdown options as well
67945
+ const completeOption = document.getElementById("completeOption");
67946
+ const saveOption = document.getElementById("saveOption");
67947
+ const completeDivider = document.getElementById("completeDivider");
67948
+ const saveDivider = document.getElementById("saveDivider");
67949
+
67950
+ if (completeOption) completeOption.style.display = "none";
67951
+ if (saveOption) saveOption.style.display = "none";
67952
+ if (completeDivider) completeDivider.style.display = "none";
67953
+ if (saveDivider) saveDivider.style.display = "none";
67954
+
67955
+ // Also hide quick action buttons if they exist
67956
+ const quickCompleteBtn = document.getElementById("quickCompleteBtn");
67957
+ const quickSaveBtn = document.getElementById("quickSaveBtn");
67958
+ if (quickCompleteBtn) quickCompleteBtn.style.display = "none";
67959
+ if (quickSaveBtn) quickSaveBtn.style.display = "none";
67960
+
67961
+ // Re-check More button visibility after hiding items
67962
+ if (typeof window.checkMoreButtonVisibility === "function") {
67963
+ window.checkMoreButtonVisibility();
67964
+ }
67965
+ } else {
67966
+ console.log("[WizardLogic] \u{1F513} Last page: Allowing normal button logic to take over");
67967
+ // On the last page, we MUST ensure the More button visibility is re-evaluated
67968
+ // because it might have been hidden on the previous page.
67969
+ if (typeof window.checkMoreButtonVisibility === "function") {
67970
+ window.checkMoreButtonVisibility();
67971
+ }
67972
+ }
67973
+ }
67974
+
67975
+ /**
67976
+ * Sets up event listeners for wizard-specific events like page changes.
67977
+ *
67978
+ * @param {Object} formObj - The Form.io form instance
67979
+ * @param {Boolean} privateExternal - Private/External flag
67980
+ * @param {String} permission - User permission level
67981
+ */
67982
+ function setupWizardEvents(formObj, privateExternal, permission) {
67983
+ if (!formObj) return;
67984
+
67985
+ if (formObj.wizard) {
67986
+ formObj.on('nextPage', () => {
67987
+ updateWizardNav(formObj);
67988
+ // Trigger progress calculation on page change
67989
+ if (typeof window.executeProgressCalculation === 'function') {
67990
+ window.executeProgressCalculation(privateExternal, permission);
67991
+ }
67992
+ });
67993
+ formObj.on('prevPage', () => {
67994
+ updateWizardNav(formObj);
67995
+ // Trigger progress calculation on page change
67996
+ if (typeof window.executeProgressCalculation === 'function') {
67997
+ window.executeProgressCalculation(privateExternal, permission);
67998
+ }
67999
+ });
68000
+ }
68001
+
68002
+ // Always handle render event to ensure buttons stay hidden
68003
+ formObj.on('render', () => {
68004
+ updateWizardNav(formObj);
68005
+ });
68006
+ }
68007
+
68008
+ window.updateWizardNav = updateWizardNav;
68009
+
68010
+ /**
68011
+ * Main initialization function for wizard logic.
68012
+ * Should be called after the Form.io form is created.
68013
+ */
68014
+ window.initializeWizardLogic = function(formObj, privateExternal, permission) {
68015
+ console.log("[WizardLogic] \u{1F9D9} Initializing wizard-specific logic...");
68016
+ setupWizardEvents(formObj, privateExternal, permission);
68017
+
68018
+ // Also listen for change events to update nav (e.g. if pages are conditionally hidden)
68019
+ formObj.on('change', () => {
68020
+ updateWizardNav(formObj);
68021
+ });
68022
+
68023
+ updateWizardNav(formObj);
68024
+ };
68025
+
68026
+ })();
68027
+
68028
+ // === SCRIPT_SEPARATOR ===
68029
+
67781
68030
  (function(){
67782
68031
  async function loadCommentsform(
67783
68032
  template,
@@ -68040,19 +68289,28 @@ window.CommentOnBack = CommentOnBack;
68040
68289
  window.__unviredSdkScriptsLoading = false;
68041
68290
  throw error;
68042
68291
  }
68043
- for (let i = 1; i <= 2; i++) {
68044
- if (scriptContents[i] && scriptContents[i].trim()) {
68045
- const scriptElement = document.createElement("script");
68046
- scriptElement.textContent = scriptContents[i];
68047
- scriptElement.setAttribute("data-unvired-script", `recogito-${i}`);
68048
- document.head.appendChild(scriptElement);
68292
+ if (options.showComments) {
68293
+ for (let i = 1; i <= 2; i++) {
68294
+ if (scriptContents[i] && scriptContents[i].trim()) {
68295
+ const scriptElement = document.createElement("script");
68296
+ scriptElement.textContent = scriptContents[i];
68297
+ scriptElement.setAttribute("data-unvired-script", `recogito-${i}`);
68298
+ document.head.appendChild(scriptElement);
68299
+ await new Promise((r) => setTimeout(r, 0));
68300
+ }
68049
68301
  }
68302
+ } else {
68303
+ console.log("[SDK:10.3] \u26A1 Skipping Recogito (comments disabled, optimized load)");
68050
68304
  }
68051
- if (scriptContents[3] && scriptContents[3].trim()) {
68305
+ const hasThemeOverrides = options.themeData && Object.keys(options.themeData).length > 0;
68306
+ if (hasThemeOverrides && scriptContents[3] && scriptContents[3].trim()) {
68052
68307
  const lessScript = document.createElement("script");
68053
68308
  lessScript.textContent = scriptContents[3];
68054
68309
  lessScript.setAttribute("data-unvired-script", "less");
68055
68310
  document.head.appendChild(lessScript);
68311
+ } else {
68312
+ console.log("[SDK:10.4] \u26A1 Skipping LESS.js (no theme overrides, optimized load)");
68313
+ window.less = window.less || { modifyVars: () => Promise.resolve() };
68056
68314
  }
68057
68315
  window.form = window.form || {};
68058
68316
  window.platform = window.platform || {};
@@ -68075,6 +68333,9 @@ window.CommentOnBack = CommentOnBack;
68075
68333
  scriptElement.textContent = scriptContent;
68076
68334
  scriptElement.setAttribute("data-unvired-script", `script-${i}`);
68077
68335
  document.head.appendChild(scriptElement);
68336
+ if (i % 5 === 0) {
68337
+ await new Promise((r) => setTimeout(r, 0));
68338
+ }
68078
68339
  }
68079
68340
  }
68080
68341
  window.__unviredSdkScriptsLoaded = true;
@@ -68300,7 +68561,7 @@ window.deleteAppDocument = async function(id) {
68300
68561
  window.getAllDocuments = getAllDocuments;
68301
68562
  window.hasDocuments = hasDocuments;
68302
68563
  function getBuildVersion() {
68303
- return "1.0.22";
68564
+ return "1.0.29";
68304
68565
  }
68305
68566
  export {
68306
68567
  getBuildVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unvired/turboforms-embed-sdk",
3
- "version": "1.0.22",
3
+ "version": "1.0.29",
4
4
  "description": "Reusable vanilla JS form library that works with React, Angular, Ionic, etc.",
5
5
  "main": "dist/unvired-forms-sdk.js",
6
6
  "types": "dist/index.d.ts",