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