@forgeroute/ui 0.4.57 → 0.4.58

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.
@@ -1,6 +1,9 @@
1
1
  import { isPlatformBrowser } from "@angular/common";
2
2
  import * as i0 from "@angular/core";
3
3
  import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, InjectionToken, Injector, PLATFORM_ID, afterNextRender, computed, effect, inject, input, makeEnvironmentProviders, output, signal, untracked } from "@angular/core";
4
+ import { AlertComponent, ButtonComponent, DetailCardComponent, HintComponent, IconComponent, ModalComponent, SectionHeaderComponent, SkeletonComponent, StackComponent, TextInputComponent } from "@forgeroute/ui";
5
+ import * as i1 from "@angular/forms";
6
+ import { FormsModule } from "@angular/forms";
4
7
  const PDF_VIEWER_WORKER_SRC = new InjectionToken("PDF_VIEWER_WORKER_SRC", {
5
8
  providedIn: "root",
6
9
  factory: () => ""
@@ -48,12 +51,14 @@ var PdfViewerComponent = class PdfViewerComponent {
48
51
  this.maxPageWidth = input(DEFAULT_MAX_WIDTH, ...ngDevMode ? [{ debugName: "maxPageWidth" }] : /* istanbul ignore next */ []);
49
52
  this.pixelRatio = input(null, ...ngDevMode ? [{ debugName: "pixelRatio" }] : /* istanbul ignore next */ []);
50
53
  this.fields = input([], ...ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []);
54
+ this.hotspots = input([], ...ngDevMode ? [{ debugName: "hotspots" }] : /* istanbul ignore next */ []);
51
55
  this.ariaLabel = input("", ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
52
56
  this.loadingText = input("Loading document…", ...ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []);
53
57
  this.errorText = input("Failed to load document.", ...ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []);
54
58
  this.unsupportedText = input("This browser can't show the document preview.", ...ngDevMode ? [{ debugName: "unsupportedText" }] : /* istanbul ignore next */ []);
55
59
  this.openText = input("Open the document", ...ngDevMode ? [{ debugName: "openText" }] : /* istanbul ignore next */ []);
56
60
  this.checkBrowserSupport = input(true, ...ngDevMode ? [{ debugName: "checkBrowserSupport" }] : /* istanbul ignore next */ []);
61
+ this.hotspotActivate = output();
57
62
  this.loaded = output();
58
63
  this.loadFailed = output();
59
64
  this.pagesRendered = output();
@@ -121,13 +126,22 @@ var PdfViewerComponent = class PdfViewerComponent {
121
126
  fontPx: Math.max(9, h * scale * .7)
122
127
  };
123
128
  });
129
+ const hotspots = this.hotspots().filter((h) => h.page === i + 1).map((h) => ({
130
+ hotspot: h,
131
+ left: h.x / size.width * 100,
132
+ top: (size.height - h.y - h.height) / size.height * 100,
133
+ width: h.width / size.width * 100,
134
+ height: h.height / size.height * 100,
135
+ fontPx: Math.max(7, Math.min(11, h.height * scale * .25))
136
+ }));
124
137
  return {
125
138
  number: i + 1,
126
139
  cssWidth,
127
140
  cssHeight,
128
141
  canvasWidth: sized[i].w,
129
142
  canvasHeight: sized[i].h,
130
- fields
143
+ fields,
144
+ hotspots
131
145
  };
132
146
  });
133
147
  }, ...ngDevMode ? [{ debugName: "views" }] : /* istanbul ignore next */ []);
@@ -421,6 +435,13 @@ var PdfViewerComponent = class PdfViewerComponent {
421
435
  isRequired: false,
422
436
  transformFunction: null
423
437
  },
438
+ hotspots: {
439
+ classPropertyName: "hotspots",
440
+ publicName: "hotspots",
441
+ isSignal: true,
442
+ isRequired: false,
443
+ transformFunction: null
444
+ },
424
445
  ariaLabel: {
425
446
  classPropertyName: "ariaLabel",
426
447
  publicName: "ariaLabel",
@@ -465,6 +486,7 @@ var PdfViewerComponent = class PdfViewerComponent {
465
486
  }
466
487
  },
467
488
  outputs: {
489
+ hotspotActivate: "hotspotActivate",
468
490
  loaded: "loaded",
469
491
  loadFailed: "loadFailed",
470
492
  pagesRendered: "pagesRendered"
@@ -498,6 +520,20 @@ var PdfViewerComponent = class PdfViewerComponent {
498
520
  <span class="pv-field-label">{{ f.label }}</span>
499
521
  </div>
500
522
  }
523
+ @for (h of p.hotspots; track h.hotspot.id) {
524
+ <div class="pv-hotspot" [attr.data-state]="h.hotspot.state" [attr.data-testid]="'pdf-hotspot-' + h.hotspot.id"
525
+ [style.left.%]="h.left" [style.top.%]="h.top" [style.width.%]="h.width" [style.height.%]="h.height">
526
+ @if (h.hotspot.state === 'signed' && h.hotspot.image) {
527
+ <img class="pv-hotspot-image" [src]="h.hotspot.image" [alt]="h.hotspot.imageAlt || 'Applied signature'" />
528
+ } @else {
529
+ <button type="button" class="pv-hotspot-button" [class.pv-hotspot-ready]="h.hotspot.state === 'ready'"
530
+ [disabled]="h.hotspot.state !== 'ready'" [attr.aria-label]="h.hotspot.ariaLabel || null"
531
+ [style.font-size.px]="h.fontPx" (click)="hotspotActivate.emit(h.hotspot.id)">
532
+ <span class="pv-hotspot-text">{{ h.hotspot.state === 'blocked' ? (h.hotspot.blockedLabel || h.hotspot.label || '') : (h.hotspot.label || '') }}</span>
533
+ </button>
534
+ }
535
+ </div>
536
+ }
501
537
  </div>
502
538
  }
503
539
  </div>
@@ -506,7 +542,7 @@ var PdfViewerComponent = class PdfViewerComponent {
506
542
  </div>
507
543
  `,
508
544
  isInline: true,
509
- styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live,.pv-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-unsupported{flex-direction:column;gap:8px;color:#334155}.pv-unsupported-text{margin:0}.pv-open{display:inline-flex;align-items:center;justify-content:center;position:relative;min-height:44px;min-width:44px;padding:0 16px;box-sizing:border-box;color:#1d4ed8;font-weight:600;text-decoration:underline;border-radius:6px}.pv-open:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"],
545
+ styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live,.pv-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-unsupported{flex-direction:column;gap:8px;color:#334155}.pv-unsupported-text{margin:0}.pv-open{display:inline-flex;align-items:center;justify-content:center;position:relative;min-height:44px;min-width:44px;padding:0 16px;box-sizing:border-box;color:#1d4ed8;font-weight:600;text-decoration:underline;border-radius:6px}.pv-open:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-hotspot{position:absolute;box-sizing:border-box}.pv-hotspot-image{display:block;width:100%;height:100%;object-fit:contain;object-position:left}.pv-hotspot-button{position:relative;box-sizing:border-box;width:100%;height:100%;white-space:nowrap;font:inherit;font-weight:500;line-height:1;border:2px solid #d1d5db;background:#f3f4f6;color:#9ca3af;cursor:not-allowed;box-shadow:0 4px 10px #0000002e}.pv-hotspot-button.pv-hotspot-ready{border-color:#2563eb;background:#dbeafe;color:#1d4ed8;cursor:pointer}.pv-hotspot-button.pv-hotspot-ready:hover{background:#bfdbfe}.pv-hotspot-button:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.pv-hotspot-text{display:block;overflow:hidden;text-overflow:ellipsis;line-height:1.2}@media(pointer:coarse){.pv-hotspot-button:after{content:\"\";position:absolute;left:0;right:0;top:50%;height:100%;min-height:44px;transform:translateY(-50%)}}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"],
510
546
  changeDetection: i0.ChangeDetectionStrategy.OnPush
511
547
  });
512
548
  }
@@ -550,6 +586,20 @@ i0.ɵɵngDeclareClassMetadata({
550
586
  <span class="pv-field-label">{{ f.label }}</span>
551
587
  </div>
552
588
  }
589
+ @for (h of p.hotspots; track h.hotspot.id) {
590
+ <div class="pv-hotspot" [attr.data-state]="h.hotspot.state" [attr.data-testid]="'pdf-hotspot-' + h.hotspot.id"
591
+ [style.left.%]="h.left" [style.top.%]="h.top" [style.width.%]="h.width" [style.height.%]="h.height">
592
+ @if (h.hotspot.state === 'signed' && h.hotspot.image) {
593
+ <img class="pv-hotspot-image" [src]="h.hotspot.image" [alt]="h.hotspot.imageAlt || 'Applied signature'" />
594
+ } @else {
595
+ <button type="button" class="pv-hotspot-button" [class.pv-hotspot-ready]="h.hotspot.state === 'ready'"
596
+ [disabled]="h.hotspot.state !== 'ready'" [attr.aria-label]="h.hotspot.ariaLabel || null"
597
+ [style.font-size.px]="h.fontPx" (click)="hotspotActivate.emit(h.hotspot.id)">
598
+ <span class="pv-hotspot-text">{{ h.hotspot.state === 'blocked' ? (h.hotspot.blockedLabel || h.hotspot.label || '') : (h.hotspot.label || '') }}</span>
599
+ </button>
600
+ }
601
+ </div>
602
+ }
553
603
  </div>
554
604
  }
555
605
  </div>
@@ -557,7 +607,7 @@ i0.ɵɵngDeclareClassMetadata({
557
607
  }
558
608
  </div>
559
609
  `,
560
- styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live,.pv-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-unsupported{flex-direction:column;gap:8px;color:#334155}.pv-unsupported-text{margin:0}.pv-open{display:inline-flex;align-items:center;justify-content:center;position:relative;min-height:44px;min-width:44px;padding:0 16px;box-sizing:border-box;color:#1d4ed8;font-weight:600;text-decoration:underline;border-radius:6px}.pv-open:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"]
610
+ styles: [":host{display:block;width:100%}.pv-root{position:relative}.pv-live,.pv-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pv-state{display:flex;align-items:center;justify-content:center;width:100%;min-height:12rem;padding:0 16px;text-align:center;font-size:.8125rem;line-height:1.4;overflow-wrap:anywhere;box-sizing:border-box}.pv-loading{color:#64748b}.pv-error{color:#dc2626}.pv-unsupported{flex-direction:column;gap:8px;color:#334155}.pv-unsupported-text{margin:0}.pv-open{display:inline-flex;align-items:center;justify-content:center;position:relative;min-height:44px;min-width:44px;padding:0 16px;box-sizing:border-box;color:#1d4ed8;font-weight:600;text-decoration:underline;border-radius:6px}.pv-open:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px}.pv-pages{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%}.pv-page{position:relative;margin:0 auto;max-width:100%}.pv-canvas{display:block;width:100%;height:auto;background:#fff;border-radius:2px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.pv-field{position:absolute;display:flex;align-items:center;box-sizing:border-box;padding:0 4px;overflow:hidden;pointer-events:none;border:1px solid;border-radius:2px;-webkit-user-select:none;user-select:none}.pv-field-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1}.pv-hotspot{position:absolute;box-sizing:border-box}.pv-hotspot-image{display:block;width:100%;height:100%;object-fit:contain;object-position:left}.pv-hotspot-button{position:relative;box-sizing:border-box;width:100%;height:100%;white-space:nowrap;font:inherit;font-weight:500;line-height:1;border:2px solid #d1d5db;background:#f3f4f6;color:#9ca3af;cursor:not-allowed;box-shadow:0 4px 10px #0000002e}.pv-hotspot-button.pv-hotspot-ready{border-color:#2563eb;background:#dbeafe;color:#1d4ed8;cursor:pointer}.pv-hotspot-button.pv-hotspot-ready:hover{background:#bfdbfe}.pv-hotspot-button:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.pv-hotspot-text{display:block;overflow:hidden;text-overflow:ellipsis;line-height:1.2}@media(pointer:coarse){.pv-hotspot-button:after{content:\"\";position:absolute;left:0;right:0;top:50%;height:100%;min-height:44px;transform:translateY(-50%)}}.pv-tone-blue{background:#dbeafe;border-color:#93c5fd;color:#1d4ed8}.pv-tone-green{background:#dcfce7;border-color:#86efac;color:#15803d}.pv-tone-amber{background:#fef3c7;border-color:#fcd34d;color:#92400e}.pv-tone-red{background:#fee2e2;border-color:#fca5a5;color:#b91c1c}.pv-tone-slate{background:#f1f5f9;border-color:#cbd5e1;color:#334155}\n"]
561
611
  }]
562
612
  }],
563
613
  ctorParameters: () => [],
@@ -626,6 +676,14 @@ i0.ɵɵngDeclareClassMetadata({
626
676
  required: false
627
677
  }]
628
678
  }],
679
+ hotspots: [{
680
+ type: i0.Input,
681
+ args: [{
682
+ isSignal: true,
683
+ alias: "hotspots",
684
+ required: false
685
+ }]
686
+ }],
629
687
  ariaLabel: [{
630
688
  type: i0.Input,
631
689
  args: [{
@@ -674,6 +732,10 @@ i0.ɵɵngDeclareClassMetadata({
674
732
  required: false
675
733
  }]
676
734
  }],
735
+ hotspotActivate: [{
736
+ type: i0.Output,
737
+ args: ["hotspotActivate"]
738
+ }],
677
739
  loaded: [{
678
740
  type: i0.Output,
679
741
  args: ["loaded"]
@@ -696,6 +758,1114 @@ function provideForgeroutePdf(options) {
696
758
  useValue: workerSrc
697
759
  }]);
698
760
  }
699
- export { PDF_VIEWER_REQUIRED_FEATURES, PDF_VIEWER_WORKER_SRC, PdfViewerComponent, PdfViewerUnsupportedError, findMissingPdfFeatures, provideForgeroutePdf };
761
+ var DocumentViewerModalComponent = class DocumentViewerModalComponent {
762
+ constructor() {
763
+ this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
764
+ this.fileName = input("Document", ...ngDevMode ? [{ debugName: "fileName" }] : /* istanbul ignore next */ []);
765
+ this.data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
766
+ this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
767
+ this.error = input("", ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
768
+ this.loadingText = input("Loading document…", ...ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []);
769
+ this.closed = output();
770
+ this.hasData = computed(() => !!this.data() && !this.loading() && !this.error(), ...ngDevMode ? [{ debugName: "hasData" }] : /* istanbul ignore next */ []);
771
+ }
772
+ blob() {
773
+ const bytes = this.data();
774
+ return bytes ? new Blob([bytes], { type: "application/pdf" }) : null;
775
+ }
776
+ download() {
777
+ const blob = this.blob();
778
+ if (!blob) return;
779
+ const url = URL.createObjectURL(blob);
780
+ const a = document.createElement("a");
781
+ a.href = url;
782
+ a.download = this.fileName() || "document.pdf";
783
+ document.body.appendChild(a);
784
+ a.click();
785
+ a.remove();
786
+ URL.revokeObjectURL(url);
787
+ }
788
+ print() {
789
+ const blob = this.blob();
790
+ if (!blob) return;
791
+ const url = URL.createObjectURL(blob);
792
+ const frame = document.createElement("iframe");
793
+ frame.style.cssText = "position:fixed;top:-10000px;left:-10000px;width:1px;height:1px;";
794
+ frame.src = url;
795
+ const cleanup = () => {
796
+ frame.remove();
797
+ URL.revokeObjectURL(url);
798
+ };
799
+ frame.onload = () => {
800
+ try {
801
+ frame.contentWindow?.addEventListener("afterprint", cleanup);
802
+ frame.contentWindow?.print();
803
+ } catch {
804
+ window.open(url, "_blank");
805
+ cleanup();
806
+ }
807
+ };
808
+ document.body.appendChild(frame);
809
+ }
810
+ static {
811
+ this.ɵfac = i0.ɵɵngDeclareFactory({
812
+ minVersion: "12.0.0",
813
+ version: "22.2.2",
814
+ ngImport: i0,
815
+ type: DocumentViewerModalComponent,
816
+ deps: [],
817
+ target: i0.ɵɵFactoryTarget.Component
818
+ });
819
+ }
820
+ static {
821
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
822
+ minVersion: "17.0.0",
823
+ version: "22.2.2",
824
+ type: DocumentViewerModalComponent,
825
+ isStandalone: true,
826
+ selector: "ui-document-viewer-modal",
827
+ inputs: {
828
+ open: {
829
+ classPropertyName: "open",
830
+ publicName: "open",
831
+ isSignal: true,
832
+ isRequired: false,
833
+ transformFunction: null
834
+ },
835
+ fileName: {
836
+ classPropertyName: "fileName",
837
+ publicName: "fileName",
838
+ isSignal: true,
839
+ isRequired: false,
840
+ transformFunction: null
841
+ },
842
+ data: {
843
+ classPropertyName: "data",
844
+ publicName: "data",
845
+ isSignal: true,
846
+ isRequired: false,
847
+ transformFunction: null
848
+ },
849
+ loading: {
850
+ classPropertyName: "loading",
851
+ publicName: "loading",
852
+ isSignal: true,
853
+ isRequired: false,
854
+ transformFunction: null
855
+ },
856
+ error: {
857
+ classPropertyName: "error",
858
+ publicName: "error",
859
+ isSignal: true,
860
+ isRequired: false,
861
+ transformFunction: null
862
+ },
863
+ loadingText: {
864
+ classPropertyName: "loadingText",
865
+ publicName: "loadingText",
866
+ isSignal: true,
867
+ isRequired: false,
868
+ transformFunction: null
869
+ }
870
+ },
871
+ outputs: { closed: "closed" },
872
+ ngImport: i0,
873
+ template: `
874
+ <ui-modal [open]="open()" [title]="fileName()" maxWidth="64rem" dialogTestId="document-viewer" (close)="closed.emit()">
875
+ <div class="dvm-actions" modal-header-end>
876
+ <ui-button variant="secondary" size="sm" data-testid="document-viewer-download" [disabled]="!hasData()" ariaLabel="Download document" (click)="download()">
877
+ <ui-icon name="download" [interactive]="false" /> Download
878
+ </ui-button>
879
+ <ui-button variant="secondary" size="sm" data-testid="document-viewer-print" [disabled]="!hasData()" ariaLabel="Print document" (click)="print()">
880
+ <ui-icon name="print" [interactive]="false" /> Print
881
+ </ui-button>
882
+ </div>
883
+ @if (loading()) {
884
+ <div class="dvm-state" role="status" aria-live="polite" data-testid="document-viewer-loading">
885
+ <ui-skeleton [height]="320" />
886
+ <span class="dvm-sr">{{ loadingText() }}</span>
887
+ </div>
888
+ } @else if (error()) {
889
+ <ui-alert variant="danger" data-testid="document-viewer-error">{{ error() }}</ui-alert>
890
+ } @else if (data(); as bytes) {
891
+ <ui-pdf-viewer [data]="bytes" [ariaLabel]="fileName()" [loadingText]="loadingText()" />
892
+ }
893
+ </ui-modal>
894
+ `,
895
+ isInline: true,
896
+ styles: [".dvm-actions{display:inline-flex;gap:8px;align-items:center}.dvm-state{display:block}.dvm-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}\n"],
897
+ dependencies: [
898
+ {
899
+ kind: "component",
900
+ type: ModalComponent,
901
+ selector: "ui-modal",
902
+ inputs: [
903
+ "open",
904
+ "title",
905
+ "description",
906
+ "maxWidth",
907
+ "bodyOverflow",
908
+ "dialogTestId",
909
+ "hideClose",
910
+ "closable",
911
+ "layout",
912
+ "closeOnBackdrop",
913
+ "closeOnEscape",
914
+ "busy",
915
+ "returnFocusTo"
916
+ ],
917
+ outputs: ["close"]
918
+ },
919
+ {
920
+ kind: "component",
921
+ type: ButtonComponent,
922
+ selector: "ui-button",
923
+ inputs: [
924
+ "variant",
925
+ "routerLink",
926
+ "queryParams",
927
+ "fragment",
928
+ "state",
929
+ "href",
930
+ "target",
931
+ "rel",
932
+ "shortLabel",
933
+ "shortBelow",
934
+ "color",
935
+ "active",
936
+ "size",
937
+ "type",
938
+ "disabled",
939
+ "loading",
940
+ "fullWidth",
941
+ "ariaLabel",
942
+ "ariaExpanded",
943
+ "ariaPressed",
944
+ "ariaDescribedBy",
945
+ "modal-footer-left",
946
+ "modal-footer-right"
947
+ ]
948
+ },
949
+ {
950
+ kind: "component",
951
+ type: IconComponent,
952
+ selector: "ui-icon",
953
+ inputs: [
954
+ "name",
955
+ "tooltip",
956
+ "ariaLabel",
957
+ "size",
958
+ "variant",
959
+ "disabled",
960
+ "loading",
961
+ "interactive"
962
+ ],
963
+ outputs: ["iconClick"]
964
+ },
965
+ {
966
+ kind: "component",
967
+ type: AlertComponent,
968
+ selector: "ui-alert",
969
+ inputs: [
970
+ "variant",
971
+ "title",
972
+ "dismissible",
973
+ "dismissAriaLabel",
974
+ "quiet",
975
+ "compact",
976
+ "inline",
977
+ "fill"
978
+ ],
979
+ outputs: ["dismissed"]
980
+ },
981
+ {
982
+ kind: "component",
983
+ type: SkeletonComponent,
984
+ selector: "ui-skeleton",
985
+ inputs: [
986
+ "height",
987
+ "width",
988
+ "radius",
989
+ "mb",
990
+ "ariaLabel"
991
+ ]
992
+ },
993
+ {
994
+ kind: "component",
995
+ type: PdfViewerComponent,
996
+ selector: "ui-pdf-viewer",
997
+ inputs: [
998
+ "src",
999
+ "data",
1000
+ "httpHeaders",
1001
+ "withCredentials",
1002
+ "workerSrc",
1003
+ "maxPageWidth",
1004
+ "pixelRatio",
1005
+ "fields",
1006
+ "hotspots",
1007
+ "ariaLabel",
1008
+ "loadingText",
1009
+ "errorText",
1010
+ "unsupportedText",
1011
+ "openText",
1012
+ "checkBrowserSupport"
1013
+ ],
1014
+ outputs: [
1015
+ "hotspotActivate",
1016
+ "loaded",
1017
+ "loadFailed",
1018
+ "pagesRendered"
1019
+ ]
1020
+ }
1021
+ ],
1022
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
1023
+ });
1024
+ }
1025
+ };
1026
+ i0.ɵɵngDeclareClassMetadata({
1027
+ minVersion: "12.0.0",
1028
+ version: "22.2.2",
1029
+ ngImport: i0,
1030
+ type: DocumentViewerModalComponent,
1031
+ decorators: [{
1032
+ type: Component,
1033
+ args: [{
1034
+ selector: "ui-document-viewer-modal",
1035
+ standalone: true,
1036
+ changeDetection: ChangeDetectionStrategy.OnPush,
1037
+ imports: [
1038
+ ModalComponent,
1039
+ ButtonComponent,
1040
+ IconComponent,
1041
+ AlertComponent,
1042
+ SkeletonComponent,
1043
+ PdfViewerComponent
1044
+ ],
1045
+ template: `
1046
+ <ui-modal [open]="open()" [title]="fileName()" maxWidth="64rem" dialogTestId="document-viewer" (close)="closed.emit()">
1047
+ <div class="dvm-actions" modal-header-end>
1048
+ <ui-button variant="secondary" size="sm" data-testid="document-viewer-download" [disabled]="!hasData()" ariaLabel="Download document" (click)="download()">
1049
+ <ui-icon name="download" [interactive]="false" /> Download
1050
+ </ui-button>
1051
+ <ui-button variant="secondary" size="sm" data-testid="document-viewer-print" [disabled]="!hasData()" ariaLabel="Print document" (click)="print()">
1052
+ <ui-icon name="print" [interactive]="false" /> Print
1053
+ </ui-button>
1054
+ </div>
1055
+ @if (loading()) {
1056
+ <div class="dvm-state" role="status" aria-live="polite" data-testid="document-viewer-loading">
1057
+ <ui-skeleton [height]="320" />
1058
+ <span class="dvm-sr">{{ loadingText() }}</span>
1059
+ </div>
1060
+ } @else if (error()) {
1061
+ <ui-alert variant="danger" data-testid="document-viewer-error">{{ error() }}</ui-alert>
1062
+ } @else if (data(); as bytes) {
1063
+ <ui-pdf-viewer [data]="bytes" [ariaLabel]="fileName()" [loadingText]="loadingText()" />
1064
+ }
1065
+ </ui-modal>
1066
+ `,
1067
+ styles: [".dvm-actions{display:inline-flex;gap:8px;align-items:center}.dvm-state{display:block}.dvm-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}\n"]
1068
+ }]
1069
+ }],
1070
+ propDecorators: {
1071
+ open: [{
1072
+ type: i0.Input,
1073
+ args: [{
1074
+ isSignal: true,
1075
+ alias: "open",
1076
+ required: false
1077
+ }]
1078
+ }],
1079
+ fileName: [{
1080
+ type: i0.Input,
1081
+ args: [{
1082
+ isSignal: true,
1083
+ alias: "fileName",
1084
+ required: false
1085
+ }]
1086
+ }],
1087
+ data: [{
1088
+ type: i0.Input,
1089
+ args: [{
1090
+ isSignal: true,
1091
+ alias: "data",
1092
+ required: false
1093
+ }]
1094
+ }],
1095
+ loading: [{
1096
+ type: i0.Input,
1097
+ args: [{
1098
+ isSignal: true,
1099
+ alias: "loading",
1100
+ required: false
1101
+ }]
1102
+ }],
1103
+ error: [{
1104
+ type: i0.Input,
1105
+ args: [{
1106
+ isSignal: true,
1107
+ alias: "error",
1108
+ required: false
1109
+ }]
1110
+ }],
1111
+ loadingText: [{
1112
+ type: i0.Input,
1113
+ args: [{
1114
+ isSignal: true,
1115
+ alias: "loadingText",
1116
+ required: false
1117
+ }]
1118
+ }],
1119
+ closed: [{
1120
+ type: i0.Output,
1121
+ args: ["closed"]
1122
+ }]
1123
+ }
1124
+ });
1125
+ const DEFAULT_TEXTS = {
1126
+ title: "Sign Document",
1127
+ loading: "Loading document…",
1128
+ step1: "Step 1: Create Your Signature",
1129
+ namePlaceholder: "Type your full name",
1130
+ previewEmpty: "Preview appears here",
1131
+ saveSignature: "Save Signature",
1132
+ change: "Change",
1133
+ step2: "Step 2: Click the buttons below to apply your signature",
1134
+ signHere: "Sign Here",
1135
+ addSignatureFirst: "Add signature above",
1136
+ allSigned: "All signatures completed",
1137
+ cancel: "Cancel",
1138
+ complete: "Complete Signing",
1139
+ submitting: "Submitting...",
1140
+ noFields: "This document has no place to sign."
1141
+ };
1142
+ const SIGNATURE_WIDTH = 600;
1143
+ const SIGNATURE_HEIGHT = 60;
1144
+ var DocumentSignModalComponent = class DocumentSignModalComponent {
1145
+ constructor() {
1146
+ this.open = input(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
1147
+ this.data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
1148
+ this.fields = input([], ...ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []);
1149
+ this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
1150
+ this.error = input("", ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
1151
+ this.signerName = input("", ...ngDevMode ? [{ debugName: "signerName" }] : /* istanbul ignore next */ []);
1152
+ this.savedSignature = input(null, ...ngDevMode ? [{ debugName: "savedSignature" }] : /* istanbul ignore next */ []);
1153
+ this.submitting = input(false, ...ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []);
1154
+ this.texts = input({}, ...ngDevMode ? [{ debugName: "texts" }] : /* istanbul ignore next */ []);
1155
+ this.signed = output();
1156
+ this.signatureCreated = output();
1157
+ this.closed = output();
1158
+ this.t = computed(() => ({
1159
+ ...DEFAULT_TEXTS,
1160
+ ...this.texts()
1161
+ }), ...ngDevMode ? [{ debugName: "t" }] : /* istanbul ignore next */ []);
1162
+ this.typedName = signal("", ...ngDevMode ? [{ debugName: "typedName" }] : /* istanbul ignore next */ []);
1163
+ this.signature = signal(null, ...ngDevMode ? [{ debugName: "signature" }] : /* istanbul ignore next */ []);
1164
+ this.applied = signal({}, ...ngDevMode ? [{ debugName: "applied" }] : /* istanbul ignore next */ []);
1165
+ this.resolved = computed(() => this.fields().map((f, i) => ({
1166
+ ...f,
1167
+ id: f.id ?? String(i + 1)
1168
+ })), ...ngDevMode ? [{ debugName: "resolved" }] : /* istanbul ignore next */ []);
1169
+ this.signedCount = computed(() => this.resolved().filter((f) => !!this.applied()[f.id]).length, ...ngDevMode ? [{ debugName: "signedCount" }] : /* istanbul ignore next */ []);
1170
+ this.allSigned = computed(() => this.resolved().length > 0 && this.signedCount() === this.resolved().length, ...ngDevMode ? [{ debugName: "allSigned" }] : /* istanbul ignore next */ []);
1171
+ this.hotspots = computed(() => {
1172
+ const fields = this.resolved();
1173
+ const image = this.signature();
1174
+ return fields.map((f, i) => {
1175
+ const applied = this.applied()[f.id];
1176
+ const label = `Sign field ${i + 1} of ${fields.length}`;
1177
+ return {
1178
+ id: f.id,
1179
+ page: f.page,
1180
+ x: f.x,
1181
+ y: f.y,
1182
+ width: f.width,
1183
+ height: f.height,
1184
+ state: applied ? "signed" : image ? "ready" : "blocked",
1185
+ label: this.t().signHere,
1186
+ blockedLabel: this.t().addSignatureFirst,
1187
+ ariaLabel: image ? label : `${label} - add your signature above first to enable signing`,
1188
+ image: applied ?? null,
1189
+ imageAlt: "Applied signature"
1190
+ };
1191
+ });
1192
+ }, ...ngDevMode ? [{ debugName: "hotspots" }] : /* istanbul ignore next */ []);
1193
+ effect(() => {
1194
+ if (!this.open()) return;
1195
+ untracked(() => {
1196
+ this.applied.set({});
1197
+ this.typedName.set(this.signerName());
1198
+ this.signature.set(null);
1199
+ const saved = this.savedSignature();
1200
+ if (saved) this.normalize(saved).then((image) => {
1201
+ if (this.open() && !this.signature()) this.signature.set(image);
1202
+ });
1203
+ });
1204
+ });
1205
+ }
1206
+ cancel() {
1207
+ this.closed.emit();
1208
+ }
1209
+ async saveTypedSignature() {
1210
+ const name = this.typedName().trim();
1211
+ if (!name) return;
1212
+ try {
1213
+ await document.fonts?.ready;
1214
+ } catch {}
1215
+ const canvas = document.createElement("canvas");
1216
+ canvas.width = SIGNATURE_WIDTH;
1217
+ canvas.height = SIGNATURE_HEIGHT;
1218
+ const ctx = canvas.getContext("2d");
1219
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1220
+ ctx.fillStyle = "#000";
1221
+ ctx.textAlign = "left";
1222
+ ctx.textBaseline = "middle";
1223
+ const maxWidth = canvas.width - 10;
1224
+ let size = 48;
1225
+ ctx.font = `bold ${size}px 'Dancing Script', cursive`;
1226
+ while (ctx.measureText(name).width > maxWidth && size > 24) {
1227
+ size -= 2;
1228
+ ctx.font = `bold ${size}px 'Dancing Script', cursive`;
1229
+ }
1230
+ ctx.fillText(name, 5, canvas.height / 2);
1231
+ const image = canvas.toDataURL("image/png");
1232
+ this.signature.set(image);
1233
+ this.signatureCreated.emit(image);
1234
+ }
1235
+ changeSignature() {
1236
+ this.signature.set(null);
1237
+ this.typedName.set("");
1238
+ this.applied.set({});
1239
+ }
1240
+ apply(fieldId) {
1241
+ const image = this.signature();
1242
+ if (!image || !this.resolved().some((f) => f.id === fieldId)) return;
1243
+ this.applied.update((a) => ({
1244
+ ...a,
1245
+ [fieldId]: image
1246
+ }));
1247
+ }
1248
+ complete() {
1249
+ if (!this.allSigned() || this.submitting()) return;
1250
+ const fields = this.resolved().map((f) => ({
1251
+ id: f.id,
1252
+ page: f.page,
1253
+ x: f.x,
1254
+ y: f.y,
1255
+ width: f.width,
1256
+ height: f.height,
1257
+ signatureImage: this.applied()[f.id]
1258
+ }));
1259
+ this.signed.emit({
1260
+ signatureDataUrl: fields[0].signatureImage,
1261
+ signedAt: (/* @__PURE__ */ new Date()).toISOString(),
1262
+ fields
1263
+ });
1264
+ }
1265
+ normalize(dataUrl) {
1266
+ return new Promise((resolve) => {
1267
+ const img = new Image();
1268
+ img.onload = () => {
1269
+ const out = document.createElement("canvas");
1270
+ out.width = SIGNATURE_WIDTH;
1271
+ out.height = SIGNATURE_HEIGHT;
1272
+ const scale = Math.min(out.width / img.width, out.height / img.height);
1273
+ const w = img.width * scale;
1274
+ const h = img.height * scale;
1275
+ out.getContext("2d").drawImage(img, 0, (out.height - h) / 2, w, h);
1276
+ resolve(out.toDataURL("image/png"));
1277
+ };
1278
+ img.onerror = () => resolve(dataUrl);
1279
+ img.src = dataUrl;
1280
+ });
1281
+ }
1282
+ static {
1283
+ this.ɵfac = i0.ɵɵngDeclareFactory({
1284
+ minVersion: "12.0.0",
1285
+ version: "22.2.2",
1286
+ ngImport: i0,
1287
+ type: DocumentSignModalComponent,
1288
+ deps: [],
1289
+ target: i0.ɵɵFactoryTarget.Component
1290
+ });
1291
+ }
1292
+ static {
1293
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
1294
+ minVersion: "17.0.0",
1295
+ version: "22.2.2",
1296
+ type: DocumentSignModalComponent,
1297
+ isStandalone: true,
1298
+ selector: "ui-document-sign-modal",
1299
+ inputs: {
1300
+ open: {
1301
+ classPropertyName: "open",
1302
+ publicName: "open",
1303
+ isSignal: true,
1304
+ isRequired: false,
1305
+ transformFunction: null
1306
+ },
1307
+ data: {
1308
+ classPropertyName: "data",
1309
+ publicName: "data",
1310
+ isSignal: true,
1311
+ isRequired: false,
1312
+ transformFunction: null
1313
+ },
1314
+ fields: {
1315
+ classPropertyName: "fields",
1316
+ publicName: "fields",
1317
+ isSignal: true,
1318
+ isRequired: false,
1319
+ transformFunction: null
1320
+ },
1321
+ loading: {
1322
+ classPropertyName: "loading",
1323
+ publicName: "loading",
1324
+ isSignal: true,
1325
+ isRequired: false,
1326
+ transformFunction: null
1327
+ },
1328
+ error: {
1329
+ classPropertyName: "error",
1330
+ publicName: "error",
1331
+ isSignal: true,
1332
+ isRequired: false,
1333
+ transformFunction: null
1334
+ },
1335
+ signerName: {
1336
+ classPropertyName: "signerName",
1337
+ publicName: "signerName",
1338
+ isSignal: true,
1339
+ isRequired: false,
1340
+ transformFunction: null
1341
+ },
1342
+ savedSignature: {
1343
+ classPropertyName: "savedSignature",
1344
+ publicName: "savedSignature",
1345
+ isSignal: true,
1346
+ isRequired: false,
1347
+ transformFunction: null
1348
+ },
1349
+ submitting: {
1350
+ classPropertyName: "submitting",
1351
+ publicName: "submitting",
1352
+ isSignal: true,
1353
+ isRequired: false,
1354
+ transformFunction: null
1355
+ },
1356
+ texts: {
1357
+ classPropertyName: "texts",
1358
+ publicName: "texts",
1359
+ isSignal: true,
1360
+ isRequired: false,
1361
+ transformFunction: null
1362
+ }
1363
+ },
1364
+ outputs: {
1365
+ signed: "signed",
1366
+ signatureCreated: "signatureCreated",
1367
+ closed: "closed"
1368
+ },
1369
+ ngImport: i0,
1370
+ template: `
1371
+ <ui-modal [open]="open()" [title]="t().title" maxWidth="56rem" bodyOverflow="auto" dialogTestId="sign-modal" (close)="cancel()">
1372
+ @if (loading()) {
1373
+ <ui-stack gap="md" align="center" role="status" aria-live="polite" data-testid="sign-loading">
1374
+ <ui-skeleton [height]="24" width="60%" />
1375
+ <ui-hint>{{ t().loading }}</ui-hint>
1376
+ </ui-stack>
1377
+ } @else if (error()) {
1378
+ <ui-alert variant="danger" data-testid="sign-error">{{ error() }}</ui-alert>
1379
+ } @else {
1380
+ <ui-stack gap="md">
1381
+ <ui-detail-card [title]="t().step1" [headingLevel]="4" [collapsible]="false" data-testid="signature-step">
1382
+ @if (!signature()) {
1383
+ <ui-stack gap="sm">
1384
+ <ui-text-input data-testid="typed-name-input" [placeholder]="t().namePlaceholder" [ariaLabel]="t().namePlaceholder"
1385
+ [ngModel]="typedName()" (ngModelChange)="typedName.set($event ?? '')" />
1386
+ <div class="ds-preview">
1387
+ @if (typedName()) {
1388
+ <span class="ds-typed" data-testid="typed-signature-preview">{{ typedName() }}</span>
1389
+ } @else {
1390
+ <span class="ds-empty">{{ t().previewEmpty }}</span>
1391
+ }
1392
+ </div>
1393
+ <ui-button variant="primary" [fullWidth]="true" [disabled]="!typedName().trim()" data-testid="save-typed-signature" (click)="saveTypedSignature()">
1394
+ <ui-icon name="check" [size]="16" [interactive]="false" /> {{ t().saveSignature }}
1395
+ </ui-button>
1396
+ </ui-stack>
1397
+ } @else {
1398
+ <ui-stack gap="sm">
1399
+ <div class="ds-saved"><img [src]="signature()!" alt="Your saved signature" class="ds-saved-img"></div>
1400
+ <ui-button variant="secondary" [ariaLabel]="t().change + ' signature'" data-testid="redraw-signature" (click)="changeSignature()">
1401
+ <ui-icon name="edit" [size]="16" [interactive]="false" /> {{ t().change }}
1402
+ </ui-button>
1403
+ </ui-stack>
1404
+ }
1405
+ </ui-detail-card>
1406
+
1407
+ @if (signature()) {
1408
+ <ui-section-header [level]="4" size="sm" [title]="t().step2" data-testid="apply-step" />
1409
+ }
1410
+
1411
+ <ui-pdf-viewer [data]="data()" [hotspots]="hotspots()" [ariaLabel]="t().title" [loadingText]="t().loading" (hotspotActivate)="apply($event)" />
1412
+ </ui-stack>
1413
+ }
1414
+
1415
+ <ui-hint modal-footer-left role="status" aria-live="polite" aria-atomic="true" data-testid="sign-progress">
1416
+ @if (fields().length === 0) { {{ t().noFields }} } @else if (allSigned()) { {{ t().allSigned }} } @else { {{ signedCount() }} of {{ fields().length }} signed }
1417
+ </ui-hint>
1418
+ <ui-stack modal-footer-right direction="horizontal" gap="sm" [wrap]="true">
1419
+ <ui-button variant="secondary" data-testid="sign-cancel" (click)="cancel()"><ui-icon name="close" [size]="16" [interactive]="false" /> {{ t().cancel }}</ui-button>
1420
+ <ui-button variant="primary" data-testid="sign-complete" [disabled]="!allSigned() || submitting()" [loading]="submitting()" (click)="complete()">
1421
+ <ui-icon name="check" [size]="16" [interactive]="false" /> {{ submitting() ? t().submitting : t().complete }}
1422
+ </ui-button>
1423
+ </ui-stack>
1424
+ </ui-modal>
1425
+ `,
1426
+ isInline: true,
1427
+ styles: [".ds-preview{display:flex;align-items:center;min-height:64px;padding:4px 12px;border:1px dashed #cbd5e1;border-radius:8px;background:#fff;overflow:hidden}.ds-empty{color:#94a3b8;font-size:.875rem}.ds-typed{font-family:Dancing Script,cursive;font-weight:700;font-size:2.25rem;line-height:1.2;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-saved{display:flex;align-items:center;min-height:64px;padding:4px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#fff}.ds-saved-img{display:block;max-width:100%;height:60px;object-fit:contain;object-position:left}\n"],
1428
+ dependencies: [
1429
+ {
1430
+ kind: "ngmodule",
1431
+ type: FormsModule
1432
+ },
1433
+ {
1434
+ kind: "directive",
1435
+ type: i1.NgControlStatus,
1436
+ selector: "[formControlName],[ngModel],[formControl]"
1437
+ },
1438
+ {
1439
+ kind: "directive",
1440
+ type: i1.NgModel,
1441
+ selector: "[ngModel]:not([formControlName]):not([formControl])",
1442
+ inputs: [
1443
+ "name",
1444
+ "disabled",
1445
+ "ngModel",
1446
+ "ngModelOptions"
1447
+ ],
1448
+ outputs: ["ngModelChange"],
1449
+ exportAs: ["ngModel"]
1450
+ },
1451
+ {
1452
+ kind: "component",
1453
+ type: AlertComponent,
1454
+ selector: "ui-alert",
1455
+ inputs: [
1456
+ "variant",
1457
+ "title",
1458
+ "dismissible",
1459
+ "dismissAriaLabel",
1460
+ "quiet",
1461
+ "compact",
1462
+ "inline",
1463
+ "fill"
1464
+ ],
1465
+ outputs: ["dismissed"]
1466
+ },
1467
+ {
1468
+ kind: "component",
1469
+ type: ButtonComponent,
1470
+ selector: "ui-button",
1471
+ inputs: [
1472
+ "variant",
1473
+ "routerLink",
1474
+ "queryParams",
1475
+ "fragment",
1476
+ "state",
1477
+ "href",
1478
+ "target",
1479
+ "rel",
1480
+ "shortLabel",
1481
+ "shortBelow",
1482
+ "color",
1483
+ "active",
1484
+ "size",
1485
+ "type",
1486
+ "disabled",
1487
+ "loading",
1488
+ "fullWidth",
1489
+ "ariaLabel",
1490
+ "ariaExpanded",
1491
+ "ariaPressed",
1492
+ "ariaDescribedBy",
1493
+ "modal-footer-left",
1494
+ "modal-footer-right"
1495
+ ]
1496
+ },
1497
+ {
1498
+ kind: "component",
1499
+ type: DetailCardComponent,
1500
+ selector: "ui-detail-card",
1501
+ inputs: [
1502
+ "title",
1503
+ "uppercaseTitle",
1504
+ "headingLevel",
1505
+ "titleId",
1506
+ "ariaLabel",
1507
+ "subtitle",
1508
+ "background",
1509
+ "headerBackground",
1510
+ "footerBackground",
1511
+ "textColor",
1512
+ "showHeader",
1513
+ "collapsible",
1514
+ "expanded",
1515
+ "showEdit",
1516
+ "editLabel",
1517
+ "editTestId",
1518
+ "editIcon",
1519
+ "editAriaLabel",
1520
+ "fill",
1521
+ "maxBodyHeight",
1522
+ "selectable",
1523
+ "selected",
1524
+ "selectedColor",
1525
+ "selectedBackground"
1526
+ ],
1527
+ outputs: [
1528
+ "expandedChange",
1529
+ "editClick",
1530
+ "selectedChange"
1531
+ ]
1532
+ },
1533
+ {
1534
+ kind: "component",
1535
+ type: HintComponent,
1536
+ selector: "ui-hint"
1537
+ },
1538
+ {
1539
+ kind: "component",
1540
+ type: IconComponent,
1541
+ selector: "ui-icon",
1542
+ inputs: [
1543
+ "name",
1544
+ "tooltip",
1545
+ "ariaLabel",
1546
+ "size",
1547
+ "variant",
1548
+ "disabled",
1549
+ "loading",
1550
+ "interactive"
1551
+ ],
1552
+ outputs: ["iconClick"]
1553
+ },
1554
+ {
1555
+ kind: "component",
1556
+ type: ModalComponent,
1557
+ selector: "ui-modal",
1558
+ inputs: [
1559
+ "open",
1560
+ "title",
1561
+ "description",
1562
+ "maxWidth",
1563
+ "bodyOverflow",
1564
+ "dialogTestId",
1565
+ "hideClose",
1566
+ "closable",
1567
+ "layout",
1568
+ "closeOnBackdrop",
1569
+ "closeOnEscape",
1570
+ "busy",
1571
+ "returnFocusTo"
1572
+ ],
1573
+ outputs: ["close"]
1574
+ },
1575
+ {
1576
+ kind: "component",
1577
+ type: SectionHeaderComponent,
1578
+ selector: "ui-section-header",
1579
+ inputs: [
1580
+ "title",
1581
+ "description",
1582
+ "icon",
1583
+ "level",
1584
+ "background",
1585
+ "textColor",
1586
+ "iconColor",
1587
+ "iconBackground",
1588
+ "bordered",
1589
+ "size",
1590
+ "noPaddingTop",
1591
+ "noPaddingLeft",
1592
+ "noPaddingBottom"
1593
+ ]
1594
+ },
1595
+ {
1596
+ kind: "component",
1597
+ type: SkeletonComponent,
1598
+ selector: "ui-skeleton",
1599
+ inputs: [
1600
+ "height",
1601
+ "width",
1602
+ "radius",
1603
+ "mb",
1604
+ "ariaLabel"
1605
+ ]
1606
+ },
1607
+ {
1608
+ kind: "component",
1609
+ type: StackComponent,
1610
+ selector: "ui-stack",
1611
+ inputs: [
1612
+ "gap",
1613
+ "direction",
1614
+ "align",
1615
+ "justify",
1616
+ "wrap",
1617
+ "minHeight",
1618
+ "width",
1619
+ "maxWidth",
1620
+ "padding",
1621
+ "centered"
1622
+ ]
1623
+ },
1624
+ {
1625
+ kind: "component",
1626
+ type: TextInputComponent,
1627
+ selector: "ui-text-input",
1628
+ inputs: [
1629
+ "label",
1630
+ "ariaLabel",
1631
+ "inputTestId",
1632
+ "placeholder",
1633
+ "prefix",
1634
+ "revealable",
1635
+ "passwordRequirements",
1636
+ "passwordRules",
1637
+ "type",
1638
+ "maxlength",
1639
+ "required",
1640
+ "autocomplete",
1641
+ "inputmode",
1642
+ "readonly",
1643
+ "hint",
1644
+ "ariaDescribedBy",
1645
+ "error",
1646
+ "phoneFormat",
1647
+ "min",
1648
+ "max",
1649
+ "maxDecimals",
1650
+ "step",
1651
+ "valueType",
1652
+ "formatter",
1653
+ "integer",
1654
+ "showErrors",
1655
+ "disabled"
1656
+ ],
1657
+ outputs: [
1658
+ "valueChange",
1659
+ "focused",
1660
+ "blurred",
1661
+ "invalidChange"
1662
+ ]
1663
+ },
1664
+ {
1665
+ kind: "component",
1666
+ type: PdfViewerComponent,
1667
+ selector: "ui-pdf-viewer",
1668
+ inputs: [
1669
+ "src",
1670
+ "data",
1671
+ "httpHeaders",
1672
+ "withCredentials",
1673
+ "workerSrc",
1674
+ "maxPageWidth",
1675
+ "pixelRatio",
1676
+ "fields",
1677
+ "hotspots",
1678
+ "ariaLabel",
1679
+ "loadingText",
1680
+ "errorText",
1681
+ "unsupportedText",
1682
+ "openText",
1683
+ "checkBrowserSupport"
1684
+ ],
1685
+ outputs: [
1686
+ "hotspotActivate",
1687
+ "loaded",
1688
+ "loadFailed",
1689
+ "pagesRendered"
1690
+ ]
1691
+ }
1692
+ ],
1693
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
1694
+ });
1695
+ }
1696
+ };
1697
+ i0.ɵɵngDeclareClassMetadata({
1698
+ minVersion: "12.0.0",
1699
+ version: "22.2.2",
1700
+ ngImport: i0,
1701
+ type: DocumentSignModalComponent,
1702
+ decorators: [{
1703
+ type: Component,
1704
+ args: [{
1705
+ selector: "ui-document-sign-modal",
1706
+ standalone: true,
1707
+ changeDetection: ChangeDetectionStrategy.OnPush,
1708
+ imports: [
1709
+ FormsModule,
1710
+ AlertComponent,
1711
+ ButtonComponent,
1712
+ DetailCardComponent,
1713
+ HintComponent,
1714
+ IconComponent,
1715
+ ModalComponent,
1716
+ SectionHeaderComponent,
1717
+ SkeletonComponent,
1718
+ StackComponent,
1719
+ TextInputComponent,
1720
+ PdfViewerComponent
1721
+ ],
1722
+ template: `
1723
+ <ui-modal [open]="open()" [title]="t().title" maxWidth="56rem" bodyOverflow="auto" dialogTestId="sign-modal" (close)="cancel()">
1724
+ @if (loading()) {
1725
+ <ui-stack gap="md" align="center" role="status" aria-live="polite" data-testid="sign-loading">
1726
+ <ui-skeleton [height]="24" width="60%" />
1727
+ <ui-hint>{{ t().loading }}</ui-hint>
1728
+ </ui-stack>
1729
+ } @else if (error()) {
1730
+ <ui-alert variant="danger" data-testid="sign-error">{{ error() }}</ui-alert>
1731
+ } @else {
1732
+ <ui-stack gap="md">
1733
+ <ui-detail-card [title]="t().step1" [headingLevel]="4" [collapsible]="false" data-testid="signature-step">
1734
+ @if (!signature()) {
1735
+ <ui-stack gap="sm">
1736
+ <ui-text-input data-testid="typed-name-input" [placeholder]="t().namePlaceholder" [ariaLabel]="t().namePlaceholder"
1737
+ [ngModel]="typedName()" (ngModelChange)="typedName.set($event ?? '')" />
1738
+ <div class="ds-preview">
1739
+ @if (typedName()) {
1740
+ <span class="ds-typed" data-testid="typed-signature-preview">{{ typedName() }}</span>
1741
+ } @else {
1742
+ <span class="ds-empty">{{ t().previewEmpty }}</span>
1743
+ }
1744
+ </div>
1745
+ <ui-button variant="primary" [fullWidth]="true" [disabled]="!typedName().trim()" data-testid="save-typed-signature" (click)="saveTypedSignature()">
1746
+ <ui-icon name="check" [size]="16" [interactive]="false" /> {{ t().saveSignature }}
1747
+ </ui-button>
1748
+ </ui-stack>
1749
+ } @else {
1750
+ <ui-stack gap="sm">
1751
+ <div class="ds-saved"><img [src]="signature()!" alt="Your saved signature" class="ds-saved-img"></div>
1752
+ <ui-button variant="secondary" [ariaLabel]="t().change + ' signature'" data-testid="redraw-signature" (click)="changeSignature()">
1753
+ <ui-icon name="edit" [size]="16" [interactive]="false" /> {{ t().change }}
1754
+ </ui-button>
1755
+ </ui-stack>
1756
+ }
1757
+ </ui-detail-card>
1758
+
1759
+ @if (signature()) {
1760
+ <ui-section-header [level]="4" size="sm" [title]="t().step2" data-testid="apply-step" />
1761
+ }
1762
+
1763
+ <ui-pdf-viewer [data]="data()" [hotspots]="hotspots()" [ariaLabel]="t().title" [loadingText]="t().loading" (hotspotActivate)="apply($event)" />
1764
+ </ui-stack>
1765
+ }
1766
+
1767
+ <ui-hint modal-footer-left role="status" aria-live="polite" aria-atomic="true" data-testid="sign-progress">
1768
+ @if (fields().length === 0) { {{ t().noFields }} } @else if (allSigned()) { {{ t().allSigned }} } @else { {{ signedCount() }} of {{ fields().length }} signed }
1769
+ </ui-hint>
1770
+ <ui-stack modal-footer-right direction="horizontal" gap="sm" [wrap]="true">
1771
+ <ui-button variant="secondary" data-testid="sign-cancel" (click)="cancel()"><ui-icon name="close" [size]="16" [interactive]="false" /> {{ t().cancel }}</ui-button>
1772
+ <ui-button variant="primary" data-testid="sign-complete" [disabled]="!allSigned() || submitting()" [loading]="submitting()" (click)="complete()">
1773
+ <ui-icon name="check" [size]="16" [interactive]="false" /> {{ submitting() ? t().submitting : t().complete }}
1774
+ </ui-button>
1775
+ </ui-stack>
1776
+ </ui-modal>
1777
+ `,
1778
+ styles: [".ds-preview{display:flex;align-items:center;min-height:64px;padding:4px 12px;border:1px dashed #cbd5e1;border-radius:8px;background:#fff;overflow:hidden}.ds-empty{color:#94a3b8;font-size:.875rem}.ds-typed{font-family:Dancing Script,cursive;font-weight:700;font-size:2.25rem;line-height:1.2;color:#000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-saved{display:flex;align-items:center;min-height:64px;padding:4px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#fff}.ds-saved-img{display:block;max-width:100%;height:60px;object-fit:contain;object-position:left}\n"]
1779
+ }]
1780
+ }],
1781
+ ctorParameters: () => [],
1782
+ propDecorators: {
1783
+ open: [{
1784
+ type: i0.Input,
1785
+ args: [{
1786
+ isSignal: true,
1787
+ alias: "open",
1788
+ required: false
1789
+ }]
1790
+ }],
1791
+ data: [{
1792
+ type: i0.Input,
1793
+ args: [{
1794
+ isSignal: true,
1795
+ alias: "data",
1796
+ required: false
1797
+ }]
1798
+ }],
1799
+ fields: [{
1800
+ type: i0.Input,
1801
+ args: [{
1802
+ isSignal: true,
1803
+ alias: "fields",
1804
+ required: false
1805
+ }]
1806
+ }],
1807
+ loading: [{
1808
+ type: i0.Input,
1809
+ args: [{
1810
+ isSignal: true,
1811
+ alias: "loading",
1812
+ required: false
1813
+ }]
1814
+ }],
1815
+ error: [{
1816
+ type: i0.Input,
1817
+ args: [{
1818
+ isSignal: true,
1819
+ alias: "error",
1820
+ required: false
1821
+ }]
1822
+ }],
1823
+ signerName: [{
1824
+ type: i0.Input,
1825
+ args: [{
1826
+ isSignal: true,
1827
+ alias: "signerName",
1828
+ required: false
1829
+ }]
1830
+ }],
1831
+ savedSignature: [{
1832
+ type: i0.Input,
1833
+ args: [{
1834
+ isSignal: true,
1835
+ alias: "savedSignature",
1836
+ required: false
1837
+ }]
1838
+ }],
1839
+ submitting: [{
1840
+ type: i0.Input,
1841
+ args: [{
1842
+ isSignal: true,
1843
+ alias: "submitting",
1844
+ required: false
1845
+ }]
1846
+ }],
1847
+ texts: [{
1848
+ type: i0.Input,
1849
+ args: [{
1850
+ isSignal: true,
1851
+ alias: "texts",
1852
+ required: false
1853
+ }]
1854
+ }],
1855
+ signed: [{
1856
+ type: i0.Output,
1857
+ args: ["signed"]
1858
+ }],
1859
+ signatureCreated: [{
1860
+ type: i0.Output,
1861
+ args: ["signatureCreated"]
1862
+ }],
1863
+ closed: [{
1864
+ type: i0.Output,
1865
+ args: ["closed"]
1866
+ }]
1867
+ }
1868
+ });
1869
+ export { DocumentSignModalComponent, DocumentViewerModalComponent, PDF_VIEWER_REQUIRED_FEATURES, PDF_VIEWER_WORKER_SRC, PdfViewerComponent, PdfViewerUnsupportedError, findMissingPdfFeatures, provideForgeroutePdf };
700
1870
 
701
1871
  //# sourceMappingURL=forgeroute-ui-pdf.mjs.map