@hubsync/esign-web-sdk 6.9.12 → 6.9.14

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.
@@ -434,11 +434,9 @@ const VerdocsSign = class {
434
434
  }
435
435
  focusNextFieldAfter(field) {
436
436
  setTimeout(() => {
437
- const fields = this.getSortedFillableFields();
438
- const currentIndex = fields.findIndex(f => f.name === field.name);
439
- if (currentIndex >= 0 && currentIndex < fields.length - 1) {
440
- this.focusFieldElement(fields[currentIndex + 1]);
441
- }
437
+ const next = this.getNextUnfilledField(field);
438
+ if (next)
439
+ this.focusFieldElement(next);
442
440
  }, 100);
443
441
  }
444
442
  focusFieldElement(field) {
@@ -453,11 +451,6 @@ const VerdocsSign = class {
453
451
  handleStartSigning() {
454
452
  this.markEnvelopeStarted();
455
453
  this.signingProgressMode = 'signing';
456
- const fields = this.getSortedFillableFields();
457
- const startField = fields.find(field => !this.isFieldActuallyFilled(field)) || fields[0];
458
- if (startField) {
459
- this.focusFieldElement(startField);
460
- }
461
454
  this.adoptingSignature = true;
462
455
  }
463
456
  async handleFieldChange(field, e) {
@@ -490,6 +483,7 @@ const VerdocsSign = class {
490
483
  }
491
484
  if (e.detail === null) {
492
485
  console.log('[SIGN] Clearing initial');
486
+ this.initialId = null;
493
487
  const updateResult = await jsSdk.updateEnvelopeField(this.endpoint, this.envelopeId, this.roleId, field.name, null, false);
494
488
  return this.updateRecipientFieldValue(field.name, updateResult);
495
489
  }
@@ -535,6 +529,7 @@ const VerdocsSign = class {
535
529
  }
536
530
  if (e.detail === null) {
537
531
  console.log('[SIGN] Clearing signature');
532
+ this.signatureId = null;
538
533
  const updateResult = await jsSdk.updateEnvelopeField(this.endpoint, this.envelopeId, this.roleId, field.name, null, false);
539
534
  return this.updateRecipientFieldValue(field.name, updateResult);
540
535
  }
@@ -600,6 +595,20 @@ const VerdocsSign = class {
600
595
  async handleNext() {
601
596
  var _a;
602
597
  if (this.nextSubmits) {
598
+ // Re-verify required fields synchronously before submitting. nextSubmits can be stale if
599
+ // a text field was cleared but not yet blurred before the button was clicked — the focusout
600
+ // save is async, so the local value hasn't updated by the time onClick fires.
601
+ const allFields = this.getSortedFillableFields();
602
+ const requiredIncomplete = allFields.some(f => f.required && !this.isFieldActuallyFilled(f));
603
+ if (requiredIncomplete) {
604
+ this.nextSubmits = false;
605
+ this.nextButtonLabel = 'Next';
606
+ const currentField = allFields.find(f => f.name === this.focusedField);
607
+ const next = this.getNextUnfilledField(currentField);
608
+ if (next)
609
+ this.focusFieldElement(next);
610
+ return;
611
+ }
603
612
  try {
604
613
  // Patches the date picker to be forcibly removed if still showing during submission
605
614
  (_a = document.getElementById('air-datepicker-global-container')) === null || _a === void 0 ? void 0 : _a.remove();
@@ -618,12 +627,10 @@ const VerdocsSign = class {
618
627
  }
619
628
  return;
620
629
  }
621
- // Find all unfilled fields and move to the next one in sequence
622
- const allUnfilled = this.getSortedFillableFields().filter(f => !this.isFieldActuallyFilled(f));
623
- const nextUnfilled = this.getNextFieldFromList(allUnfilled);
624
- if (nextUnfilled) {
625
- this.focusFieldElement(nextUnfilled);
626
- }
630
+ const currentField = this.getSortedFillableFields().find(f => f.name === this.focusedField);
631
+ const next = this.getNextUnfilledField(currentField);
632
+ if (next)
633
+ this.focusFieldElement(next);
627
634
  }
628
635
  handleNextOptional() {
629
636
  const unfilledOptional = this.getSortedFillableFields().filter(f => !f.required && !this.isFieldActuallyFilled(f));
@@ -647,8 +654,10 @@ const VerdocsSign = class {
647
654
  }
648
655
  // See if everything that "needs to be" filled in is, and all "fillable fields" are valid
649
656
  checkRecipientFields() {
650
- const invalidFields = this.getRecipientFields().filter(field => !jsSdk.isFieldValid(field, this.getRecipientFields()));
651
- if (invalidFields.length < 1) {
657
+ const allFields = this.getSortedFillableFields();
658
+ const requiredIncomplete = allFields.some(f => f.required && !this.isFieldActuallyFilled(f));
659
+ const invalidFilled = allFields.some(f => this.isFieldActuallyFilled(f) && !jsSdk.isFieldValid(f, this.getRecipientFields()));
660
+ if (!requiredIncomplete && !invalidFilled) {
652
661
  this.nextButtonLabel = 'Finish';
653
662
  if (!this.nextSubmits) {
654
663
  this.nextSubmits = true;
@@ -692,20 +701,15 @@ const VerdocsSign = class {
692
701
  (field.type !== 'radio' || field.value === 'true') &&
693
702
  (field.type !== 'checkbox' || field.value === 'true'));
694
703
  }
695
- getNextRequiredField() {
696
- // Find and focus the next incomplete field (that is fillable)
697
- const emptyFields = this.getSortedFillableFields().filter(field => field.required && !this.isFieldActuallyFilled(field));
698
- jsSdk.sortFields(emptyFields);
699
- if (emptyFields.length === 0) {
700
- const allUnfilled = this.getSortedFillableFields().filter(field => !this.isFieldActuallyFilled(field));
701
- jsSdk.sortFields(allUnfilled);
702
- if (allUnfilled.length > 0) {
703
- // If we are here, there are no required fields left, but there are optional ones.
704
- return this.getNextFieldFromList(allUnfilled);
705
- }
706
- return null;
707
- }
708
- return this.getNextFieldFromList(emptyFields);
704
+ getNextUnfilledField(after) {
705
+ const allFields = this.getSortedFillableFields();
706
+ const startIndex = after ? allFields.findIndex(f => f.name === after.name) + 1 : 0;
707
+ // Look forward from current position first
708
+ const nextAfter = allFields.slice(startIndex).find(f => !this.isFieldActuallyFilled(f));
709
+ if (nextAfter)
710
+ return nextAfter;
711
+ // Wrap to beginning if nothing unfilled ahead
712
+ return allFields.slice(0, startIndex).find(f => !this.isFieldActuallyFilled(f)) || null;
709
713
  }
710
714
  getNextFieldFromList(fields) {
711
715
  const focusedIndex = fields.findIndex(field => field.name === this.focusedField);
@@ -738,14 +742,16 @@ const VerdocsSign = class {
738
742
  // Remove existing flags
739
743
  const existingFlags = controlsDiv.querySelectorAll('.verdocs-flag-instance');
740
744
  existingFlags.forEach(el => el.remove());
741
- let nextField = this.getNextRequiredField();
742
745
  const focusedFieldObj = this.getRecipientFields().find(f => f.name === this.focusedField);
743
- // If the currently focused field is unfilled, we should point the flag to IT, not the next one.
744
- // getNextRequiredField() is designed for the "Next" button (skipping current), but the visual flag
745
- // should guide the user to the current task if it's incomplete.
746
+ // If the currently focused field is unfilled, point the flag to it.
747
+ // Otherwise find the next unfilled field forward from the current position.
748
+ let nextField;
746
749
  if (focusedFieldObj && !this.isFieldActuallyFilled(focusedFieldObj)) {
747
750
  nextField = focusedFieldObj;
748
751
  }
752
+ else {
753
+ nextField = this.getNextUnfilledField(focusedFieldObj);
754
+ }
749
755
  if (nextField && nextField.page === pageInfo.pageNumber && nextField.document_id === pageInfo.documentId) {
750
756
  const variant = 'fill';
751
757
  let label = 'FILL';
@@ -1082,7 +1088,7 @@ const VerdocsSign = class {
1082
1088
  return (index.h("span", { class: "remaining-count" }, remaining, " required field", remaining === 1 ? '' : 's', " left"));
1083
1089
  }
1084
1090
  return (index.h("span", { class: "remaining-count" }, index.h("span", { class: "check-icon", innerHTML: Icons.CheckCircleIcon }), "All required fields complete", optionalLeft > 0 && index.h("span", { class: "separator" }, "|"), optionalLeft > 0 && (index.h("span", { class: "review-optional", onClick: () => this.handleNextOptional() }, "Review ", optionalLeft, " optional"))));
1085
- })(), !this.finishLater && (index.h("verdocs-button", { size: "xsmall", label: this.nextButtonLabel === 'Next' ? 'Next Required' : this.nextButtonLabel, disabled: !this.agreed || this.submitting, onClick: () => this.handleNext() })), index.h("div", { class: { 'icon-button': true, 'minus': true, 'disabled': this.zoomLevel === 'normal' }, innerHTML: ToolbarMinusIcon, onClick: () => this.handleZoomOut() }), index.h("div", { class: { 'icon-button': true, 'plus': true, 'disabled': this.zoomLevel === 'zoom2' }, innerHTML: ToolbarPlusIcon, onClick: () => this.handleZoomIn() }), index.h("verdocs-dropdown", { options: !this.isDone && !this.finishLater ? inProgressMenuOptions : doneMenuOptions, onOptionSelected: e => this.handleOptionSelected(e) })))), this.toolbarStyle === 'controls' && (index.h("div", { class: "controls-toolbar" }, index.h("div", { class: "left-controls" }, index.h("div", { class: "title" }, this.envelope.name)), index.h("div", { class: "center-controls", style: { display: 'none' } }, index.h("span", { class: "label" }, "Page"), index.h("div", { class: "select-wrapper" }, index.h("verdocs-select-input", { options: pageOptions, value: this.pageNumber.toString(), onInput: e => this.handlePageSelect(e) })), index.h("span", { class: "count" }, "of ", totalPages)), index.h("div", { class: "right-controls" }, index.h("verdocs-button", { class: "mobile-next-button", label: this.nextButtonLabel, size: "xsmall", disabled: !this.agreed || this.submitting, onClick: () => this.handleNext() }), index.h("div", { class: { 'icon-button': true, 'minus': true, 'disabled': this.zoomLevel === 'normal' }, innerHTML: ToolbarMinusIcon, onClick: () => this.handleZoomOut() }), index.h("div", { class: { 'icon-button': true, 'plus': true, 'disabled': this.zoomLevel === 'zoom2' }, innerHTML: ToolbarPlusIcon, onClick: () => this.handleZoomIn() }), index.h("div", { class: "icon-button download", innerHTML: ToolbarDownloadIcon, onClick: () => this.handleOptionSelected({ detail: { id: 'download' } }) }), index.h("div", { class: "icon-button print", innerHTML: ToolbarPrintIcon, onClick: () => this.handleOptionSelected({ detail: { id: 'print' } }) })))), index.h("verdocs-signing-progress", { mode: this.signingProgressMode, focusedField: this.focusedField, fields: this.getSortedFillableFields(), recipientFields: this.getRecipientFields(), onStarted: () => {
1091
+ })(), !this.finishLater && (index.h("verdocs-button", { size: "xsmall", label: this.nextButtonLabel, disabled: !this.agreed || this.submitting, onClick: () => this.handleNext() })), index.h("div", { class: { 'icon-button': true, 'minus': true, 'disabled': this.zoomLevel === 'normal' }, innerHTML: ToolbarMinusIcon, onClick: () => this.handleZoomOut() }), index.h("div", { class: { 'icon-button': true, 'plus': true, 'disabled': this.zoomLevel === 'zoom2' }, innerHTML: ToolbarPlusIcon, onClick: () => this.handleZoomIn() }), index.h("verdocs-dropdown", { options: !this.isDone && !this.finishLater ? inProgressMenuOptions : doneMenuOptions, onOptionSelected: e => this.handleOptionSelected(e) })))), this.toolbarStyle === 'controls' && (index.h("div", { class: "controls-toolbar" }, index.h("div", { class: "left-controls" }, index.h("div", { class: "title" }, this.envelope.name)), index.h("div", { class: "center-controls", style: { display: 'none' } }, index.h("span", { class: "label" }, "Page"), index.h("div", { class: "select-wrapper" }, index.h("verdocs-select-input", { options: pageOptions, value: this.pageNumber.toString(), onInput: e => this.handlePageSelect(e) })), index.h("span", { class: "count" }, "of ", totalPages)), index.h("div", { class: "right-controls" }, index.h("verdocs-button", { class: "mobile-next-button", label: this.nextButtonLabel, size: "xsmall", disabled: !this.agreed || this.submitting, onClick: () => this.handleNext() }), index.h("div", { class: { 'icon-button': true, 'minus': true, 'disabled': this.zoomLevel === 'normal' }, innerHTML: ToolbarMinusIcon, onClick: () => this.handleZoomOut() }), index.h("div", { class: { 'icon-button': true, 'plus': true, 'disabled': this.zoomLevel === 'zoom2' }, innerHTML: ToolbarPlusIcon, onClick: () => this.handleZoomIn() }), index.h("div", { class: "icon-button download", innerHTML: ToolbarDownloadIcon, onClick: () => this.handleOptionSelected({ detail: { id: 'download' } }) }), index.h("div", { class: "icon-button print", innerHTML: ToolbarPrintIcon, onClick: () => this.handleOptionSelected({ detail: { id: 'print' } }) })))), index.h("verdocs-signing-progress", { mode: this.signingProgressMode, focusedField: this.focusedField, fields: this.getSortedFillableFields(), recipientFields: this.getRecipientFields(), onStarted: () => {
1086
1092
  this.handleStartSigning();
1087
1093
  }, onNext: () => this.handleNext(), onPrevious: () => this.handlePrev(), onExit: () => this.handleNext() }), index.h("div", { class: `document signed-document-container zoom-${this.zoomLevel}` }, (this.envelope.documents || []).map(envelopeDocument => {
1088
1094
  const pageNumbers = jsSdk.integerSequence(1, envelopeDocument.pages);
@@ -1123,7 +1129,10 @@ const VerdocsSign = class {
1123
1129
  this.showSpinner = false;
1124
1130
  this.adoptingSignature = false;
1125
1131
  this.markEnvelopeStarted();
1126
- // Apply the new signature/initials to the field that triggered the dialog.
1132
+ // Apply the new signature/initials to the field that triggered the dialog (e.g. user
1133
+ // clicked an existing sig/initial field). Track which field was applied so we can
1134
+ // advance forward from it rather than jumping back to the start of the document.
1135
+ let appliedToField = null;
1127
1136
  if (this.focusedField) {
1128
1137
  const fieldObj = this.getRecipientFields().find(f => f.name === this.focusedField);
1129
1138
  if (fieldObj) {
@@ -1131,10 +1140,16 @@ const VerdocsSign = class {
1131
1140
  if (id) {
1132
1141
  const updateResult = await jsSdk.updateEnvelopeField(this.endpoint, this.envelopeId, this.roleId, fieldObj.name, id, false);
1133
1142
  this.updateRecipientFieldValue(fieldObj.name, updateResult);
1143
+ appliedToField = fieldObj;
1134
1144
  }
1135
1145
  }
1136
1146
  this.focusedField = '';
1137
1147
  }
1148
+ // Navigate to the next unfilled field: forward from where we applied (or from the
1149
+ // beginning when adopting at session start with no pre-focused field).
1150
+ const nextField = this.getNextUnfilledField(appliedToField !== null && appliedToField !== void 0 ? appliedToField : undefined);
1151
+ if (nextField)
1152
+ this.focusFieldElement(nextField);
1138
1153
  // Update any existing field elements in the DOM with the new IDs. This prevents them from
1139
1154
  // needing to show the adoption dialog again if they are clicked.
1140
1155
  const sigFields = this.el.querySelectorAll('verdocs-field-signature');