@smartbit4all/ng-client 7.3.39 → 7.3.41

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, reflectComponentType, Injectable, inject, DOCUMENT, PLATFORM_ID, Optional, Inject, SkipSelf, NgModule, RendererStyleFlags2, input, computed, Component, HostListener, HostBinding, Directive, ViewContainerRef, ElementRef, Renderer2, ChangeDetectorRef, Input, output, Injector, signal, afterNextRender, CSP_NONCE, ViewChild, ViewChildren, effect, untracked, NgZone, forwardRef, createComponent, EnvironmentInjector, ApplicationRef, DestroyRef, ChangeDetectionStrategy, ViewEncapsulation, Pipe, viewChild, runInInjectionContext, EventEmitter, Output, makeEnvironmentProviders, importProvidersFrom, provideEnvironmentInitializer } from '@angular/core';
2
+ import { InjectionToken, reflectComponentType, Injectable, inject, DOCUMENT, PLATFORM_ID, Optional, Inject, SkipSelf, NgModule, RendererStyleFlags2, input, computed, Component, HostListener, HostBinding, Directive, ViewContainerRef, ElementRef, Renderer2, ChangeDetectorRef, Input, output, Injector, signal, afterNextRender, CSP_NONCE, ViewChild, ViewChildren, effect, untracked, NgZone, DestroyRef, forwardRef, createComponent, EnvironmentInjector, ApplicationRef, ChangeDetectionStrategy, ViewEncapsulation, Pipe, viewChild, runInInjectionContext, EventEmitter, Output, makeEnvironmentProviders, importProvidersFrom, provideEnvironmentInitializer } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpHeaders, HttpContext, HttpErrorResponse, HttpParams, provideHttpClient, withInterceptors, withInterceptorsFromDi } from '@angular/common/http';
5
5
  import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
@@ -64,6 +64,8 @@ const SMART_MESSAGE_DEFAULTS = {
64
64
  'valueSet.cascade.selectParentFirst': 'Select {0} first',
65
65
  /** Placeholder of the filter input atop a combo box panel. */
66
66
  'select.filter.placeholder': 'Search',
67
+ /** Label of the select-all box atop a multi-select panel. */
68
+ 'select.selectAll.label': 'Select all',
67
69
  };
68
70
  /** The configured text of a message key with its arguments in place; the key itself if unknown. */
69
71
  function formatMessage(config, key, ...args) {
@@ -7791,6 +7793,60 @@ var CodeEditorLang;
7791
7793
  CodeEditorLang["CUSTOM"] = "CUSTOM";
7792
7794
  })(CodeEditorLang || (CodeEditorLang = {}));
7793
7795
 
7796
+ /**
7797
+ * Form layout definition
7798
+ * Contains form layout definition objects.
7799
+ *
7800
+ * The version of the OpenAPI document: 1.0.0
7801
+ * Contact: info@it4all.hu
7802
+ *
7803
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
7804
+ * https://openapi-generator.tech
7805
+ * Do not edit the class manually.
7806
+ */
7807
+
7808
+ /**
7809
+ * Form layout definition
7810
+ * Contains form layout definition objects.
7811
+ *
7812
+ * The version of the OpenAPI document: 1.0.0
7813
+ * Contact: info@it4all.hu
7814
+ *
7815
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
7816
+ * https://openapi-generator.tech
7817
+ * Do not edit the class manually.
7818
+ */
7819
+ /**
7820
+ * A place a file widget takes a file from: FILE the file picker, CAMERA_PHOTO the device camera for a photo, CAMERA_VIDEO the device camera for a video, MICROPHONE the microphone.
7821
+ */
7822
+ var FileUploaderSource;
7823
+ (function (FileUploaderSource) {
7824
+ FileUploaderSource["FILE"] = "FILE";
7825
+ FileUploaderSource["CAMERA_PHOTO"] = "CAMERA_PHOTO";
7826
+ FileUploaderSource["CAMERA_VIDEO"] = "CAMERA_VIDEO";
7827
+ FileUploaderSource["MICROPHONE"] = "MICROPHONE";
7828
+ })(FileUploaderSource || (FileUploaderSource = {}));
7829
+
7830
+ /**
7831
+ * Form layout definition
7832
+ * Contains form layout definition objects.
7833
+ *
7834
+ * The version of the OpenAPI document: 1.0.0
7835
+ * Contact: info@it4all.hu
7836
+ *
7837
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
7838
+ * https://openapi-generator.tech
7839
+ * Do not edit the class manually.
7840
+ */
7841
+ /**
7842
+ * Whether the widget shows the stored file itself (image, video player, audio player) on the card: NONE shows the icon, the name and the size only, FULL shows the file above the name line.
7843
+ */
7844
+ var FileUploaderThumbnail;
7845
+ (function (FileUploaderThumbnail) {
7846
+ FileUploaderThumbnail["NONE"] = "NONE";
7847
+ FileUploaderThumbnail["FULL"] = "FULL";
7848
+ })(FileUploaderThumbnail || (FileUploaderThumbnail = {}));
7849
+
7794
7850
  /**
7795
7851
  * Form layout definition
7796
7852
  * Contains form layout definition objects.
@@ -7822,6 +7878,27 @@ var RecordingUploaderPropertiesOpenDirectionEnum;
7822
7878
  })(RecordingUploaderPropertiesOpenDirectionEnum || (RecordingUploaderPropertiesOpenDirectionEnum = {}));
7823
7879
  ;
7824
7880
 
7881
+ /**
7882
+ * Form layout definition
7883
+ * Contains form layout definition objects.
7884
+ *
7885
+ * The version of the OpenAPI document: 1.0.0
7886
+ * Contact: info@it4all.hu
7887
+ *
7888
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
7889
+ * https://openapi-generator.tech
7890
+ * Do not edit the class manually.
7891
+ */
7892
+ /**
7893
+ * When a multi-select lists a select-all box atop its panel: never, only along with the filter input (from the filter's minimum count of options on), or always.
7894
+ */
7895
+ var SelectAllMode;
7896
+ (function (SelectAllMode) {
7897
+ SelectAllMode["NONE"] = "NONE";
7898
+ SelectAllMode["LIMIT"] = "LIMIT";
7899
+ SelectAllMode["FULL"] = "FULL";
7900
+ })(SelectAllMode || (SelectAllMode = {}));
7901
+
7825
7902
  /**
7826
7903
  * Form layout definition
7827
7904
  * Contains form layout definition objects.
@@ -9022,7 +9099,55 @@ class UploadWidgetUtils {
9022
9099
  const value = parseFloat((bytes / Math.pow(k, i)).toFixed(1));
9023
9100
  return `${value} ${sizes[i]}`;
9024
9101
  }
9025
- }
9102
+ /** The recording mime of a media kind: webm where the browser records it, else mp4 (Safari). */
9103
+ static chooseRecorderMimeType(kind) {
9104
+ return MediaRecorder.isTypeSupported(`${kind}/webm`) ? `${kind}/webm` : `${kind}/mp4`;
9105
+ }
9106
+ /** A recording as a file named by the prefix and the local time, its extension by its mime. */
9107
+ static createRecordingFile(blob, prefix, fallbackMimeType) {
9108
+ const formattedDate = new Date().toLocaleString('sv-SE').replace(' ', '_').replace(/:/g, '-');
9109
+ const mimeType = blob.type || fallbackMimeType;
9110
+ const ext = mimeType.includes('webm') ? 'webm' : 'mp4';
9111
+ return new File([blob], `${prefix}_${formattedDate}.${ext}`, { type: mimeType });
9112
+ }
9113
+ /** The zone's texts: a descriptor's text per key, the client's default for a missing one. */
9114
+ static resolveTexts(texts) {
9115
+ return { ...UPLOAD_ZONE_DEFAULT_TEXTS, ...texts };
9116
+ }
9117
+ /** Fills the `{name}` placeholders of a text, which the server sends raw. */
9118
+ static fillPlaceholders(text, values) {
9119
+ return text.replace(/\{(\w+)\}/g, (placeholder, name) => name in values ? String(values[name]) : placeholder);
9120
+ }
9121
+ }
9122
+ /** The client's text of every key, shown where the descriptor's texts lack the key. */
9123
+ const UPLOAD_ZONE_DEFAULT_TEXTS = {
9124
+ addFile: 'Dokumentum hozzáadása',
9125
+ browseOrDrag: 'tallózás vagy behúzás',
9126
+ maxSize: 'max. {size} MB',
9127
+ upload: 'Feltöltés',
9128
+ unsupportedFormat: '"{fileName}" - nem támogatott formátum',
9129
+ fileTooLarge: '"{fileName}" - túl nagy fájl (max {size} MB)',
9130
+ capturePhoto: 'Fotó készítése',
9131
+ captureVideo: 'Videó készítése',
9132
+ recordAudio: 'Hangfelvétel',
9133
+ photo: 'fotó',
9134
+ video: 'videó',
9135
+ audio: 'hangfelvétel',
9136
+ or: 'vagy',
9137
+ captureOnlyHint: '{sources} készítése',
9138
+ takePicture: 'Kép készítése',
9139
+ cameraOn: 'Kamera bekapcsolása',
9140
+ cameraOff: 'Kamera kikapcsolása',
9141
+ switchOnCameraHint: 'Kapcsolja be a kamerát a kép készítéséhez!',
9142
+ switchOnForVideo: 'Kapcsolja be a kamerát a videó felvételéhez!',
9143
+ startRecording: 'Felvétel indítása',
9144
+ stopRecording: 'Felvétel leállítása',
9145
+ recording: 'Felvétel folyamatban…',
9146
+ pickVideo: 'Videó kiválasztása',
9147
+ cameraError: 'A kamera nem érhető el.',
9148
+ microphoneError: 'A mikrofon nem érhető el.',
9149
+ play: 'Lejátszás',
9150
+ };
9026
9151
 
9027
9152
  class SmartfileuploaderComponent {
9028
9153
  constructor() {
@@ -9042,6 +9167,10 @@ class SmartfileuploaderComponent {
9042
9167
  ...(ngDevMode ? [{ debugName: "autoUpload" }] : /* istanbul ignore next */ []));
9043
9168
  this.isDisabled = input(false, /* @ts-ignore */
9044
9169
  ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
9170
+ /** False in a capture-only zone: no picker and drop zone, the list and the checks stay. The
9171
+ * upload button goes with the picker, so a host hiding it needs autoUpload. */
9172
+ this.pickerShown = input(true, /* @ts-ignore */
9173
+ ...(ngDevMode ? [{ debugName: "pickerShown" }] : /* istanbul ignore next */ []));
9045
9174
  this.isDragOver = false;
9046
9175
  this.errors = [];
9047
9176
  this.previewUrls = new Map();
@@ -9049,13 +9178,14 @@ class SmartfileuploaderComponent {
9049
9178
  ngOnInit() {
9050
9179
  const defaultI18n = {
9051
9180
  addFile: 'dokumentum hozzáadása',
9052
- browseOrDrag: 'tallózás vagy behúzás',
9181
+ browseOrDrag: UPLOAD_ZONE_DEFAULT_TEXTS.browseOrDrag,
9053
9182
  maxSize: `max. ${this.maxSizeMb()} MB`,
9054
9183
  formats: 'PDF, docx, xls formátum',
9055
- upload: 'Feltöltés',
9184
+ upload: UPLOAD_ZONE_DEFAULT_TEXTS.upload,
9056
9185
  };
9057
9186
  this.i18n = { ...defaultI18n, ...this.i18n };
9058
9187
  }
9188
+ /** Checks the formats and the size of picked, dropped and captured files alike. */
9059
9189
  processFiles(fileList) {
9060
9190
  this.errors = [];
9061
9191
  var validFiles = [];
@@ -9069,12 +9199,17 @@ class SmartfileuploaderComponent {
9069
9199
  .map((f) => f.replace('.', '').trim().toLowerCase());
9070
9200
  var isAllowed = trimmedFormats.includes(ext);
9071
9201
  if (!isAllowed) {
9072
- this.errors.push(`"${file.name}" - nem támogatott formátum`);
9202
+ const message = this.i18n?.unsupportedFormat ?? UPLOAD_ZONE_DEFAULT_TEXTS.unsupportedFormat;
9203
+ this.errors.push(UploadWidgetUtils.fillPlaceholders(message, { fileName: file.name }));
9073
9204
  hasError = true;
9074
9205
  }
9075
9206
  }
9076
9207
  if (file.size > this.maxSizeMb() * 1024 * 1024) {
9077
- this.errors.push(`"${file.name}" - túl nagy fájl (max ${this.maxSizeMb()} MB)`);
9208
+ const message = this.i18n?.fileTooLarge ?? UPLOAD_ZONE_DEFAULT_TEXTS.fileTooLarge;
9209
+ this.errors.push(UploadWidgetUtils.fillPlaceholders(message, {
9210
+ fileName: file.name,
9211
+ size: this.maxSizeMb(),
9212
+ }));
9078
9213
  hasError = true;
9079
9214
  }
9080
9215
  if (!hasError) {
@@ -9099,6 +9234,9 @@ class SmartfileuploaderComponent {
9099
9234
  }
9100
9235
  }
9101
9236
  onDrop(event) {
9237
+ if (!this.pickerShown()) {
9238
+ return;
9239
+ }
9102
9240
  event.preventDefault();
9103
9241
  this.isDragOver = false;
9104
9242
  if (!event.dataTransfer?.files)
@@ -9107,6 +9245,9 @@ class SmartfileuploaderComponent {
9107
9245
  this.processFiles(fileList);
9108
9246
  }
9109
9247
  onDragOver(event) {
9248
+ if (!this.pickerShown()) {
9249
+ return;
9250
+ }
9110
9251
  event.preventDefault();
9111
9252
  this.isDragOver = true;
9112
9253
  }
@@ -9193,68 +9334,144 @@ class SmartfileuploaderComponent {
9193
9334
  };
9194
9335
  }
9195
9336
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartfileuploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9196
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartfileuploaderComponent, isStandalone: true, selector: "smartfileuploader", inputs: { uploadCallback: { classPropertyName: "uploadCallback", publicName: "uploadCallback", isSignal: true, isRequired: true, transformFunction: null }, fileFormats: { classPropertyName: "fileFormats", publicName: "fileFormats", isSignal: true, isRequired: false, transformFunction: null }, maxSizeMb: { classPropertyName: "maxSizeMb", publicName: "maxSizeMb", isSignal: true, isRequired: false, transformFunction: null }, i18n: { classPropertyName: "i18n", publicName: "i18n", isSignal: false, isRequired: false, transformFunction: null }, useIconButton: { classPropertyName: "useIconButton", publicName: "useIconButton", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"container\"\n [ngClass]=\"{ disabledWidget: isDisabled() }\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.dragover]=\"isDragOver\"\n>\n <div class=\"fileContainer\" (click)=\"fileInput.click()\">\n <input\n #fileInput\n id=\"addFile\"\n placeholder=\"fileInput\"\n type=\"file\"\n (change)=\"getFile($event)\"\n class=\"file\"\n accept=\"{{ fileFormats()?.join(', ') }}\"\n [size]=\"maxSizeMb()\"\n [multiple]=\"isMultiple()\"\n [disabled]=\"isDisabled()\"\n style=\"display: none\"\n />\n <div class=\"fileUploadContentContainer\">\n <div class=\"icon\">\n @if (useIconButton()) {\n <mat-label class=\"addFileButton\">\n <mat-icon fontSet=\"material-symbols-outlined\" color=\"primary\" class=\"addCircle\"\n >add_circle</mat-icon\n >\n </mat-label>\n }\n @if (!useIconButton()) {\n <button mat-raised-button color=\"primary\" class=\"addFileButton\">\n {{ i18n!.addFile }}\n </button>\n }\n </div>\n <div class=\"labels\">\n @if (useIconButton()) {\n <mat-label class=\"label primary title\">\n {{ i18n!.addFile }}\n </mat-label>\n }\n <mat-label class=\"label secondary\"> {{ i18n!.browseOrDrag }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.maxSize }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.formats }} </mat-label>\n </div>\n @if (files.length) {\n <div class=\"uploadButton\">\n <ui-action-button\n (actionClick)=\"uploadFile($event)\"\n [code]=\"'default-upload'\"\n [descriptor]=\"uploadButton\"\n >\n </ui-action-button>\n </div>\n }\n </div>\n </div>\n\n @if (errors.length) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"'error'\" [color]=\"'warn'\"></smart-icon>\n <div class=\"errors\">\n @for (error of errors; track error) {\n <span>{{ error }}</span>\n }\n </div>\n </div>\n }\n\n @if (files.length) {\n <div class=\"uploadedFilesContainer\">\n @for (file of files; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @if (filePreviewUrl(file)) {\n <img [src]=\"filePreviewUrl(file)\" [alt]=\"file.name\" width=\"50\" height=\"50\" />\n } @else {\n <smart-icon [icon]=\"'insert_drive_file'\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file.name }}</span>\n <span class=\"fileSize\">{{ formatSize(file.size) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file)\"\n [attr.data-testid]=\"'default_download'\"\n ></smart-icon>\n <smart-icon\n class=\"removeIcon\"\n icon=\"delete\"\n [attr.data-testid]=\"'default_remove'\"\n (click)=\"remove(i)\"\n ></smart-icon>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem}.container{display:flex;flex-direction:column;border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileContainer{cursor:pointer;padding:1rem;display:flex;flex-direction:column}.fileContainer:hover{background-color:rgb(from var(--border-color) r g b / .1)}.disabledWidget ::ng-deep .fileContainer:hover{background-color:unset;cursor:unset}.disabledWidget ::ng-deep *{opacity:.85}.dragover{background-color:rgb(from var(--border-color) r g b / .1)}.fileUploadContentContainer{display:flex;flex-direction:row;gap:1rem}.icon mat-icon{font-size:3rem;width:unset;height:unset}.icon{align-content:center}.labels{flex:1;display:flex;flex-direction:column;justify-content:center;width:fit-content}.uploadButton{align-content:center}.primary{color:var(--primary-color)}.secondary{color:var(--gray)}.label{margin:unset}.subLabel{font-size:smaller}.title{padding-bottom:.3rem}.errorMessage,.uploadedFilesContainer{border-top:2px solid var(--border-color)}.errorMessage{display:flex;flex-direction:row;align-items:center;color:var(--warn-color);padding:.5rem 1rem;gap:1rem}.errorMessage ::ng-deep mat-icon{color:var(--warn-color)}.errors{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;gap:1rem}.uploadedFile:last-child{border-bottom:none}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }] }); }
9337
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartfileuploaderComponent, isStandalone: true, selector: "smartfileuploader", inputs: { uploadCallback: { classPropertyName: "uploadCallback", publicName: "uploadCallback", isSignal: true, isRequired: true, transformFunction: null }, fileFormats: { classPropertyName: "fileFormats", publicName: "fileFormats", isSignal: true, isRequired: false, transformFunction: null }, maxSizeMb: { classPropertyName: "maxSizeMb", publicName: "maxSizeMb", isSignal: true, isRequired: false, transformFunction: null }, i18n: { classPropertyName: "i18n", publicName: "i18n", isSignal: false, isRequired: false, transformFunction: null }, useIconButton: { classPropertyName: "useIconButton", publicName: "useIconButton", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, pickerShown: { classPropertyName: "pickerShown", publicName: "pickerShown", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"container\"\n [ngClass]=\"{ disabledWidget: isDisabled() }\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.dragover]=\"isDragOver\"\n [class.captureOnly]=\"!pickerShown()\"\n>\n @if (pickerShown()) {\n <div class=\"fileContainer\" (click)=\"fileInput.click()\">\n <input\n #fileInput\n id=\"addFile\"\n placeholder=\"fileInput\"\n type=\"file\"\n (change)=\"getFile($event)\"\n class=\"file\"\n accept=\"{{ fileFormats()?.join(', ') }}\"\n [size]=\"maxSizeMb()\"\n [multiple]=\"isMultiple()\"\n [disabled]=\"isDisabled()\"\n style=\"display: none\"\n />\n <div class=\"fileUploadContentContainer\">\n <div class=\"icon\">\n @if (useIconButton()) {\n <mat-label class=\"addFileButton\">\n <mat-icon fontSet=\"material-symbols-outlined\" color=\"primary\" class=\"addCircle\"\n >add_circle</mat-icon\n >\n </mat-label>\n }\n @if (!useIconButton()) {\n <button mat-raised-button color=\"primary\" class=\"addFileButton\">\n {{ i18n!.addFile }}\n </button>\n }\n </div>\n <div class=\"labels\">\n @if (useIconButton()) {\n <mat-label class=\"label primary title\">\n {{ i18n!.addFile }}\n </mat-label>\n }\n <mat-label class=\"label secondary\"> {{ i18n!.browseOrDrag }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.maxSize }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.formats }} </mat-label>\n </div>\n @if (files.length) {\n <div class=\"uploadButton\">\n <ui-action-button\n (actionClick)=\"uploadFile($event)\"\n [code]=\"'default-upload'\"\n [descriptor]=\"uploadButton\"\n >\n </ui-action-button>\n </div>\n }\n </div>\n </div>\n }\n\n @if (errors.length) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"'error'\" [color]=\"'warn'\"></smart-icon>\n <div class=\"errors\">\n @for (error of errors; track error) {\n <span>{{ error }}</span>\n }\n </div>\n </div>\n }\n\n @if (files.length) {\n <div class=\"uploadedFilesContainer\">\n @for (file of files; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @if (filePreviewUrl(file)) {\n <img [src]=\"filePreviewUrl(file)\" [alt]=\"file.name\" width=\"50\" height=\"50\" />\n } @else {\n <smart-icon [icon]=\"'insert_drive_file'\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file.name }}</span>\n <span class=\"fileSize\">{{ formatSize(file.size) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file)\"\n [attr.data-testid]=\"'default_download'\"\n ></smart-icon>\n <smart-icon\n class=\"removeIcon\"\n icon=\"delete\"\n [attr.data-testid]=\"'default_remove'\"\n (click)=\"remove(i)\"\n ></smart-icon>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem}.container{display:flex;flex-direction:column;border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.container.captureOnly{border:none}.fileContainer{cursor:pointer;padding:1rem;display:flex;flex-direction:column}.fileContainer:hover{background-color:rgb(from var(--border-color) r g b / .1)}.disabledWidget ::ng-deep .fileContainer:hover{background-color:unset;cursor:unset}.disabledWidget ::ng-deep *{opacity:.85}.dragover{background-color:rgb(from var(--border-color) r g b / .1)}.fileUploadContentContainer{display:flex;flex-direction:row;gap:1rem}.icon mat-icon{font-size:3rem;width:unset;height:unset}.icon{align-content:center}.labels{flex:1;display:flex;flex-direction:column;justify-content:center;width:fit-content}.uploadButton{align-content:center}.primary{color:var(--primary-color)}.secondary{color:var(--gray)}.label{margin:unset}.subLabel{font-size:smaller}.title{padding-bottom:.3rem}.errorMessage,.uploadedFilesContainer{border-top:2px solid var(--border-color)}.errorMessage{display:flex;flex-direction:row;align-items:center;color:var(--warn-color);padding:.5rem 1rem;gap:1rem}.errorMessage ::ng-deep mat-icon{color:var(--warn-color)}.errors{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;gap:1rem}.uploadedFile:last-child{border-bottom:none}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }] }); }
9197
9338
  }
9198
9339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartfileuploaderComponent, decorators: [{
9199
9340
  type: Component,
9200
- args: [{ selector: 'smartfileuploader', imports: [NgClass, MatLabel, MatIcon, MatButton, UiActionButtonComponent, SmartIconComponent], template: "<div\n class=\"container\"\n [ngClass]=\"{ disabledWidget: isDisabled() }\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.dragover]=\"isDragOver\"\n>\n <div class=\"fileContainer\" (click)=\"fileInput.click()\">\n <input\n #fileInput\n id=\"addFile\"\n placeholder=\"fileInput\"\n type=\"file\"\n (change)=\"getFile($event)\"\n class=\"file\"\n accept=\"{{ fileFormats()?.join(', ') }}\"\n [size]=\"maxSizeMb()\"\n [multiple]=\"isMultiple()\"\n [disabled]=\"isDisabled()\"\n style=\"display: none\"\n />\n <div class=\"fileUploadContentContainer\">\n <div class=\"icon\">\n @if (useIconButton()) {\n <mat-label class=\"addFileButton\">\n <mat-icon fontSet=\"material-symbols-outlined\" color=\"primary\" class=\"addCircle\"\n >add_circle</mat-icon\n >\n </mat-label>\n }\n @if (!useIconButton()) {\n <button mat-raised-button color=\"primary\" class=\"addFileButton\">\n {{ i18n!.addFile }}\n </button>\n }\n </div>\n <div class=\"labels\">\n @if (useIconButton()) {\n <mat-label class=\"label primary title\">\n {{ i18n!.addFile }}\n </mat-label>\n }\n <mat-label class=\"label secondary\"> {{ i18n!.browseOrDrag }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.maxSize }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.formats }} </mat-label>\n </div>\n @if (files.length) {\n <div class=\"uploadButton\">\n <ui-action-button\n (actionClick)=\"uploadFile($event)\"\n [code]=\"'default-upload'\"\n [descriptor]=\"uploadButton\"\n >\n </ui-action-button>\n </div>\n }\n </div>\n </div>\n\n @if (errors.length) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"'error'\" [color]=\"'warn'\"></smart-icon>\n <div class=\"errors\">\n @for (error of errors; track error) {\n <span>{{ error }}</span>\n }\n </div>\n </div>\n }\n\n @if (files.length) {\n <div class=\"uploadedFilesContainer\">\n @for (file of files; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @if (filePreviewUrl(file)) {\n <img [src]=\"filePreviewUrl(file)\" [alt]=\"file.name\" width=\"50\" height=\"50\" />\n } @else {\n <smart-icon [icon]=\"'insert_drive_file'\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file.name }}</span>\n <span class=\"fileSize\">{{ formatSize(file.size) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file)\"\n [attr.data-testid]=\"'default_download'\"\n ></smart-icon>\n <smart-icon\n class=\"removeIcon\"\n icon=\"delete\"\n [attr.data-testid]=\"'default_remove'\"\n (click)=\"remove(i)\"\n ></smart-icon>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem}.container{display:flex;flex-direction:column;border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileContainer{cursor:pointer;padding:1rem;display:flex;flex-direction:column}.fileContainer:hover{background-color:rgb(from var(--border-color) r g b / .1)}.disabledWidget ::ng-deep .fileContainer:hover{background-color:unset;cursor:unset}.disabledWidget ::ng-deep *{opacity:.85}.dragover{background-color:rgb(from var(--border-color) r g b / .1)}.fileUploadContentContainer{display:flex;flex-direction:row;gap:1rem}.icon mat-icon{font-size:3rem;width:unset;height:unset}.icon{align-content:center}.labels{flex:1;display:flex;flex-direction:column;justify-content:center;width:fit-content}.uploadButton{align-content:center}.primary{color:var(--primary-color)}.secondary{color:var(--gray)}.label{margin:unset}.subLabel{font-size:smaller}.title{padding-bottom:.3rem}.errorMessage,.uploadedFilesContainer{border-top:2px solid var(--border-color)}.errorMessage{display:flex;flex-direction:row;align-items:center;color:var(--warn-color);padding:.5rem 1rem;gap:1rem}.errorMessage ::ng-deep mat-icon{color:var(--warn-color)}.errors{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;gap:1rem}.uploadedFile:last-child{border-bottom:none}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}\n"] }]
9341
+ args: [{ selector: 'smartfileuploader', imports: [NgClass, MatLabel, MatIcon, MatButton, UiActionButtonComponent, SmartIconComponent], template: "<div\n class=\"container\"\n [ngClass]=\"{ disabledWidget: isDisabled() }\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.dragover]=\"isDragOver\"\n [class.captureOnly]=\"!pickerShown()\"\n>\n @if (pickerShown()) {\n <div class=\"fileContainer\" (click)=\"fileInput.click()\">\n <input\n #fileInput\n id=\"addFile\"\n placeholder=\"fileInput\"\n type=\"file\"\n (change)=\"getFile($event)\"\n class=\"file\"\n accept=\"{{ fileFormats()?.join(', ') }}\"\n [size]=\"maxSizeMb()\"\n [multiple]=\"isMultiple()\"\n [disabled]=\"isDisabled()\"\n style=\"display: none\"\n />\n <div class=\"fileUploadContentContainer\">\n <div class=\"icon\">\n @if (useIconButton()) {\n <mat-label class=\"addFileButton\">\n <mat-icon fontSet=\"material-symbols-outlined\" color=\"primary\" class=\"addCircle\"\n >add_circle</mat-icon\n >\n </mat-label>\n }\n @if (!useIconButton()) {\n <button mat-raised-button color=\"primary\" class=\"addFileButton\">\n {{ i18n!.addFile }}\n </button>\n }\n </div>\n <div class=\"labels\">\n @if (useIconButton()) {\n <mat-label class=\"label primary title\">\n {{ i18n!.addFile }}\n </mat-label>\n }\n <mat-label class=\"label secondary\"> {{ i18n!.browseOrDrag }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.maxSize }} </mat-label>\n <mat-label class=\"subLabel primary\"> {{ i18n!.formats }} </mat-label>\n </div>\n @if (files.length) {\n <div class=\"uploadButton\">\n <ui-action-button\n (actionClick)=\"uploadFile($event)\"\n [code]=\"'default-upload'\"\n [descriptor]=\"uploadButton\"\n >\n </ui-action-button>\n </div>\n }\n </div>\n </div>\n }\n\n @if (errors.length) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"'error'\" [color]=\"'warn'\"></smart-icon>\n <div class=\"errors\">\n @for (error of errors; track error) {\n <span>{{ error }}</span>\n }\n </div>\n </div>\n }\n\n @if (files.length) {\n <div class=\"uploadedFilesContainer\">\n @for (file of files; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @if (filePreviewUrl(file)) {\n <img [src]=\"filePreviewUrl(file)\" [alt]=\"file.name\" width=\"50\" height=\"50\" />\n } @else {\n <smart-icon [icon]=\"'insert_drive_file'\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file.name }}</span>\n <span class=\"fileSize\">{{ formatSize(file.size) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file)\"\n [attr.data-testid]=\"'default_download'\"\n ></smart-icon>\n <smart-icon\n class=\"removeIcon\"\n icon=\"delete\"\n [attr.data-testid]=\"'default_remove'\"\n (click)=\"remove(i)\"\n ></smart-icon>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem}.container{display:flex;flex-direction:column;border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.container.captureOnly{border:none}.fileContainer{cursor:pointer;padding:1rem;display:flex;flex-direction:column}.fileContainer:hover{background-color:rgb(from var(--border-color) r g b / .1)}.disabledWidget ::ng-deep .fileContainer:hover{background-color:unset;cursor:unset}.disabledWidget ::ng-deep *{opacity:.85}.dragover{background-color:rgb(from var(--border-color) r g b / .1)}.fileUploadContentContainer{display:flex;flex-direction:row;gap:1rem}.icon mat-icon{font-size:3rem;width:unset;height:unset}.icon{align-content:center}.labels{flex:1;display:flex;flex-direction:column;justify-content:center;width:fit-content}.uploadButton{align-content:center}.primary{color:var(--primary-color)}.secondary{color:var(--gray)}.label{margin:unset}.subLabel{font-size:smaller}.title{padding-bottom:.3rem}.errorMessage,.uploadedFilesContainer{border-top:2px solid var(--border-color)}.errorMessage{display:flex;flex-direction:row;align-items:center;color:var(--warn-color);padding:.5rem 1rem;gap:1rem}.errorMessage ::ng-deep mat-icon{color:var(--warn-color)}.errors{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;gap:1rem}.uploadedFile:last-child{border-bottom:none}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}\n"] }]
9201
9342
  }], propDecorators: { fileInput: [{
9202
9343
  type: ViewChild,
9203
9344
  args: ['fileInput']
9204
9345
  }], uploadCallback: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadCallback", required: true }] }], fileFormats: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileFormats", required: false }] }], maxSizeMb: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSizeMb", required: false }] }], i18n: [{
9205
9346
  type: Input
9206
- }], useIconButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIconButton", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: false }] }], autoUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoUpload", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }] } });
9347
+ }], useIconButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIconButton", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: false }] }], autoUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoUpload", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], pickerShown: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickerShown", required: false }] }] } });
9207
9348
 
9208
9349
  class PhotoCaptureWidgetComponent {
9209
- get cameraActive() {
9210
- return this.cameraActiveState();
9211
- }
9212
- set cameraActive(active) {
9213
- this.cameraActiveState.set(active);
9214
- }
9215
- get isCaptured() {
9216
- return this.isCapturedState();
9217
- }
9218
- set isCaptured(captured) {
9219
- this.isCapturedState.set(captured);
9220
- }
9221
9350
  constructor() {
9222
9351
  this.maxFileSize = input(/* @ts-ignore */
9223
9352
  ...(ngDevMode ? [undefined, { debugName: "maxFileSize" }] : /* istanbul ignore next */ []));
9353
+ /** PHOTO takes a picture; VIDEO records a video with the webcam or picks one on a desktop. */
9354
+ this.mode = input('PHOTO', /* @ts-ignore */
9355
+ ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
9356
+ /** True when the zone's capture row carries the button: the widget then opens only by
9357
+ * openCapture(). */
9358
+ this.externalTrigger = input(false, /* @ts-ignore */
9359
+ ...(ngDevMode ? [{ debugName: "externalTrigger" }] : /* istanbul ignore next */ []));
9360
+ /** The zone's texts; the buttons follow them. */
9361
+ this.texts = input(UPLOAD_ZONE_DEFAULT_TEXTS, /* @ts-ignore */
9362
+ ...(ngDevMode ? [{ debugName: "texts" }] : /* istanbul ignore next */ []));
9224
9363
  this.photoCaptured = output();
9364
+ /** The desktop webcam panel of an externally triggered photo widget, opened by openCapture(). */
9365
+ this.isPanelOpen = signal(false, /* @ts-ignore */
9366
+ ...(ngDevMode ? [{ debugName: "isPanelOpen" }] : /* istanbul ignore next */ []));
9225
9367
  /**
9226
9368
  * Both are written after an `await` — the camera stream, the compression — so a signal
9227
9369
  * each: the click that started it has long been checked by then.
9228
9370
  */
9229
9371
  this.cameraActiveState = signal(false, /* @ts-ignore */
9230
9372
  ...(ngDevMode ? [{ debugName: "cameraActiveState" }] : /* istanbul ignore next */ []));
9373
+ /** Set when the browser gives no camera, shown in place of the switch-on hint. */
9374
+ this.cameraError = signal(false, /* @ts-ignore */
9375
+ ...(ngDevMode ? [{ debugName: "cameraError" }] : /* istanbul ignore next */ []));
9376
+ this.isRecordingState = signal(false, /* @ts-ignore */
9377
+ ...(ngDevMode ? [{ debugName: "isRecordingState" }] : /* istanbul ignore next */ []));
9231
9378
  this.isCapturedState = signal(false, /* @ts-ignore */
9232
9379
  ...(ngDevMode ? [{ debugName: "isCapturedState" }] : /* istanbul ignore next */ []));
9233
- this.captureButton = {
9234
- type: UiActionButtonType.RAISED,
9235
- title: 'Kép készítése',
9236
- icon: 'camera',
9237
- iconPosition: IconPosition.PRE,
9238
- color: 'primary',
9239
- };
9240
- this.updateToggleButton();
9380
+ /** Advanced by stopCamera(), so a stream the browser gives after a close is stopped at once. */
9381
+ this.cameraRequest = 0;
9382
+ this.toggleCameraButton = computed(() => this.createButton(this.cameraActive ? this.texts().cameraOff : this.texts().cameraOn, 'power_settings_new', this.cameraActive ? 'red' : 'primary'), /* @ts-ignore */
9383
+ ...(ngDevMode ? [{ debugName: "toggleCameraButton" }] : /* istanbul ignore next */ []));
9384
+ this.captureButton = computed(() => this.createButton(this.texts().takePicture, 'camera'), /* @ts-ignore */
9385
+ ...(ngDevMode ? [{ debugName: "captureButton" }] : /* istanbul ignore next */ []));
9386
+ this.startRecordingButton = computed(() => this.createButton(this.texts().startRecording, 'fiber_manual_record'), /* @ts-ignore */
9387
+ ...(ngDevMode ? [{ debugName: "startRecordingButton" }] : /* istanbul ignore next */ []));
9388
+ this.stopRecordingButton = computed(() => this.createButton(this.texts().stopRecording, 'stop', 'red'), /* @ts-ignore */
9389
+ ...(ngDevMode ? [{ debugName: "stopRecordingButton" }] : /* istanbul ignore next */ []));
9390
+ this.pickVideoButton = computed(() => this.createButton(this.texts().pickVideo, 'video_library'), /* @ts-ignore */
9391
+ ...(ngDevMode ? [{ debugName: "pickVideoButton" }] : /* istanbul ignore next */ []));
9392
+ }
9393
+ get cameraActive() {
9394
+ return this.cameraActiveState();
9395
+ }
9396
+ set cameraActive(active) {
9397
+ this.cameraActiveState.set(active);
9398
+ }
9399
+ get isRecording() {
9400
+ return this.isRecordingState();
9401
+ }
9402
+ set isRecording(recording) {
9403
+ this.isRecordingState.set(recording);
9404
+ }
9405
+ get isCaptured() {
9406
+ return this.isCapturedState();
9407
+ }
9408
+ set isCaptured(captured) {
9409
+ this.isCapturedState.set(captured);
9241
9410
  }
9242
9411
  isMobile() {
9243
9412
  return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
9244
9413
  }
9414
+ /** A phone opens its own camera, a desktop the webcam panel. */
9415
+ openCapture() {
9416
+ if (this.isMobile()) {
9417
+ this.fileInputRef.nativeElement.click();
9418
+ return;
9419
+ }
9420
+ if (this.isPanelOpen()) {
9421
+ this.stopCamera();
9422
+ }
9423
+ this.isPanelOpen.update((open) => !open);
9424
+ }
9425
+ ngOnDestroy() {
9426
+ this.stopCamera();
9427
+ }
9245
9428
  async startCamera() {
9246
- this.stream = await navigator.mediaDevices.getUserMedia({ video: true });
9429
+ this.cameraError.set(false);
9430
+ const request = ++this.cameraRequest;
9431
+ let stream;
9432
+ try {
9433
+ stream = await this.openCameraStream();
9434
+ }
9435
+ catch {
9436
+ if (request === this.cameraRequest) {
9437
+ this.cameraError.set(true);
9438
+ }
9439
+ return;
9440
+ }
9441
+ if (request !== this.cameraRequest) {
9442
+ stream.getTracks().forEach((track) => track.stop());
9443
+ return;
9444
+ }
9445
+ this.stream = stream;
9247
9446
  this.videoRef.nativeElement.srcObject = this.stream;
9248
9447
  this.videoRef.nativeElement.play();
9249
9448
  this.cameraActive = true;
9250
9449
  this.isCaptured = false;
9251
- this.updateToggleButton();
9252
9450
  }
9451
+ /** A video asks for the sound too; a desktop without a microphone records a silent one. */
9452
+ async openCameraStream() {
9453
+ if (this.mode() === 'VIDEO') {
9454
+ try {
9455
+ return await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
9456
+ }
9457
+ catch {
9458
+ // No microphone answers: the camera alone is asked below.
9459
+ }
9460
+ }
9461
+ return navigator.mediaDevices.getUserMedia({ video: true });
9462
+ }
9463
+ /** Closing the camera mid-recording discards the recording. */
9253
9464
  stopCamera() {
9465
+ this.cameraRequest++;
9466
+ if (this.recorder) {
9467
+ this.recorder.onstop = null;
9468
+ this.recorder.stop();
9469
+ this.recorder = undefined;
9470
+ }
9471
+ this.isRecording = false;
9254
9472
  this.stream?.getTracks().forEach((track) => track.stop());
9255
9473
  this.stream = undefined;
9256
9474
  this.cameraActive = false;
9257
- this.updateToggleButton();
9258
9475
  }
9259
9476
  async capturePhoto() {
9260
9477
  const video = this.videoRef.nativeElement;
@@ -9277,6 +9494,34 @@ class PhotoCaptureWidgetComponent {
9277
9494
  this.isCaptured = true;
9278
9495
  this.stopCamera();
9279
9496
  }
9497
+ /** A browser that records neither webm nor mp4 refuses the recorder: the camera error shows. */
9498
+ startRecording() {
9499
+ let recorder;
9500
+ try {
9501
+ recorder = new MediaRecorder(this.stream, {
9502
+ mimeType: UploadWidgetUtils.chooseRecorderMimeType('video'),
9503
+ });
9504
+ }
9505
+ catch {
9506
+ this.cameraError.set(true);
9507
+ return;
9508
+ }
9509
+ const chunks = [];
9510
+ recorder.ondataavailable = (event) => chunks.push(event.data);
9511
+ recorder.onstop = () => {
9512
+ const blob = new Blob(chunks, { type: recorder.mimeType });
9513
+ this.recorder = undefined;
9514
+ this.photoCaptured.emit([UploadWidgetUtils.createRecordingFile(blob, 'video', 'video/mp4')]);
9515
+ this.stopCamera();
9516
+ };
9517
+ recorder.start();
9518
+ this.recorder = recorder;
9519
+ this.isRecording = true;
9520
+ }
9521
+ /** The recording state holds until onstop hands the video over and stops the camera. */
9522
+ stopRecording() {
9523
+ this.recorder?.stop();
9524
+ }
9280
9525
  getPhotoDataURL() {
9281
9526
  return this.canvasRef.nativeElement.toDataURL('image/png');
9282
9527
  }
@@ -9311,26 +9556,6 @@ class PhotoCaptureWidgetComponent {
9311
9556
  this.startCamera();
9312
9557
  }
9313
9558
  }
9314
- updateToggleButton() {
9315
- let icon = 'power_settings_new';
9316
- let title;
9317
- let color;
9318
- if (this.cameraActive) {
9319
- title = 'Kamera kikapcsolása';
9320
- color = 'red';
9321
- }
9322
- else {
9323
- title = 'Kamera bekapcsolása';
9324
- color = 'primary';
9325
- }
9326
- this.toggleCameraButton = {
9327
- type: UiActionButtonType.RAISED,
9328
- title: title,
9329
- icon: icon,
9330
- color,
9331
- iconPosition: IconPosition.PRE,
9332
- };
9333
- }
9334
9559
  async compressImageFile(file, maxFileSize) {
9335
9560
  if (!file.type.startsWith('image/'))
9336
9561
  return file;
@@ -9388,13 +9613,16 @@ class PhotoCaptureWidgetComponent {
9388
9613
  return file;
9389
9614
  }
9390
9615
  }
9616
+ createButton(title, icon, color = 'primary') {
9617
+ return { type: UiActionButtonType.RAISED, title, icon, iconPosition: IconPosition.PRE, color };
9618
+ }
9391
9619
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PhotoCaptureWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9392
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PhotoCaptureWidgetComponent, isStandalone: true, selector: "photo-capture-widget", inputs: { maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { photoCaptured: "photoCaptured" }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true }, { propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }, { propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"photoWidgetContainer\">\n @if (!isMobile()) {\n <video #video autoplay [hidden]=\"isCaptured || !cameraActive\"></video>\n <canvas #canvas [hidden]=\"!isCaptured || cameraActive\"></canvas>\n @if (!cameraActive && !isCaptured) {\n <p class=\"message\">Kapcsolja be a kamer\u00E1t a k\u00E9p k\u00E9sz\u00EDt\u00E9s\u00E9hez!</p>\n }\n <div class=\"controls\">\n <!-- START CAMERA -->\n <ui-action-button [descriptor]=\"toggleCameraButton\" (actionClick)=\"toggleCamera()\">\n </ui-action-button>\n <!-- CAPTURE CAMERA -->\n <ui-action-button\n [disabled]=\"!cameraActive\"\n [descriptor]=\"captureButton\"\n (actionClick)=\"capturePhoto()\"\n >\n </ui-action-button>\n </div>\n }\n\n @if (isMobile()) {\n <div class=\"controls\">\n <input\n #fileInput\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n <ui-action-button [descriptor]=\"captureButton\" (actionClick)=\"fileInput.click()\">\n </ui-action-button>\n </div>\n }\n</div>\n", styles: [".photoWidgetContainer{border-radius:5px;width:100%;max-width:100%;display:flex;flex-direction:column;justify-content:center;border:1px solid #dee2e6}.message{text-align:center;color:#6b7280}video,canvas{border-top-right-radius:5px;border-top-left-radius:5px;width:100%}.controls{padding:.5rem;display:flex;gap:1rem;flex-direction:row;justify-content:center;background:#f8f9fa;border-top:1px solid #dee2e6;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.controls ::ng-deep button{border-radius:3px}\n"], dependencies: [{ kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9620
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PhotoCaptureWidgetComponent, isStandalone: true, selector: "photo-capture-widget", inputs: { maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, externalTrigger: { classPropertyName: "externalTrigger", publicName: "externalTrigger", isSignal: true, isRequired: false, transformFunction: null }, texts: { classPropertyName: "texts", publicName: "texts", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { photoCaptured: "photoCaptured" }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true }, { propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }, { propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "@if (isMobile()) {\n <input\n #fileInput\n type=\"file\"\n [accept]=\"mode() === 'VIDEO' ? 'video/*' : 'image/*'\"\n capture=\"environment\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n @if (!externalTrigger()) {\n <div class=\"photoWidgetContainer\">\n <div class=\"controls\">\n <ui-action-button [descriptor]=\"captureButton()\" (actionClick)=\"fileInput.click()\">\n </ui-action-button>\n </div>\n </div>\n }\n} @else if (!externalTrigger() || isPanelOpen()) {\n <div class=\"photoWidgetContainer\">\n <video #video autoplay [muted]=\"true\" [hidden]=\"isCaptured || !cameraActive\"></video>\n <canvas #canvas [hidden]=\"!isCaptured || cameraActive\"></canvas>\n @if (cameraError()) {\n <p class=\"message\">{{ texts().cameraError }}</p>\n } @else if (isRecording) {\n <p class=\"message\">{{ texts().recording }}</p>\n } @else if (!cameraActive && !isCaptured) {\n @if (mode() === 'VIDEO') {\n <p class=\"message\">{{ texts().switchOnForVideo }}</p>\n } @else {\n <p class=\"message\">{{ texts().switchOnCameraHint }}</p>\n }\n }\n <div class=\"controls\">\n <!-- START CAMERA -->\n <ui-action-button\n class=\"toggleCameraButton\"\n [disabled]=\"isRecording\"\n [descriptor]=\"toggleCameraButton()\"\n (actionClick)=\"toggleCamera()\"\n >\n </ui-action-button>\n @if (mode() === 'VIDEO') {\n <!-- RECORD / STOP VIDEO -->\n @if (isRecording) {\n <ui-action-button\n class=\"stopRecordingButton\"\n [descriptor]=\"stopRecordingButton()\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n } @else {\n <ui-action-button\n class=\"startRecordingButton\"\n [disabled]=\"!cameraActive\"\n [descriptor]=\"startRecordingButton()\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n <!-- PICK VIDEO FILE -->\n <input\n #fileInput\n type=\"file\"\n accept=\"video/*\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n <ui-action-button\n class=\"pickVideoButton\"\n [disabled]=\"isRecording\"\n [descriptor]=\"pickVideoButton()\"\n (actionClick)=\"fileInput.click()\"\n >\n </ui-action-button>\n } @else {\n <!-- CAPTURE CAMERA -->\n <ui-action-button\n class=\"capturePhotoButton\"\n [disabled]=\"!cameraActive\"\n [descriptor]=\"captureButton()\"\n (actionClick)=\"capturePhoto()\"\n >\n </ui-action-button>\n }\n </div>\n </div>\n}\n", styles: [".photoWidgetContainer{border-radius:5px;width:100%;max-width:100%;display:flex;flex-direction:column;justify-content:center;border:1px solid #dee2e6}.message{text-align:center;color:#6b7280}video,canvas{border-top-right-radius:5px;border-top-left-radius:5px;width:100%}.controls{padding:.5rem;display:flex;gap:1rem;flex-direction:row;justify-content:center;background:#f8f9fa;border-top:1px solid #dee2e6;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.controls ::ng-deep button{border-radius:3px}\n"], dependencies: [{ kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9393
9621
  }
9394
9622
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PhotoCaptureWidgetComponent, decorators: [{
9395
9623
  type: Component,
9396
- args: [{ selector: 'photo-capture-widget', imports: [UiActionButtonComponent], template: "<div class=\"photoWidgetContainer\">\n @if (!isMobile()) {\n <video #video autoplay [hidden]=\"isCaptured || !cameraActive\"></video>\n <canvas #canvas [hidden]=\"!isCaptured || cameraActive\"></canvas>\n @if (!cameraActive && !isCaptured) {\n <p class=\"message\">Kapcsolja be a kamer\u00E1t a k\u00E9p k\u00E9sz\u00EDt\u00E9s\u00E9hez!</p>\n }\n <div class=\"controls\">\n <!-- START CAMERA -->\n <ui-action-button [descriptor]=\"toggleCameraButton\" (actionClick)=\"toggleCamera()\">\n </ui-action-button>\n <!-- CAPTURE CAMERA -->\n <ui-action-button\n [disabled]=\"!cameraActive\"\n [descriptor]=\"captureButton\"\n (actionClick)=\"capturePhoto()\"\n >\n </ui-action-button>\n </div>\n }\n\n @if (isMobile()) {\n <div class=\"controls\">\n <input\n #fileInput\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n <ui-action-button [descriptor]=\"captureButton\" (actionClick)=\"fileInput.click()\">\n </ui-action-button>\n </div>\n }\n</div>\n", styles: [".photoWidgetContainer{border-radius:5px;width:100%;max-width:100%;display:flex;flex-direction:column;justify-content:center;border:1px solid #dee2e6}.message{text-align:center;color:#6b7280}video,canvas{border-top-right-radius:5px;border-top-left-radius:5px;width:100%}.controls{padding:.5rem;display:flex;gap:1rem;flex-direction:row;justify-content:center;background:#f8f9fa;border-top:1px solid #dee2e6;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.controls ::ng-deep button{border-radius:3px}\n"] }]
9397
- }], ctorParameters: () => [], propDecorators: { videoRef: [{
9624
+ args: [{ selector: 'photo-capture-widget', imports: [UiActionButtonComponent], template: "@if (isMobile()) {\n <input\n #fileInput\n type=\"file\"\n [accept]=\"mode() === 'VIDEO' ? 'video/*' : 'image/*'\"\n capture=\"environment\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n @if (!externalTrigger()) {\n <div class=\"photoWidgetContainer\">\n <div class=\"controls\">\n <ui-action-button [descriptor]=\"captureButton()\" (actionClick)=\"fileInput.click()\">\n </ui-action-button>\n </div>\n </div>\n }\n} @else if (!externalTrigger() || isPanelOpen()) {\n <div class=\"photoWidgetContainer\">\n <video #video autoplay [muted]=\"true\" [hidden]=\"isCaptured || !cameraActive\"></video>\n <canvas #canvas [hidden]=\"!isCaptured || cameraActive\"></canvas>\n @if (cameraError()) {\n <p class=\"message\">{{ texts().cameraError }}</p>\n } @else if (isRecording) {\n <p class=\"message\">{{ texts().recording }}</p>\n } @else if (!cameraActive && !isCaptured) {\n @if (mode() === 'VIDEO') {\n <p class=\"message\">{{ texts().switchOnForVideo }}</p>\n } @else {\n <p class=\"message\">{{ texts().switchOnCameraHint }}</p>\n }\n }\n <div class=\"controls\">\n <!-- START CAMERA -->\n <ui-action-button\n class=\"toggleCameraButton\"\n [disabled]=\"isRecording\"\n [descriptor]=\"toggleCameraButton()\"\n (actionClick)=\"toggleCamera()\"\n >\n </ui-action-button>\n @if (mode() === 'VIDEO') {\n <!-- RECORD / STOP VIDEO -->\n @if (isRecording) {\n <ui-action-button\n class=\"stopRecordingButton\"\n [descriptor]=\"stopRecordingButton()\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n } @else {\n <ui-action-button\n class=\"startRecordingButton\"\n [disabled]=\"!cameraActive\"\n [descriptor]=\"startRecordingButton()\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n <!-- PICK VIDEO FILE -->\n <input\n #fileInput\n type=\"file\"\n accept=\"video/*\"\n (change)=\"onFileSelected($event)\"\n style=\"display: none\"\n />\n <ui-action-button\n class=\"pickVideoButton\"\n [disabled]=\"isRecording\"\n [descriptor]=\"pickVideoButton()\"\n (actionClick)=\"fileInput.click()\"\n >\n </ui-action-button>\n } @else {\n <!-- CAPTURE CAMERA -->\n <ui-action-button\n class=\"capturePhotoButton\"\n [disabled]=\"!cameraActive\"\n [descriptor]=\"captureButton()\"\n (actionClick)=\"capturePhoto()\"\n >\n </ui-action-button>\n }\n </div>\n </div>\n}\n", styles: [".photoWidgetContainer{border-radius:5px;width:100%;max-width:100%;display:flex;flex-direction:column;justify-content:center;border:1px solid #dee2e6}.message{text-align:center;color:#6b7280}video,canvas{border-top-right-radius:5px;border-top-left-radius:5px;width:100%}.controls{padding:.5rem;display:flex;gap:1rem;flex-direction:row;justify-content:center;background:#f8f9fa;border-top:1px solid #dee2e6;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.controls ::ng-deep button{border-radius:3px}\n"] }]
9625
+ }], propDecorators: { videoRef: [{
9398
9626
  type: ViewChild,
9399
9627
  args: ['video']
9400
9628
  }], canvasRef: [{
@@ -9403,7 +9631,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9403
9631
  }], fileInputRef: [{
9404
9632
  type: ViewChild,
9405
9633
  args: ['fileInput']
9406
- }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], photoCaptured: [{ type: i0.Output, args: ["photoCaptured"] }] } });
9634
+ }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], externalTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalTrigger", required: false }] }], texts: [{ type: i0.Input, args: [{ isSignal: true, alias: "texts", required: false }] }], photoCaptured: [{ type: i0.Output, args: ["photoCaptured"] }] } });
9407
9635
 
9408
9636
  class VoiceRecordWidgetComponent {
9409
9637
  constructor() {
@@ -9411,12 +9639,21 @@ class VoiceRecordWidgetComponent {
9411
9639
  this.changeDetectorRef = inject(ChangeDetectorRef);
9412
9640
  this.openDirection = input('RIGHT', /* @ts-ignore */
9413
9641
  ...(ngDevMode ? [{ debugName: "openDirection" }] : /* istanbul ignore next */ []));
9642
+ /** The zone's texts, the microphone error line's among them. */
9643
+ this.texts = input(UPLOAD_ZONE_DEFAULT_TEXTS, /* @ts-ignore */
9644
+ ...(ngDevMode ? [{ debugName: "texts" }] : /* istanbul ignore next */ []));
9645
+ /** True in the upload zone only; the deprecated recordingUploader shows no error line. */
9646
+ this.showMicrophoneError = input(false, /* @ts-ignore */
9647
+ ...(ngDevMode ? [{ debugName: "showMicrophoneError" }] : /* istanbul ignore next */ []));
9414
9648
  this.recordingSaved = output();
9415
9649
  this.isRecording = false;
9416
9650
  this.recordedBlob = null;
9417
9651
  this.time = '00:00';
9418
9652
  this.isPlaying = false;
9419
9653
  this.isWaveformOpen = false;
9654
+ /** Set when the browser gives no microphone, until the next start. */
9655
+ this.microphoneError = signal(false, /* @ts-ignore */
9656
+ ...(ngDevMode ? [{ debugName: "microphoneError" }] : /* istanbul ignore next */ []));
9420
9657
  this.micButton = {
9421
9658
  title: '',
9422
9659
  type: UiActionButtonType.ICON,
@@ -9486,8 +9723,7 @@ class VoiceRecordWidgetComponent {
9486
9723
  barRadius: 5,
9487
9724
  });
9488
9725
  this.wavesurfer.setVolume(1);
9489
- //So we support Safari
9490
- const mimeType = MediaRecorder.isTypeSupported('audio/webm') ? 'audio/webm' : 'audio/mp4';
9726
+ const mimeType = UploadWidgetUtils.chooseRecorderMimeType('audio');
9491
9727
  this.record = this.wavesurfer.registerPlugin(RecordPlugin.create({
9492
9728
  renderRecordedAudio: true,
9493
9729
  scrollingWaveform: true,
@@ -9527,6 +9763,7 @@ class VoiceRecordWidgetComponent {
9527
9763
  if (!this.record)
9528
9764
  throw new Error('Voice recorder plugin is not initialized.');
9529
9765
  this.updateViewState(() => {
9766
+ this.microphoneError.set(false);
9530
9767
  this.isWaveformOpen = true;
9531
9768
  this.isRecording = true;
9532
9769
  this.isPlaying = false;
@@ -9544,6 +9781,7 @@ class VoiceRecordWidgetComponent {
9544
9781
  this.updateViewState(() => {
9545
9782
  this.isRecording = false;
9546
9783
  this.isWaveformOpen = !!this.recordedBlob;
9784
+ this.microphoneError.set(true);
9547
9785
  });
9548
9786
  throw error;
9549
9787
  }
@@ -9574,13 +9812,7 @@ class VoiceRecordWidgetComponent {
9574
9812
  }
9575
9813
  saveRecording() {
9576
9814
  if (this.recordedBlob) {
9577
- let now = new Date();
9578
- let formattedDate = now.toLocaleString('sv-SE').replace(' ', '_').replace(/:/g, '-');
9579
- //Safari support
9580
- let mimeType = this.recordedBlob.type || 'audio/mp4';
9581
- let ext = mimeType.includes('webm') ? 'webm' : 'mp4';
9582
- let fileName = `recording_${formattedDate}.${ext}`;
9583
- let file = new File([this.recordedBlob], fileName, { type: mimeType });
9815
+ const file = UploadWidgetUtils.createRecordingFile(this.recordedBlob, 'recording', 'audio/mp4');
9584
9816
  this.recordingSaved.emit(file);
9585
9817
  // Destroy completely so next recording initializes fresh
9586
9818
  this.wavesurfer?.destroy();
@@ -9635,18 +9867,18 @@ class VoiceRecordWidgetComponent {
9635
9867
  });
9636
9868
  }
9637
9869
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: VoiceRecordWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9638
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: VoiceRecordWidgetComponent, isStandalone: true, selector: "voice-record-widget", inputs: { openDirection: { classPropertyName: "openDirection", publicName: "openDirection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { recordingSaved: "recordingSaved" }, viewQueries: [{ propertyName: "waveformRef", first: true, predicate: ["waveform"], descendants: true }, { propertyName: "mainButton", first: true, predicate: ["mainButton"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div\n class=\"recorderContainer\"\n [class.direction-left]=\"isLeftDirection\"\n [class.direction-right]=\"!isLeftDirection\"\n [class.active]=\"isWaveformOpen || isRecording || !!recordedBlob\"\n [class.isRecording]=\"isRecording\"\n [class.hasRecording]=\"recordedBlob\"\n >\n <div class=\"recorderMain\">\n <div class=\"recorderToolbar\">\n <!-- Start Recording -->\n @if (!isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"micButton\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Stop Recording -->\n @if (isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"stopButton\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Save Recording -->\n @if (recordedBlob) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"saveButton\"\n (actionClick)=\"saveRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Start Play -->\n @if (recordedBlob && !isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"playButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n <!-- Stop Play -->\n @if (recordedBlob && isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"stopPlaybackButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n @if (isRecording) {\n <div class=\"progress\">{{ time }}</div>\n }\n </div>\n\n <div class=\"waveformBand\" [class.open]=\"isWaveformOpen || isRecording || !!recordedBlob\">\n <div class=\"waveformGrid\"></div>\n <div class=\"waveform\" #waveform></div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;min-width:0}:host ::ng-deep .waveform{height:unset!important}.recorderContainer{display:flex;flex-direction:row;justify-content:space-between;width:100%;min-width:0;align-items:center;gap:.5rem}.active ::ng-deep .recorderToolbar{border:1px solid #e5e7eb;border-radius:.5rem}.isRecording ::ng-deep .recorderToolbar{padding-right:1rem}.recorderToolbar ::ng-deep .sb4-red,.recorderToolbar ::ng-deep .sb4-primary{border:1px solid #e5e7eb;box-shadow:unset}.active ::ng-deep .recorderToolbar ::ng-deep .sb4-red,.active ::ng-deep .recorderToolbar ::ng-deep .sb4-primary{border:unset}.mainButton ::ng-deep .sb4-red,.mainButton ::ng-deep .sb4-primary{padding:.5rem .75rem}.recorderMain{display:flex;align-items:center;min-width:0;flex:1}.direction-right .recorderMain{flex-direction:row}.direction-left .recorderMain{flex-direction:row-reverse}.waveform{width:100%;height:45px}.waveformBand{position:relative;display:grid;align-items:center;width:0;max-width:0;min-width:0;opacity:0;overflow:hidden;border-radius:5px;flex:1 1 0;transform:scaleX(.96);will-change:opacity,transform,margin;transition:max-width .22s ease,opacity .18s ease,margin .22s ease,transform .22s ease}.waveformBand.open{min-width:35px;max-width:100%;opacity:1;transform:scaleX(1)}.direction-right .waveformBand{margin-left:0}.direction-left .waveformBand{margin-right:0}.direction-right .waveformBand.open{margin-left:.45rem}.direction-left .waveformBand.open{margin-right:.45rem}.waveformGrid{position:absolute;inset:0;border:1px solid #e5e7eb;border-radius:.5rem;background:repeating-linear-gradient(to right,rgba(148,163,184,.35) 0,rgba(148,163,184,.35) 2px,transparent 2px,transparent 8px),linear-gradient(to bottom,#94a3b814,#94a3b805);pointer-events:none}.recorderToolbar{background-color:transparent;display:flex;flex-direction:row;align-items:center}.progress{align-content:center;font-size:1rem;height:100%;color:#6b7280}.hasRecording ::ng-deep .recorderToolbar ui-action-button{border-right:1px solid #e5e7eb}.hasRecording ::ng-deep .recorderToolbar ui-action-button:last-child{border-right:unset}\n"], dependencies: [{ kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9870
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: VoiceRecordWidgetComponent, isStandalone: true, selector: "voice-record-widget", inputs: { openDirection: { classPropertyName: "openDirection", publicName: "openDirection", isSignal: true, isRequired: false, transformFunction: null }, texts: { classPropertyName: "texts", publicName: "texts", isSignal: true, isRequired: false, transformFunction: null }, showMicrophoneError: { classPropertyName: "showMicrophoneError", publicName: "showMicrophoneError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { recordingSaved: "recordingSaved" }, viewQueries: [{ propertyName: "waveformRef", first: true, predicate: ["waveform"], descendants: true }, { propertyName: "mainButton", first: true, predicate: ["mainButton"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div\n class=\"recorderContainer\"\n [class.direction-left]=\"isLeftDirection\"\n [class.direction-right]=\"!isLeftDirection\"\n [class.active]=\"isWaveformOpen || isRecording || !!recordedBlob\"\n [class.isRecording]=\"isRecording\"\n [class.hasRecording]=\"recordedBlob\"\n >\n <div class=\"recorderMain\">\n <div class=\"recorderToolbar\">\n <!-- Start Recording -->\n @if (!isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"micButton\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Stop Recording -->\n @if (isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"stopButton\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Save Recording -->\n @if (recordedBlob) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"saveButton\"\n (actionClick)=\"saveRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Start Play -->\n @if (recordedBlob && !isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"playButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n <!-- Stop Play -->\n @if (recordedBlob && isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"stopPlaybackButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n @if (isRecording) {\n <div class=\"progress\">{{ time }}</div>\n }\n </div>\n\n <div class=\"waveformBand\" [class.open]=\"isWaveformOpen || isRecording || !!recordedBlob\">\n <div class=\"waveformGrid\"></div>\n <div class=\"waveform\" #waveform></div>\n </div>\n </div>\n</div>\n@if (showMicrophoneError() && microphoneError()) {\n <p class=\"message\">{{ texts().microphoneError }}</p>\n}\n", styles: [":host{display:block;width:100%;min-width:0}.message{text-align:center;color:#6b7280}:host ::ng-deep .waveform{height:unset!important}.recorderContainer{display:flex;flex-direction:row;justify-content:space-between;width:100%;min-width:0;align-items:center;gap:.5rem}.active ::ng-deep .recorderToolbar{border:1px solid #e5e7eb;border-radius:.5rem}.isRecording ::ng-deep .recorderToolbar{padding-right:1rem}.recorderToolbar ::ng-deep .sb4-red,.recorderToolbar ::ng-deep .sb4-primary{border:1px solid #e5e7eb;box-shadow:unset}.active ::ng-deep .recorderToolbar ::ng-deep .sb4-red,.active ::ng-deep .recorderToolbar ::ng-deep .sb4-primary{border:unset}.mainButton ::ng-deep .sb4-red,.mainButton ::ng-deep .sb4-primary{padding:.5rem .75rem}.recorderMain{display:flex;align-items:center;min-width:0;flex:1}.direction-right .recorderMain{flex-direction:row}.direction-left .recorderMain{flex-direction:row-reverse}.waveform{width:100%;height:45px}.waveformBand{position:relative;display:grid;align-items:center;width:0;max-width:0;min-width:0;opacity:0;overflow:hidden;border-radius:5px;flex:1 1 0;transform:scaleX(.96);will-change:opacity,transform,margin;transition:max-width .22s ease,opacity .18s ease,margin .22s ease,transform .22s ease}.waveformBand.open{min-width:35px;max-width:100%;opacity:1;transform:scaleX(1)}.direction-right .waveformBand{margin-left:0}.direction-left .waveformBand{margin-right:0}.direction-right .waveformBand.open{margin-left:.45rem}.direction-left .waveformBand.open{margin-right:.45rem}.waveformGrid{position:absolute;inset:0;border:1px solid #e5e7eb;border-radius:.5rem;background:repeating-linear-gradient(to right,rgba(148,163,184,.35) 0,rgba(148,163,184,.35) 2px,transparent 2px,transparent 8px),linear-gradient(to bottom,#94a3b814,#94a3b805);pointer-events:none}.recorderToolbar{background-color:transparent;display:flex;flex-direction:row;align-items:center}.progress{align-content:center;font-size:1rem;height:100%;color:#6b7280}.hasRecording ::ng-deep .recorderToolbar ui-action-button{border-right:1px solid #e5e7eb}.hasRecording ::ng-deep .recorderToolbar ui-action-button:last-child{border-right:unset}\n"], dependencies: [{ kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9639
9871
  }
9640
9872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: VoiceRecordWidgetComponent, decorators: [{
9641
9873
  type: Component,
9642
- args: [{ selector: 'voice-record-widget', imports: [UiActionButtonComponent], template: "<div\n class=\"recorderContainer\"\n [class.direction-left]=\"isLeftDirection\"\n [class.direction-right]=\"!isLeftDirection\"\n [class.active]=\"isWaveformOpen || isRecording || !!recordedBlob\"\n [class.isRecording]=\"isRecording\"\n [class.hasRecording]=\"recordedBlob\"\n >\n <div class=\"recorderMain\">\n <div class=\"recorderToolbar\">\n <!-- Start Recording -->\n @if (!isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"micButton\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Stop Recording -->\n @if (isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"stopButton\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Save Recording -->\n @if (recordedBlob) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"saveButton\"\n (actionClick)=\"saveRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Start Play -->\n @if (recordedBlob && !isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"playButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n <!-- Stop Play -->\n @if (recordedBlob && isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"stopPlaybackButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n @if (isRecording) {\n <div class=\"progress\">{{ time }}</div>\n }\n </div>\n\n <div class=\"waveformBand\" [class.open]=\"isWaveformOpen || isRecording || !!recordedBlob\">\n <div class=\"waveformGrid\"></div>\n <div class=\"waveform\" #waveform></div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;min-width:0}:host ::ng-deep .waveform{height:unset!important}.recorderContainer{display:flex;flex-direction:row;justify-content:space-between;width:100%;min-width:0;align-items:center;gap:.5rem}.active ::ng-deep .recorderToolbar{border:1px solid #e5e7eb;border-radius:.5rem}.isRecording ::ng-deep .recorderToolbar{padding-right:1rem}.recorderToolbar ::ng-deep .sb4-red,.recorderToolbar ::ng-deep .sb4-primary{border:1px solid #e5e7eb;box-shadow:unset}.active ::ng-deep .recorderToolbar ::ng-deep .sb4-red,.active ::ng-deep .recorderToolbar ::ng-deep .sb4-primary{border:unset}.mainButton ::ng-deep .sb4-red,.mainButton ::ng-deep .sb4-primary{padding:.5rem .75rem}.recorderMain{display:flex;align-items:center;min-width:0;flex:1}.direction-right .recorderMain{flex-direction:row}.direction-left .recorderMain{flex-direction:row-reverse}.waveform{width:100%;height:45px}.waveformBand{position:relative;display:grid;align-items:center;width:0;max-width:0;min-width:0;opacity:0;overflow:hidden;border-radius:5px;flex:1 1 0;transform:scaleX(.96);will-change:opacity,transform,margin;transition:max-width .22s ease,opacity .18s ease,margin .22s ease,transform .22s ease}.waveformBand.open{min-width:35px;max-width:100%;opacity:1;transform:scaleX(1)}.direction-right .waveformBand{margin-left:0}.direction-left .waveformBand{margin-right:0}.direction-right .waveformBand.open{margin-left:.45rem}.direction-left .waveformBand.open{margin-right:.45rem}.waveformGrid{position:absolute;inset:0;border:1px solid #e5e7eb;border-radius:.5rem;background:repeating-linear-gradient(to right,rgba(148,163,184,.35) 0,rgba(148,163,184,.35) 2px,transparent 2px,transparent 8px),linear-gradient(to bottom,#94a3b814,#94a3b805);pointer-events:none}.recorderToolbar{background-color:transparent;display:flex;flex-direction:row;align-items:center}.progress{align-content:center;font-size:1rem;height:100%;color:#6b7280}.hasRecording ::ng-deep .recorderToolbar ui-action-button{border-right:1px solid #e5e7eb}.hasRecording ::ng-deep .recorderToolbar ui-action-button:last-child{border-right:unset}\n"] }]
9874
+ args: [{ selector: 'voice-record-widget', imports: [UiActionButtonComponent], template: "<div\n class=\"recorderContainer\"\n [class.direction-left]=\"isLeftDirection\"\n [class.direction-right]=\"!isLeftDirection\"\n [class.active]=\"isWaveformOpen || isRecording || !!recordedBlob\"\n [class.isRecording]=\"isRecording\"\n [class.hasRecording]=\"recordedBlob\"\n >\n <div class=\"recorderMain\">\n <div class=\"recorderToolbar\">\n <!-- Start Recording -->\n @if (!isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"micButton\"\n (actionClick)=\"startRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Stop Recording -->\n @if (isRecording) {\n <ui-action-button\n class=\"mainButton\"\n #mainButton\n [descriptor]=\"stopButton\"\n (actionClick)=\"stopRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Save Recording -->\n @if (recordedBlob) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"saveButton\"\n (actionClick)=\"saveRecording()\"\n >\n </ui-action-button>\n }\n\n <!-- Start Play -->\n @if (recordedBlob && !isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"playButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n <!-- Stop Play -->\n @if (recordedBlob && isPlaying) {\n <ui-action-button\n class=\"mainButton\"\n [descriptor]=\"stopPlaybackButton\"\n (actionClick)=\"replayRecording()\"\n ></ui-action-button>\n }\n\n @if (isRecording) {\n <div class=\"progress\">{{ time }}</div>\n }\n </div>\n\n <div class=\"waveformBand\" [class.open]=\"isWaveformOpen || isRecording || !!recordedBlob\">\n <div class=\"waveformGrid\"></div>\n <div class=\"waveform\" #waveform></div>\n </div>\n </div>\n</div>\n@if (showMicrophoneError() && microphoneError()) {\n <p class=\"message\">{{ texts().microphoneError }}</p>\n}\n", styles: [":host{display:block;width:100%;min-width:0}.message{text-align:center;color:#6b7280}:host ::ng-deep .waveform{height:unset!important}.recorderContainer{display:flex;flex-direction:row;justify-content:space-between;width:100%;min-width:0;align-items:center;gap:.5rem}.active ::ng-deep .recorderToolbar{border:1px solid #e5e7eb;border-radius:.5rem}.isRecording ::ng-deep .recorderToolbar{padding-right:1rem}.recorderToolbar ::ng-deep .sb4-red,.recorderToolbar ::ng-deep .sb4-primary{border:1px solid #e5e7eb;box-shadow:unset}.active ::ng-deep .recorderToolbar ::ng-deep .sb4-red,.active ::ng-deep .recorderToolbar ::ng-deep .sb4-primary{border:unset}.mainButton ::ng-deep .sb4-red,.mainButton ::ng-deep .sb4-primary{padding:.5rem .75rem}.recorderMain{display:flex;align-items:center;min-width:0;flex:1}.direction-right .recorderMain{flex-direction:row}.direction-left .recorderMain{flex-direction:row-reverse}.waveform{width:100%;height:45px}.waveformBand{position:relative;display:grid;align-items:center;width:0;max-width:0;min-width:0;opacity:0;overflow:hidden;border-radius:5px;flex:1 1 0;transform:scaleX(.96);will-change:opacity,transform,margin;transition:max-width .22s ease,opacity .18s ease,margin .22s ease,transform .22s ease}.waveformBand.open{min-width:35px;max-width:100%;opacity:1;transform:scaleX(1)}.direction-right .waveformBand{margin-left:0}.direction-left .waveformBand{margin-right:0}.direction-right .waveformBand.open{margin-left:.45rem}.direction-left .waveformBand.open{margin-right:.45rem}.waveformGrid{position:absolute;inset:0;border:1px solid #e5e7eb;border-radius:.5rem;background:repeating-linear-gradient(to right,rgba(148,163,184,.35) 0,rgba(148,163,184,.35) 2px,transparent 2px,transparent 8px),linear-gradient(to bottom,#94a3b814,#94a3b805);pointer-events:none}.recorderToolbar{background-color:transparent;display:flex;flex-direction:row;align-items:center}.progress{align-content:center;font-size:1rem;height:100%;color:#6b7280}.hasRecording ::ng-deep .recorderToolbar ui-action-button{border-right:1px solid #e5e7eb}.hasRecording ::ng-deep .recorderToolbar ui-action-button:last-child{border-right:unset}\n"] }]
9643
9875
  }], propDecorators: { waveformRef: [{
9644
9876
  type: ViewChild,
9645
9877
  args: ['waveform']
9646
9878
  }], mainButton: [{
9647
9879
  type: ViewChild,
9648
9880
  args: ['mainButton', { read: ElementRef }]
9649
- }], openDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDirection", required: false }] }], recordingSaved: [{ type: i0.Output, args: ["recordingSaved"] }] } });
9881
+ }], openDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDirection", required: false }] }], texts: [{ type: i0.Input, args: [{ isSignal: true, alias: "texts", required: false }] }], showMicrophoneError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMicrophoneError", required: false }] }], recordingSaved: [{ type: i0.Output, args: ["recordingSaved"] }] } });
9650
9882
 
9651
9883
  class UploadWidgetComponent {
9652
9884
  constructor() {
@@ -9656,8 +9888,18 @@ class UploadWidgetComponent {
9656
9888
  ...(ngDevMode ? [{ debugName: "isMultiple" }] : /* istanbul ignore next */ []));
9657
9889
  this.isDisabled = input(false, /* @ts-ignore */
9658
9890
  ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
9891
+ this.sources = input(undefined, /* @ts-ignore */
9892
+ ...(ngDevMode ? [{ debugName: "sources" }] : /* istanbul ignore next */ []));
9659
9893
  this.uploadFilesEvent = output();
9660
9894
  this.uploadWidgetType = UploadWidgetType;
9895
+ this.fileUploaderSource = FileUploaderSource;
9896
+ /** The recorder opens below the capture row at a click on the microphone button. */
9897
+ this.isRecorderOpen = signal(false, /* @ts-ignore */
9898
+ ...(ngDevMode ? [{ debugName: "isRecorderOpen" }] : /* istanbul ignore next */ []));
9899
+ /** The descriptor's texts over the client's defaults, handed down to the capture widgets. */
9900
+ this.texts = UPLOAD_ZONE_DEFAULT_TEXTS;
9901
+ /** Cached per text set, so change detection hands each button the same descriptor. */
9902
+ this.captureButtons = new Map();
9661
9903
  this.maxSizeMb = 25;
9662
9904
  }
9663
9905
  ngOnInit() {
@@ -9674,13 +9916,17 @@ class UploadWidgetComponent {
9674
9916
  this.fileFormats = [uploadDescriptor.formats];
9675
9917
  }
9676
9918
  // fileFormats = this.descriptor.upload?.formats;
9919
+ this.texts = UploadWidgetUtils.resolveTexts(uploadDescriptor?.texts);
9677
9920
  this.i18n = {
9678
- addFile: uploadDescriptor?.title ?? 'Dokumentum hozzáadása',
9679
- browseOrDrag: uploadDescriptor?.description ?? 'tallózás vagy behúzás',
9921
+ addFile: uploadDescriptor?.title ?? this.texts.addFile,
9922
+ browseOrDrag: uploadDescriptor?.description ?? this.texts.browseOrDrag,
9680
9923
  formats: uploadDescriptor?.formats ?? '',
9681
- maxSize: `max. ${this.maxSizeMb} MB`,
9682
- upload: uploadDescriptor?.uploadButtonTitle ?? 'Feltöltés',
9924
+ maxSize: UploadWidgetUtils.fillPlaceholders(this.texts.maxSize, { size: this.maxSizeMb }),
9925
+ upload: uploadDescriptor?.uploadButtonTitle ?? this.texts.upload,
9926
+ unsupportedFormat: this.texts.unsupportedFormat,
9927
+ fileTooLarge: this.texts.fileTooLarge,
9683
9928
  };
9929
+ this.captureButtons.clear();
9684
9930
  }
9685
9931
  upload(files) {
9686
9932
  this.uploadFilesEvent.emit({
@@ -9689,23 +9935,75 @@ class UploadWidgetComponent {
9689
9935
  });
9690
9936
  this.fileUploadMaterial.files = [];
9691
9937
  }
9938
+ /** A captured file takes the picker's path: the same checks, the list or the upload. */
9692
9939
  uploadRecording(file) {
9693
- this.loadFilesIntoWidget([file]);
9940
+ this.fileUploadMaterial.processFiles([file]);
9694
9941
  }
9695
9942
  uploadImage(files) {
9696
- this.loadFilesIntoWidget(files);
9943
+ this.fileUploadMaterial.processFiles(files);
9697
9944
  }
9698
- loadFilesIntoWidget(files) {
9699
- if (this.autoUpload) {
9700
- this.uploadFilesEvent.emit({
9701
- files: files,
9702
- uploadDescriptor: this.uploadDescriptor(),
9703
- });
9945
+ /** True when the sources decide the zone: they are set and not the default FILE alone beside
9946
+ * uploadWidgets. */
9947
+ hasSources() {
9948
+ const sources = this.sources() ?? [];
9949
+ const isDefaultOnly = sources.length === 1 && sources[0] === FileUploaderSource.FILE;
9950
+ return !!sources.length && !(isDefaultOnly && !!this.uploadDescriptor()?.uploadWidgets?.length);
9951
+ }
9952
+ isSourceNeeded(source) {
9953
+ return this.sources()?.includes(source) ?? false;
9954
+ }
9955
+ isPickerShown() {
9956
+ return !this.hasSources() || this.isSourceNeeded(FileUploaderSource.FILE);
9957
+ }
9958
+ isCaptureOnly() {
9959
+ return !this.isPickerShown();
9960
+ }
9961
+ /** Capture-only uploads at once whatever the descriptor says, as there is no upload button. */
9962
+ isUploadImmediate() {
9963
+ return !!this.autoUpload || this.isCaptureOnly();
9964
+ }
9965
+ getCaptureSources() {
9966
+ return (this.sources() ?? []).filter((source) => source !== FileUploaderSource.FILE);
9967
+ }
9968
+ startCapture(source) {
9969
+ if (source === FileUploaderSource.CAMERA_PHOTO) {
9970
+ this.photoCapture?.openCapture();
9704
9971
  }
9705
- else {
9706
- this.fileUploadMaterial.files.push(...files);
9972
+ else if (source === FileUploaderSource.CAMERA_VIDEO) {
9973
+ this.videoCapture?.openCapture();
9974
+ }
9975
+ else if (source === FileUploaderSource.MICROPHONE) {
9976
+ this.isRecorderOpen.update((open) => !open);
9707
9977
  }
9708
9978
  }
9979
+ getCaptureButtonClass(source) {
9980
+ return CAPTURE_BUTTONS[source].cssClass;
9981
+ }
9982
+ getCaptureButton(source) {
9983
+ if (!this.captureButtons.has(source)) {
9984
+ const button = CAPTURE_BUTTONS[source];
9985
+ this.captureButtons.set(source, {
9986
+ title: '',
9987
+ type: UiActionButtonType.ICON,
9988
+ icon: button.icon,
9989
+ iconPosition: IconPosition.PRE,
9990
+ color: 'primary',
9991
+ tooltip: { tooltip: this.texts[button.tooltip] },
9992
+ });
9993
+ }
9994
+ return this.captureButtons.get(source);
9995
+ }
9996
+ /** The hint of a capture-only zone names its sources, as the picker's lines name the files.
9997
+ * Its grammar is owned by the captureOnlyHint and or texts. */
9998
+ getCaptureOnlyHint() {
9999
+ const nouns = this.getCaptureSources().map((source) => this.texts[CAPTURE_BUTTONS[source].noun]);
10000
+ const last = nouns.pop();
10001
+ const joined = nouns.length ? `${nouns.join(', ')} ${this.texts.or} ${last}` : last;
10002
+ const hint = UploadWidgetUtils.fillPlaceholders(this.texts.captureOnlyHint, {
10003
+ sources: joined,
10004
+ });
10005
+ return `${hint.charAt(0).toUpperCase()}${hint.slice(1)} · ${this.i18n?.maxSize}`;
10006
+ }
9709
10007
  widgetNeeded(type) {
9710
10008
  return this.uploadDescriptor()?.uploadWidgets?.includes(type) ?? false;
9711
10009
  }
@@ -9714,26 +10012,172 @@ class UploadWidgetComponent {
9714
10012
  }
9715
10013
  get defaultUploadDescriptor() {
9716
10014
  return {
9717
- title: 'Dokumentum hozzáadása',
9718
- description: 'tallózás vagy behúzás',
10015
+ title: UPLOAD_ZONE_DEFAULT_TEXTS.addFile,
10016
+ description: UPLOAD_ZONE_DEFAULT_TEXTS.browseOrDrag,
9719
10017
  maxSize: '25',
9720
10018
  autoUpload: false,
9721
10019
  };
9722
10020
  }
9723
10021
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UploadWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9724
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: UploadWidgetComponent, isStandalone: true, selector: "smart-upload-widget", inputs: { uploadDescriptor: { classPropertyName: "uploadDescriptor", publicName: "uploadDescriptor", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: true, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { uploadFilesEvent: "uploadFilesEvent" }, viewQueries: [{ propertyName: "fileUploadMaterial", first: true, predicate: ["fileUploadMaterial"], descendants: true }], ngImport: i0, template: "<div class=\"sb4UploadWidget\">\n <!-- IMAGE TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.IMAGE) || widgetNeeded(uploadWidgetType.ALL)) {\n <photo-capture-widget\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n (photoCaptured)=\"uploadImage($event)\"\n >\n </photo-capture-widget>\n }\n\n <!-- SOUND TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.SOUND) || widgetNeeded(uploadWidgetType.ALL)) {\n <voice-record-widget (recordingSaved)=\"uploadRecording($event)\"> </voice-record-widget>\n }\n <smartfileuploader\n #fileUploadMaterial\n [i18n]=\"i18n\"\n [fileFormats]=\"fileFormats\"\n [maxSizeMb]=\"maxSizeMb\"\n [uploadCallback]=\"upload.bind(this)\"\n [isMultiple]=\"isMultiple()\"\n [autoUpload]=\"autoUpload\"\n [isDisabled]=\"isDisabled()\"\n ></smartfileuploader>\n</div>\n", styles: ["photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}voice-record-widget{padding:.5rem;border-bottom:1px solid #e5e7eb}voice-record-widget ::ng-deep .sb4-red,voice-record-widget ::ng-deep .sb4-primary,voice-record-widget ::ng-deep ui-action-button{border:unset!important}@media(max-width:900px){:host{width:100%}}\n"], dependencies: [{ kind: "component", type: PhotoCaptureWidgetComponent, selector: "photo-capture-widget", inputs: ["maxFileSize"], outputs: ["photoCaptured"] }, { kind: "component", type: VoiceRecordWidgetComponent, selector: "voice-record-widget", inputs: ["openDirection"], outputs: ["recordingSaved"] }, { kind: "component", type: SmartfileuploaderComponent, selector: "smartfileuploader", inputs: ["uploadCallback", "fileFormats", "maxSizeMb", "i18n", "useIconButton", "isMultiple", "autoUpload", "isDisabled"] }] }); }
10022
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: UploadWidgetComponent, isStandalone: true, selector: "smart-upload-widget", inputs: { uploadDescriptor: { classPropertyName: "uploadDescriptor", publicName: "uploadDescriptor", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: true, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, sources: { classPropertyName: "sources", publicName: "sources", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { uploadFilesEvent: "uploadFilesEvent" }, viewQueries: [{ propertyName: "fileUploadMaterial", first: true, predicate: ["fileUploadMaterial"], descendants: true }, { propertyName: "photoCapture", first: true, predicate: ["photoCapture"], descendants: true }, { propertyName: "videoCapture", first: true, predicate: ["videoCapture"], descendants: true }], ngImport: i0, template: "<div class=\"sb4UploadWidget\">\n @if (hasSources()) {\n <!-- CAPTURE ROW OF THE SOURCES, hidden in view mode -->\n @if (getCaptureSources().length && !isDisabled()) {\n <div class=\"captureRow\" [class.captureOnly]=\"isCaptureOnly()\">\n <div class=\"captureButtons\">\n @for (source of getCaptureSources(); track source) {\n <ui-action-button\n class=\"{{ getCaptureButtonClass(source) }}\"\n [descriptor]=\"getCaptureButton(source)\"\n (actionClick)=\"startCapture(source)\"\n ></ui-action-button>\n }\n </div>\n @if (isCaptureOnly()) {\n <div class=\"captureHint\">{{ getCaptureOnlyHint() }}</div>\n }\n </div>\n }\n @if (isSourceNeeded(fileUploaderSource.CAMERA_PHOTO)) {\n <photo-capture-widget\n #photoCapture\n [mode]=\"'PHOTO'\"\n [externalTrigger]=\"true\"\n [texts]=\"texts\"\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n (photoCaptured)=\"uploadImage($event)\"\n ></photo-capture-widget>\n }\n @if (isSourceNeeded(fileUploaderSource.CAMERA_VIDEO)) {\n <photo-capture-widget\n #videoCapture\n [mode]=\"'VIDEO'\"\n [externalTrigger]=\"true\"\n [texts]=\"texts\"\n (photoCaptured)=\"uploadImage($event)\"\n ></photo-capture-widget>\n }\n @if (isRecorderOpen()) {\n <voice-record-widget\n [texts]=\"texts\"\n [showMicrophoneError]=\"true\"\n (recordingSaved)=\"uploadRecording($event)\"\n ></voice-record-widget>\n }\n } @else {\n <!-- IMAGE TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.IMAGE) || widgetNeeded(uploadWidgetType.ALL)) {\n <photo-capture-widget\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n [texts]=\"texts\"\n (photoCaptured)=\"uploadImage($event)\"\n >\n </photo-capture-widget>\n }\n\n <!-- SOUND TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.SOUND) || widgetNeeded(uploadWidgetType.ALL)) {\n <voice-record-widget\n [texts]=\"texts\"\n [showMicrophoneError]=\"true\"\n (recordingSaved)=\"uploadRecording($event)\"\n ></voice-record-widget>\n }\n }\n <smartfileuploader\n #fileUploadMaterial\n [i18n]=\"i18n\"\n [fileFormats]=\"fileFormats\"\n [maxSizeMb]=\"maxSizeMb\"\n [uploadCallback]=\"upload.bind(this)\"\n [isMultiple]=\"isMultiple()\"\n [autoUpload]=\"isUploadImmediate()\"\n [isDisabled]=\"isDisabled()\"\n [pickerShown]=\"isPickerShown()\"\n ></smartfileuploader>\n</div>\n", styles: ["photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}voice-record-widget{padding:.5rem;border-bottom:1px solid #e5e7eb}voice-record-widget ::ng-deep .sb4-red,voice-record-widget ::ng-deep .sb4-primary,voice-record-widget ::ng-deep ui-action-button{border:unset!important}@media(max-width:900px){:host{width:100%}}.captureRow{display:flex;justify-content:center;padding:.5rem;border-bottom:1px solid #e5e7eb}.captureRow.captureOnly{border-bottom:unset;flex-direction:column;align-items:center;padding:.875rem .5rem;gap:.375rem}.captureButtons{display:flex;gap:.5rem}.captureButtons ::ng-deep button{border:unset}.captureHint{font-size:12px;color:#6b7280}\n"], dependencies: [{ kind: "component", type: PhotoCaptureWidgetComponent, selector: "photo-capture-widget", inputs: ["maxFileSize", "mode", "externalTrigger", "texts"], outputs: ["photoCaptured"] }, { kind: "component", type: VoiceRecordWidgetComponent, selector: "voice-record-widget", inputs: ["openDirection", "texts", "showMicrophoneError"], outputs: ["recordingSaved"] }, { kind: "component", type: SmartfileuploaderComponent, selector: "smartfileuploader", inputs: ["uploadCallback", "fileFormats", "maxSizeMb", "i18n", "useIconButton", "isMultiple", "autoUpload", "isDisabled", "pickerShown"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9725
10023
  }
9726
10024
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UploadWidgetComponent, decorators: [{
9727
10025
  type: Component,
9728
- args: [{ selector: 'smart-upload-widget', imports: [PhotoCaptureWidgetComponent, VoiceRecordWidgetComponent, SmartfileuploaderComponent], template: "<div class=\"sb4UploadWidget\">\n <!-- IMAGE TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.IMAGE) || widgetNeeded(uploadWidgetType.ALL)) {\n <photo-capture-widget\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n (photoCaptured)=\"uploadImage($event)\"\n >\n </photo-capture-widget>\n }\n\n <!-- SOUND TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.SOUND) || widgetNeeded(uploadWidgetType.ALL)) {\n <voice-record-widget (recordingSaved)=\"uploadRecording($event)\"> </voice-record-widget>\n }\n <smartfileuploader\n #fileUploadMaterial\n [i18n]=\"i18n\"\n [fileFormats]=\"fileFormats\"\n [maxSizeMb]=\"maxSizeMb\"\n [uploadCallback]=\"upload.bind(this)\"\n [isMultiple]=\"isMultiple()\"\n [autoUpload]=\"autoUpload\"\n [isDisabled]=\"isDisabled()\"\n ></smartfileuploader>\n</div>\n", styles: ["photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}voice-record-widget{padding:.5rem;border-bottom:1px solid #e5e7eb}voice-record-widget ::ng-deep .sb4-red,voice-record-widget ::ng-deep .sb4-primary,voice-record-widget ::ng-deep ui-action-button{border:unset!important}@media(max-width:900px){:host{width:100%}}\n"] }]
10026
+ args: [{ selector: 'smart-upload-widget', imports: [
10027
+ PhotoCaptureWidgetComponent,
10028
+ VoiceRecordWidgetComponent,
10029
+ SmartfileuploaderComponent,
10030
+ UiActionButtonComponent,
10031
+ ], template: "<div class=\"sb4UploadWidget\">\n @if (hasSources()) {\n <!-- CAPTURE ROW OF THE SOURCES, hidden in view mode -->\n @if (getCaptureSources().length && !isDisabled()) {\n <div class=\"captureRow\" [class.captureOnly]=\"isCaptureOnly()\">\n <div class=\"captureButtons\">\n @for (source of getCaptureSources(); track source) {\n <ui-action-button\n class=\"{{ getCaptureButtonClass(source) }}\"\n [descriptor]=\"getCaptureButton(source)\"\n (actionClick)=\"startCapture(source)\"\n ></ui-action-button>\n }\n </div>\n @if (isCaptureOnly()) {\n <div class=\"captureHint\">{{ getCaptureOnlyHint() }}</div>\n }\n </div>\n }\n @if (isSourceNeeded(fileUploaderSource.CAMERA_PHOTO)) {\n <photo-capture-widget\n #photoCapture\n [mode]=\"'PHOTO'\"\n [externalTrigger]=\"true\"\n [texts]=\"texts\"\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n (photoCaptured)=\"uploadImage($event)\"\n ></photo-capture-widget>\n }\n @if (isSourceNeeded(fileUploaderSource.CAMERA_VIDEO)) {\n <photo-capture-widget\n #videoCapture\n [mode]=\"'VIDEO'\"\n [externalTrigger]=\"true\"\n [texts]=\"texts\"\n (photoCaptured)=\"uploadImage($event)\"\n ></photo-capture-widget>\n }\n @if (isRecorderOpen()) {\n <voice-record-widget\n [texts]=\"texts\"\n [showMicrophoneError]=\"true\"\n (recordingSaved)=\"uploadRecording($event)\"\n ></voice-record-widget>\n }\n } @else {\n <!-- IMAGE TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.IMAGE) || widgetNeeded(uploadWidgetType.ALL)) {\n <photo-capture-widget\n [maxFileSize]=\"maxSizeMb * 1024 * 1024\"\n [texts]=\"texts\"\n (photoCaptured)=\"uploadImage($event)\"\n >\n </photo-capture-widget>\n }\n\n <!-- SOUND TYPE WIDGET -->\n @if (widgetNeeded(uploadWidgetType.SOUND) || widgetNeeded(uploadWidgetType.ALL)) {\n <voice-record-widget\n [texts]=\"texts\"\n [showMicrophoneError]=\"true\"\n (recordingSaved)=\"uploadRecording($event)\"\n ></voice-record-widget>\n }\n }\n <smartfileuploader\n #fileUploadMaterial\n [i18n]=\"i18n\"\n [fileFormats]=\"fileFormats\"\n [maxSizeMb]=\"maxSizeMb\"\n [uploadCallback]=\"upload.bind(this)\"\n [isMultiple]=\"isMultiple()\"\n [autoUpload]=\"isUploadImmediate()\"\n [isDisabled]=\"isDisabled()\"\n [pickerShown]=\"isPickerShown()\"\n ></smartfileuploader>\n</div>\n", styles: ["photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}voice-record-widget{padding:.5rem;border-bottom:1px solid #e5e7eb}voice-record-widget ::ng-deep .sb4-red,voice-record-widget ::ng-deep .sb4-primary,voice-record-widget ::ng-deep ui-action-button{border:unset!important}@media(max-width:900px){:host{width:100%}}.captureRow{display:flex;justify-content:center;padding:.5rem;border-bottom:1px solid #e5e7eb}.captureRow.captureOnly{border-bottom:unset;flex-direction:column;align-items:center;padding:.875rem .5rem;gap:.375rem}.captureButtons{display:flex;gap:.5rem}.captureButtons ::ng-deep button{border:unset}.captureHint{font-size:12px;color:#6b7280}\n"] }]
9729
10032
  }], propDecorators: { fileUploadMaterial: [{
9730
10033
  type: ViewChild,
9731
10034
  args: ['fileUploadMaterial']
9732
- }], uploadDescriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadDescriptor", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: true }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], uploadFilesEvent: [{ type: i0.Output, args: ["uploadFilesEvent"] }] } });
10035
+ }], photoCapture: [{
10036
+ type: ViewChild,
10037
+ args: ['photoCapture']
10038
+ }], videoCapture: [{
10039
+ type: ViewChild,
10040
+ args: ['videoCapture']
10041
+ }], uploadDescriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadDescriptor", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: true }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], sources: [{ type: i0.Input, args: [{ isSignal: true, alias: "sources", required: false }] }], uploadFilesEvent: [{ type: i0.Output, args: ["uploadFilesEvent"] }] } });
10042
+ const CAPTURE_BUTTONS = {
10043
+ [FileUploaderSource.CAMERA_PHOTO]: {
10044
+ icon: 'photo_camera',
10045
+ cssClass: 'capturePhotoButton',
10046
+ tooltip: 'capturePhoto',
10047
+ noun: 'photo',
10048
+ },
10049
+ [FileUploaderSource.CAMERA_VIDEO]: {
10050
+ icon: 'videocam',
10051
+ cssClass: 'captureVideoButton',
10052
+ tooltip: 'captureVideo',
10053
+ noun: 'video',
10054
+ },
10055
+ [FileUploaderSource.MICROPHONE]: {
10056
+ icon: 'mic',
10057
+ cssClass: 'recordAudioButton',
10058
+ tooltip: 'recordAudio',
10059
+ noun: 'audio',
10060
+ },
10061
+ };
10062
+
10063
+ const FILE_PREVIEW_KEY_PREFIX = 'filePreview.';
10064
+ /** The preview element of a mime type, or `undefined` when the file has no preview. */
10065
+ function getFilePreviewKind(mimeType) {
10066
+ const type = mimeType?.split('/')[0];
10067
+ return type === 'image' || type === 'video' || type === 'audio' ? type : undefined;
10068
+ }
10069
+ /** The server's preview key of a single-file widget (`FileWidgetHandlerApi.getPreviewItemKey`). */
10070
+ function createSingleFilePreviewKey(widgetKey) {
10071
+ return FILE_PREVIEW_KEY_PREFIX + widgetKey;
10072
+ }
10073
+ /** The server's preview key of a list row: the widget key and the object id of the dataUri. */
10074
+ function createListFilePreviewKey(widgetKey, dataUri) {
10075
+ const path = dataUri.split(/[?#]/)[0];
10076
+ const objectId = path.substring(path.lastIndexOf('/') + 1).split('.')[0];
10077
+ return `${FILE_PREVIEW_KEY_PREFIX}${widgetKey}.${objectId}`;
10078
+ }
10079
+ /**
10080
+ * Loads the previews of a file editor through the view's authenticated download and owns their
10081
+ * blob URLs: a URL is revoked when its file leaves the requests and when the editor is destroyed.
10082
+ * Created in the editor's injection context; the view uuid is the editor's client's.
10083
+ */
10084
+ class FilePreviewLoader {
10085
+ constructor() {
10086
+ this.viewContext = inject(SmartViewContextService);
10087
+ this.smartComponent = injectSmartComponent();
10088
+ this.requests = signal([], /* @ts-ignore */
10089
+ ...(ngDevMode ? [{ debugName: "requests" }] : /* istanbul ignore next */ []));
10090
+ this.previewsState = signal(new Map(), /* @ts-ignore */
10091
+ ...(ngDevMode ? [{ debugName: "previewsState" }] : /* istanbul ignore next */ []));
10092
+ this.loadingDataUris = new Set();
10093
+ /** Not fetched again while it stays in the requests, as every model write sets them anew. */
10094
+ this.failedDataUris = new Set();
10095
+ this.destroyed = false;
10096
+ effect(() => this.loadPreviews(this.smartComponent?.widgetUuid(), this.requests()));
10097
+ inject(DestroyRef).onDestroy(() => {
10098
+ this.destroyed = true;
10099
+ this.previewsState().forEach((preview) => URL.revokeObjectURL(preview.url));
10100
+ });
10101
+ }
10102
+ /** Sets the files to preview; a file of no preview kind is ignored. */
10103
+ setRequests(requests) {
10104
+ this.requests.set(requests.filter((request) => getFilePreviewKind(request.mimeType)));
10105
+ }
10106
+ /** The loaded preview of a file, `undefined` while loading or without one. */
10107
+ getPreview(dataUri) {
10108
+ return dataUri ? this.previewsState().get(dataUri) : undefined;
10109
+ }
10110
+ /**
10111
+ * Turns a video preview whose media reports no video track into an audio preview of the same
10112
+ * blob URL, as a voice note may be stored with a video mime type; call it at `loadedmetadata`.
10113
+ */
10114
+ applyVideoMetadata(dataUri, video) {
10115
+ const preview = this.previewsState().get(dataUri);
10116
+ if (preview?.kind === 'video' && video.videoWidth === 0 && video.videoHeight === 0) {
10117
+ const previews = new Map(this.previewsState());
10118
+ previews.set(dataUri, { ...preview, kind: 'audio' });
10119
+ this.previewsState.set(previews);
10120
+ }
10121
+ }
10122
+ loadPreviews(viewUuid, requests) {
10123
+ untracked(() => {
10124
+ const previews = new Map(this.previewsState());
10125
+ previews.forEach((preview, dataUri) => {
10126
+ if (!this.isRequested(dataUri)) {
10127
+ URL.revokeObjectURL(preview.url);
10128
+ previews.delete(dataUri);
10129
+ }
10130
+ });
10131
+ if (previews.size !== this.previewsState().size) {
10132
+ this.previewsState.set(previews);
10133
+ }
10134
+ this.failedDataUris.forEach((dataUri) => {
10135
+ if (!this.isRequested(dataUri)) {
10136
+ this.failedDataUris.delete(dataUri);
10137
+ }
10138
+ });
10139
+ if (viewUuid) {
10140
+ requests
10141
+ .filter((request) => !previews.has(request.dataUri))
10142
+ .filter((request) => !this.loadingDataUris.has(request.dataUri))
10143
+ .filter((request) => !this.failedDataUris.has(request.dataUri))
10144
+ .forEach((request) => this.loadPreview(viewUuid, request));
10145
+ }
10146
+ });
10147
+ }
10148
+ async loadPreview(viewUuid, request) {
10149
+ this.loadingDataUris.add(request.dataUri);
10150
+ let data;
10151
+ try {
10152
+ data = await this.viewContext.downloadResource(viewUuid, request.key);
10153
+ }
10154
+ catch {
10155
+ // A file the server has not registered keeps the card without its preview.
10156
+ if (this.isRequested(request.dataUri)) {
10157
+ this.failedDataUris.add(request.dataUri);
10158
+ }
10159
+ return;
10160
+ }
10161
+ finally {
10162
+ this.loadingDataUris.delete(request.dataUri);
10163
+ }
10164
+ if (this.destroyed || !this.isRequested(request.dataUri)) {
10165
+ return;
10166
+ }
10167
+ const url = URL.createObjectURL(new Blob([data], { type: request.mimeType }));
10168
+ const previews = new Map(this.previewsState());
10169
+ previews.set(request.dataUri, { kind: getFilePreviewKind(request.mimeType), url });
10170
+ this.previewsState.set(previews);
10171
+ }
10172
+ isRequested(dataUri) {
10173
+ return this.requests().some((request) => request.dataUri === dataUri);
10174
+ }
10175
+ }
9733
10176
 
9734
10177
  class SmartFileEditorComponent {
9735
10178
  constructor() {
9736
10179
  this.cdr = inject(ChangeDetectorRef);
10180
+ this.previewLoader = new FilePreviewLoader();
9737
10181
  this.uploadFilesEvent = output();
9738
10182
  // ---- ControlValueAccessor implementation ----
9739
10183
  this.onChange = (value) => { };
@@ -9761,8 +10205,23 @@ class SmartFileEditorComponent {
9761
10205
  undoIcon: { identifier: 'undo' },
9762
10206
  };
9763
10207
  }
10208
+ this.requestPreview();
9764
10209
  this.cdr.markForCheck();
9765
10210
  }
10211
+ /** With thumbnail FULL the current value is previewed; any other value drops the preview. */
10212
+ requestPreview() {
10213
+ const value = this._widgetInstance.value;
10214
+ const isFull = this._widgetInstance.fileUploaderProperties?.thumbnail === FileUploaderThumbnail.FULL;
10215
+ this.previewLoader.setRequests(isFull && this.isTypeSupported(value)
10216
+ ? [
10217
+ {
10218
+ key: createSingleFilePreviewKey(this._widgetInstance.key),
10219
+ dataUri: value.dataUri,
10220
+ mimeType: value.mimeType,
10221
+ },
10222
+ ]
10223
+ : []);
10224
+ }
9766
10225
  upload(event) {
9767
10226
  if (!event.files || event.files.length == 0) {
9768
10227
  return;
@@ -9783,10 +10242,12 @@ class SmartFileEditorComponent {
9783
10242
  clear() {
9784
10243
  this.clearedFile = this._widgetInstance.value;
9785
10244
  this._widgetInstance.value = null;
10245
+ this.requestPreview();
9786
10246
  this.onChange(null);
9787
10247
  }
9788
10248
  undoClear() {
9789
10249
  this._widgetInstance.value = this.clearedFile;
10250
+ this.requestPreview();
9790
10251
  this.onChange(this.clearedFile);
9791
10252
  this.clearedFile = undefined;
9792
10253
  }
@@ -9836,6 +10297,7 @@ class SmartFileEditorComponent {
9836
10297
  if (value) {
9837
10298
  this.clearedFile = undefined;
9838
10299
  }
10300
+ this.requestPreview();
9839
10301
  this.cdr.markForCheck();
9840
10302
  }
9841
10303
  }
@@ -9861,6 +10323,15 @@ class SmartFileEditorComponent {
9861
10323
  get fileIcon() {
9862
10324
  return 'insert_drive_file';
9863
10325
  }
10326
+ get preview() {
10327
+ return this.previewLoader.getPreview(this._widgetInstance.value?.dataUri);
10328
+ }
10329
+ onPreviewMetadata(event) {
10330
+ const dataUri = this._widgetInstance.value?.dataUri;
10331
+ if (dataUri) {
10332
+ this.previewLoader.applyVideoMetadata(dataUri, event.target);
10333
+ }
10334
+ }
9864
10335
  get changeButton() {
9865
10336
  var props = this._widgetInstance.fileUploaderProperties;
9866
10337
  var baseAction = props.changeAction ?? props.uploadAction;
@@ -9905,7 +10376,7 @@ class SmartFileEditorComponent {
9905
10376
  useExisting: forwardRef(() => SmartFileEditorComponent),
9906
10377
  multi: true,
9907
10378
  },
9908
- ], ngImport: i0, template: "@if (widgetInstance && widgetInstance.fileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else if (!widgetInstance.value || fileToChange) {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.fileUploaderProperties.uploadDescriptor!\"\n [isMultiple]=\"false\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n @if (clearedFile && !isDisabled) {\n <div class=\"undoClearContainer\">\n <ui-action-button\n class=\"removeIcon undoClearButton\"\n (actionClick)=\"undoClear()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n </div>\n }\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"uploadedFile\">\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ widgetInstance.value?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(widgetInstance.value?.size)) }}</span>\n </div>\n </div>\n\n <div class=\"fileActions\">\n <smart-ui-action-toolbar [id]=\"widgetInstance.toolbarId\"></smart-ui-action-toolbar>\n\n @if (!fileToChange) {\n <ui-action-button\n class=\"changeButton\"\n (actionClick)=\"change(widgetInstance.value)\"\n [disabled]=\"isDisabled\"\n [descriptor]=\"changeButton\"\n >\n </ui-action-button>\n @if (!isDisabled && isClearEnabled) {\n <ui-action-button\n class=\"deleteButton\"\n (actionClick)=\"clear()\"\n [descriptor]=\"deleteButton\"\n ></ui-action-button>\n }\n } @else {\n <ui-action-button\n class=\"removeIcon\"\n (actionClick)=\"cancelChange()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n }\n </div>\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.fileEditorComponent:has(::ng-deep smartfileuploader) ::ng-deep .uploadedFile{border-top:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button,.undoClearContainer ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover,.undoClearContainer ::ng-deep button:hover{border:unset}.undoClearContainer{display:flex;justify-content:flex-end;padding:0 1rem .5rem}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .changeButton *,:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 12px,#f1f1f1 12px 24px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
10379
+ ], ngImport: i0, template: "@if (widgetInstance && widgetInstance.fileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else if (!widgetInstance.value || fileToChange) {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.fileUploaderProperties.uploadDescriptor!\"\n [sources]=\"widgetInstance.fileUploaderProperties.sources\"\n [isMultiple]=\"false\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n @if (clearedFile && !isDisabled) {\n <div class=\"undoClearContainer\">\n <ui-action-button\n class=\"removeIcon undoClearButton\"\n (actionClick)=\"undoClear()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n </div>\n }\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n @if (preview; as filePreview) {\n <div class=\"filePreview\">\n @switch (filePreview.kind) {\n @case ('image') {\n <img [src]=\"filePreview.url\" [alt]=\"widgetInstance.value?.fileName\" />\n }\n @case ('video') {\n <video\n controls\n [src]=\"filePreview.url\"\n (loadedmetadata)=\"onPreviewMetadata($event)\"\n ></video>\n }\n @case ('audio') {\n <audio controls [src]=\"filePreview.url\"></audio>\n }\n }\n </div>\n }\n <div class=\"uploadedFile\">\n @if (!preview) {\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n }\n\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ widgetInstance.value?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(widgetInstance.value?.size)) }}</span>\n </div>\n </div>\n\n <div class=\"fileActions\">\n <smart-ui-action-toolbar [id]=\"widgetInstance.toolbarId\"></smart-ui-action-toolbar>\n\n @if (!fileToChange) {\n <ui-action-button\n class=\"changeButton\"\n (actionClick)=\"change(widgetInstance.value)\"\n [disabled]=\"isDisabled\"\n [descriptor]=\"changeButton\"\n >\n </ui-action-button>\n @if (!isDisabled && isClearEnabled) {\n <ui-action-button\n class=\"deleteButton\"\n (actionClick)=\"clear()\"\n [descriptor]=\"deleteButton\"\n ></ui-action-button>\n }\n } @else {\n <ui-action-button\n class=\"removeIcon\"\n (actionClick)=\"cancelChange()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n }\n </div>\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.fileEditorComponent:has(::ng-deep smartfileuploader) ::ng-deep .uploadedFile{border-top:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button,.undoClearContainer ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover,.undoClearContainer ::ng-deep button:hover{border:unset}.undoClearContainer{display:flex;justify-content:flex-end;padding:0 1rem .5rem}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.filePreview{padding:.75rem 1rem 0}.filePreview img,.filePreview video{display:block;width:100%;max-height:200px;object-fit:contain;background:#f1f1f1;border-radius:4px}.filePreview audio{display:block;width:100%}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .changeButton *,:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 12px,#f1f1f1 12px 24px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled", "sources"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
9909
10380
  }
9910
10381
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartFileEditorComponent, decorators: [{
9911
10382
  type: Component,
@@ -9915,7 +10386,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9915
10386
  useExisting: forwardRef(() => SmartFileEditorComponent),
9916
10387
  multi: true,
9917
10388
  },
9918
- ], imports: [NgClass, NgStyle, SmartIconComponent, UploadWidgetComponent, UiActionToolbarComponent, UiActionButtonComponent], template: "@if (widgetInstance && widgetInstance.fileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else if (!widgetInstance.value || fileToChange) {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.fileUploaderProperties.uploadDescriptor!\"\n [isMultiple]=\"false\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n @if (clearedFile && !isDisabled) {\n <div class=\"undoClearContainer\">\n <ui-action-button\n class=\"removeIcon undoClearButton\"\n (actionClick)=\"undoClear()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n </div>\n }\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"uploadedFile\">\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ widgetInstance.value?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(widgetInstance.value?.size)) }}</span>\n </div>\n </div>\n\n <div class=\"fileActions\">\n <smart-ui-action-toolbar [id]=\"widgetInstance.toolbarId\"></smart-ui-action-toolbar>\n\n @if (!fileToChange) {\n <ui-action-button\n class=\"changeButton\"\n (actionClick)=\"change(widgetInstance.value)\"\n [disabled]=\"isDisabled\"\n [descriptor]=\"changeButton\"\n >\n </ui-action-button>\n @if (!isDisabled && isClearEnabled) {\n <ui-action-button\n class=\"deleteButton\"\n (actionClick)=\"clear()\"\n [descriptor]=\"deleteButton\"\n ></ui-action-button>\n }\n } @else {\n <ui-action-button\n class=\"removeIcon\"\n (actionClick)=\"cancelChange()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n }\n </div>\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.fileEditorComponent:has(::ng-deep smartfileuploader) ::ng-deep .uploadedFile{border-top:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button,.undoClearContainer ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover,.undoClearContainer ::ng-deep button:hover{border:unset}.undoClearContainer{display:flex;justify-content:flex-end;padding:0 1rem .5rem}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .changeButton *,:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 12px,#f1f1f1 12px 24px)}\n"] }]
10389
+ ], imports: [NgClass, NgStyle, SmartIconComponent, UploadWidgetComponent, UiActionToolbarComponent, UiActionButtonComponent], template: "@if (widgetInstance && widgetInstance.fileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else if (!widgetInstance.value || fileToChange) {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.fileUploaderProperties.uploadDescriptor!\"\n [sources]=\"widgetInstance.fileUploaderProperties.sources\"\n [isMultiple]=\"false\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n @if (clearedFile && !isDisabled) {\n <div class=\"undoClearContainer\">\n <ui-action-button\n class=\"removeIcon undoClearButton\"\n (actionClick)=\"undoClear()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n </div>\n }\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n @if (preview; as filePreview) {\n <div class=\"filePreview\">\n @switch (filePreview.kind) {\n @case ('image') {\n <img [src]=\"filePreview.url\" [alt]=\"widgetInstance.value?.fileName\" />\n }\n @case ('video') {\n <video\n controls\n [src]=\"filePreview.url\"\n (loadedmetadata)=\"onPreviewMetadata($event)\"\n ></video>\n }\n @case ('audio') {\n <audio controls [src]=\"filePreview.url\"></audio>\n }\n }\n </div>\n }\n <div class=\"uploadedFile\">\n @if (!preview) {\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n }\n\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ widgetInstance.value?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(widgetInstance.value?.size)) }}</span>\n </div>\n </div>\n\n <div class=\"fileActions\">\n <smart-ui-action-toolbar [id]=\"widgetInstance.toolbarId\"></smart-ui-action-toolbar>\n\n @if (!fileToChange) {\n <ui-action-button\n class=\"changeButton\"\n (actionClick)=\"change(widgetInstance.value)\"\n [disabled]=\"isDisabled\"\n [descriptor]=\"changeButton\"\n >\n </ui-action-button>\n @if (!isDisabled && isClearEnabled) {\n <ui-action-button\n class=\"deleteButton\"\n (actionClick)=\"clear()\"\n [descriptor]=\"deleteButton\"\n ></ui-action-button>\n }\n } @else {\n <ui-action-button\n class=\"removeIcon\"\n (actionClick)=\"cancelChange()\"\n [descriptor]=\"removeButton\"\n ></ui-action-button>\n }\n </div>\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius)}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.fileEditorComponent:has(::ng-deep smartfileuploader) ::ng-deep .uploadedFile{border-top:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button,.undoClearContainer ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover,.undoClearContainer ::ng-deep button:hover{border:unset}.undoClearContainer{display:flex;justify-content:flex-end;padding:0 1rem .5rem}.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.filePreview{padding:.75rem 1rem 0}.filePreview img,.filePreview video{display:block;width:100%;max-height:200px;object-fit:contain;background:#f1f1f1;border-radius:4px}.filePreview audio{display:block;width:100%}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .changeButton *,:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 12px,#f1f1f1 12px 24px)}\n"] }]
9919
10390
  }], propDecorators: { widgetInstance: [{
9920
10391
  type: Input
9921
10392
  }], uploadFilesEvent: [{ type: i0.Output, args: ["uploadFilesEvent"] }] } });
@@ -10824,6 +11295,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
10824
11295
  class SmartMultiFileEditorComponent {
10825
11296
  constructor() {
10826
11297
  this.cdr = inject(ChangeDetectorRef);
11298
+ this.previewLoader = new FilePreviewLoader();
10827
11299
  this.uploadFilesEvent = output();
10828
11300
  this.fileEvent = output();
10829
11301
  // ---- ControlValueAccessor implementation ----
@@ -10846,8 +11318,28 @@ class SmartMultiFileEditorComponent {
10846
11318
  ? structuredClone(value)
10847
11319
  : JSON.parse(JSON.stringify(value));
10848
11320
  this.isDisabled = !!value.isDisabled;
11321
+ const texts = value.multiFileUploaderProperties?.uploadDescriptor?.texts;
11322
+ this.playTooltip = { tooltip: UploadWidgetUtils.resolveTexts(texts).play };
11323
+ this.requestPreviews();
10849
11324
  this.cdr.markForCheck();
10850
11325
  }
11326
+ /** With thumbnail FULL the image rows and the expanded player's row are previewed. */
11327
+ requestPreviews() {
11328
+ const files = this.isFullThumbnail && Array.isArray(this._widgetInstance.value)
11329
+ ? this._widgetInstance.value
11330
+ : [];
11331
+ this.previewLoader.setRequests(files
11332
+ .filter((file) => this.getPreviewKind(file) === 'image' || file.dataUri === this.expandedDataUri)
11333
+ .map((file) => ({
11334
+ key: createListFilePreviewKey(this._widgetInstance.key, file.dataUri),
11335
+ dataUri: file.dataUri,
11336
+ mimeType: file.mimeType,
11337
+ })));
11338
+ }
11339
+ togglePlayer(dataUri) {
11340
+ this.expandedDataUri = this.expandedDataUri === dataUri ? undefined : dataUri;
11341
+ this.requestPreviews();
11342
+ }
10851
11343
  upload(event) {
10852
11344
  if (!event.files || event.files.length == 0) {
10853
11345
  return;
@@ -10921,6 +11413,7 @@ class SmartMultiFileEditorComponent {
10921
11413
  writeValue(value) {
10922
11414
  if (value !== undefined && this._widgetInstance) {
10923
11415
  this._widgetInstance.value = value;
11416
+ this.requestPreviews();
10924
11417
  this.cdr.markForCheck();
10925
11418
  }
10926
11419
  }
@@ -10941,6 +11434,19 @@ class SmartMultiFileEditorComponent {
10941
11434
  get fileIcon() {
10942
11435
  return 'insert_drive_file';
10943
11436
  }
11437
+ get isFullThumbnail() {
11438
+ return (this._widgetInstance.multiFileUploaderProperties?.thumbnail === FileUploaderThumbnail.FULL);
11439
+ }
11440
+ /** The preview kind of a row, `undefined` without thumbnail FULL or for another file type. */
11441
+ getPreviewKind(file) {
11442
+ return this.isFullThumbnail ? getFilePreviewKind(file?.mimeType) : undefined;
11443
+ }
11444
+ getPreview(dataUri) {
11445
+ return this.previewLoader.getPreview(dataUri);
11446
+ }
11447
+ onPreviewMetadata(dataUri, event) {
11448
+ this.previewLoader.applyVideoMetadata(dataUri, event.target);
11449
+ }
10944
11450
  get errorIcon() {
10945
11451
  return 'error';
10946
11452
  }
@@ -10951,7 +11457,7 @@ class SmartMultiFileEditorComponent {
10951
11457
  useExisting: forwardRef(() => SmartMultiFileEditorComponent),
10952
11458
  multi: true,
10953
11459
  },
10954
- ], ngImport: i0, template: "@if (widgetInstance && widgetInstance.multiFileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.multiFileUploaderProperties.uploadDescriptor!\"\n [isMultiple]=\"true\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"scrollable\">\n @for (file of widgetInstance.value; track file; let i = $index) {\n <div class=\"uploadedFile\">\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(file?.size)) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <!--\n One toolbar per file, each resolving the widget's actions for itself and\n carrying its own file. The hidden sibling whose list these used to read is\n gone with the collection machinery (ADR-0006).\n -->\n <smart-ui-action-toolbar\n [id]=\"widgetInstance.toolbarId\"\n [actionParams]=\"{ _dataUri: file.dataUri }\"\n ></smart-ui-action-toolbar>\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file.dataUri)\"\n ></smart-icon>\n @if (!file.readOnly && !isDisabled) {\n <smart-icon\n class=\"removeIcon\"\n [icon]=\"removeIcon\"\n (click)=\"file.readOnly === false && deleteFile(file.dataUri)\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius);overflow:hidden}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column;border-top:1px solid #e0e0e0}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.scrollable{max-height:30vh;overflow-y:auto}.scrollable>div:not(:last-child){border-bottom:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover{border:unset}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 6px,#f1f1f1 6px 12px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled"], outputs: ["uploadFilesEvent"] }] }); }
11460
+ ], ngImport: i0, template: "@if (widgetInstance && widgetInstance.multiFileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.multiFileUploaderProperties.uploadDescriptor!\"\n [sources]=\"widgetInstance.multiFileUploaderProperties.sources\"\n [isMultiple]=\"true\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"scrollable\">\n @for (file of widgetInstance.value; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @let previewKind = getPreviewKind(file);\n @let thumbnail = previewKind === 'image' ? getPreview(file.dataUri) : undefined;\n @if (thumbnail) {\n <img class=\"fileThumbnail\" [src]=\"thumbnail.url\" [alt]=\"file.fileName\" />\n } @else if (previewKind === 'video' || previewKind === 'audio') {\n <button\n type=\"button\"\n class=\"playTile\"\n [class.audioTile]=\"previewKind === 'audio'\"\n [class.open]=\"expandedDataUri === file.dataUri\"\n [smartTooltip]=\"playTooltip\"\n (click)=\"togglePlayer(file.dataUri)\"\n >\n <smart-icon\n [icon]=\"previewKind === 'audio' ? 'graphic_eq' : 'play_arrow'\"\n ></smart-icon>\n </button>\n } @else {\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(file?.size)) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <!--\n One toolbar per file, each resolving the widget's actions for itself and\n carrying its own file. The hidden sibling whose list these used to read is\n gone with the collection machinery (ADR-0006).\n -->\n <smart-ui-action-toolbar\n [id]=\"widgetInstance.toolbarId\"\n [actionParams]=\"{ _dataUri: file.dataUri }\"\n ></smart-ui-action-toolbar>\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file.dataUri)\"\n ></smart-icon>\n @if (!file.readOnly && !isDisabled) {\n <smart-icon\n class=\"removeIcon\"\n [icon]=\"removeIcon\"\n (click)=\"file.readOnly === false && deleteFile(file.dataUri)\"\n ></smart-icon>\n }\n </div>\n </div>\n @if (expandedDataUri === file.dataUri) {\n @if (getPreview(file.dataUri); as player) {\n <div class=\"filePlayer\">\n @if (player.kind === 'audio') {\n <audio controls [src]=\"player.url\"></audio>\n } @else {\n <video\n controls\n [src]=\"player.url\"\n (loadedmetadata)=\"onPreviewMetadata(file.dataUri, $event)\"\n ></video>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius);overflow:hidden}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column;border-top:1px solid #e0e0e0}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.scrollable{max-height:30vh;overflow-y:auto}.scrollable>div:not(:last-child){border-bottom:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover{border:unset}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileThumbnail,.playTile{width:3rem;height:3rem;flex:none;border-radius:4px}.fileThumbnail{object-fit:cover;background:#f1f1f1}.playTile{display:flex;align-items:center;justify-content:center;padding:0;border:none;background:#2f3550;color:#fff;cursor:pointer}.playTile.audioTile{background:#e8eaf6;color:var(--primary-color)}.playTile.open{outline:2px solid var(--primary-color);outline-offset:1px}.playTile smart-icon ::ng-deep mat-icon{font-size:2rem;color:inherit}.scrollable>.uploadedFile:has(+.filePlayer){border-bottom:none}.filePlayer{padding:0 1rem .75rem 5rem}.filePlayer video{display:block;width:100%;max-height:160px;background:#000;border-radius:4px}.filePlayer audio{display:block;width:100%}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 6px,#f1f1f1 6px 12px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip", "smartTooltipClass"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled", "sources"], outputs: ["uploadFilesEvent"] }] }); }
10955
11461
  }
10956
11462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartMultiFileEditorComponent, decorators: [{
10957
11463
  type: Component,
@@ -10961,7 +11467,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
10961
11467
  useExisting: forwardRef(() => SmartMultiFileEditorComponent),
10962
11468
  multi: true,
10963
11469
  },
10964
- ], imports: [NgClass, NgStyle, UiActionToolbarComponent, SmartIconComponent, UploadWidgetComponent], template: "@if (widgetInstance && widgetInstance.multiFileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.multiFileUploaderProperties.uploadDescriptor!\"\n [isMultiple]=\"true\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"scrollable\">\n @for (file of widgetInstance.value; track file; let i = $index) {\n <div class=\"uploadedFile\">\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(file?.size)) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <!--\n One toolbar per file, each resolving the widget's actions for itself and\n carrying its own file. The hidden sibling whose list these used to read is\n gone with the collection machinery (ADR-0006).\n -->\n <smart-ui-action-toolbar\n [id]=\"widgetInstance.toolbarId\"\n [actionParams]=\"{ _dataUri: file.dataUri }\"\n ></smart-ui-action-toolbar>\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file.dataUri)\"\n ></smart-icon>\n @if (!file.readOnly && !isDisabled) {\n <smart-icon\n class=\"removeIcon\"\n [icon]=\"removeIcon\"\n (click)=\"file.readOnly === false && deleteFile(file.dataUri)\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius);overflow:hidden}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column;border-top:1px solid #e0e0e0}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.scrollable{max-height:30vh;overflow-y:auto}.scrollable>div:not(:last-child){border-bottom:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover{border:unset}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 6px,#f1f1f1 6px 12px)}\n"] }]
11470
+ ], imports: [
11471
+ NgClass,
11472
+ NgStyle,
11473
+ SmartTooltipDirective,
11474
+ UiActionToolbarComponent,
11475
+ SmartIconComponent,
11476
+ UploadWidgetComponent,
11477
+ ], template: "@if (widgetInstance && widgetInstance.multiFileUploaderProperties) {\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ widgetInstance.label }}\n </h4>\n }\n <div class=\"fileEditorComponent\">\n @if (widgetInstance.value && !isTypeSupported(widgetInstance.value)) {\n <div class=\"errorMessage\">\n <smart-icon [icon]=\"errorIcon\" [color]=\"'var(--warn-color)'\"></smart-icon>\n <span> Unsupported widgetInstance.value type for this widget.</span>\n </div>\n } @else {\n <smart-upload-widget\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [uploadDescriptor]=\"widgetInstance.multiFileUploaderProperties.uploadDescriptor!\"\n [sources]=\"widgetInstance.multiFileUploaderProperties.sources\"\n [isMultiple]=\"true\"\n [isDisabled]=\"isDisabled\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div\n [ngClass]=\"{ disabledWidget: isDisabled }\"\n class=\"uploadedFileContainer\"\n [style.display]=\"\n widgetInstance.value && isTypeSupported(widgetInstance.value) ? 'block' : 'none'\n \"\n >\n <div class=\"scrollable\">\n @for (file of widgetInstance.value; track file; let i = $index) {\n <div class=\"uploadedFile\">\n @let previewKind = getPreviewKind(file);\n @let thumbnail = previewKind === 'image' ? getPreview(file.dataUri) : undefined;\n @if (thumbnail) {\n <img class=\"fileThumbnail\" [src]=\"thumbnail.url\" [alt]=\"file.fileName\" />\n } @else if (previewKind === 'video' || previewKind === 'audio') {\n <button\n type=\"button\"\n class=\"playTile\"\n [class.audioTile]=\"previewKind === 'audio'\"\n [class.open]=\"expandedDataUri === file.dataUri\"\n [smartTooltip]=\"playTooltip\"\n (click)=\"togglePlayer(file.dataUri)\"\n >\n <smart-icon\n [icon]=\"previewKind === 'audio' ? 'graphic_eq' : 'play_arrow'\"\n ></smart-icon>\n </button>\n } @else {\n <smart-icon class=\"uploadedFileIcon\" [icon]=\"fileIcon\"></smart-icon>\n }\n <div class=\"fileData\">\n <div class=\"fileDataContainer\">\n <span class=\"fileName\">{{ file?.fileName }}</span>\n <span class=\"fileSize\">{{ formatSize($safeNavigationMigration(file?.size)) }}</span>\n </div>\n </div>\n <div class=\"fileActions\">\n <!--\n One toolbar per file, each resolving the widget's actions for itself and\n carrying its own file. The hidden sibling whose list these used to read is\n gone with the collection machinery (ADR-0006).\n -->\n <smart-ui-action-toolbar\n [id]=\"widgetInstance.toolbarId\"\n [actionParams]=\"{ _dataUri: file.dataUri }\"\n ></smart-ui-action-toolbar>\n <smart-icon\n class=\"downloadIcon\"\n icon=\"download\"\n (click)=\"downloadFile(file.dataUri)\"\n ></smart-icon>\n @if (!file.readOnly && !isDisabled) {\n <smart-icon\n class=\"removeIcon\"\n [icon]=\"removeIcon\"\n (click)=\"file.readOnly === false && deleteFile(file.dataUri)\"\n ></smart-icon>\n }\n </div>\n </div>\n @if (expandedDataUri === file.dataUri) {\n @if (getPreview(file.dataUri); as player) {\n <div class=\"filePlayer\">\n @if (player.kind === 'audio') {\n <audio controls [src]=\"player.url\"></audio>\n } @else {\n <video\n controls\n [src]=\"player.url\"\n (loadedmetadata)=\"onPreviewMetadata(file.dataUri, $event)\"\n ></video>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n </div>\n}\n", styles: [":host{--border-color: #a6aabd60;--def-border-radius: .5rem;width:100%}.fileEditorComponent{border:2px dashed var(--border-color);border-radius:var(--def-border-radius);overflow:hidden}.fileEditorComponent ::ng-deep smartfileuploader ::ng-deep .container{border:unset;border-radius:unset}.uploadedFileContainer{display:flex;flex-direction:column;border-top:1px solid #e0e0e0}.uploadedFile{display:flex;flex-direction:row;justify-content:flex-start;align-items:center;padding:1rem;gap:1rem}.scrollable{max-height:30vh;overflow-y:auto}.scrollable>div:not(:last-child){border-bottom:1px solid #e0e0e0}.fileSize{display:flex;flex-direction:row;font-size:smaller}.fileData{flex:1;display:flex;flex-direction:column}.fileDataContainer{display:flex;flex-direction:column;justify-content:flex-end;width:fit-content}.fileActions{display:flex;flex-direction:row;justify-content:flex-end;gap:.5rem}.fileActions ::ng-deep button{border:unset}.fileActions ::ng-deep button:hover{border:unset}.removeIcon ::ng-deep i,.removeIcon ::ng-deep mat-icon{color:var(--warn-color)}.removeIcon ::ng-deep mat-icon,.downloadIcon ::ng-deep mat-icon{font-size:2rem}.removeIcon:hover,.downloadIcon:hover{cursor:pointer}smart-icon{display:flex;align-items:center}smart-icon ::ng-deep mat-icon{font-size:3rem;width:unset;height:unset}.uploadedFileIcon{width:3rem;display:flex;justify-content:center}.fileThumbnail,.playTile{width:3rem;height:3rem;flex:none;border-radius:4px}.fileThumbnail{object-fit:cover;background:#f1f1f1}.playTile{display:flex;align-items:center;justify-content:center;padding:0;border:none;background:#2f3550;color:#fff;cursor:pointer}.playTile.audioTile{background:#e8eaf6;color:var(--primary-color)}.playTile.open{outline:2px solid var(--primary-color);outline-offset:1px}.playTile smart-icon ::ng-deep mat-icon{font-size:2rem;color:inherit}.scrollable>.uploadedFile:has(+.filePlayer){border-bottom:none}.filePlayer{padding:0 1rem .75rem 5rem}.filePlayer video{display:block;width:100%;max-height:160px;background:#000;border-radius:4px}.filePlayer audio{display:block;width:100%}.fileEditorComponent:has(::ng-deep .errorMessage){border-color:var(--warn-color)}.errorMessage{padding:1rem;font-size:1.5rem;color:var(--warn-color);display:flex;flex-direction:row;align-items:center;gap:1rem}:host ::ng-deep .disabledWidget ::ng-deep .fileData *{opacity:.7}:host ::ng-deep smartfileuploader ::ng-deep .uploadedFile{background:repeating-linear-gradient(45deg,#fafafa,#fafafa 6px,#f1f1f1 6px 12px)}\n"] }]
10965
11478
  }], propDecorators: { widgetInstance: [{
10966
11479
  type: Input
10967
11480
  }], uploadFilesEvent: [{ type: i0.Output, args: ["uploadFilesEvent"] }], fileEvent: [{ type: i0.Output, args: ["fileEvent"] }] } });
@@ -11191,7 +11704,7 @@ class SmartVoiceRecorderComponent {
11191
11704
  useExisting: forwardRef(() => SmartVoiceRecorderComponent),
11192
11705
  multi: true,
11193
11706
  },
11194
- ], ngImport: i0, template: "<voice-record-widget [openDirection]=\"openDirection\" (recordingSaved)=\"uploadRecording($event)\">\n</voice-record-widget>\n", styles: [":host{display:block;width:100%;min-width:0}\n"], dependencies: [{ kind: "component", type: VoiceRecordWidgetComponent, selector: "voice-record-widget", inputs: ["openDirection"], outputs: ["recordingSaved"] }] }); }
11707
+ ], ngImport: i0, template: "<voice-record-widget [openDirection]=\"openDirection\" (recordingSaved)=\"uploadRecording($event)\">\n</voice-record-widget>\n", styles: [":host{display:block;width:100%;min-width:0}\n"], dependencies: [{ kind: "component", type: VoiceRecordWidgetComponent, selector: "voice-record-widget", inputs: ["openDirection", "texts", "showMicrophoneError"], outputs: ["recordingSaved"] }] }); }
11195
11708
  }
11196
11709
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartVoiceRecorderComponent, decorators: [{
11197
11710
  type: Component,
@@ -12456,8 +12969,62 @@ class SmartformwidgetComponent {
12456
12969
  this.onValueChange?.next(null);
12457
12970
  this.handleBlurEvent(this.widgetInstance);
12458
12971
  }
12972
+ /** Whether the multi-select lists a select-all box atop its panel, by its SelectAllMode. */
12973
+ hasSelectAll() {
12974
+ const mode = this.widgetInstance.multiSelectProperties?.selectAll ??
12975
+ SelectAllMode.LIMIT;
12976
+ return mode === SelectAllMode.FULL || (mode === SelectAllMode.LIMIT && this.hasSelectFilter());
12977
+ }
12978
+ get selectAllLabel() {
12979
+ return formatMessage(this.smartConfig, 'select.selectAll.label');
12980
+ }
12981
+ /** The listed options the select-all box picks: the enabled ones, the empty item aside. */
12982
+ selectableOptions() {
12983
+ const items = [];
12984
+ for (const option of this.selectOptions()) {
12985
+ const list = option.type === SmartFormWidgetType.ITEM_GROUP ? option.valueList : [option];
12986
+ for (const item of list) {
12987
+ if (!item.isDisabled && !this.service.isEmptyItem(item)) {
12988
+ items.push(item);
12989
+ }
12990
+ }
12991
+ }
12992
+ return items;
12993
+ }
12994
+ selectedValues() {
12995
+ const widget = this.widgetInstance;
12996
+ const value = this.form().controls[widget.key]?.value;
12997
+ return Array.isArray(value) ? value : [];
12998
+ }
12999
+ /** How many of the listed options are selected: every one, some of them or none. */
13000
+ selectAllState() {
13001
+ const widget = this.widgetInstance;
13002
+ const compare = widget.compareWith ?? this.compareItems;
13003
+ const selected = this.selectedValues();
13004
+ const listed = this.selectableOptions();
13005
+ const count = listed.filter((item) => selected.some((v) => compare(item.value, v))).length;
13006
+ return count === 0 ? 'none' : count === listed.length ? 'all' : 'some';
13007
+ }
13008
+ /**
13009
+ * Selects every listed option, or deselects them all once every one is selected. The options
13010
+ * the filter leaves out keep their state either way.
13011
+ */
13012
+ toggleSelectAll(select) {
13013
+ const widget = this.widgetInstance;
13014
+ const compare = widget.compareWith ?? this.compareItems;
13015
+ const selected = this.selectedValues();
13016
+ const listed = this.selectableOptions();
13017
+ const isListed = (v) => listed.some((item) => compare(item.value, v));
13018
+ const isSelected = (item) => selected.some((v) => compare(item.value, v));
13019
+ const value = this.selectAllState() === 'all'
13020
+ ? selected.filter((v) => !isListed(v))
13021
+ : [...selected, ...listed.filter((item) => !isSelected(item)).map((item) => item.value)];
13022
+ this.form().controls[widget.key].setValue(value);
13023
+ this.onValueChange?.next(value);
13024
+ this.refocusSelectFilter(select);
13025
+ }
12459
13026
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartformwidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12460
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartformwidgetComponent, isStandalone: true, selector: "smartformwidget", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, widgetInstance: { classPropertyName: "widgetInstance", publicName: "widgetInstance", isSignal: false, isRequired: false, transformFunction: null }, onBlur: { classPropertyName: "onBlur", publicName: "onBlur", isSignal: true, isRequired: false, transformFunction: null }, onValueChange: { classPropertyName: "onValueChange", publicName: "onValueChange", isSignal: false, isRequired: false, transformFunction: null }, labelColor: { classPropertyName: "labelColor", publicName: "labelColor", isSignal: true, isRequired: false, transformFunction: null }, sophisticatedValueChange: { classPropertyName: "sophisticatedValueChange", publicName: "sophisticatedValueChange", isSignal: true, isRequired: true, transformFunction: null }, blurSophisticatedValueChange: { classPropertyName: "blurSophisticatedValueChange", publicName: "blurSophisticatedValueChange", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueCleared: "valueCleared" }, viewQueries: [{ propertyName: "selectFilterInput", first: true, predicate: ["selectFilterInput"], descendants: true, isSignal: true }, { propertyName: "chipInputChild", first: true, predicate: ["chipInput"], descendants: true }, { propertyName: "customComponentVcRef", first: true, predicate: ["customComponent"], descendants: true, read: ViewContainerRef }, { propertyName: "quill", first: true, predicate: ["quillEditor"], descendants: true }, { propertyName: "sb4Textarea", first: true, predicate: ["sb4Textarea"], descendants: true }, { propertyName: "dateInputChild", first: true, predicate: ["dateInput"], descendants: true }, { propertyName: "timeInputChild", first: true, predicate: ["timeInput"], descendants: true }], ngImport: i0, template: "<div class=\"container material\" [formGroup]=\"form()\">\n @if (widgetInstance.isVisible === undefined ? true : widgetInstance.isVisible) {\n <div\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [class.sb4-widget-required]=\"isRequired()\"\n class=\"container\"\n >\n @if (widgetInstance.type === smartFormWidgetType.CONTAINER) {\n <div [attr.data-testid]=\"widgetInstance.key\" [ngClass]=\"getDirection()\">\n @for (widget of visibleChildren; track widget) {\n <smartformwidget\n [form]=\"form()\"\n [widgetInstance]=\"widget\"\n class=\"container-item\"\n [ngClass]=\"widget.cssClass ?? ''\"\n [onBlur]=\"onBlur()\"\n [onValueChange]=\"onValueChange\"\n [sophisticatedValueChange]=\"sophisticatedValueChange()\"\n [blurSophisticatedValueChange]=\"blurSophisticatedValueChange()\"\n class=\"{{ widget.key }}\"\n [labelColor]=\"labelColor()\"\n ></smartformwidget>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD) {\n <div (capsLock)=\"capsOn = $event\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n @if (!widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [attr.inputmode]=\"\n widgetInstance.inputMode ? widgetInstance.inputMode.toLocaleLowerCase() : 'text'\n \"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? (hidePassword ? 'password' : 'text') : '' }}\"\n (keydown.enter)=\"onKeydown()\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n [mask]=\"widgetInstance.mask\"\n />\n }\n <!-- [mask]=\"widgetInstance.mask ?? ''\" -->\n @if (widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n (click)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? 'password' : '' }}\"\n [matAutocomplete]=\"textFieldAuto\"\n (keydown.enter)=\"onKeydown()\"\n />\n }\n @if (widgetInstance.isPassword) {\n <button mat-icon-button matSuffix (click)=\"togglePasswordVisibility($event)\">\n <mat-icon fontSet=\"material-symbols-outlined\">{{\n hidePassword ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n }\n <mat-autocomplete #textFieldAuto=\"matAutocomplete\">\n @for (option of filteredOptions | async; track option) {\n <mat-option [value]=\"option.label\">\n <span [innerHTML]=\"option.label | highlight: toHighlight\"></span>\n </mat-option>\n }\n </mat-autocomplete>\n @if (capsOn && widgetInstance.isPassword) {\n <span class=\"mat-error\">\n {{ widgetInstance.capsLockWarning }}\n </span>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n @if (capsOn && widgetInstance.isPassword) {\n <smart-icon\n [icon]=\"widgetInstance.capsLockWarningIcon ?? 'keyboard_capslock'\"\n color=\"warn\"\n ></smart-icon>\n }\n @if (widgetInstance.icon && widgetInstance.iconPosition === 'PRE') {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n ></smart-icon>\n }\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <div class=\"textFieldButtons\">\n @if (widgetInstance.textFieldProperties?.clearable) {\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearField(widgetInstance.key)\"\n />\n }\n </div>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon\n [icon]=\"widgetInstance.textFieldButton.icon\"\n [color]=\"widgetInstance.textFieldButton.iconColor\"\n >\n </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_NUMBER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n [type]=\"'number'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [min]=\"widgetInstance.minValues ?? null\"\n [max]=\"widgetInstance.maxValues ?? null\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (widgetInstance.icon) {\n <smart-icon [icon]=\"widgetInstance.icon\" matSuffix> </smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_CHIPS) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipList aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip-row [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ value }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip-row>\n }\n <input\n #chipInput\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [matChipInputAddOnBlur]=\"addOnBlur\"\n [readonly]=\"widgetInstance.isReadonly\"\n [matAutocomplete]=\"chipAuto\"\n (matChipInputTokenEnd)=\"add($event)\"\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n <mat-autocomplete\n #chipAuto=\"matAutocomplete\"\n (optionSelected)=\"selected($event, widgetInstance)\"\n >\n @for (item of widgetInstance.valueList; track item) {\n <mat-option [disabled]=\"widgetInstance.isDisabled\" [value]=\"item.value\">\n {{ item.label }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-chip-grid>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_LOOKUP) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipListLookup aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ getChipsValue(value) }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip>\n }\n <input\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipListLookup\"\n [matChipInputSeparatorKeyCodes]=\"emptySeparatorKeysCodes\"\n [matChipInputAddOnBlur]=\"false\"\n [readonly]=\"true\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n </mat-chip-grid>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_BOX) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <textarea\n class=\"sb4-textarea\"\n #sb4Textarea\n cols=\"30\"\n cdkTextareaAutosize\n [cdkAutosizeMinRows]=\"widgetInstance.textBoxProperties?.minRows ?? 1\"\n [cdkAutosizeMaxRows]=\"widgetInstance.textBoxProperties?.maxRows ?? undefined\"\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n ></textarea>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance.hint || widgetInstance.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n <div class=\"checkbox-item-container\">\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key }}\"\n (change)=\"onValueChange?.next(widgetInstance)\"\n (change)=\"onBlur()?.next(widgetInstance)\"\n >\n {{ widgetInstance.label }}\n </mat-checkbox>\n </div>\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX_2) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n @for (checkbox of widgetInstance.valueList; track checkbox; let i = $index) {\n <div class=\"checkbox-item-container\">\n @if (checkbox.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"checkbox-item-image\"\n [src]=\"checkbox.imageUrl\"\n />\n }\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key + '.' + checkbox.key }}\"\n [value]=\"checkbox.value\"\n (change)=\"onValueChange?.next(checkbox)\"\n [disabled]=\"widgetInstance.isDisabled!\"\n >\n {{ checkbox.label }}\n </mat-checkbox>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RADIO_BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-radio-group\n class=\"input radio-section widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [attr.data-testid]=\"widgetInstance.key\"\n aria-label=\"{{ widgetInstance.label }}\"\n appearance=\"outline\"\n formControlName=\"{{ widgetInstance.key }}\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <div [ngClass]=\"getDirection()\">\n @for (radio of widgetInstance.valueList; track radio) {\n <div class=\"radio-item-container\">\n @if (radio.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"radio-item-image\"\n [src]=\"radio.imageUrl\"\n />\n }\n <mat-radio-button\n class=\"selecatbleObject\"\n value=\"{{ radio.value }}\"\n [ngClass]=\"getDirection()\"\n (change)=\"onValueChange?.next(radio.value)\"\n [disabled]=\"widgetInstance.isDisabled\"\n >\n {{ radio.label }}\n </mat-radio-button>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n <div class=\"radio-icon\">\n @if (widgetInstance.icon) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n >\n </smart-icon>\n }\n </div>\n </div>\n </mat-radio-group>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_PICKER) {\n <div class=\"datePicker widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n matInput\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (change)=\"handleBlurEvent(widgetInstance)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MONTH_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div class=\"{{ labelColor() }} smart-form-widget-label\">\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <lib-smart-month-picker\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n [control]=\"form().controls[widgetInstance.key]\"\n (valueChange)=\"handleYearMonthPicked($event)\"\n ></lib-smart-month-picker>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_TIME_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div class=\"dateTimePickerContainer\">\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n #dateInput\n matInput\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n [id]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (blur)=\"onDatePickerBlur($event)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n @if (hasCreated) {\n <mat-form-field\n class=\"input widgetContent time\"\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\"\n appearance=\"outline\"\n >\n <input\n #timeInput\n [formControlName]=\"widgetInstance.key + '-time'\"\n [attr.data-testid]=\"widgetInstance.key + '-time'\"\n [id]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n (blur)=\"onTimePickerBlur($event)\"\n matInput\n />\n </mat-form-field>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n (selectionChange)=\"onValueChange?.next($event.value)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}\n </mat-option>\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.selectProperties?.clearable) {\n <span matSuffix class=\"textFieldButtons\" (click)=\"$event.stopPropagation()\">\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearSelect(widgetInstance.key)\"\n />\n </span>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT_MULTIPLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n multiple\n (selectionChange)=\"onValueChange?.next($event.value); refocusSelectFilter(select)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}</mat-option\n >\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.LABEL) {\n <div class=\"label widgetContainer\" [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\">\n <div class=\"label-title labelContainer\" [ngClass]=\"widgetInstance.cssClass ?? ''\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance.widgetDescription) {\n <p>{{ widgetInstance.widgetDescription }}</p>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TIME) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent time {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent(widgetInstance)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TOGGLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <mat-slide-toggle\n formControlName=\"{{ widgetInstance.key }}\"\n [attr.data-testid]=\"widgetInstance.key\"\n (change)=\"onValueChange?.next($event)\"\n [labelPosition]=\"widgetInstance.toggleLabelPosition ?? 'before'\"\n >{{ !widgetInstance.showLabel ? widgetInstance.label : '' }}</mat-slide-toggle\n ><span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.INDICATOR) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"smartIndicator widgetContent\">\n <div\n class=\"indicatorItems {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n >\n @for (item of indicatorItems; track item; let i = $index) {\n <div class=\"indicatorItem\" [ngClass]=\"getIndicatorItemClass(i)\"></div>\n }\n </div>\n <p [ngClass]=\"getIndicatorStatusLabelColor()\">\n {{ getIndicatorStatusLabel() }}\n </p>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RECORDING_UPLOADER) {\n <div class=\"widgetContainer\">\n <div class=\"widgetItemContainer\">\n <smart-voice-recorder\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MULTI_FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-multi-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n (fileEvent)=\"executeUiAction($event.uiAction)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.IMAGE) {\n <div class=\"widgetContainer imageContainer\">\n @if (widgetInstance.showLabel && getWidgetLabel(widgetInstance)) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance.imageProperties?.image) {\n <smart-icon\n [imageResource]=\"$safeNavigationMigration(widgetInstance.imageProperties?.image)\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n } @else if (widgetInstance.value) {\n <smart-icon\n [(ngModel)]=\"widgetInstance.value\"\n [imageResource]=\"widgetInstance.value\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIV) {\n <div\n class=\"smartDiv\"\n [innerHTML]=\"sanitizeHtml(getWidgetLabel(widgetInstance))\"\n [ngClass]=\"getNgClass()\"\n [class.clickable]=\"!!widgetInstance.divProperties?.onClick\"\n [ngStyle]=\"getStyle()\"\n (click)=\"onDivClick()\"\n ></div>\n }\n @if (widgetInstance.type === smartFormWidgetType.HTML) {\n <smart-html-widget\n [widgetInstance]=\"widgetInstance\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-html-widget>\n }\n @if (widgetInstance.type === smartFormWidgetType.SVG) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [innerHTML]=\"sanitizeHtml(widgetInstance.value)\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIVIDER) {\n <div class=\"widgetContainer\">\n <hr\n class=\"smartDivider {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <button\n mat-button\n [attr.data-testid]=\"widgetInstance.key\"\n [ngClass]=\"getButtonType(widgetInstance.uiActionDescriptor)\"\n [color]=\"$safeNavigationMigration(widgetInstance.uiActionDescriptor?.color)\"\n (click)=\"onButtonClicked(widgetInstance)\"\n >\n @if (isOnlyIcon(widgetInstance.uiActionDescriptor)) {\n @if (widgetInstance.uiActionDescriptor?.icon) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n } @else {\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'PRE'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n {{ widgetInstance.uiActionDescriptor?.title }}\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'POST'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n }\n </button>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.COMPONENT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"labelContainer {{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"widgetContent\">\n <ng-template #customComponent></ng-template>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RICH_TEXT) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <quill-editor\n #quillEditor\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [modules]=\"\n widgetInstance.isDisabled ? emptyQuillToolbar : widgetInstance.quillModules\n \"\n [placeholder]=\"widgetInstance.placeholder ?? ''\"\n [readOnly]=\"widgetInstance.isReadonly ?? false\"\n [maxLength]=\"widgetInstance.maxLength ?? 0\"\n (onContentChanged)=\"onRichTextEditorContentChanged($event)\"\n ></quill-editor>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\" class=\"rich-text-editor-leeway-counter\">{{\n getRichTextEditorLengthLeeway()\n }}</mat-hint>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SORTABLE) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <lib-sortable-widget\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n ></lib-sortable-widget>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MATRIX) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <table class=\"matrixTable widgetContent\">\n <tr>\n <th></th>\n @for (option of widgetInstance.value.columns; track option) {\n <th class=\"optionLabel\">\n {{ option.displayValue }}\n </th>\n }\n </tr>\n @for (question of widgetInstance.value.rows; track question; let i = $index) {\n <tr>\n <th class=\"questionLabel\">\n <label>{{ question.displayValue }}</label>\n </th>\n @for (option of widgetInstance.value.columns; track option; let j = $index) {\n <td class=\"selectTd\">\n @if (!widgetInstance.isMultiple) {\n <mat-radio-group\n [formControlName]=\"widgetInstance.key + '.' + question.code\"\n [name]=\"'q' + i\"\n >\n <mat-radio-button [value]=\"option.code\"> </mat-radio-button>\n </mat-radio-group>\n }\n @if (widgetInstance.isMultiple) {\n <div>\n <mat-checkbox\n [formControlName]=\"\n widgetInstance.key + '.data.' + question.code + '.' + option.code\n \"\n [value]=\"widgetInstance.value['data'][question.code][option.code]\"\n [checked]=\"true\"\n ></mat-checkbox>\n </div>\n }\n </td>\n }\n <br />\n @if (widgetInstance.button) {\n <button mat-icon-button (click)=\"removeMatrixRow(question)\">\n <smart-icon icon=\"close\"></smart-icon>\n </button>\n }\n </tr>\n }\n </table>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.YOUTUBE_PLAYER) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} {{ widgetInstance.cssLabelClass }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <youtube-player\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n videoId=\"{{ widgetInstance.videoId }}\"\n [width]=\"widgetInstance.width\"\n [height]=\"widgetInstance.height\"\n [startSeconds]=\"widgetInstance.startSeconds\"\n [endSeconds]=\"widgetInstance.endSeconds\"\n ></youtube-player>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container:not(.ql-disabled) li[data-list=checked]>.ql-ui,.ql-container:not(.ql-disabled) li[data-list=unchecked]>.ql-ui{cursor:pointer}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor p,.ql-editor ol,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{margin:0;padding:0}@supports (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-set:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor table{border-collapse:collapse}.ql-editor td{border:1px solid #000;padding:2px 5px}.ql-editor ol{padding-left:1.5em}.ql-editor li{list-style-type:none;padding-left:1.5em;position:relative}.ql-editor li>.ql-ui:before{display:inline-block;margin-left:-1.5em;margin-right:.3em;text-align:right;white-space:nowrap;width:1.2em}.ql-editor li[data-list=checked]>.ql-ui,.ql-editor li[data-list=unchecked]>.ql-ui{color:#777}.ql-editor li[data-list=bullet]>.ql-ui:before{content:\"\\2022\"}.ql-editor li[data-list=checked]>.ql-ui:before{content:\"\\2611\"}.ql-editor li[data-list=unchecked]>.ql-ui:before{content:\"\\2610\"}@supports (counter-set:none){.ql-editor li[data-list]{counter-set:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list]{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered]{counter-increment:list-0}.ql-editor li[data-list=ordered]>.ql-ui:before{content:counter(list-0,decimal) \". \"}.ql-editor li[data-list=ordered].ql-indent-1{counter-increment:list-1}.ql-editor li[data-list=ordered].ql-indent-1>.ql-ui:before{content:counter(list-1,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-set:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-2{counter-increment:list-2}.ql-editor li[data-list=ordered].ql-indent-2>.ql-ui:before{content:counter(list-2,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-set:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-3{counter-increment:list-3}.ql-editor li[data-list=ordered].ql-indent-3>.ql-ui:before{content:counter(list-3,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-set:list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-4{counter-increment:list-4}.ql-editor li[data-list=ordered].ql-indent-4>.ql-ui:before{content:counter(list-4,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-set:list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-5{counter-increment:list-5}.ql-editor li[data-list=ordered].ql-indent-5>.ql-ui:before{content:counter(list-5,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-set:list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-6{counter-increment:list-6}.ql-editor li[data-list=ordered].ql-indent-6>.ql-ui:before{content:counter(list-6,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-set:list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-reset:list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-7{counter-increment:list-7}.ql-editor li[data-list=ordered].ql-indent-7>.ql-ui:before{content:counter(list-7,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-set:list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-reset:list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-8{counter-increment:list-8}.ql-editor li[data-list=ordered].ql-indent-8>.ql-ui:before{content:counter(list-8,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-set:list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-reset:list-9}}.ql-editor li[data-list=ordered].ql-indent-9{counter-increment:list-9}.ql-editor li[data-list=ordered].ql-indent-9>.ql-ui:before{content:counter(list-9,decimal) \". \"}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor li.ql-direction-rtl{padding-right:1.5em}.ql-editor li.ql-direction-rtl>.ql-ui:before{margin-left:.3em;margin-right:-1.5em;text-align:left}.ql-editor table{table-layout:fixed;width:100%}.ql-editor table td{outline:none}.ql-editor .ql-code-block-container{font-family:monospace}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor .ql-ui{position:absolute}.ql-editor.ql-blank:before{color:#0009;content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow.ql-toolbar:after,.ql-snow .ql-toolbar:after{clear:both;content:\"\";display:table}.ql-snow.ql-toolbar button,.ql-snow .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow.ql-toolbar button svg,.ql-snow .ql-toolbar button svg{float:left;height:100%}.ql-snow.ql-toolbar button:active:hover,.ql-snow .ql-toolbar button:active:hover{outline:none}.ql-snow.ql-toolbar input.ql-image[type=file],.ql-snow .ql-toolbar input.ql-image[type=file]{display:none}.ql-snow.ql-toolbar button:hover,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar button:focus,.ql-snow .ql-toolbar button:focus,.ql-snow.ql-toolbar button.ql-active,.ql-snow .ql-toolbar button.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item.ql-selected{color:#06c}.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill{fill:#06c}.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter{stroke:#06c}@media(pointer:coarse){.ql-snow.ql-toolbar button:hover:not(.ql-active),.ql-snow .ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow,.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:\"\";display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-thin,.ql-snow .ql-stroke.ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor .ql-code-block-container{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor .ql-code-block-container{margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor .ql-code-block-container{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label:before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=\"\"]):before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-label:before,.ql-snow .ql-picker.ql-header .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"1\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{content:\"Heading 1\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"2\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{content:\"Heading 2\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"3\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{content:\"Heading 3\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"4\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{content:\"Heading 4\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"5\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{content:\"Heading 5\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"6\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{content:\"Heading 6\"}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-label:before,.ql-snow .ql-picker.ql-font .ql-picker-item:before{content:\"Sans Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{content:\"Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{content:\"Monospace\"}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-label:before,.ql-snow .ql-picker.ql-size .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{content:\"Small\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{content:\"Large\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{content:\"Huge\"}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-code-block-container{position:relative}.ql-code-block-container .ql-ui{right:5px;top:5px}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label,.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow+.ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip:before{content:\"Visit URL:\";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action:after{border-right:1px solid #ccc;content:\"Edit\";margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove:before{content:\"Remove\";margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action:after{border-right:0;content:\"Save\";padding-right:0}.ql-snow .ql-tooltip[data-mode=link]:before{content:\"Enter link:\"}.ql-snow .ql-tooltip[data-mode=formula]:before{content:\"Enter formula:\"}.ql-snow .ql-tooltip[data-mode=video]:before{content:\"Enter video:\"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc}.checkbox-section,.radio-section{display:flex;flex-direction:column}.input{width:100%}.direction-col,.toggle-col{display:flex;flex-direction:column;gap:.5em}.toggle-col>label{font-size:.75rem;color:#6b7280;padding-left:.5em}.direction-row{display:flex;flex-direction:row;align-items:center;gap:.5em}.selecatbleObject{margin:.5em}.radioLabel{color:var(--primary-color);text-align:left!important}.container{height:100%}.input{height:100%;display:flex;flex-direction:column}.checkbox{flex-direction:column}.mat-form-field-wrapper{padding-bottom:0!important}.input .mat-mdc-standard-chip.mat-chip-with-trailing-icon{padding-right:12px}.time-picker{display:flex;flex-direction:row;height:100%;border:solid 2px lightgrey;padding:1em;border-radius:4px}.time-picker:hover{border-color:#000}::ng-deep .mat-h4 .mat-body-1 .mat-typography h4{margin:0}.label{margin:28px 0 8px}.smartIndicator{display:flex;flex-direction:column;gap:.25rem;width:-moz-fit-content;width:fit-content}.indicatorItems{display:flex;flex-direction:row;gap:.25rem}.indicatorItem{width:3rem;height:.25rem;background-color:#d3d3d3;border-radius:.5rem}.radio-error{width:-moz-fit-content;width:fit-content;display:flex;flex-direction:row;gap:.5rem}.mat-calendar-previous-button,.mat-calendar-next-button{padding:0;min-width:0;width:40px!important;height:40px!important;flex-shrink:0;line-height:40px;border-radius:50%}.mat-calendar-arrow{height:36px!important;display:flex!important;flex-direction:column!important;justify-content:center}.radio-item-container,.checkbox-item-container{display:flex;flex-direction:column}.widgetContent::ng-deep .ql-container{height:200px;width:460px}.dateTimePickerContainer{display:flex;flex-direction:row;gap:.25rem}.dateTimePickerContainer mat-form-field{flex:1}.date,.time{width:100%}.date .mat-form-field-infix,.time .mat-form-field-infix{width:inherit!important}::ng-deep .mat-icon.mat-drag-indicator{--drag-indicator: #3b3b3b;color:var(--drag-indicator)}.matrixTable{width:100%;border-spacing:0 1rem}.matrixTable th{padding:.25rem}.matrixTable .optionLabel,.matrixTable td{text-align:center}.example-month-picker .mat-calendar-period-button{pointer-events:none}.example-month-picker .mat-calendar-arrow{display:none}.textFieldContainer{display:flex;flex-direction:row}.textFieldContainer{align-content:center;border:1px solid #cbd5e1;border-radius:3px;background-color:#fff}.textFieldContainer input{border:unset}.textFieldContainer:focus-within:not(:has(input:disabled)){outline:0 none;outline-offset:0;box-shadow:0 0 0 .2rem #a6d5fa;border-color:#2196f3}.textFieldContainer:has(input:disabled) .clearButton{cursor:not-allowed;opacity:.6}.comboBoxFilter{display:flex;flex-direction:row;align-items:center;gap:.5rem;min-height:48px;padding:0 1rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.comboBoxFilter:focus-within{border-bottom-color:var(--mat-sys-primary, #3f51b5)}.comboBoxFilter .mat-icon{flex:0 0 auto;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .54))}.comboBoxFilter input{flex:1 1 auto;min-width:0;border:none;outline:none;background:transparent;font:inherit;color:inherit}.textFieldButtons{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.clearButton .mat-mdc-raised-button,.clearButton button{background-color:unset!important;border:unset;color:#6b7280!important;box-shadow:unset;font-size:1rem!important}.clearButton .mat-icon.mat-primary{color:#6b7280!important}.clearButton .mat-mdc-raised-button:hover,.clearButton button:hover{color:#6b7280cc!important;background-color:unset;border:unset;box-shadow:unset;font-size:1rem!important}.mat-mdc-form-field-infix{display:flex;flex-direction:row}textarea:not(:placeholder-shown)~label{top:-.75em!important;font-size:12px!important}.disabledEditor *{-webkit-user-modify:read-only;-moz-user-modify:read-only;user-modify:read-only}.sb4-textarea{--sb4-textarea-line-height: 20px;line-height:var(--sb4-textarea-line-height);overflow-y:auto!important}.widgetContainer .imageIcon{max-width:unset!important;height:unset!important}.material .sb4-textarea{resize:vertical!important}.material .smart-form-widget-label{font-weight:700}.material .mat-mdc-form-field-subscript-wrapper{display:none}.label-right{display:flex;gap:.5rem;flex-direction:row-reverse}.label-left{display:flex;gap:.5rem;flex-direction:row}.label-top{display:flex;gap:.5rem;flex-direction:column}.label-bottom{display:flex;gap:.5rem;flex-direction:column-reverse}.smartDiv{width:100%}.clickable{cursor:pointer}\n/*!\n * Quill Editor v2.0.3\n * https://quilljs.com\n * Copyright (c) 2017-2024, Slab\n * Copyright (c) 2014, Jason Chen\n * Copyright (c) 2013, salesforce.com\n */\n"], dependencies: [{ kind: "component", type: SmartformwidgetComponent, selector: "smartformwidget", inputs: ["form", "widgetInstance", "onBlur", "onValueChange", "labelColor", "sophisticatedValueChange", "blurSophisticatedValueChange"], outputs: ["valueCleared"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TrackCapsDirective, selector: "[capsLock]", outputs: ["capsLock"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "typeFromDecimals", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix", "defaultValueOnBlur", "value", "disabled", "touched"], outputs: ["valueChange", "touchedChange", "maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "directive", type: MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "component", type: MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "directive", type: MatChipRemove, selector: "[matChipRemove]" }, { kind: "directive", type: MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "directive", type: CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: SmartMonthPickerComponent, selector: "lib-smart-month-picker", inputs: ["widgetInstance", "control"], outputs: ["valueChange"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOptgroup, selector: "mat-optgroup", inputs: ["label", "disabled"], exportAs: ["matOptgroup"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: SmartVoiceRecorderComponent, selector: "smart-voice-recorder", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: SmartFileEditorComponent, selector: "smart-file-editor", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: SmartMultiFileEditorComponent, selector: "smart-multi-file-editor", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent", "fileEvent"] }, { kind: "component", type: SmartHtmlWidgetComponent, selector: "smart-html-widget", inputs: ["widgetInstance"] }, { kind: "component", type: QuillEditorComponent, selector: "quill-editor" }, { kind: "component", type: SortableWidgetComponent, selector: "lib-sortable-widget", inputs: ["widgetInstance"] }, { kind: "component", type: YouTubePlayer, selector: "youtube-player", inputs: ["videoId", "height", "width", "startSeconds", "endSeconds", "suggestedQuality", "playerVars", "disableCookies", "loadApi", "disablePlaceholder", "showBeforeIframeApiLoads", "placeholderButtonLabel", "placeholderImageQuality"], outputs: ["ready", "stateChange", "error", "apiChange", "playbackQualityChange", "playbackRateChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HighlightPipe, name: "highlight" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
13027
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartformwidgetComponent, isStandalone: true, selector: "smartformwidget", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, widgetInstance: { classPropertyName: "widgetInstance", publicName: "widgetInstance", isSignal: false, isRequired: false, transformFunction: null }, onBlur: { classPropertyName: "onBlur", publicName: "onBlur", isSignal: true, isRequired: false, transformFunction: null }, onValueChange: { classPropertyName: "onValueChange", publicName: "onValueChange", isSignal: false, isRequired: false, transformFunction: null }, labelColor: { classPropertyName: "labelColor", publicName: "labelColor", isSignal: true, isRequired: false, transformFunction: null }, sophisticatedValueChange: { classPropertyName: "sophisticatedValueChange", publicName: "sophisticatedValueChange", isSignal: true, isRequired: true, transformFunction: null }, blurSophisticatedValueChange: { classPropertyName: "blurSophisticatedValueChange", publicName: "blurSophisticatedValueChange", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { valueCleared: "valueCleared" }, viewQueries: [{ propertyName: "selectFilterInput", first: true, predicate: ["selectFilterInput"], descendants: true, isSignal: true }, { propertyName: "chipInputChild", first: true, predicate: ["chipInput"], descendants: true }, { propertyName: "customComponentVcRef", first: true, predicate: ["customComponent"], descendants: true, read: ViewContainerRef }, { propertyName: "quill", first: true, predicate: ["quillEditor"], descendants: true }, { propertyName: "sb4Textarea", first: true, predicate: ["sb4Textarea"], descendants: true }, { propertyName: "dateInputChild", first: true, predicate: ["dateInput"], descendants: true }, { propertyName: "timeInputChild", first: true, predicate: ["timeInput"], descendants: true }], ngImport: i0, template: "<div class=\"container material\" [formGroup]=\"form()\">\n @if (widgetInstance.isVisible === undefined ? true : widgetInstance.isVisible) {\n <div\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [class.sb4-widget-required]=\"isRequired()\"\n class=\"container\"\n >\n @if (widgetInstance.type === smartFormWidgetType.CONTAINER) {\n <div [attr.data-testid]=\"widgetInstance.key\" [ngClass]=\"getDirection()\">\n @for (widget of visibleChildren; track widget) {\n <smartformwidget\n [form]=\"form()\"\n [widgetInstance]=\"widget\"\n class=\"container-item\"\n [ngClass]=\"widget.cssClass ?? ''\"\n [onBlur]=\"onBlur()\"\n [onValueChange]=\"onValueChange\"\n [sophisticatedValueChange]=\"sophisticatedValueChange()\"\n [blurSophisticatedValueChange]=\"blurSophisticatedValueChange()\"\n class=\"{{ widget.key }}\"\n [labelColor]=\"labelColor()\"\n ></smartformwidget>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD) {\n <div (capsLock)=\"capsOn = $event\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n @if (!widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [attr.inputmode]=\"\n widgetInstance.inputMode ? widgetInstance.inputMode.toLocaleLowerCase() : 'text'\n \"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? (hidePassword ? 'password' : 'text') : '' }}\"\n (keydown.enter)=\"onKeydown()\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n [mask]=\"widgetInstance.mask\"\n />\n }\n <!-- [mask]=\"widgetInstance.mask ?? ''\" -->\n @if (widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n (click)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? 'password' : '' }}\"\n [matAutocomplete]=\"textFieldAuto\"\n (keydown.enter)=\"onKeydown()\"\n />\n }\n @if (widgetInstance.isPassword) {\n <button mat-icon-button matSuffix (click)=\"togglePasswordVisibility($event)\">\n <mat-icon fontSet=\"material-symbols-outlined\">{{\n hidePassword ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n }\n <mat-autocomplete #textFieldAuto=\"matAutocomplete\">\n @for (option of filteredOptions | async; track option) {\n <mat-option [value]=\"option.label\">\n <span [innerHTML]=\"option.label | highlight: toHighlight\"></span>\n </mat-option>\n }\n </mat-autocomplete>\n @if (capsOn && widgetInstance.isPassword) {\n <span class=\"mat-error\">\n {{ widgetInstance.capsLockWarning }}\n </span>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n @if (capsOn && widgetInstance.isPassword) {\n <smart-icon\n [icon]=\"widgetInstance.capsLockWarningIcon ?? 'keyboard_capslock'\"\n color=\"warn\"\n ></smart-icon>\n }\n @if (widgetInstance.icon && widgetInstance.iconPosition === 'PRE') {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n ></smart-icon>\n }\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <div class=\"textFieldButtons\">\n @if (widgetInstance.textFieldProperties?.clearable) {\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearField(widgetInstance.key)\"\n />\n }\n </div>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon\n [icon]=\"widgetInstance.textFieldButton.icon\"\n [color]=\"widgetInstance.textFieldButton.iconColor\"\n >\n </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_NUMBER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n [type]=\"'number'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [min]=\"widgetInstance.minValues ?? null\"\n [max]=\"widgetInstance.maxValues ?? null\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (widgetInstance.icon) {\n <smart-icon [icon]=\"widgetInstance.icon\" matSuffix> </smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_CHIPS) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipList aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip-row [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ value }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip-row>\n }\n <input\n #chipInput\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [matChipInputAddOnBlur]=\"addOnBlur\"\n [readonly]=\"widgetInstance.isReadonly\"\n [matAutocomplete]=\"chipAuto\"\n (matChipInputTokenEnd)=\"add($event)\"\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n <mat-autocomplete\n #chipAuto=\"matAutocomplete\"\n (optionSelected)=\"selected($event, widgetInstance)\"\n >\n @for (item of widgetInstance.valueList; track item) {\n <mat-option [disabled]=\"widgetInstance.isDisabled\" [value]=\"item.value\">\n {{ item.label }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-chip-grid>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_LOOKUP) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipListLookup aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ getChipsValue(value) }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip>\n }\n <input\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipListLookup\"\n [matChipInputSeparatorKeyCodes]=\"emptySeparatorKeysCodes\"\n [matChipInputAddOnBlur]=\"false\"\n [readonly]=\"true\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n </mat-chip-grid>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_BOX) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <textarea\n class=\"sb4-textarea\"\n #sb4Textarea\n cols=\"30\"\n cdkTextareaAutosize\n [cdkAutosizeMinRows]=\"widgetInstance.textBoxProperties?.minRows ?? 1\"\n [cdkAutosizeMaxRows]=\"widgetInstance.textBoxProperties?.maxRows ?? undefined\"\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n ></textarea>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance.hint || widgetInstance.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n <div class=\"checkbox-item-container\">\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key }}\"\n (change)=\"onValueChange?.next(widgetInstance)\"\n (change)=\"onBlur()?.next(widgetInstance)\"\n >\n {{ widgetInstance.label }}\n </mat-checkbox>\n </div>\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX_2) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n @for (checkbox of widgetInstance.valueList; track checkbox; let i = $index) {\n <div class=\"checkbox-item-container\">\n @if (checkbox.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"checkbox-item-image\"\n [src]=\"checkbox.imageUrl\"\n />\n }\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key + '.' + checkbox.key }}\"\n [value]=\"checkbox.value\"\n (change)=\"onValueChange?.next(checkbox)\"\n [disabled]=\"widgetInstance.isDisabled!\"\n >\n {{ checkbox.label }}\n </mat-checkbox>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RADIO_BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-radio-group\n class=\"input radio-section widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [attr.data-testid]=\"widgetInstance.key\"\n aria-label=\"{{ widgetInstance.label }}\"\n appearance=\"outline\"\n formControlName=\"{{ widgetInstance.key }}\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <div [ngClass]=\"getDirection()\">\n @for (radio of widgetInstance.valueList; track radio) {\n <div class=\"radio-item-container\">\n @if (radio.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"radio-item-image\"\n [src]=\"radio.imageUrl\"\n />\n }\n <mat-radio-button\n class=\"selecatbleObject\"\n value=\"{{ radio.value }}\"\n [ngClass]=\"getDirection()\"\n (change)=\"onValueChange?.next(radio.value)\"\n [disabled]=\"widgetInstance.isDisabled\"\n >\n {{ radio.label }}\n </mat-radio-button>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n <div class=\"radio-icon\">\n @if (widgetInstance.icon) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n >\n </smart-icon>\n }\n </div>\n </div>\n </mat-radio-group>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_PICKER) {\n <div class=\"datePicker widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n matInput\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (change)=\"handleBlurEvent(widgetInstance)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MONTH_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div class=\"{{ labelColor() }} smart-form-widget-label\">\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <lib-smart-month-picker\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n [control]=\"form().controls[widgetInstance.key]\"\n (valueChange)=\"handleYearMonthPicked($event)\"\n ></lib-smart-month-picker>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_TIME_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div class=\"dateTimePickerContainer\">\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n #dateInput\n matInput\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n [id]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (blur)=\"onDatePickerBlur($event)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n @if (hasCreated) {\n <mat-form-field\n class=\"input widgetContent time\"\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\"\n appearance=\"outline\"\n >\n <input\n #timeInput\n [formControlName]=\"widgetInstance.key + '-time'\"\n [attr.data-testid]=\"widgetInstance.key + '-time'\"\n [id]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n (blur)=\"onTimePickerBlur($event)\"\n matInput\n />\n </mat-form-field>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n (selectionChange)=\"onValueChange?.next($event.value)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}\n </mat-option>\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.selectProperties?.clearable) {\n <span matSuffix class=\"textFieldButtons\" (click)=\"$event.stopPropagation()\">\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearSelect(widgetInstance.key)\"\n />\n </span>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT_MULTIPLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n multiple\n (selectionChange)=\"onValueChange?.next($event.value); refocusSelectFilter(select)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @if (hasSelectAll()) {\n <div class=\"comboBoxSelectAll\" (keydown)=\"$event.stopPropagation()\">\n <mat-checkbox\n [checked]=\"selectAllState() === 'all'\"\n [indeterminate]=\"selectAllState() === 'some'\"\n (change)=\"toggleSelectAll(select)\"\n >{{ selectAllLabel }}</mat-checkbox\n >\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}</mat-option\n >\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.LABEL) {\n <div class=\"label widgetContainer\" [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\">\n <div class=\"label-title labelContainer\" [ngClass]=\"widgetInstance.cssClass ?? ''\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance.widgetDescription) {\n <p>{{ widgetInstance.widgetDescription }}</p>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TIME) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent time {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent(widgetInstance)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TOGGLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <mat-slide-toggle\n formControlName=\"{{ widgetInstance.key }}\"\n [attr.data-testid]=\"widgetInstance.key\"\n (change)=\"onValueChange?.next($event)\"\n [labelPosition]=\"widgetInstance.toggleLabelPosition ?? 'before'\"\n >{{ !widgetInstance.showLabel ? widgetInstance.label : '' }}</mat-slide-toggle\n ><span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.INDICATOR) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"smartIndicator widgetContent\">\n <div\n class=\"indicatorItems {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n >\n @for (item of indicatorItems; track item; let i = $index) {\n <div class=\"indicatorItem\" [ngClass]=\"getIndicatorItemClass(i)\"></div>\n }\n </div>\n <p [ngClass]=\"getIndicatorStatusLabelColor()\">\n {{ getIndicatorStatusLabel() }}\n </p>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RECORDING_UPLOADER) {\n <div class=\"widgetContainer\">\n <div class=\"widgetItemContainer\">\n <smart-voice-recorder\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MULTI_FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-multi-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n (fileEvent)=\"executeUiAction($event.uiAction)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.IMAGE) {\n <div class=\"widgetContainer imageContainer\">\n @if (widgetInstance.showLabel && getWidgetLabel(widgetInstance)) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance.imageProperties?.image) {\n <smart-icon\n [imageResource]=\"$safeNavigationMigration(widgetInstance.imageProperties?.image)\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n } @else if (widgetInstance.value) {\n <smart-icon\n [(ngModel)]=\"widgetInstance.value\"\n [imageResource]=\"widgetInstance.value\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIV) {\n <div\n class=\"smartDiv\"\n [innerHTML]=\"sanitizeHtml(getWidgetLabel(widgetInstance))\"\n [ngClass]=\"getNgClass()\"\n [class.clickable]=\"!!widgetInstance.divProperties?.onClick\"\n [ngStyle]=\"getStyle()\"\n (click)=\"onDivClick()\"\n ></div>\n }\n @if (widgetInstance.type === smartFormWidgetType.HTML) {\n <smart-html-widget\n [widgetInstance]=\"widgetInstance\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-html-widget>\n }\n @if (widgetInstance.type === smartFormWidgetType.SVG) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [innerHTML]=\"sanitizeHtml(widgetInstance.value)\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIVIDER) {\n <div class=\"widgetContainer\">\n <hr\n class=\"smartDivider {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <button\n mat-button\n [attr.data-testid]=\"widgetInstance.key\"\n [ngClass]=\"getButtonType(widgetInstance.uiActionDescriptor)\"\n [color]=\"$safeNavigationMigration(widgetInstance.uiActionDescriptor?.color)\"\n (click)=\"onButtonClicked(widgetInstance)\"\n >\n @if (isOnlyIcon(widgetInstance.uiActionDescriptor)) {\n @if (widgetInstance.uiActionDescriptor?.icon) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n } @else {\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'PRE'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n {{ widgetInstance.uiActionDescriptor?.title }}\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'POST'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n }\n </button>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.COMPONENT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"labelContainer {{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"widgetContent\">\n <ng-template #customComponent></ng-template>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RICH_TEXT) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <quill-editor\n #quillEditor\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [modules]=\"\n widgetInstance.isDisabled ? emptyQuillToolbar : widgetInstance.quillModules\n \"\n [placeholder]=\"widgetInstance.placeholder ?? ''\"\n [readOnly]=\"widgetInstance.isReadonly ?? false\"\n [maxLength]=\"widgetInstance.maxLength ?? 0\"\n (onContentChanged)=\"onRichTextEditorContentChanged($event)\"\n ></quill-editor>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\" class=\"rich-text-editor-leeway-counter\">{{\n getRichTextEditorLengthLeeway()\n }}</mat-hint>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SORTABLE) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <lib-sortable-widget\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n ></lib-sortable-widget>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MATRIX) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <table class=\"matrixTable widgetContent\">\n <tr>\n <th></th>\n @for (option of widgetInstance.value.columns; track option) {\n <th class=\"optionLabel\">\n {{ option.displayValue }}\n </th>\n }\n </tr>\n @for (question of widgetInstance.value.rows; track question; let i = $index) {\n <tr>\n <th class=\"questionLabel\">\n <label>{{ question.displayValue }}</label>\n </th>\n @for (option of widgetInstance.value.columns; track option; let j = $index) {\n <td class=\"selectTd\">\n @if (!widgetInstance.isMultiple) {\n <mat-radio-group\n [formControlName]=\"widgetInstance.key + '.' + question.code\"\n [name]=\"'q' + i\"\n >\n <mat-radio-button [value]=\"option.code\"> </mat-radio-button>\n </mat-radio-group>\n }\n @if (widgetInstance.isMultiple) {\n <div>\n <mat-checkbox\n [formControlName]=\"\n widgetInstance.key + '.data.' + question.code + '.' + option.code\n \"\n [value]=\"widgetInstance.value['data'][question.code][option.code]\"\n [checked]=\"true\"\n ></mat-checkbox>\n </div>\n }\n </td>\n }\n <br />\n @if (widgetInstance.button) {\n <button mat-icon-button (click)=\"removeMatrixRow(question)\">\n <smart-icon icon=\"close\"></smart-icon>\n </button>\n }\n </tr>\n }\n </table>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.YOUTUBE_PLAYER) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} {{ widgetInstance.cssLabelClass }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <youtube-player\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n videoId=\"{{ widgetInstance.videoId }}\"\n [width]=\"widgetInstance.width\"\n [height]=\"widgetInstance.height\"\n [startSeconds]=\"widgetInstance.startSeconds\"\n [endSeconds]=\"widgetInstance.endSeconds\"\n ></youtube-player>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container:not(.ql-disabled) li[data-list=checked]>.ql-ui,.ql-container:not(.ql-disabled) li[data-list=unchecked]>.ql-ui{cursor:pointer}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor p,.ql-editor ol,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{margin:0;padding:0}@supports (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-set:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor table{border-collapse:collapse}.ql-editor td{border:1px solid #000;padding:2px 5px}.ql-editor ol{padding-left:1.5em}.ql-editor li{list-style-type:none;padding-left:1.5em;position:relative}.ql-editor li>.ql-ui:before{display:inline-block;margin-left:-1.5em;margin-right:.3em;text-align:right;white-space:nowrap;width:1.2em}.ql-editor li[data-list=checked]>.ql-ui,.ql-editor li[data-list=unchecked]>.ql-ui{color:#777}.ql-editor li[data-list=bullet]>.ql-ui:before{content:\"\\2022\"}.ql-editor li[data-list=checked]>.ql-ui:before{content:\"\\2611\"}.ql-editor li[data-list=unchecked]>.ql-ui:before{content:\"\\2610\"}@supports (counter-set:none){.ql-editor li[data-list]{counter-set:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list]{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered]{counter-increment:list-0}.ql-editor li[data-list=ordered]>.ql-ui:before{content:counter(list-0,decimal) \". \"}.ql-editor li[data-list=ordered].ql-indent-1{counter-increment:list-1}.ql-editor li[data-list=ordered].ql-indent-1>.ql-ui:before{content:counter(list-1,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-set:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-2{counter-increment:list-2}.ql-editor li[data-list=ordered].ql-indent-2>.ql-ui:before{content:counter(list-2,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-set:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-3{counter-increment:list-3}.ql-editor li[data-list=ordered].ql-indent-3>.ql-ui:before{content:counter(list-3,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-set:list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-4{counter-increment:list-4}.ql-editor li[data-list=ordered].ql-indent-4>.ql-ui:before{content:counter(list-4,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-set:list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-5{counter-increment:list-5}.ql-editor li[data-list=ordered].ql-indent-5>.ql-ui:before{content:counter(list-5,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-set:list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-6{counter-increment:list-6}.ql-editor li[data-list=ordered].ql-indent-6>.ql-ui:before{content:counter(list-6,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-set:list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-reset:list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-7{counter-increment:list-7}.ql-editor li[data-list=ordered].ql-indent-7>.ql-ui:before{content:counter(list-7,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-set:list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-reset:list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-8{counter-increment:list-8}.ql-editor li[data-list=ordered].ql-indent-8>.ql-ui:before{content:counter(list-8,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-set:list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-reset:list-9}}.ql-editor li[data-list=ordered].ql-indent-9{counter-increment:list-9}.ql-editor li[data-list=ordered].ql-indent-9>.ql-ui:before{content:counter(list-9,decimal) \". \"}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor li.ql-direction-rtl{padding-right:1.5em}.ql-editor li.ql-direction-rtl>.ql-ui:before{margin-left:.3em;margin-right:-1.5em;text-align:left}.ql-editor table{table-layout:fixed;width:100%}.ql-editor table td{outline:none}.ql-editor .ql-code-block-container{font-family:monospace}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor .ql-ui{position:absolute}.ql-editor.ql-blank:before{color:#0009;content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow.ql-toolbar:after,.ql-snow .ql-toolbar:after{clear:both;content:\"\";display:table}.ql-snow.ql-toolbar button,.ql-snow .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow.ql-toolbar button svg,.ql-snow .ql-toolbar button svg{float:left;height:100%}.ql-snow.ql-toolbar button:active:hover,.ql-snow .ql-toolbar button:active:hover{outline:none}.ql-snow.ql-toolbar input.ql-image[type=file],.ql-snow .ql-toolbar input.ql-image[type=file]{display:none}.ql-snow.ql-toolbar button:hover,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar button:focus,.ql-snow .ql-toolbar button:focus,.ql-snow.ql-toolbar button.ql-active,.ql-snow .ql-toolbar button.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item.ql-selected{color:#06c}.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill{fill:#06c}.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter{stroke:#06c}@media(pointer:coarse){.ql-snow.ql-toolbar button:hover:not(.ql-active),.ql-snow .ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow,.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:\"\";display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-thin,.ql-snow .ql-stroke.ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor .ql-code-block-container{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor .ql-code-block-container{margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor .ql-code-block-container{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label:before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=\"\"]):before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-label:before,.ql-snow .ql-picker.ql-header .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"1\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{content:\"Heading 1\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"2\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{content:\"Heading 2\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"3\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{content:\"Heading 3\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"4\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{content:\"Heading 4\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"5\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{content:\"Heading 5\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"6\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{content:\"Heading 6\"}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-label:before,.ql-snow .ql-picker.ql-font .ql-picker-item:before{content:\"Sans Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{content:\"Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{content:\"Monospace\"}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-label:before,.ql-snow .ql-picker.ql-size .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{content:\"Small\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{content:\"Large\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{content:\"Huge\"}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-code-block-container{position:relative}.ql-code-block-container .ql-ui{right:5px;top:5px}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label,.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow+.ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip:before{content:\"Visit URL:\";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action:after{border-right:1px solid #ccc;content:\"Edit\";margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove:before{content:\"Remove\";margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action:after{border-right:0;content:\"Save\";padding-right:0}.ql-snow .ql-tooltip[data-mode=link]:before{content:\"Enter link:\"}.ql-snow .ql-tooltip[data-mode=formula]:before{content:\"Enter formula:\"}.ql-snow .ql-tooltip[data-mode=video]:before{content:\"Enter video:\"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc}.checkbox-section,.radio-section{display:flex;flex-direction:column}.input{width:100%}.direction-col,.toggle-col{display:flex;flex-direction:column;gap:.5em}.toggle-col>label{font-size:.75rem;color:#6b7280;padding-left:.5em}.direction-row{display:flex;flex-direction:row;align-items:center;gap:.5em}.selecatbleObject{margin:.5em}.radioLabel{color:var(--primary-color);text-align:left!important}.container{height:100%}.input{height:100%;display:flex;flex-direction:column}.checkbox{flex-direction:column}.mat-form-field-wrapper{padding-bottom:0!important}.input .mat-mdc-standard-chip.mat-chip-with-trailing-icon{padding-right:12px}.time-picker{display:flex;flex-direction:row;height:100%;border:solid 2px lightgrey;padding:1em;border-radius:4px}.time-picker:hover{border-color:#000}::ng-deep .mat-h4 .mat-body-1 .mat-typography h4{margin:0}.label{margin:28px 0 8px}.smartIndicator{display:flex;flex-direction:column;gap:.25rem;width:-moz-fit-content;width:fit-content}.indicatorItems{display:flex;flex-direction:row;gap:.25rem}.indicatorItem{width:3rem;height:.25rem;background-color:#d3d3d3;border-radius:.5rem}.radio-error{width:-moz-fit-content;width:fit-content;display:flex;flex-direction:row;gap:.5rem}.mat-calendar-previous-button,.mat-calendar-next-button{padding:0;min-width:0;width:40px!important;height:40px!important;flex-shrink:0;line-height:40px;border-radius:50%}.mat-calendar-arrow{height:36px!important;display:flex!important;flex-direction:column!important;justify-content:center}.radio-item-container,.checkbox-item-container{display:flex;flex-direction:column}.widgetContent::ng-deep .ql-container{height:200px;width:460px}.dateTimePickerContainer{display:flex;flex-direction:row;gap:.25rem}.dateTimePickerContainer mat-form-field{flex:1}.date,.time{width:100%}.date .mat-form-field-infix,.time .mat-form-field-infix{width:inherit!important}::ng-deep .mat-icon.mat-drag-indicator{--drag-indicator: #3b3b3b;color:var(--drag-indicator)}.matrixTable{width:100%;border-spacing:0 1rem}.matrixTable th{padding:.25rem}.matrixTable .optionLabel,.matrixTable td{text-align:center}.example-month-picker .mat-calendar-period-button{pointer-events:none}.example-month-picker .mat-calendar-arrow{display:none}.textFieldContainer{display:flex;flex-direction:row}.textFieldContainer{align-content:center;border:1px solid #cbd5e1;border-radius:3px;background-color:#fff}.textFieldContainer input{border:unset}.textFieldContainer:focus-within:not(:has(input:disabled)){outline:0 none;outline-offset:0;box-shadow:0 0 0 .2rem #a6d5fa;border-color:#2196f3}.textFieldContainer:has(input:disabled) .clearButton{cursor:not-allowed;opacity:.6}.comboBoxFilter{display:flex;flex-direction:row;align-items:center;gap:.5rem;min-height:48px;padding:0 1rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.comboBoxFilter:focus-within{border-bottom-color:var(--mat-sys-primary, #3f51b5)}.comboBoxFilter .mat-icon{flex:0 0 auto;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .54))}.comboBoxFilter input{flex:1 1 auto;min-width:0;border:none;outline:none;background:transparent;font:inherit;color:inherit}.comboBoxSelectAll{display:flex;align-items:center;min-height:48px;padding:0 .25rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.textFieldButtons{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.clearButton .mat-mdc-raised-button,.clearButton button{background-color:unset!important;border:unset;color:#6b7280!important;box-shadow:unset;font-size:1rem!important}.clearButton .mat-icon.mat-primary{color:#6b7280!important}.clearButton .mat-mdc-raised-button:hover,.clearButton button:hover{color:#6b7280cc!important;background-color:unset;border:unset;box-shadow:unset;font-size:1rem!important}.mat-mdc-form-field-infix{display:flex;flex-direction:row}textarea:not(:placeholder-shown)~label{top:-.75em!important;font-size:12px!important}.disabledEditor *{-webkit-user-modify:read-only;-moz-user-modify:read-only;user-modify:read-only}.sb4-textarea{--sb4-textarea-line-height: 20px;line-height:var(--sb4-textarea-line-height);overflow-y:auto!important}.widgetContainer .imageIcon{max-width:unset!important;height:unset!important}.material .sb4-textarea{resize:vertical!important}.material .smart-form-widget-label{font-weight:700}.material .mat-mdc-form-field-subscript-wrapper{display:none}.label-right{display:flex;gap:.5rem;flex-direction:row-reverse}.label-left{display:flex;gap:.5rem;flex-direction:row}.label-top{display:flex;gap:.5rem;flex-direction:column}.label-bottom{display:flex;gap:.5rem;flex-direction:column-reverse}.smartDiv{width:100%}.clickable{cursor:pointer}\n/*!\n * Quill Editor v2.0.3\n * https://quilljs.com\n * Copyright (c) 2017-2024, Slab\n * Copyright (c) 2014, Jason Chen\n * Copyright (c) 2013, salesforce.com\n */\n"], dependencies: [{ kind: "component", type: SmartformwidgetComponent, selector: "smartformwidget", inputs: ["form", "widgetInstance", "onBlur", "onValueChange", "labelColor", "sophisticatedValueChange", "blurSophisticatedValueChange"], outputs: ["valueCleared"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TrackCapsDirective, selector: "[capsLock]", outputs: ["capsLock"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "typeFromDecimals", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix", "defaultValueOnBlur", "value", "disabled", "touched"], outputs: ["valueChange", "touchedChange", "maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "directive", type: MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"], outputs: ["actionFired"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "component", type: MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "directive", type: MatChipRemove, selector: "[matChipRemove]" }, { kind: "directive", type: MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "directive", type: CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: SmartMonthPickerComponent, selector: "lib-smart-month-picker", inputs: ["widgetInstance", "control"], outputs: ["valueChange"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOptgroup, selector: "mat-optgroup", inputs: ["label", "disabled"], exportAs: ["matOptgroup"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: SmartVoiceRecorderComponent, selector: "smart-voice-recorder", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: SmartFileEditorComponent, selector: "smart-file-editor", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: SmartMultiFileEditorComponent, selector: "smart-multi-file-editor", inputs: ["widgetInstance"], outputs: ["uploadFilesEvent", "fileEvent"] }, { kind: "component", type: SmartHtmlWidgetComponent, selector: "smart-html-widget", inputs: ["widgetInstance"] }, { kind: "component", type: QuillEditorComponent, selector: "quill-editor" }, { kind: "component", type: SortableWidgetComponent, selector: "lib-sortable-widget", inputs: ["widgetInstance"] }, { kind: "component", type: YouTubePlayer, selector: "youtube-player", inputs: ["videoId", "height", "width", "startSeconds", "endSeconds", "suggestedQuality", "playerVars", "disableCookies", "loadApi", "disablePlaceholder", "showBeforeIframeApiLoads", "placeholderButtonLabel", "placeholderImageQuality"], outputs: ["ready", "stateChange", "error", "apiChange", "playbackQualityChange", "playbackRateChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HighlightPipe, name: "highlight" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
12461
13028
  }
12462
13029
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartformwidgetComponent, decorators: [{
12463
13030
  type: Component,
@@ -12508,7 +13075,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
12508
13075
  YouTubePlayer,
12509
13076
  AsyncPipe,
12510
13077
  HighlightPipe,
12511
- ], template: "<div class=\"container material\" [formGroup]=\"form()\">\n @if (widgetInstance.isVisible === undefined ? true : widgetInstance.isVisible) {\n <div\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [class.sb4-widget-required]=\"isRequired()\"\n class=\"container\"\n >\n @if (widgetInstance.type === smartFormWidgetType.CONTAINER) {\n <div [attr.data-testid]=\"widgetInstance.key\" [ngClass]=\"getDirection()\">\n @for (widget of visibleChildren; track widget) {\n <smartformwidget\n [form]=\"form()\"\n [widgetInstance]=\"widget\"\n class=\"container-item\"\n [ngClass]=\"widget.cssClass ?? ''\"\n [onBlur]=\"onBlur()\"\n [onValueChange]=\"onValueChange\"\n [sophisticatedValueChange]=\"sophisticatedValueChange()\"\n [blurSophisticatedValueChange]=\"blurSophisticatedValueChange()\"\n class=\"{{ widget.key }}\"\n [labelColor]=\"labelColor()\"\n ></smartformwidget>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD) {\n <div (capsLock)=\"capsOn = $event\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n @if (!widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [attr.inputmode]=\"\n widgetInstance.inputMode ? widgetInstance.inputMode.toLocaleLowerCase() : 'text'\n \"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? (hidePassword ? 'password' : 'text') : '' }}\"\n (keydown.enter)=\"onKeydown()\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n [mask]=\"widgetInstance.mask\"\n />\n }\n <!-- [mask]=\"widgetInstance.mask ?? ''\" -->\n @if (widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n (click)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? 'password' : '' }}\"\n [matAutocomplete]=\"textFieldAuto\"\n (keydown.enter)=\"onKeydown()\"\n />\n }\n @if (widgetInstance.isPassword) {\n <button mat-icon-button matSuffix (click)=\"togglePasswordVisibility($event)\">\n <mat-icon fontSet=\"material-symbols-outlined\">{{\n hidePassword ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n }\n <mat-autocomplete #textFieldAuto=\"matAutocomplete\">\n @for (option of filteredOptions | async; track option) {\n <mat-option [value]=\"option.label\">\n <span [innerHTML]=\"option.label | highlight: toHighlight\"></span>\n </mat-option>\n }\n </mat-autocomplete>\n @if (capsOn && widgetInstance.isPassword) {\n <span class=\"mat-error\">\n {{ widgetInstance.capsLockWarning }}\n </span>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n @if (capsOn && widgetInstance.isPassword) {\n <smart-icon\n [icon]=\"widgetInstance.capsLockWarningIcon ?? 'keyboard_capslock'\"\n color=\"warn\"\n ></smart-icon>\n }\n @if (widgetInstance.icon && widgetInstance.iconPosition === 'PRE') {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n ></smart-icon>\n }\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <div class=\"textFieldButtons\">\n @if (widgetInstance.textFieldProperties?.clearable) {\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearField(widgetInstance.key)\"\n />\n }\n </div>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon\n [icon]=\"widgetInstance.textFieldButton.icon\"\n [color]=\"widgetInstance.textFieldButton.iconColor\"\n >\n </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_NUMBER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n [type]=\"'number'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [min]=\"widgetInstance.minValues ?? null\"\n [max]=\"widgetInstance.maxValues ?? null\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (widgetInstance.icon) {\n <smart-icon [icon]=\"widgetInstance.icon\" matSuffix> </smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_CHIPS) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipList aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip-row [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ value }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip-row>\n }\n <input\n #chipInput\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [matChipInputAddOnBlur]=\"addOnBlur\"\n [readonly]=\"widgetInstance.isReadonly\"\n [matAutocomplete]=\"chipAuto\"\n (matChipInputTokenEnd)=\"add($event)\"\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n <mat-autocomplete\n #chipAuto=\"matAutocomplete\"\n (optionSelected)=\"selected($event, widgetInstance)\"\n >\n @for (item of widgetInstance.valueList; track item) {\n <mat-option [disabled]=\"widgetInstance.isDisabled\" [value]=\"item.value\">\n {{ item.label }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-chip-grid>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_LOOKUP) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipListLookup aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ getChipsValue(value) }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip>\n }\n <input\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipListLookup\"\n [matChipInputSeparatorKeyCodes]=\"emptySeparatorKeysCodes\"\n [matChipInputAddOnBlur]=\"false\"\n [readonly]=\"true\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n </mat-chip-grid>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_BOX) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <textarea\n class=\"sb4-textarea\"\n #sb4Textarea\n cols=\"30\"\n cdkTextareaAutosize\n [cdkAutosizeMinRows]=\"widgetInstance.textBoxProperties?.minRows ?? 1\"\n [cdkAutosizeMaxRows]=\"widgetInstance.textBoxProperties?.maxRows ?? undefined\"\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n ></textarea>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance.hint || widgetInstance.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n <div class=\"checkbox-item-container\">\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key }}\"\n (change)=\"onValueChange?.next(widgetInstance)\"\n (change)=\"onBlur()?.next(widgetInstance)\"\n >\n {{ widgetInstance.label }}\n </mat-checkbox>\n </div>\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX_2) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n @for (checkbox of widgetInstance.valueList; track checkbox; let i = $index) {\n <div class=\"checkbox-item-container\">\n @if (checkbox.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"checkbox-item-image\"\n [src]=\"checkbox.imageUrl\"\n />\n }\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key + '.' + checkbox.key }}\"\n [value]=\"checkbox.value\"\n (change)=\"onValueChange?.next(checkbox)\"\n [disabled]=\"widgetInstance.isDisabled!\"\n >\n {{ checkbox.label }}\n </mat-checkbox>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RADIO_BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-radio-group\n class=\"input radio-section widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [attr.data-testid]=\"widgetInstance.key\"\n aria-label=\"{{ widgetInstance.label }}\"\n appearance=\"outline\"\n formControlName=\"{{ widgetInstance.key }}\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <div [ngClass]=\"getDirection()\">\n @for (radio of widgetInstance.valueList; track radio) {\n <div class=\"radio-item-container\">\n @if (radio.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"radio-item-image\"\n [src]=\"radio.imageUrl\"\n />\n }\n <mat-radio-button\n class=\"selecatbleObject\"\n value=\"{{ radio.value }}\"\n [ngClass]=\"getDirection()\"\n (change)=\"onValueChange?.next(radio.value)\"\n [disabled]=\"widgetInstance.isDisabled\"\n >\n {{ radio.label }}\n </mat-radio-button>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n <div class=\"radio-icon\">\n @if (widgetInstance.icon) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n >\n </smart-icon>\n }\n </div>\n </div>\n </mat-radio-group>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_PICKER) {\n <div class=\"datePicker widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n matInput\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (change)=\"handleBlurEvent(widgetInstance)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MONTH_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div class=\"{{ labelColor() }} smart-form-widget-label\">\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <lib-smart-month-picker\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n [control]=\"form().controls[widgetInstance.key]\"\n (valueChange)=\"handleYearMonthPicked($event)\"\n ></lib-smart-month-picker>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_TIME_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div class=\"dateTimePickerContainer\">\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n #dateInput\n matInput\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n [id]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (blur)=\"onDatePickerBlur($event)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n @if (hasCreated) {\n <mat-form-field\n class=\"input widgetContent time\"\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\"\n appearance=\"outline\"\n >\n <input\n #timeInput\n [formControlName]=\"widgetInstance.key + '-time'\"\n [attr.data-testid]=\"widgetInstance.key + '-time'\"\n [id]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n (blur)=\"onTimePickerBlur($event)\"\n matInput\n />\n </mat-form-field>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n (selectionChange)=\"onValueChange?.next($event.value)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}\n </mat-option>\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.selectProperties?.clearable) {\n <span matSuffix class=\"textFieldButtons\" (click)=\"$event.stopPropagation()\">\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearSelect(widgetInstance.key)\"\n />\n </span>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT_MULTIPLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n multiple\n (selectionChange)=\"onValueChange?.next($event.value); refocusSelectFilter(select)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}</mat-option\n >\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.LABEL) {\n <div class=\"label widgetContainer\" [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\">\n <div class=\"label-title labelContainer\" [ngClass]=\"widgetInstance.cssClass ?? ''\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance.widgetDescription) {\n <p>{{ widgetInstance.widgetDescription }}</p>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TIME) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent time {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent(widgetInstance)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TOGGLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <mat-slide-toggle\n formControlName=\"{{ widgetInstance.key }}\"\n [attr.data-testid]=\"widgetInstance.key\"\n (change)=\"onValueChange?.next($event)\"\n [labelPosition]=\"widgetInstance.toggleLabelPosition ?? 'before'\"\n >{{ !widgetInstance.showLabel ? widgetInstance.label : '' }}</mat-slide-toggle\n ><span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.INDICATOR) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"smartIndicator widgetContent\">\n <div\n class=\"indicatorItems {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n >\n @for (item of indicatorItems; track item; let i = $index) {\n <div class=\"indicatorItem\" [ngClass]=\"getIndicatorItemClass(i)\"></div>\n }\n </div>\n <p [ngClass]=\"getIndicatorStatusLabelColor()\">\n {{ getIndicatorStatusLabel() }}\n </p>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RECORDING_UPLOADER) {\n <div class=\"widgetContainer\">\n <div class=\"widgetItemContainer\">\n <smart-voice-recorder\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MULTI_FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-multi-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n (fileEvent)=\"executeUiAction($event.uiAction)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.IMAGE) {\n <div class=\"widgetContainer imageContainer\">\n @if (widgetInstance.showLabel && getWidgetLabel(widgetInstance)) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance.imageProperties?.image) {\n <smart-icon\n [imageResource]=\"$safeNavigationMigration(widgetInstance.imageProperties?.image)\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n } @else if (widgetInstance.value) {\n <smart-icon\n [(ngModel)]=\"widgetInstance.value\"\n [imageResource]=\"widgetInstance.value\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIV) {\n <div\n class=\"smartDiv\"\n [innerHTML]=\"sanitizeHtml(getWidgetLabel(widgetInstance))\"\n [ngClass]=\"getNgClass()\"\n [class.clickable]=\"!!widgetInstance.divProperties?.onClick\"\n [ngStyle]=\"getStyle()\"\n (click)=\"onDivClick()\"\n ></div>\n }\n @if (widgetInstance.type === smartFormWidgetType.HTML) {\n <smart-html-widget\n [widgetInstance]=\"widgetInstance\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-html-widget>\n }\n @if (widgetInstance.type === smartFormWidgetType.SVG) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [innerHTML]=\"sanitizeHtml(widgetInstance.value)\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIVIDER) {\n <div class=\"widgetContainer\">\n <hr\n class=\"smartDivider {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <button\n mat-button\n [attr.data-testid]=\"widgetInstance.key\"\n [ngClass]=\"getButtonType(widgetInstance.uiActionDescriptor)\"\n [color]=\"$safeNavigationMigration(widgetInstance.uiActionDescriptor?.color)\"\n (click)=\"onButtonClicked(widgetInstance)\"\n >\n @if (isOnlyIcon(widgetInstance.uiActionDescriptor)) {\n @if (widgetInstance.uiActionDescriptor?.icon) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n } @else {\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'PRE'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n {{ widgetInstance.uiActionDescriptor?.title }}\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'POST'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n }\n </button>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.COMPONENT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"labelContainer {{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"widgetContent\">\n <ng-template #customComponent></ng-template>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RICH_TEXT) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <quill-editor\n #quillEditor\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [modules]=\"\n widgetInstance.isDisabled ? emptyQuillToolbar : widgetInstance.quillModules\n \"\n [placeholder]=\"widgetInstance.placeholder ?? ''\"\n [readOnly]=\"widgetInstance.isReadonly ?? false\"\n [maxLength]=\"widgetInstance.maxLength ?? 0\"\n (onContentChanged)=\"onRichTextEditorContentChanged($event)\"\n ></quill-editor>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\" class=\"rich-text-editor-leeway-counter\">{{\n getRichTextEditorLengthLeeway()\n }}</mat-hint>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SORTABLE) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <lib-sortable-widget\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n ></lib-sortable-widget>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MATRIX) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <table class=\"matrixTable widgetContent\">\n <tr>\n <th></th>\n @for (option of widgetInstance.value.columns; track option) {\n <th class=\"optionLabel\">\n {{ option.displayValue }}\n </th>\n }\n </tr>\n @for (question of widgetInstance.value.rows; track question; let i = $index) {\n <tr>\n <th class=\"questionLabel\">\n <label>{{ question.displayValue }}</label>\n </th>\n @for (option of widgetInstance.value.columns; track option; let j = $index) {\n <td class=\"selectTd\">\n @if (!widgetInstance.isMultiple) {\n <mat-radio-group\n [formControlName]=\"widgetInstance.key + '.' + question.code\"\n [name]=\"'q' + i\"\n >\n <mat-radio-button [value]=\"option.code\"> </mat-radio-button>\n </mat-radio-group>\n }\n @if (widgetInstance.isMultiple) {\n <div>\n <mat-checkbox\n [formControlName]=\"\n widgetInstance.key + '.data.' + question.code + '.' + option.code\n \"\n [value]=\"widgetInstance.value['data'][question.code][option.code]\"\n [checked]=\"true\"\n ></mat-checkbox>\n </div>\n }\n </td>\n }\n <br />\n @if (widgetInstance.button) {\n <button mat-icon-button (click)=\"removeMatrixRow(question)\">\n <smart-icon icon=\"close\"></smart-icon>\n </button>\n }\n </tr>\n }\n </table>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.YOUTUBE_PLAYER) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} {{ widgetInstance.cssLabelClass }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <youtube-player\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n videoId=\"{{ widgetInstance.videoId }}\"\n [width]=\"widgetInstance.width\"\n [height]=\"widgetInstance.height\"\n [startSeconds]=\"widgetInstance.startSeconds\"\n [endSeconds]=\"widgetInstance.endSeconds\"\n ></youtube-player>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container:not(.ql-disabled) li[data-list=checked]>.ql-ui,.ql-container:not(.ql-disabled) li[data-list=unchecked]>.ql-ui{cursor:pointer}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor p,.ql-editor ol,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{margin:0;padding:0}@supports (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-set:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor table{border-collapse:collapse}.ql-editor td{border:1px solid #000;padding:2px 5px}.ql-editor ol{padding-left:1.5em}.ql-editor li{list-style-type:none;padding-left:1.5em;position:relative}.ql-editor li>.ql-ui:before{display:inline-block;margin-left:-1.5em;margin-right:.3em;text-align:right;white-space:nowrap;width:1.2em}.ql-editor li[data-list=checked]>.ql-ui,.ql-editor li[data-list=unchecked]>.ql-ui{color:#777}.ql-editor li[data-list=bullet]>.ql-ui:before{content:\"\\2022\"}.ql-editor li[data-list=checked]>.ql-ui:before{content:\"\\2611\"}.ql-editor li[data-list=unchecked]>.ql-ui:before{content:\"\\2610\"}@supports (counter-set:none){.ql-editor li[data-list]{counter-set:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list]{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered]{counter-increment:list-0}.ql-editor li[data-list=ordered]>.ql-ui:before{content:counter(list-0,decimal) \". \"}.ql-editor li[data-list=ordered].ql-indent-1{counter-increment:list-1}.ql-editor li[data-list=ordered].ql-indent-1>.ql-ui:before{content:counter(list-1,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-set:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-2{counter-increment:list-2}.ql-editor li[data-list=ordered].ql-indent-2>.ql-ui:before{content:counter(list-2,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-set:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-3{counter-increment:list-3}.ql-editor li[data-list=ordered].ql-indent-3>.ql-ui:before{content:counter(list-3,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-set:list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-4{counter-increment:list-4}.ql-editor li[data-list=ordered].ql-indent-4>.ql-ui:before{content:counter(list-4,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-set:list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-5{counter-increment:list-5}.ql-editor li[data-list=ordered].ql-indent-5>.ql-ui:before{content:counter(list-5,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-set:list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-6{counter-increment:list-6}.ql-editor li[data-list=ordered].ql-indent-6>.ql-ui:before{content:counter(list-6,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-set:list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-reset:list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-7{counter-increment:list-7}.ql-editor li[data-list=ordered].ql-indent-7>.ql-ui:before{content:counter(list-7,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-set:list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-reset:list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-8{counter-increment:list-8}.ql-editor li[data-list=ordered].ql-indent-8>.ql-ui:before{content:counter(list-8,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-set:list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-reset:list-9}}.ql-editor li[data-list=ordered].ql-indent-9{counter-increment:list-9}.ql-editor li[data-list=ordered].ql-indent-9>.ql-ui:before{content:counter(list-9,decimal) \". \"}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor li.ql-direction-rtl{padding-right:1.5em}.ql-editor li.ql-direction-rtl>.ql-ui:before{margin-left:.3em;margin-right:-1.5em;text-align:left}.ql-editor table{table-layout:fixed;width:100%}.ql-editor table td{outline:none}.ql-editor .ql-code-block-container{font-family:monospace}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor .ql-ui{position:absolute}.ql-editor.ql-blank:before{color:#0009;content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow.ql-toolbar:after,.ql-snow .ql-toolbar:after{clear:both;content:\"\";display:table}.ql-snow.ql-toolbar button,.ql-snow .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow.ql-toolbar button svg,.ql-snow .ql-toolbar button svg{float:left;height:100%}.ql-snow.ql-toolbar button:active:hover,.ql-snow .ql-toolbar button:active:hover{outline:none}.ql-snow.ql-toolbar input.ql-image[type=file],.ql-snow .ql-toolbar input.ql-image[type=file]{display:none}.ql-snow.ql-toolbar button:hover,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar button:focus,.ql-snow .ql-toolbar button:focus,.ql-snow.ql-toolbar button.ql-active,.ql-snow .ql-toolbar button.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item.ql-selected{color:#06c}.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill{fill:#06c}.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter{stroke:#06c}@media(pointer:coarse){.ql-snow.ql-toolbar button:hover:not(.ql-active),.ql-snow .ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow,.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:\"\";display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-thin,.ql-snow .ql-stroke.ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor .ql-code-block-container{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor .ql-code-block-container{margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor .ql-code-block-container{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label:before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=\"\"]):before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-label:before,.ql-snow .ql-picker.ql-header .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"1\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{content:\"Heading 1\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"2\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{content:\"Heading 2\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"3\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{content:\"Heading 3\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"4\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{content:\"Heading 4\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"5\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{content:\"Heading 5\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"6\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{content:\"Heading 6\"}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-label:before,.ql-snow .ql-picker.ql-font .ql-picker-item:before{content:\"Sans Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{content:\"Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{content:\"Monospace\"}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-label:before,.ql-snow .ql-picker.ql-size .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{content:\"Small\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{content:\"Large\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{content:\"Huge\"}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-code-block-container{position:relative}.ql-code-block-container .ql-ui{right:5px;top:5px}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label,.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow+.ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip:before{content:\"Visit URL:\";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action:after{border-right:1px solid #ccc;content:\"Edit\";margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove:before{content:\"Remove\";margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action:after{border-right:0;content:\"Save\";padding-right:0}.ql-snow .ql-tooltip[data-mode=link]:before{content:\"Enter link:\"}.ql-snow .ql-tooltip[data-mode=formula]:before{content:\"Enter formula:\"}.ql-snow .ql-tooltip[data-mode=video]:before{content:\"Enter video:\"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc}.checkbox-section,.radio-section{display:flex;flex-direction:column}.input{width:100%}.direction-col,.toggle-col{display:flex;flex-direction:column;gap:.5em}.toggle-col>label{font-size:.75rem;color:#6b7280;padding-left:.5em}.direction-row{display:flex;flex-direction:row;align-items:center;gap:.5em}.selecatbleObject{margin:.5em}.radioLabel{color:var(--primary-color);text-align:left!important}.container{height:100%}.input{height:100%;display:flex;flex-direction:column}.checkbox{flex-direction:column}.mat-form-field-wrapper{padding-bottom:0!important}.input .mat-mdc-standard-chip.mat-chip-with-trailing-icon{padding-right:12px}.time-picker{display:flex;flex-direction:row;height:100%;border:solid 2px lightgrey;padding:1em;border-radius:4px}.time-picker:hover{border-color:#000}::ng-deep .mat-h4 .mat-body-1 .mat-typography h4{margin:0}.label{margin:28px 0 8px}.smartIndicator{display:flex;flex-direction:column;gap:.25rem;width:-moz-fit-content;width:fit-content}.indicatorItems{display:flex;flex-direction:row;gap:.25rem}.indicatorItem{width:3rem;height:.25rem;background-color:#d3d3d3;border-radius:.5rem}.radio-error{width:-moz-fit-content;width:fit-content;display:flex;flex-direction:row;gap:.5rem}.mat-calendar-previous-button,.mat-calendar-next-button{padding:0;min-width:0;width:40px!important;height:40px!important;flex-shrink:0;line-height:40px;border-radius:50%}.mat-calendar-arrow{height:36px!important;display:flex!important;flex-direction:column!important;justify-content:center}.radio-item-container,.checkbox-item-container{display:flex;flex-direction:column}.widgetContent::ng-deep .ql-container{height:200px;width:460px}.dateTimePickerContainer{display:flex;flex-direction:row;gap:.25rem}.dateTimePickerContainer mat-form-field{flex:1}.date,.time{width:100%}.date .mat-form-field-infix,.time .mat-form-field-infix{width:inherit!important}::ng-deep .mat-icon.mat-drag-indicator{--drag-indicator: #3b3b3b;color:var(--drag-indicator)}.matrixTable{width:100%;border-spacing:0 1rem}.matrixTable th{padding:.25rem}.matrixTable .optionLabel,.matrixTable td{text-align:center}.example-month-picker .mat-calendar-period-button{pointer-events:none}.example-month-picker .mat-calendar-arrow{display:none}.textFieldContainer{display:flex;flex-direction:row}.textFieldContainer{align-content:center;border:1px solid #cbd5e1;border-radius:3px;background-color:#fff}.textFieldContainer input{border:unset}.textFieldContainer:focus-within:not(:has(input:disabled)){outline:0 none;outline-offset:0;box-shadow:0 0 0 .2rem #a6d5fa;border-color:#2196f3}.textFieldContainer:has(input:disabled) .clearButton{cursor:not-allowed;opacity:.6}.comboBoxFilter{display:flex;flex-direction:row;align-items:center;gap:.5rem;min-height:48px;padding:0 1rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.comboBoxFilter:focus-within{border-bottom-color:var(--mat-sys-primary, #3f51b5)}.comboBoxFilter .mat-icon{flex:0 0 auto;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .54))}.comboBoxFilter input{flex:1 1 auto;min-width:0;border:none;outline:none;background:transparent;font:inherit;color:inherit}.textFieldButtons{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.clearButton .mat-mdc-raised-button,.clearButton button{background-color:unset!important;border:unset;color:#6b7280!important;box-shadow:unset;font-size:1rem!important}.clearButton .mat-icon.mat-primary{color:#6b7280!important}.clearButton .mat-mdc-raised-button:hover,.clearButton button:hover{color:#6b7280cc!important;background-color:unset;border:unset;box-shadow:unset;font-size:1rem!important}.mat-mdc-form-field-infix{display:flex;flex-direction:row}textarea:not(:placeholder-shown)~label{top:-.75em!important;font-size:12px!important}.disabledEditor *{-webkit-user-modify:read-only;-moz-user-modify:read-only;user-modify:read-only}.sb4-textarea{--sb4-textarea-line-height: 20px;line-height:var(--sb4-textarea-line-height);overflow-y:auto!important}.widgetContainer .imageIcon{max-width:unset!important;height:unset!important}.material .sb4-textarea{resize:vertical!important}.material .smart-form-widget-label{font-weight:700}.material .mat-mdc-form-field-subscript-wrapper{display:none}.label-right{display:flex;gap:.5rem;flex-direction:row-reverse}.label-left{display:flex;gap:.5rem;flex-direction:row}.label-top{display:flex;gap:.5rem;flex-direction:column}.label-bottom{display:flex;gap:.5rem;flex-direction:column-reverse}.smartDiv{width:100%}.clickable{cursor:pointer}\n/*!\n * Quill Editor v2.0.3\n * https://quilljs.com\n * Copyright (c) 2017-2024, Slab\n * Copyright (c) 2014, Jason Chen\n * Copyright (c) 2013, salesforce.com\n */\n"] }]
13078
+ ], template: "<div class=\"container material\" [formGroup]=\"form()\">\n @if (widgetInstance.isVisible === undefined ? true : widgetInstance.isVisible) {\n <div\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [class.sb4-widget-required]=\"isRequired()\"\n class=\"container\"\n >\n @if (widgetInstance.type === smartFormWidgetType.CONTAINER) {\n <div [attr.data-testid]=\"widgetInstance.key\" [ngClass]=\"getDirection()\">\n @for (widget of visibleChildren; track widget) {\n <smartformwidget\n [form]=\"form()\"\n [widgetInstance]=\"widget\"\n class=\"container-item\"\n [ngClass]=\"widget.cssClass ?? ''\"\n [onBlur]=\"onBlur()\"\n [onValueChange]=\"onValueChange\"\n [sophisticatedValueChange]=\"sophisticatedValueChange()\"\n [blurSophisticatedValueChange]=\"blurSophisticatedValueChange()\"\n class=\"{{ widget.key }}\"\n [labelColor]=\"labelColor()\"\n ></smartformwidget>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD) {\n <div (capsLock)=\"capsOn = $event\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n @if (!widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [attr.inputmode]=\"\n widgetInstance.inputMode ? widgetInstance.inputMode.toLocaleLowerCase() : 'text'\n \"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? (hidePassword ? 'password' : 'text') : '' }}\"\n (keydown.enter)=\"onKeydown()\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n [mask]=\"widgetInstance.mask\"\n />\n }\n <!-- [mask]=\"widgetInstance.mask ?? ''\" -->\n @if (widgetInstance.selection) {\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n (click)=\"onValueChange?.next($event)\"\n type=\"{{ widgetInstance.isPassword ? 'password' : '' }}\"\n [matAutocomplete]=\"textFieldAuto\"\n (keydown.enter)=\"onKeydown()\"\n />\n }\n @if (widgetInstance.isPassword) {\n <button mat-icon-button matSuffix (click)=\"togglePasswordVisibility($event)\">\n <mat-icon fontSet=\"material-symbols-outlined\">{{\n hidePassword ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n }\n <mat-autocomplete #textFieldAuto=\"matAutocomplete\">\n @for (option of filteredOptions | async; track option) {\n <mat-option [value]=\"option.label\">\n <span [innerHTML]=\"option.label | highlight: toHighlight\"></span>\n </mat-option>\n }\n </mat-autocomplete>\n @if (capsOn && widgetInstance.isPassword) {\n <span class=\"mat-error\">\n {{ widgetInstance.capsLockWarning }}\n </span>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n @if (capsOn && widgetInstance.isPassword) {\n <smart-icon\n [icon]=\"widgetInstance.capsLockWarningIcon ?? 'keyboard_capslock'\"\n color=\"warn\"\n ></smart-icon>\n }\n @if (widgetInstance.icon && widgetInstance.iconPosition === 'PRE') {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n ></smart-icon>\n }\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <div class=\"textFieldButtons\">\n @if (widgetInstance.textFieldProperties?.clearable) {\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearField(widgetInstance.key)\"\n />\n }\n </div>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon\n [icon]=\"widgetInstance.textFieldButton.icon\"\n [color]=\"widgetInstance.textFieldButton.iconColor\"\n >\n </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_NUMBER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input textField widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n [type]=\"'number'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [min]=\"widgetInstance.minValues ?? null\"\n [max]=\"widgetInstance.maxValues ?? null\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n <span matPrefix>\n {{ widgetInstance.prefix }}\n </span>\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (widgetInstance.icon) {\n <smart-icon [icon]=\"widgetInstance.icon\" matSuffix> </smart-icon>\n }\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.textFieldButton) {\n <button\n matSuffix\n mat-button\n color=\"{{ widgetInstance.textFieldButton.color }}\"\n (click)=\"widgetInstance.textFieldButton.callback(widgetInstance)\"\n >\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().PRE &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n {{ widgetInstance.textFieldButton.label }}\n @if (\n widgetInstance.textFieldButton.iconPosition ===\n smartFormTextFieldButtonIconPosition().POST &&\n widgetInstance.textFieldButton.icon\n ) {\n <smart-icon [icon]=\"widgetInstance.textFieldButton.icon\"> </smart-icon>\n }\n </button>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_CHIPS) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipList aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip-row [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ value }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip-row>\n }\n <input\n #chipInput\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipList\"\n [matChipInputSeparatorKeyCodes]=\"separatorKeysCodes\"\n [matChipInputAddOnBlur]=\"addOnBlur\"\n [readonly]=\"widgetInstance.isReadonly\"\n [matAutocomplete]=\"chipAuto\"\n (matChipInputTokenEnd)=\"add($event)\"\n (change)=\"handleBlurEvent($event)\"\n (input)=\"onValueChange?.next($event)\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n <mat-autocomplete\n #chipAuto=\"matAutocomplete\"\n (optionSelected)=\"selected($event, widgetInstance)\"\n >\n @for (item of widgetInstance.valueList; track item) {\n <mat-option [disabled]=\"widgetInstance.isDisabled\" [value]=\"item.value\">\n {{ item.label }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-chip-grid>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_FIELD_LOOKUP) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-chip-grid #chipListLookup aria-label=\"{{ widgetInstance.label }}\">\n @for (value of widgetInstance.value; track value) {\n <mat-chip [disabled]=\"widgetInstance.isDisabled\" (removed)=\"remove(value)\">\n {{ getChipsValue(value) }}\n <button matChipRemove>\n <mat-icon fontSet=\"material-symbols-outlined\">cancel</mat-icon>\n </button>\n </mat-chip>\n }\n <input\n [attr.data-testid]=\"widgetInstance.key\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matChipInputFor]=\"chipListLookup\"\n [matChipInputSeparatorKeyCodes]=\"emptySeparatorKeysCodes\"\n [matChipInputAddOnBlur]=\"false\"\n [readonly]=\"true\"\n [disabled]=\"widgetInstance.isDisabled\"\n />\n </mat-chip-grid>\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TEXT_BOX) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <textarea\n class=\"sb4-textarea\"\n #sb4Textarea\n cols=\"30\"\n cdkTextareaAutosize\n [cdkAutosizeMinRows]=\"widgetInstance.textBoxProperties?.minRows ?? 1\"\n [cdkAutosizeMaxRows]=\"widgetInstance.textBoxProperties?.maxRows ?? undefined\"\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'string'\"\n [value]=\"widgetInstance.value\"\n [readonly]=\"widgetInstance.isReadonly\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent($event)\"\n maxlength=\"{{ widgetInstance.maxLength }}\"\n ></textarea>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\">{{\n widgetInstance.maxLength - form().controls[widgetInstance.key].value.length\n }}</mat-hint>\n }\n </mat-form-field>\n @if (\n !widgetInstance.hint || widgetInstance.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n <div class=\"checkbox-item-container\">\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key }}\"\n (change)=\"onValueChange?.next(widgetInstance)\"\n (change)=\"onBlur()?.next(widgetInstance)\"\n >\n {{ widgetInstance.label }}\n </mat-checkbox>\n </div>\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.CHECK_BOX_2) {\n <div [attr.data-testid]=\"widgetInstance.key\" class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"input checkbox widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <section class=\"checkbox-section\" [ngClass]=\"getDirection()\">\n @for (checkbox of widgetInstance.valueList; track checkbox; let i = $index) {\n <div class=\"checkbox-item-container\">\n @if (checkbox.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"checkbox-item-image\"\n [src]=\"checkbox.imageUrl\"\n />\n }\n <mat-checkbox\n class=\"selecatbleObject\"\n formControlName=\"{{ widgetInstance.key + '.' + checkbox.key }}\"\n [value]=\"checkbox.value\"\n (change)=\"onValueChange?.next(checkbox)\"\n [disabled]=\"widgetInstance.isDisabled!\"\n >\n {{ checkbox.label }}\n </mat-checkbox>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </section>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RADIO_BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-radio-group\n class=\"input radio-section widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n [attr.data-testid]=\"widgetInstance.key\"\n aria-label=\"{{ widgetInstance.label }}\"\n appearance=\"outline\"\n formControlName=\"{{ widgetInstance.key }}\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"radioLabel\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <div [ngClass]=\"getDirection()\">\n @for (radio of widgetInstance.valueList; track radio) {\n <div class=\"radio-item-container\">\n @if (radio.imageUrl) {\n <img\n title=\"{{ widgetInstance.key }}\"\n class=\"radio-item-image\"\n [src]=\"radio.imageUrl\"\n />\n }\n <mat-radio-button\n class=\"selecatbleObject\"\n value=\"{{ radio.value }}\"\n [ngClass]=\"getDirection()\"\n (change)=\"onValueChange?.next(radio.value)\"\n [disabled]=\"widgetInstance.isDisabled\"\n >\n {{ radio.label }}\n </mat-radio-button>\n </div>\n }\n <div class=\"radio-error\">\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n <div class=\"radio-icon\">\n @if (widgetInstance.icon) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n >\n </smart-icon>\n }\n </div>\n </div>\n </mat-radio-group>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_PICKER) {\n <div class=\"datePicker widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n matInput\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (change)=\"handleBlurEvent(widgetInstance)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MONTH_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div class=\"{{ labelColor() }} smart-form-widget-label\">\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <lib-smart-month-picker\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n [control]=\"form().controls[widgetInstance.key]\"\n (valueChange)=\"handleYearMonthPicked($event)\"\n ></lib-smart-month-picker>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DATE_TIME_PICKER) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div class=\"dateTimePickerContainer\">\n <mat-form-field\n class=\"input widgetContent date {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker (closed)=\"handleBlurEvent(widgetInstance)\"></mat-datepicker>\n <input\n #dateInput\n matInput\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [min]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.minDate ?? null)\"\n [max]=\"convertToLocalDateTime(widgetInstance.dateFieldProperties?.maxDate ?? null)\"\n [id]=\"widgetInstance.key\"\n [value]=\"widgetInstance.value\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n [matDatepicker]=\"picker\"\n (blur)=\"onDatePickerBlur($event)\"\n (dateChange)=\"onValueChange?.next(widgetInstance)\"\n [matDatepickerFilter]=\"widgetInstance.filter ?? dateFilter\"\n />\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n <mat-hint>\n {{ widgetInstance.dateFormatHint }}\n </mat-hint>\n </mat-form-field>\n @if (hasCreated) {\n <mat-form-field\n class=\"input widgetContent time\"\n [ngClass]=\"widgetInstance.cssClass ?? ''\"\n [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\"\n appearance=\"outline\"\n >\n <input\n #timeInput\n [formControlName]=\"widgetInstance.key + '-time'\"\n [attr.data-testid]=\"widgetInstance.key + '-time'\"\n [id]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n (blur)=\"onTimePickerBlur($event)\"\n matInput\n />\n </mat-form-field>\n }\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <div\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </div>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n (selectionChange)=\"onValueChange?.next($event.value)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}\n </mat-option>\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n <span matSuffix>\n {{ widgetInstance.suffix }}\n </span>\n @if (\n widgetInstance.icon &&\n (!widgetInstance.iconPosition || widgetInstance.iconPosition === 'POST')\n ) {\n <smart-icon\n [icon]=\"widgetInstance.icon\"\n [color]=\"widgetInstance.iconColor ?? 'primary'\"\n matSuffix\n ></smart-icon>\n }\n @if (widgetInstance.selectProperties?.clearable) {\n <span matSuffix class=\"textFieldButtons\" (click)=\"$event.stopPropagation()\">\n <ui-action-button\n class=\"clearButton\"\n [addBasicClasses]=\"false\"\n [descriptor]=\"clearButtonDescriptor\"\n (actionClick)=\"clearSelect(widgetInstance.key)\"\n />\n </span>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SELECT_MULTIPLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <mat-select\n #select\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n multiple\n (selectionChange)=\"onValueChange?.next($event.value); refocusSelectFilter(select)\"\n (opened)=\"focusSelectFilter()\"\n (closed)=\"handleBlurEvent(widgetInstance); clearSelectFilter()\"\n [disabled]=\"widgetInstance.isDisabled!\"\n [compareWith]=\"\n widgetInstance.compareWith == null ? compareItems : widgetInstance.compareWith\n \"\n placeholder=\"{{ selectionPlaceholder }}\"\n >\n @if (hasSelectFilter()) {\n <div class=\"comboBoxFilter\">\n <mat-icon fontSet=\"material-symbols-outlined\">search</mat-icon>\n <input\n #selectFilterInput\n type=\"text\"\n autocomplete=\"off\"\n [value]=\"selectFilter()\"\n [placeholder]=\"selectFilterPlaceholder\"\n (input)=\"onSelectFilterInput(select, $any($event.target).value)\"\n (keydown)=\"onSelectFilterKeydown(select, $event)\"\n />\n </div>\n }\n @if (hasSelectAll()) {\n <div class=\"comboBoxSelectAll\" (keydown)=\"$event.stopPropagation()\">\n <mat-checkbox\n [checked]=\"selectAllState() === 'all'\"\n [indeterminate]=\"selectAllState() === 'some'\"\n (change)=\"toggleSelectAll(select)\"\n >{{ selectAllLabel }}</mat-checkbox\n >\n </div>\n }\n @for (option of selectOptions(); track option) {\n <div>\n @if (option.type === getType().ITEM_GROUP) {\n <mat-optgroup [label]=\"option.label\" [disabled]=\"option.isDisabled\">\n @for (innerOption of option.valueList; track innerOption) {\n <mat-option [value]=\"innerOption.value\" [disabled]=\"innerOption.isDisabled\">\n @if (innerOption.icon) {\n <smart-icon\n [icon]=\"innerOption.icon\"\n [color]=\"innerOption.iconColor\"\n ></smart-icon>\n }\n {{ innerOption.label }}</mat-option\n >\n }\n </mat-optgroup>\n }\n @if (option.type === getType().ITEM) {\n <mat-option [value]=\"option.value\" [disabled]=\"option.isDisabled\">\n @if (option.icon) {\n <smart-icon [icon]=\"option.icon\" [color]=\"option.iconColor\"></smart-icon>\n }\n {{ option.label }}</mat-option\n >\n }\n </div>\n }\n </mat-select>\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n @if (isToolbarPresent()) {\n <smart-ui-action-toolbar\n class=\"textFieldToolbar\"\n matSuffix\n [id]=\"widgetInstance.toolbarId\"\n ></smart-ui-action-toolbar>\n }\n </mat-form-field>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.LABEL) {\n <div class=\"label widgetContainer\" [ngStyle]=\"{ width: widgetInstance.minWidth + 'px' }\">\n <div class=\"label-title labelContainer\" [ngClass]=\"widgetInstance.cssClass ?? ''\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance.widgetDescription) {\n <p>{{ widgetInstance.widgetDescription }}</p>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TIME) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <mat-form-field\n class=\"input widgetContent time {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n appearance=\"outline\"\n >\n @if (!widgetInstance.showLabel) {\n <mat-label class=\"label\" [ngClass]=\"widgetInstance.cssLabelClass ?? ''\">\n {{ getWidgetLabel(widgetInstance) }}\n </mat-label>\n }\n <input\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [type]=\"'time'\"\n placeholder=\"{{ widgetInstance.placeholder }}\"\n matInput\n (change)=\"handleBlurEvent(widgetInstance)\"\n />\n <span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n matSuffix\n ></smart-icon>\n }\n </mat-form-field>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.TOGGLE) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <div class=\"labelContainer\">\n <h4\n class=\"{{ labelColor() }} smart-form-widget-label {{\n widgetInstance.cssLabelClass ?? ''\n }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <mat-slide-toggle\n formControlName=\"{{ widgetInstance.key }}\"\n [attr.data-testid]=\"widgetInstance.key\"\n (change)=\"onValueChange?.next($event)\"\n [labelPosition]=\"widgetInstance.toggleLabelPosition ?? 'before'\"\n >{{ !widgetInstance.showLabel ? widgetInstance.label : '' }}</mat-slide-toggle\n ><span class=\"mat-error\">\n {{ widgetInstance.error }}\n </span>\n @if (widgetInstance.error && widgetInstance.errorIcon) {\n <smart-icon\n [icon]=\"widgetInstance.errorIcon\"\n [color]=\"widgetInstance.errorIconColor ?? 'warn'\"\n ></smart-icon>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.INDICATOR) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} labelContainer {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"smartIndicator widgetContent\">\n <div\n class=\"indicatorItems {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n >\n @for (item of indicatorItems; track item; let i = $index) {\n <div class=\"indicatorItem\" [ngClass]=\"getIndicatorItemClass(i)\"></div>\n }\n </div>\n <p [ngClass]=\"getIndicatorStatusLabelColor()\">\n {{ getIndicatorStatusLabel() }}\n </p>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RECORDING_UPLOADER) {\n <div class=\"widgetContainer\">\n <div class=\"widgetItemContainer\">\n <smart-voice-recorder\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MULTI_FILE_UPLOADER) {\n <div class=\"widgetContainer\">\n <smart-multi-file-editor\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n (uploadFilesEvent)=\"upload($event)\"\n (fileEvent)=\"executeUiAction($event.uiAction)\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.IMAGE) {\n <div class=\"widgetContainer imageContainer\">\n @if (widgetInstance.showLabel && getWidgetLabel(widgetInstance)) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance.imageProperties?.image) {\n <smart-icon\n [imageResource]=\"$safeNavigationMigration(widgetInstance.imageProperties?.image)\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n } @else if (widgetInstance.value) {\n <smart-icon\n [(ngModel)]=\"widgetInstance.value\"\n [imageResource]=\"widgetInstance.value\"\n class=\"widgetContent {{ widgetInstance.imageCss ?? '' }}\"\n alt=\"Image\"\n title=\"{{ widgetInstance.key }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-icon>\n }\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIV) {\n <div\n class=\"smartDiv\"\n [innerHTML]=\"sanitizeHtml(getWidgetLabel(widgetInstance))\"\n [ngClass]=\"getNgClass()\"\n [class.clickable]=\"!!widgetInstance.divProperties?.onClick\"\n [ngStyle]=\"getStyle()\"\n (click)=\"onDivClick()\"\n ></div>\n }\n @if (widgetInstance.type === smartFormWidgetType.HTML) {\n <smart-html-widget\n [widgetInstance]=\"widgetInstance\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></smart-html-widget>\n }\n @if (widgetInstance.type === smartFormWidgetType.SVG) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [innerHTML]=\"sanitizeHtml(widgetInstance.value)\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n ></div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.DIVIDER) {\n <div class=\"widgetContainer\">\n <hr\n class=\"smartDivider {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n />\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.BUTTON) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"labelContainer {{ labelColor() }} {{ widgetInstance.cssLabelClass ?? '' }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div\n class=\"widgetContent {{ widgetInstance.cssClass ?? '' }}\"\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n >\n <button\n mat-button\n [attr.data-testid]=\"widgetInstance.key\"\n [ngClass]=\"getButtonType(widgetInstance.uiActionDescriptor)\"\n [color]=\"$safeNavigationMigration(widgetInstance.uiActionDescriptor?.color)\"\n (click)=\"onButtonClicked(widgetInstance)\"\n >\n @if (isOnlyIcon(widgetInstance.uiActionDescriptor)) {\n @if (widgetInstance.uiActionDescriptor?.icon) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n } @else {\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'PRE'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n {{ widgetInstance.uiActionDescriptor?.title }}\n @if (\n widgetInstance.uiActionDescriptor?.icon &&\n widgetInstance.uiActionDescriptor?.iconPosition === 'POST'\n ) {\n <smart-icon\n [icon]=\"widgetInstance.uiActionDescriptor!.icon!\"\n [color]=\"\n widgetInstance.uiActionDescriptor?.iconColor ??\n widgetInstance.uiActionDescriptor?.color\n \"\n ></smart-icon>\n }\n }\n </button>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.COMPONENT) {\n <div class=\"widgetContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"labelContainer {{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n <div class=\"widgetContent\">\n <ng-template #customComponent></ng-template>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.RICH_TEXT) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <quill-editor\n #quillEditor\n [formControlName]=\"widgetInstance.key\"\n [id]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [modules]=\"\n widgetInstance.isDisabled ? emptyQuillToolbar : widgetInstance.quillModules\n \"\n [placeholder]=\"widgetInstance.placeholder ?? ''\"\n [readOnly]=\"widgetInstance.isReadonly ?? false\"\n [maxLength]=\"widgetInstance.maxLength ?? 0\"\n (onContentChanged)=\"onRichTextEditorContentChanged($event)\"\n ></quill-editor>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n @if (widgetInstance.showCharacterLimitSuffix && widgetInstance.maxLength) {\n <mat-hint matSuffix align=\"end\" class=\"rich-text-editor-leeway-counter\">{{\n getRichTextEditorLengthLeeway()\n }}</mat-hint>\n }\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.SORTABLE) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <div class=\"widgetContent\">\n <lib-sortable-widget\n [formControlName]=\"widgetInstance.key\"\n [attr.data-testid]=\"widgetInstance.key\"\n [widgetInstance]=\"widgetInstance\"\n ></lib-sortable-widget>\n </div>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.MATRIX) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4 class=\"{{ labelColor() }}\">\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <table class=\"matrixTable widgetContent\">\n <tr>\n <th></th>\n @for (option of widgetInstance.value.columns; track option) {\n <th class=\"optionLabel\">\n {{ option.displayValue }}\n </th>\n }\n </tr>\n @for (question of widgetInstance.value.rows; track question; let i = $index) {\n <tr>\n <th class=\"questionLabel\">\n <label>{{ question.displayValue }}</label>\n </th>\n @for (option of widgetInstance.value.columns; track option; let j = $index) {\n <td class=\"selectTd\">\n @if (!widgetInstance.isMultiple) {\n <mat-radio-group\n [formControlName]=\"widgetInstance.key + '.' + question.code\"\n [name]=\"'q' + i\"\n >\n <mat-radio-button [value]=\"option.code\"> </mat-radio-button>\n </mat-radio-group>\n }\n @if (widgetInstance.isMultiple) {\n <div>\n <mat-checkbox\n [formControlName]=\"\n widgetInstance.key + '.data.' + question.code + '.' + option.code\n \"\n [value]=\"widgetInstance.value['data'][question.code][option.code]\"\n [checked]=\"true\"\n ></mat-checkbox>\n </div>\n }\n </td>\n }\n <br />\n @if (widgetInstance.button) {\n <button mat-icon-button (click)=\"removeMatrixRow(question)\">\n <smart-icon icon=\"close\"></smart-icon>\n </button>\n }\n </tr>\n }\n </table>\n </div>\n }\n @if (widgetInstance.type === smartFormWidgetType.YOUTUBE_PLAYER) {\n <div class=\"widgetContainer\">\n <div class=\"labelContainer\">\n @if (widgetInstance.showLabel) {\n <h4\n class=\"{{ labelColor() }} {{ widgetInstance.cssLabelClass }}\"\n [ngClass]=\"getLabelNgClass()\"\n [ngStyle]=\"getLabelStyle()\"\n >\n {{ getWidgetLabel(widgetInstance) }}\n </h4>\n }\n @if (widgetInstance?.hint?.position === SmartWidgetHintPosition.LABEL) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n <youtube-player\n [ngClass]=\"getNgClass()\"\n [ngStyle]=\"getStyle()\"\n videoId=\"{{ widgetInstance.videoId }}\"\n [width]=\"widgetInstance.width\"\n [height]=\"widgetInstance.height\"\n [startSeconds]=\"widgetInstance.startSeconds\"\n [endSeconds]=\"widgetInstance.endSeconds\"\n ></youtube-player>\n @if (\n !widgetInstance?.hint ||\n widgetInstance?.hint?.position === SmartWidgetHintPosition.INPUT\n ) {\n <mat-hint>{{ widgetInstance.hint?.text }}</mat-hint>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [".ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container:not(.ql-disabled) li[data-list=checked]>.ql-ui,.ql-container:not(.ql-disabled) li[data-list=unchecked]>.ql-ui{cursor:pointer}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor p,.ql-editor ol,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{margin:0;padding:0}@supports (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-set:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor table{border-collapse:collapse}.ql-editor td{border:1px solid #000;padding:2px 5px}.ql-editor ol{padding-left:1.5em}.ql-editor li{list-style-type:none;padding-left:1.5em;position:relative}.ql-editor li>.ql-ui:before{display:inline-block;margin-left:-1.5em;margin-right:.3em;text-align:right;white-space:nowrap;width:1.2em}.ql-editor li[data-list=checked]>.ql-ui,.ql-editor li[data-list=unchecked]>.ql-ui{color:#777}.ql-editor li[data-list=bullet]>.ql-ui:before{content:\"\\2022\"}.ql-editor li[data-list=checked]>.ql-ui:before{content:\"\\2611\"}.ql-editor li[data-list=unchecked]>.ql-ui:before{content:\"\\2610\"}@supports (counter-set:none){.ql-editor li[data-list]{counter-set:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list]{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered]{counter-increment:list-0}.ql-editor li[data-list=ordered]>.ql-ui:before{content:counter(list-0,decimal) \". \"}.ql-editor li[data-list=ordered].ql-indent-1{counter-increment:list-1}.ql-editor li[data-list=ordered].ql-indent-1>.ql-ui:before{content:counter(list-1,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-set:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-2{counter-increment:list-2}.ql-editor li[data-list=ordered].ql-indent-2>.ql-ui:before{content:counter(list-2,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-set:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-3{counter-increment:list-3}.ql-editor li[data-list=ordered].ql-indent-3>.ql-ui:before{content:counter(list-3,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-set:list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-4{counter-increment:list-4}.ql-editor li[data-list=ordered].ql-indent-4>.ql-ui:before{content:counter(list-4,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-set:list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-5{counter-increment:list-5}.ql-editor li[data-list=ordered].ql-indent-5>.ql-ui:before{content:counter(list-5,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-set:list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-6{counter-increment:list-6}.ql-editor li[data-list=ordered].ql-indent-6>.ql-ui:before{content:counter(list-6,decimal) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-set:list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-reset:list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-7{counter-increment:list-7}.ql-editor li[data-list=ordered].ql-indent-7>.ql-ui:before{content:counter(list-7,lower-alpha) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-set:list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-reset:list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-8{counter-increment:list-8}.ql-editor li[data-list=ordered].ql-indent-8>.ql-ui:before{content:counter(list-8,lower-roman) \". \"}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-set:list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-reset:list-9}}.ql-editor li[data-list=ordered].ql-indent-9{counter-increment:list-9}.ql-editor li[data-list=ordered].ql-indent-9>.ql-ui:before{content:counter(list-9,decimal) \". \"}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor li.ql-direction-rtl{padding-right:1.5em}.ql-editor li.ql-direction-rtl>.ql-ui:before{margin-left:.3em;margin-right:-1.5em;text-align:left}.ql-editor table{table-layout:fixed;width:100%}.ql-editor table td{outline:none}.ql-editor .ql-code-block-container{font-family:monospace}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor .ql-ui{position:absolute}.ql-editor.ql-blank:before{color:#0009;content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow.ql-toolbar:after,.ql-snow .ql-toolbar:after{clear:both;content:\"\";display:table}.ql-snow.ql-toolbar button,.ql-snow .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow.ql-toolbar button svg,.ql-snow .ql-toolbar button svg{float:left;height:100%}.ql-snow.ql-toolbar button:active:hover,.ql-snow .ql-toolbar button:active:hover{outline:none}.ql-snow.ql-toolbar input.ql-image[type=file],.ql-snow .ql-toolbar input.ql-image[type=file]{display:none}.ql-snow.ql-toolbar button:hover,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar button:focus,.ql-snow .ql-toolbar button:focus,.ql-snow.ql-toolbar button.ql-active,.ql-snow .ql-toolbar button.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item.ql-selected{color:#06c}.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill{fill:#06c}.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter{stroke:#06c}@media(pointer:coarse){.ql-snow.ql-toolbar button:hover:not(.ql-active),.ql-snow .ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow,.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:\"\";display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-thin,.ql-snow .ql-stroke.ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor .ql-code-block-container{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor .ql-code-block-container{margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor .ql-code-block-container{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label:before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=\"\"]):before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-label:before,.ql-snow .ql-picker.ql-header .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"1\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{content:\"Heading 1\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"2\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{content:\"Heading 2\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"3\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{content:\"Heading 3\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"4\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{content:\"Heading 4\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"5\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{content:\"Heading 5\"}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value=\"6\"]:before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{content:\"Heading 6\"}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-label:before,.ql-snow .ql-picker.ql-font .ql-picker-item:before{content:\"Sans Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{content:\"Serif\"}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]:before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{content:\"Monospace\"}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-label:before,.ql-snow .ql-picker.ql-size .ql-picker-item:before{content:\"Normal\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{content:\"Small\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{content:\"Large\"}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]:before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{content:\"Huge\"}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]:before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]:before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-code-block-container{position:relative}.ql-code-block-container .ql-ui{right:5px;top:5px}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label,.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow+.ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip:before{content:\"Visit URL:\";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action:after{border-right:1px solid #ccc;content:\"Edit\";margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove:before{content:\"Remove\";margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action:after{border-right:0;content:\"Save\";padding-right:0}.ql-snow .ql-tooltip[data-mode=link]:before{content:\"Enter link:\"}.ql-snow .ql-tooltip[data-mode=formula]:before{content:\"Enter formula:\"}.ql-snow .ql-tooltip[data-mode=video]:before{content:\"Enter video:\"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc}.checkbox-section,.radio-section{display:flex;flex-direction:column}.input{width:100%}.direction-col,.toggle-col{display:flex;flex-direction:column;gap:.5em}.toggle-col>label{font-size:.75rem;color:#6b7280;padding-left:.5em}.direction-row{display:flex;flex-direction:row;align-items:center;gap:.5em}.selecatbleObject{margin:.5em}.radioLabel{color:var(--primary-color);text-align:left!important}.container{height:100%}.input{height:100%;display:flex;flex-direction:column}.checkbox{flex-direction:column}.mat-form-field-wrapper{padding-bottom:0!important}.input .mat-mdc-standard-chip.mat-chip-with-trailing-icon{padding-right:12px}.time-picker{display:flex;flex-direction:row;height:100%;border:solid 2px lightgrey;padding:1em;border-radius:4px}.time-picker:hover{border-color:#000}::ng-deep .mat-h4 .mat-body-1 .mat-typography h4{margin:0}.label{margin:28px 0 8px}.smartIndicator{display:flex;flex-direction:column;gap:.25rem;width:-moz-fit-content;width:fit-content}.indicatorItems{display:flex;flex-direction:row;gap:.25rem}.indicatorItem{width:3rem;height:.25rem;background-color:#d3d3d3;border-radius:.5rem}.radio-error{width:-moz-fit-content;width:fit-content;display:flex;flex-direction:row;gap:.5rem}.mat-calendar-previous-button,.mat-calendar-next-button{padding:0;min-width:0;width:40px!important;height:40px!important;flex-shrink:0;line-height:40px;border-radius:50%}.mat-calendar-arrow{height:36px!important;display:flex!important;flex-direction:column!important;justify-content:center}.radio-item-container,.checkbox-item-container{display:flex;flex-direction:column}.widgetContent::ng-deep .ql-container{height:200px;width:460px}.dateTimePickerContainer{display:flex;flex-direction:row;gap:.25rem}.dateTimePickerContainer mat-form-field{flex:1}.date,.time{width:100%}.date .mat-form-field-infix,.time .mat-form-field-infix{width:inherit!important}::ng-deep .mat-icon.mat-drag-indicator{--drag-indicator: #3b3b3b;color:var(--drag-indicator)}.matrixTable{width:100%;border-spacing:0 1rem}.matrixTable th{padding:.25rem}.matrixTable .optionLabel,.matrixTable td{text-align:center}.example-month-picker .mat-calendar-period-button{pointer-events:none}.example-month-picker .mat-calendar-arrow{display:none}.textFieldContainer{display:flex;flex-direction:row}.textFieldContainer{align-content:center;border:1px solid #cbd5e1;border-radius:3px;background-color:#fff}.textFieldContainer input{border:unset}.textFieldContainer:focus-within:not(:has(input:disabled)){outline:0 none;outline-offset:0;box-shadow:0 0 0 .2rem #a6d5fa;border-color:#2196f3}.textFieldContainer:has(input:disabled) .clearButton{cursor:not-allowed;opacity:.6}.comboBoxFilter{display:flex;flex-direction:row;align-items:center;gap:.5rem;min-height:48px;padding:0 1rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.comboBoxFilter:focus-within{border-bottom-color:var(--mat-sys-primary, #3f51b5)}.comboBoxFilter .mat-icon{flex:0 0 auto;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .54))}.comboBoxFilter input{flex:1 1 auto;min-width:0;border:none;outline:none;background:transparent;font:inherit;color:inherit}.comboBoxSelectAll{display:flex;align-items:center;min-height:48px;padding:0 .25rem;border-bottom:1px solid var(--mat-sys-outline-variant, rgba(0, 0, 0, .12))}.textFieldButtons{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.clearButton .mat-mdc-raised-button,.clearButton button{background-color:unset!important;border:unset;color:#6b7280!important;box-shadow:unset;font-size:1rem!important}.clearButton .mat-icon.mat-primary{color:#6b7280!important}.clearButton .mat-mdc-raised-button:hover,.clearButton button:hover{color:#6b7280cc!important;background-color:unset;border:unset;box-shadow:unset;font-size:1rem!important}.mat-mdc-form-field-infix{display:flex;flex-direction:row}textarea:not(:placeholder-shown)~label{top:-.75em!important;font-size:12px!important}.disabledEditor *{-webkit-user-modify:read-only;-moz-user-modify:read-only;user-modify:read-only}.sb4-textarea{--sb4-textarea-line-height: 20px;line-height:var(--sb4-textarea-line-height);overflow-y:auto!important}.widgetContainer .imageIcon{max-width:unset!important;height:unset!important}.material .sb4-textarea{resize:vertical!important}.material .smart-form-widget-label{font-weight:700}.material .mat-mdc-form-field-subscript-wrapper{display:none}.label-right{display:flex;gap:.5rem;flex-direction:row-reverse}.label-left{display:flex;gap:.5rem;flex-direction:row}.label-top{display:flex;gap:.5rem;flex-direction:column}.label-bottom{display:flex;gap:.5rem;flex-direction:column-reverse}.smartDiv{width:100%}.clickable{cursor:pointer}\n/*!\n * Quill Editor v2.0.3\n * https://quilljs.com\n * Copyright (c) 2017-2024, Slab\n * Copyright (c) 2014, Jason Chen\n * Copyright (c) 2013, salesforce.com\n */\n"] }]
12512
13079
  }], ctorParameters: () => [], propDecorators: { selectFilterInput: [{ type: i0.ViewChild, args: ['selectFilterInput', { isSignal: true }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], widgetInstance: [{
12513
13080
  type: Input
12514
13081
  }], onBlur: [{ type: i0.Input, args: [{ isSignal: true, alias: "onBlur", required: false }] }], onValueChange: [{
@@ -17900,6 +18467,7 @@ class SmartformLayoutDefinitionService {
17900
18467
  serverErrorIcon: layoutDefinition.errorIcon,
17901
18468
  serverErrorColor: layoutDefinition.errorColor,
17902
18469
  toolbarId: layoutDefinition.toolbarId,
18470
+ multiSelectProperties: layoutDefinition.properties?.['SELECT_MULTIPLE_properties'],
17903
18471
  };
17904
18472
  if (layoutDefinition.values) {
17905
18473
  widget.valueList = layoutDefinition.values.map((value) => {
@@ -27869,7 +28437,7 @@ class UiActionFileUploadDialogComponent {
27869
28437
  this.service.cancel();
27870
28438
  }
27871
28439
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UiActionFileUploadDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27872
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: UiActionFileUploadDialogComponent, isStandalone: true, selector: "lib-ui-action-file-upload-dialog", ngImport: i0, template: "<div class=\"folderNameDialogContainer\">\n <div class=\"headerContainer\">\n <h3 class=\"color-accent-700\">\n {{ getTitle() }}\n </h3>\n </div>\n\n @if(getText()){\n <p>\n {{ getText() }}\n </p>\n } @if(descriptor){\n <smart-upload-widget\n [uploadDescriptor]=\"descriptor.upload\"\n [isMultiple]=\"isMultiple ?? true\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div class=\"folderNameDialogButtonsContainer\">\n <ui-action-button [descriptor]=\"cancelButton\" (actionClick)=\"cancel()\"></ui-action-button>\n </div>\n</div>\n", styles: [".folderNameDialogContainer{display:flex;flex-direction:column;justify-content:center;gap:1rem;min-width:30vw}photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}.headerContainer{display:flex;flex-direction:row;justify-content:space-between;align-items:center;padding-top:.5rem}.headerContainer ::ng-deep button{color:var(--primary-color);border:unset}.headerContainer h3{margin:0;font-size:1.5rem}.folderNameDialogButtonsContainer{display:flex;flex-direction:row;justify-content:flex-start;gap:.5rem}.message{text-align:center;color:#6b7280}.uploadField{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:1rem;padding:1rem}.folderNameDialogButtonsContainer ::ng-deep button:hover{background-color:rgba(from var(--primary-color) r g b/.8)}.headerContainer ::ng-deep button:hover{background-color:rgba(from var(--primary-color) r g b/.1)}@media(max-width:900px){.folderNameDialogContainer{width:100%}}.fileSize{padding-left:1rem;display:flex;justify-content:flex-end}.fileData{display:flex;flex-direction:column;justify-content:flex-end;padding-right:1rem}\n"], dependencies: [{ kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
28440
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: UiActionFileUploadDialogComponent, isStandalone: true, selector: "lib-ui-action-file-upload-dialog", ngImport: i0, template: "<div class=\"folderNameDialogContainer\">\n <div class=\"headerContainer\">\n <h3 class=\"color-accent-700\">\n {{ getTitle() }}\n </h3>\n </div>\n\n @if(getText()){\n <p>\n {{ getText() }}\n </p>\n } @if(descriptor){\n <smart-upload-widget\n [uploadDescriptor]=\"descriptor.upload\"\n [isMultiple]=\"isMultiple ?? true\"\n (uploadFilesEvent)=\"upload($event)\"\n />\n }\n\n <div class=\"folderNameDialogButtonsContainer\">\n <ui-action-button [descriptor]=\"cancelButton\" (actionClick)=\"cancel()\"></ui-action-button>\n </div>\n</div>\n", styles: [".folderNameDialogContainer{display:flex;flex-direction:column;justify-content:center;gap:1rem;min-width:30vw}photo-capture-widget{width:100%;max-width:100%;overflow:hidden;display:flex;flex-direction:column;align-items:center}.headerContainer{display:flex;flex-direction:row;justify-content:space-between;align-items:center;padding-top:.5rem}.headerContainer ::ng-deep button{color:var(--primary-color);border:unset}.headerContainer h3{margin:0;font-size:1.5rem}.folderNameDialogButtonsContainer{display:flex;flex-direction:row;justify-content:flex-start;gap:.5rem}.message{text-align:center;color:#6b7280}.uploadField{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:1rem;padding:1rem}.folderNameDialogButtonsContainer ::ng-deep button:hover{background-color:rgba(from var(--primary-color) r g b/.8)}.headerContainer ::ng-deep button:hover{background-color:rgba(from var(--primary-color) r g b/.1)}@media(max-width:900px){.folderNameDialogContainer{width:100%}}.fileSize{padding-left:1rem;display:flex;justify-content:flex-end}.fileData{display:flex;flex-direction:column;justify-content:flex-end;padding-right:1rem}\n"], dependencies: [{ kind: "component", type: UploadWidgetComponent, selector: "smart-upload-widget", inputs: ["uploadDescriptor", "isMultiple", "isDisabled", "sources"], outputs: ["uploadFilesEvent"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "tab", "rowState", "addedCssClass", "addBasicClasses", "iconPlaceholder", "chords"], outputs: ["actionClick", "actionDoubleClick"] }] }); }
27873
28441
  }
27874
28442
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: UiActionFileUploadDialogComponent, decorators: [{
27875
28443
  type: Component,
@@ -28744,5 +29312,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
28744
29312
  * Generated bundle index. Do not edit.
28745
29313
  */
28746
29314
 
28747
- export { ACLEntry, APIS$5 as APIS, AclEditingViewComponent, ApiModule$5 as ApiModule, ApiQueueService, BASE_PATH$7 as BASE_PATH, COLLECTION_FORMATS$7 as COLLECTION_FORMATS, CUSTOM_DIAGRAM_OPTIONS, CloseResult, CodeEditorLang, ComponentFactoryService, ComponentType, ComponentWidgetType, Configuration$7 as Configuration, DEFAULT_ROW_LAYOUT, DIALOG_DISABLE_CLOSE, DataChangeKind, DefaultChartOptionsProvider, DefaultUiActionCode_CLOSE, DrawTime, EMPTY_PARAMS, ExpandableSectionButtonIconPosition, ExpandableSectionButtonType, ExpandableSectionComponent, FilterExpressionBoolOperator$1 as FilterExpressionBoolOperator, FilterExpressionBuilderGroupBuilderGroupKindEnum, FilterExpressionBuilderUiModelTypeEnum, FilterExpressionDataType, FilterExpressionFieldWidgetType, FilterExpressionOperation, FilterExpressionOrderByOrderEnum, GenericPageComponent, GeoMapDataLoadingMode, GeoMapDataSourceType, GeoMapItemKind, GeoMapOperationMode, GeoMapSelectionMode, GeoMapTextType, GridColumnContentType, GridDataAccessConfigKindEnum, GridDefaultRowActionTrigger, GridRowStateDisplay, GridSelectionMode, GridSelectionType, GridUiActionType, GridViewDescriptorKindEnum, HighlightPipe, IS_ASYNC_PARAM_NAME, IconPosition, ImageResourceKindEnum, InvalidSmartlinkComponent, LayoutDirection, LinkTargetEnum, MAP_ENGINE, MapEngine, MenuOpenDirection, MenuTriggerType, MessageOptionType, MessageTextType, MessageType, NAMED_VALIDATOR, NamedValidatorOperationEnum, NamedValidatorService, NoPermissionPageComponent, PageExportFieldScope, PageExportSelectionKind, PageExportValueType, PageExportValuesSource, REUSE_ROUTER_SLOT_COMPONENT, ROOT_CONTAINER_UUID, ROUTER_SLOT_ID, RecordingUploaderPropertiesOpenDirectionEnum, SMART_DATE_FORMATS, SMART_DEFAULT_VIEW_COMPONENTS, SMART_MESSAGE_DEFAULTS, SMART_NG_CLIENT_CONFIG, SMART_ROW_LAYOUT_COMPONENT, SearchPageComponent, SelectionDefinitionTypeEnum, SelectionDefinitionValueSetValueTypeEnum, ServerRequestType, SessionAPIS, SessionErrorBehaviour, SessionService, SmartActionHost, SmartActionType, SmartBackendBootstrapService, SmartComponent, SmartComponentApiClient, SmartComponentDetachedDirective, SmartComponentHost, SmartComponentLayoutComponent, SmartDateFnsAdapter, SmartDatePipe, SmartDateTimePipe, SmartDefaultErrorUiService, SmartDiagramComponent, SmartDialog, SmartEmbeddedSlotDirective, SmartExpandableSectionService, SmartFileEditorComponent, SmartFilterComponent, SmartFilterEditorContentComponent, SmartFilterEditorService, SmartFilterExpressionFieldComponent, SmartFilterPosition, SmartFilterType, SmartFilterWidgetComponent, SmartFormInputMode, SmartFormTextFieldButtonIconPosition, SmartFormWidgetDirection, SmartFormWidgetType, SmartFormWidgetWidth, SmartGridButtonType, SmartGridComponent, SmartGridDataLayout, SmartGridService, SmartGridType, SmartIconComponent, SmartIconService, SmartKeybindingService, SmartLayoutDef, SmartLinkChannelVariableInPath, SmartLinkMigrationStatusStatusEnum, SmartLinkUuidVariableInPath, SmartMapComponent, SmartMultiFileEditorComponent, SmartNavbarComponent, SmartNavbarService, SmartNavigationService, SmartNgClientFeatureKind, SmartService, SmartSessionService, SmartSessionTimerComponent, SmartTable, SmartTableButtonType, SmartTableHeaderPropertyType, SmartTableInterfaceTypeEnum, SmartTableOptionButtonDirection, SmartTableOrder, SmartTableType, SmartTimePipe, SmartTooltipDirective, SmartTreeComponent, SmartTreeNodeButtonType, SmartUserSettinsIconPosition, SmartValidatorName, SmartValueSetStore, SmartViewContextService, SmartViewRedirect, SmartVoiceRecorderComponent, SmartWidgetHintPosition, SmartWidgetHintPositionEnum, SmartdialogService, SmartfileuploaderComponent, SmartformComponent, SmartformLayoutDefinitionService, SmarttreeGenericService, SmarttreeService, SubjectSelectorComponent, ThemeService, ToggleLabelPosition, ToolbarAlignment, ToolbarAppearance, ToolbarDirection, TreeArrowPosition, TreeGridControl, USE_ADVANCED_FILTER, UiActionButtonComponent, UiActionButtonType, UiActionConfirmDialogService, UiActionDescriptorService, UiActionDialogButtonComponent, UiActionDialogType, UiActionFeedbackType, UiActionInputDialogService, UiActionInputType, UiActionService, UiActionToolbarComponent, UiActionTooltipTooltipPositionEnum, UiBadgeComponent, UiBadgeDirective, UploadWidgetType, ValidationResultPageComponent, ValueChangeMode, ValueSetDependencyWhenParentEmptyEnum, ViewContextRebuiltError, ViewEventHandlerViewEventTypeEnum, ViewService, ViewState, ViewType, barChart, bubbleChart, createBasicOptions, doughnutChart, formatChord, formatMessage, hasGroupEditActions, horizontalBarChart, horizontalStackedBarChart, injectSmartComponent, isMacPlatform, isMergedExtra, matches, multiAxisLineChart, parseChord, pieChart, polarAreaChart, provideSmartNgClient, radarChart, registerSmartWidget, resolveDateLocale, resolveSlot, resolveSmartNgClientConfig, resolveViewHandler, scatterChart, stackedBarChart, transformDataToBarLikeDataSet, transformDataToBasicDataSets, transformDataToBubble, transformDataToScatter, withSmartDiagram, withSmartMap };
29315
+ export { ACLEntry, APIS$5 as APIS, AclEditingViewComponent, ApiModule$5 as ApiModule, ApiQueueService, BASE_PATH$7 as BASE_PATH, COLLECTION_FORMATS$7 as COLLECTION_FORMATS, CUSTOM_DIAGRAM_OPTIONS, CloseResult, CodeEditorLang, ComponentFactoryService, ComponentType, ComponentWidgetType, Configuration$7 as Configuration, DEFAULT_ROW_LAYOUT, DIALOG_DISABLE_CLOSE, DataChangeKind, DefaultChartOptionsProvider, DefaultUiActionCode_CLOSE, DrawTime, EMPTY_PARAMS, ExpandableSectionButtonIconPosition, ExpandableSectionButtonType, ExpandableSectionComponent, FileUploaderSource, FileUploaderThumbnail, FilterExpressionBoolOperator$1 as FilterExpressionBoolOperator, FilterExpressionBuilderGroupBuilderGroupKindEnum, FilterExpressionBuilderUiModelTypeEnum, FilterExpressionDataType, FilterExpressionFieldWidgetType, FilterExpressionOperation, FilterExpressionOrderByOrderEnum, GenericPageComponent, GeoMapDataLoadingMode, GeoMapDataSourceType, GeoMapItemKind, GeoMapOperationMode, GeoMapSelectionMode, GeoMapTextType, GridColumnContentType, GridDataAccessConfigKindEnum, GridDefaultRowActionTrigger, GridRowStateDisplay, GridSelectionMode, GridSelectionType, GridUiActionType, GridViewDescriptorKindEnum, HighlightPipe, IS_ASYNC_PARAM_NAME, IconPosition, ImageResourceKindEnum, InvalidSmartlinkComponent, LayoutDirection, LinkTargetEnum, MAP_ENGINE, MapEngine, MenuOpenDirection, MenuTriggerType, MessageOptionType, MessageTextType, MessageType, NAMED_VALIDATOR, NamedValidatorOperationEnum, NamedValidatorService, NoPermissionPageComponent, PageExportFieldScope, PageExportSelectionKind, PageExportValueType, PageExportValuesSource, REUSE_ROUTER_SLOT_COMPONENT, ROOT_CONTAINER_UUID, ROUTER_SLOT_ID, RecordingUploaderPropertiesOpenDirectionEnum, SMART_DATE_FORMATS, SMART_DEFAULT_VIEW_COMPONENTS, SMART_MESSAGE_DEFAULTS, SMART_NG_CLIENT_CONFIG, SMART_ROW_LAYOUT_COMPONENT, SearchPageComponent, SelectAllMode, SelectionDefinitionTypeEnum, SelectionDefinitionValueSetValueTypeEnum, ServerRequestType, SessionAPIS, SessionErrorBehaviour, SessionService, SmartActionHost, SmartActionType, SmartBackendBootstrapService, SmartComponent, SmartComponentApiClient, SmartComponentDetachedDirective, SmartComponentHost, SmartComponentLayoutComponent, SmartDateFnsAdapter, SmartDatePipe, SmartDateTimePipe, SmartDefaultErrorUiService, SmartDiagramComponent, SmartDialog, SmartEmbeddedSlotDirective, SmartExpandableSectionService, SmartFileEditorComponent, SmartFilterComponent, SmartFilterEditorContentComponent, SmartFilterEditorService, SmartFilterExpressionFieldComponent, SmartFilterPosition, SmartFilterType, SmartFilterWidgetComponent, SmartFormInputMode, SmartFormTextFieldButtonIconPosition, SmartFormWidgetDirection, SmartFormWidgetType, SmartFormWidgetWidth, SmartGridButtonType, SmartGridComponent, SmartGridDataLayout, SmartGridService, SmartGridType, SmartIconComponent, SmartIconService, SmartKeybindingService, SmartLayoutDef, SmartLinkChannelVariableInPath, SmartLinkMigrationStatusStatusEnum, SmartLinkUuidVariableInPath, SmartMapComponent, SmartMultiFileEditorComponent, SmartNavbarComponent, SmartNavbarService, SmartNavigationService, SmartNgClientFeatureKind, SmartService, SmartSessionService, SmartSessionTimerComponent, SmartTable, SmartTableButtonType, SmartTableHeaderPropertyType, SmartTableInterfaceTypeEnum, SmartTableOptionButtonDirection, SmartTableOrder, SmartTableType, SmartTimePipe, SmartTooltipDirective, SmartTreeComponent, SmartTreeNodeButtonType, SmartUserSettinsIconPosition, SmartValidatorName, SmartValueSetStore, SmartViewContextService, SmartViewRedirect, SmartVoiceRecorderComponent, SmartWidgetHintPosition, SmartWidgetHintPositionEnum, SmartdialogService, SmartfileuploaderComponent, SmartformComponent, SmartformLayoutDefinitionService, SmarttreeGenericService, SmarttreeService, SubjectSelectorComponent, ThemeService, ToggleLabelPosition, ToolbarAlignment, ToolbarAppearance, ToolbarDirection, TreeArrowPosition, TreeGridControl, USE_ADVANCED_FILTER, UiActionButtonComponent, UiActionButtonType, UiActionConfirmDialogService, UiActionDescriptorService, UiActionDialogButtonComponent, UiActionDialogType, UiActionFeedbackType, UiActionInputDialogService, UiActionInputType, UiActionService, UiActionToolbarComponent, UiActionTooltipTooltipPositionEnum, UiBadgeComponent, UiBadgeDirective, UploadWidgetType, ValidationResultPageComponent, ValueChangeMode, ValueSetDependencyWhenParentEmptyEnum, ViewContextRebuiltError, ViewEventHandlerViewEventTypeEnum, ViewService, ViewState, ViewType, barChart, bubbleChart, createBasicOptions, doughnutChart, formatChord, formatMessage, hasGroupEditActions, horizontalBarChart, horizontalStackedBarChart, injectSmartComponent, isMacPlatform, isMergedExtra, matches, multiAxisLineChart, parseChord, pieChart, polarAreaChart, provideSmartNgClient, radarChart, registerSmartWidget, resolveDateLocale, resolveSlot, resolveSmartNgClientConfig, resolveViewHandler, scatterChart, stackedBarChart, transformDataToBarLikeDataSet, transformDataToBasicDataSets, transformDataToBubble, transformDataToScatter, withSmartDiagram, withSmartMap };
28748
29316
  //# sourceMappingURL=smartbit4all-ng-client.mjs.map