@solcre-org/core-ui 2.11.36 → 2.11.38

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.
@@ -121,7 +121,7 @@
121
121
  margin-top: calc(var(--_sepatarion-y)*1.2);
122
122
  }
123
123
 
124
- :root .c-popup > .u-flex{
124
+ .c-popup .c-popup__btns{
125
125
  justify-content: center;
126
126
  margin-top: calc(var(--_sepatarion-y)*1.6);
127
127
  }
@@ -146,7 +146,7 @@
146
146
  margin-left: 0;
147
147
  }
148
148
 
149
- :root .c-popup--xl .u-flex{
149
+ .c-popup--xl .c-popup__btns{
150
150
  justify-content: flex-end;
151
151
  }
152
152
 
@@ -989,6 +989,7 @@ class FileFieldComponent extends BaseFieldComponent {
989
989
  selectedFiles = signal([]);
990
990
  existingFiles = signal([]);
991
991
  previewUrls = signal([]);
992
+ previewBlobs = signal([]);
992
993
  errorMessage = signal('');
993
994
  errorParams = signal(null);
994
995
  displayErrorMessage = computed(() => {
@@ -1002,8 +1003,80 @@ class FileFieldComponent extends BaseFieldComponent {
1002
1003
  allFiles = computed(() => {
1003
1004
  const existing = this.existingFiles();
1004
1005
  const selected = this.selectedFiles();
1006
+ const blobs = this.previewBlobs();
1007
+ if (blobs.length > 0) {
1008
+ return [...selected, ...blobs];
1009
+ }
1005
1010
  return [...existing, ...selected];
1006
1011
  });
1012
+ previewUrlsEffect = effect(() => {
1013
+ const previewUrls = this.getPreviewUrls();
1014
+ if (previewUrls.length > 0) {
1015
+ this.createBlobsFromUrls(previewUrls);
1016
+ }
1017
+ });
1018
+ getPreviewUrls() {
1019
+ const field = this.field();
1020
+ const rowData = this.rowData();
1021
+ const previewUrls = field.previewUrls;
1022
+ if (!previewUrls) {
1023
+ return [];
1024
+ }
1025
+ if (typeof previewUrls === 'function') {
1026
+ const result = rowData ? previewUrls(rowData) : [];
1027
+ return result;
1028
+ }
1029
+ const result = Array.isArray(previewUrls) ? previewUrls : [];
1030
+ return result;
1031
+ }
1032
+ async createBlobsFromUrls(urls) {
1033
+ const blobs = [];
1034
+ for (let i = 0; i < urls.length; i++) {
1035
+ try {
1036
+ const url = urls[i];
1037
+ const response = await fetch(url);
1038
+ if (!response.ok) {
1039
+ throw new Error(`HTTP error! status: ${response.status}`);
1040
+ }
1041
+ const blob = await response.blob();
1042
+ const filename = this.extractFilenameFromUrl(url) || `preview-image-${i + 1}.jpg`;
1043
+ const file = new File([blob], filename, {
1044
+ type: blob.type || 'image/jpeg',
1045
+ lastModified: Date.now()
1046
+ });
1047
+ file.__isPreviewFile = true;
1048
+ file.__originalUrl = url;
1049
+ blobs.push(file);
1050
+ }
1051
+ catch (error) {
1052
+ console.error(`❌ Error loading preview image from URL: ${urls[i]}`, error);
1053
+ }
1054
+ }
1055
+ this.previewBlobs.set(blobs);
1056
+ }
1057
+ extractFilenameFromUrl(url) {
1058
+ try {
1059
+ const urlObj = new URL(url);
1060
+ const pathname = urlObj.pathname;
1061
+ const segments = pathname.split('/');
1062
+ const lastSegment = segments[segments.length - 1];
1063
+ if (lastSegment && lastSegment.includes('.')) {
1064
+ return lastSegment;
1065
+ }
1066
+ const params = urlObj.searchParams;
1067
+ const contentDisposition = params.get('response-content-disposition');
1068
+ if (contentDisposition) {
1069
+ const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
1070
+ if (filenameMatch && filenameMatch[1]) {
1071
+ return filenameMatch[1].replace(/['"]/g, '');
1072
+ }
1073
+ }
1074
+ return null;
1075
+ }
1076
+ catch {
1077
+ return null;
1078
+ }
1079
+ }
1007
1080
  ngOnInit() {
1008
1081
  super.ngOnInit();
1009
1082
  this.initializeFiles();
@@ -1036,7 +1109,10 @@ class FileFieldComponent extends BaseFieldComponent {
1036
1109
  }
1037
1110
  initializeFiles() {
1038
1111
  const currentValue = this.value();
1039
- if (currentValue) {
1112
+ const field = this.field();
1113
+ const hasPreviewUrls = field.previewUrls && ((Array.isArray(field.previewUrls) && field.previewUrls.length > 0) ||
1114
+ (typeof field.previewUrls === 'function'));
1115
+ if (currentValue && !hasPreviewUrls) {
1040
1116
  if (currentValue instanceof File) {
1041
1117
  this.selectedFiles.set([currentValue]);
1042
1118
  this.generatePreviews([currentValue]);
@@ -1052,6 +1128,10 @@ class FileFieldComponent extends BaseFieldComponent {
1052
1128
  this.existingFiles.set([currentValue]);
1053
1129
  }
1054
1130
  }
1131
+ else if (hasPreviewUrls) {
1132
+ this.selectedFiles.set([]);
1133
+ this.existingFiles.set([]);
1134
+ }
1055
1135
  }
1056
1136
  isServerFile(value) {
1057
1137
  return value && typeof value === 'object' && 'id' in value && 'filename' in value;
@@ -1225,15 +1305,21 @@ class FileFieldComponent extends BaseFieldComponent {
1225
1305
  return -1;
1226
1306
  return this.selectedFiles().indexOf(file);
1227
1307
  }
1308
+ isPreviewFile(file) {
1309
+ return !this.isServerFile(file) && file.__isPreviewFile === true;
1310
+ }
1311
+ getOriginalUrl(file) {
1312
+ return this.isPreviewFile(file) ? file.__originalUrl : null;
1313
+ }
1228
1314
  onBlurInput() {
1229
1315
  this.onBlur();
1230
1316
  }
1231
1317
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1232
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n @if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <div class=\"c-attachments__pic\">\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n <!-- <picture class=\"c-attachments__pic c-pic\">\n <img [src]=\"previewUrls()[getPreviewIndex(file)]\" [alt]=\"file.name\" loading=\"lazy\">\n </picture> -->\n </div>\n }\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading"] }] });
1318
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: FileFieldComponent, isStandalone: true, selector: "core-file-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }, { kind: "component", type: ImagePreviewComponent, selector: "core-image-preview", inputs: ["src", "alt", "title", "width", "height", "objectFit", "borderRadius", "cursor", "loading"] }] });
1233
1319
  }
1234
1320
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: FileFieldComponent, decorators: [{
1235
1321
  type: Component,
1236
- args: [{ selector: 'core-file-field', standalone: true, imports: [CommonModule, FormsModule, TranslateModule, ReactiveFormsModule, FieldErrorsComponent, IconCompatPipe, ImagePreviewComponent], hostDirectives: [CoreHostDirective], template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n @if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <div class=\"c-attachments__pic\">\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n <!-- <picture class=\"c-attachments__pic c-pic\">\n <img [src]=\"previewUrls()[getPreviewIndex(file)]\" [alt]=\"file.name\" loading=\"lazy\">\n </picture> -->\n </div>\n }\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n" }]
1322
+ args: [{ selector: 'core-file-field', standalone: true, imports: [CommonModule, FormsModule, TranslateModule, ReactiveFormsModule, FieldErrorsComponent, IconCompatPipe, ImagePreviewComponent], hostDirectives: [CoreHostDirective], template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n @if (field().label) {\n <span class=\"c-entry-text\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n }\n <div class=\"c-entry-file\" [class.has-error]=\"hasError()\">\n @if(fieldConfig().multiple || isEditMode() || allFiles().length === 0) {\n <label class=\"c-entry-file__label\">\n <span class=\"icon-upload c-entry-file__icon\"></span>\n <input\n type=\"file\"\n class=\"c-entry-file__input\"\n (change)=\"onFileSelected($event)\"\n [accept]=\"fieldConfig().accept\"\n [multiple]=\"fieldConfig().multiple\"\n (blur)=\"onBlurInput()\"\n [readonly]=\"isReadonly()\"\n >\n {{ fieldConfig().placeholder ?? fieldConfig().label | translate }}\n @if(fieldConfig().acceptString) {\n <br>\n <span class=\"c-entry-file__filename\" id=\"file-name\">{{ fieldConfig().acceptString }}</span>\n }\n </label>\n }\n\n @if (allFiles().length > 0) {\n <div class=\"c-attachments\">\n <p class=\"c-entry-text\">{{ 'files.attachedFiles' | translate }}</p>\n \n <ul class=\"c-attachments__list\">\n @for (file of allFiles(); track $index; let i = $index) {\n <li class=\"c-attachments__item\">\n <div class=\"c-bulleted-text\">\n @if(!isServerFile(file)) {\n <time>{{ getCurrentDate() }}</time>\n <span>{{ getCurrentUser() }}</span>\n }\n </div>\n \n <div class=\"c-attachments__holder\">\n @if(!isServerFile(file) && file.type.startsWith('image/') && fieldConfig().showPreview !== false) {\n <div class=\"c-attachments__content\">\n <div class=\"c-attachments__pic\">\n @if(isPreviewFile(file) && getOriginalUrl(file)) {\n <core-image-preview\n [src]=\"getOriginalUrl(file)!\"\n [alt]=\"file.name\"\n ></core-image-preview>\n } @else if(getPreviewIndex(file) >= 0 && previewUrls()[getPreviewIndex(file)]) {\n <core-image-preview\n [src]=\"previewUrls()[getPreviewIndex(file)]\"\n [alt]=\"file.name\"\n ></core-image-preview>\n }\n </div>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n </div>\n } @else {\n <a class=\"c-attachments__content\">\n @if(isServerFile(file)) {\n <span class=\"icon-file\"></span>\n {{ file.filename }}\n } @else {\n <span [class]=\"getFileIcon(file)\"></span>\n <div class=\"c-attachments__text\">\n <span class=\"c-attachments__name-file\">{{ file.name }}</span>\n <span class=\"c-attachments__file-size\">({{ formatFileSize(file.size) }})</span>\n </div>\n }\n </a>\n }\n\n <div class=\"c-attachments__actions u-flex u-flex--wrap\">\n <button \n type=\"button\" \n class=\"c-link context:error\" \n (click)=\"removeFile(i)\"\n [title]=\"'files.remove' | translate\"\n >\n <span class=\"icon-delete\"></span>\n {{ 'files.remove' | translate }}\n </button>\n\n @if(fieldConfig().customActions) {\n @for(action of fieldConfig().customActions; track action.id) {\n <button \n type=\"button\"\n class=\"c-link c-link--underlined\" \n (click)=\"action.action(file)\"\n [title]=\"action.label | translate\"\n >\n {{ action.label | translate }}\n <span [ngClass]=\"action.icon | coreIconCompat\"></span>\n </button>\n }\n }\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n <core-field-errors [errors]=\"errors()\" />\n @if(displayErrorMessage()) {\n <span class=\"c-entry-error\">{{ displayErrorMessage()!.key | translate:displayErrorMessage()!.params }}</span>\n }\n</label>\n" }]
1237
1323
  }] });
1238
1324
 
1239
1325
  var NumberFieldConfigType;
@@ -6137,11 +6223,11 @@ class ConfirmationDialogComponent {
6137
6223
  }
6138
6224
  }
6139
6225
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ConfirmationDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6140
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ConfirmationDialogComponent, isStandalone: true, selector: "core-confirmation-dialog", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { confirm: "confirm", cancel: "cancel" }, queries: [{ propertyName: "customContentTemplate", first: true, predicate: ["customContent"], descendants: true }], viewQueries: [{ propertyName: "popupElement", first: true, predicate: ["popup"], descendants: true }, { propertyName: "overlayElement", first: true, predicate: ["overlay"], descendants: true }], hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-popup\" \n [class.c-popup--xl]=\"config().size === 'xl'\" \n [class.is-visible]=\"isOpen()\" \n [ngClass]=\"config().customClass\"\n #popup \n *ngIf=\"isOpen()\">\n <div class=\"c-popup__overlay\" (click)=\"onCancel()\" #overlay></div>\n <div class=\"c-popup__holder\">\n @if(config().showCloseButton) {\n <core-generic-button\n [config]=\"closeButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().icon) {\n <span class=\"c-popup__icon\" [ngClass]=\"config().icon | coreIconCompat\"></span>\n }\n\n <p class=\"c-popup__title u-heading u-fz--600\">\n {{ config().title | translate: config().messageParams }}\n </p>\n\n @if (config().customTemplate) {\n <ng-container *ngTemplateOutlet=\"config().customTemplate!; context: config().customTemplateContext\"></ng-container>\n } @else {\n \n @if (config().message) {\n <p class=\"c-popup__text u-text\">\n {{ config().message ?? '' | translate: config().messageParams }}\n </p>\n }\n\n @if (config().inputConfig) {\n <label class=\"c-popup__form c-entry-item\">\n <span class=\"c-entry-text\">\n {{ config().inputConfig?.label ?? '' | translate }}\n @if (!config().inputConfig?.validationValue) {\n <!-- Todo: D\u00F3nde est\u00E1 el .u-text--muted ? -->\n <span class=\"u-text--muted\"> ({{ 'common.optional' | translate }})</span>\n }\n </span>\n <input \n class=\"c-entry-input\"\n type=\"text\"\n [placeholder]=\"config().inputConfig?.placeholder ?? '' | translate\"\n [(ngModel)]=\"inputValue\"\n (ngModelChange)=\"onInputChange($event)\"\n [required]=\"!!config().inputConfig?.validationValue\"\n >\n </label>\n }\n\n }\n\n <div class=\"u-flex u-push-t--xl\">\n @if (config().showCancelButton !== false) {\n <core-generic-button\n [config]=\"cancelButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().showConfirmButton !== false) {\n <core-generic-button\n [config]=\"confirmButtonConfig()\"\n (buttonClick)=\"onConfirm()\">\n </core-generic-button>\n }\n </div>\n </div>\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }] });
6226
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ConfirmationDialogComponent, isStandalone: true, selector: "core-confirmation-dialog", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { confirm: "confirm", cancel: "cancel" }, queries: [{ propertyName: "customContentTemplate", first: true, predicate: ["customContent"], descendants: true }], viewQueries: [{ propertyName: "popupElement", first: true, predicate: ["popup"], descendants: true }, { propertyName: "overlayElement", first: true, predicate: ["overlay"], descendants: true }], hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div class=\"c-popup\" \n [class.c-popup--xl]=\"config().size === 'xl'\" \n [class.is-visible]=\"isOpen()\" \n [ngClass]=\"config().customClass\"\n #popup \n *ngIf=\"isOpen()\">\n <div class=\"c-popup__overlay\" (click)=\"onCancel()\" #overlay></div>\n <div class=\"c-popup__holder\">\n @if(config().showCloseButton) {\n <core-generic-button\n [config]=\"closeButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().icon) {\n <span class=\"c-popup__icon\" [ngClass]=\"config().icon | coreIconCompat\"></span>\n }\n\n <p class=\"c-popup__title u-heading u-fz--600\">\n {{ config().title | translate: config().messageParams }}\n </p>\n\n @if (config().customTemplate) {\n <ng-container *ngTemplateOutlet=\"config().customTemplate!; context: config().customTemplateContext\"></ng-container>\n } @else {\n \n @if (config().message) {\n <p class=\"c-popup__text u-text\">\n {{ config().message ?? '' | translate: config().messageParams }}\n </p>\n }\n\n @if (config().inputConfig) {\n <label class=\"c-popup__form c-entry-item\">\n <span class=\"c-entry-text\">\n {{ config().inputConfig?.label ?? '' | translate }}\n @if (!config().inputConfig?.validationValue) {\n <!-- Todo: D\u00F3nde est\u00E1 el .u-text--muted ? -->\n <span class=\"u-text--muted\"> ({{ 'common.optional' | translate }})</span>\n }\n </span>\n <input \n class=\"c-entry-input\"\n type=\"text\"\n [placeholder]=\"config().inputConfig?.placeholder ?? '' | translate\"\n [(ngModel)]=\"inputValue\"\n (ngModelChange)=\"onInputChange($event)\"\n [required]=\"!!config().inputConfig?.validationValue\"\n >\n </label>\n }\n\n }\n\n <div class=\"c-popup__btns u-flex u-push-t--xl\">\n @if (config().showCancelButton !== false) {\n <core-generic-button\n [config]=\"cancelButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().showConfirmButton !== false) {\n <core-generic-button\n [config]=\"confirmButtonConfig()\"\n (buttonClick)=\"onConfirm()\">\n </core-generic-button>\n }\n </div>\n </div>\n</div>", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }, { kind: "pipe", type: IconCompatPipe, name: "coreIconCompat" }] });
6141
6227
  }
6142
6228
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
6143
6229
  type: Component,
6144
- args: [{ selector: 'core-confirmation-dialog', standalone: true, imports: [CommonModule, TranslateModule, FormsModule, GenericButtonComponent, IconCompatPipe], hostDirectives: [CoreHostDirective], template: "<div class=\"c-popup\" \n [class.c-popup--xl]=\"config().size === 'xl'\" \n [class.is-visible]=\"isOpen()\" \n [ngClass]=\"config().customClass\"\n #popup \n *ngIf=\"isOpen()\">\n <div class=\"c-popup__overlay\" (click)=\"onCancel()\" #overlay></div>\n <div class=\"c-popup__holder\">\n @if(config().showCloseButton) {\n <core-generic-button\n [config]=\"closeButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().icon) {\n <span class=\"c-popup__icon\" [ngClass]=\"config().icon | coreIconCompat\"></span>\n }\n\n <p class=\"c-popup__title u-heading u-fz--600\">\n {{ config().title | translate: config().messageParams }}\n </p>\n\n @if (config().customTemplate) {\n <ng-container *ngTemplateOutlet=\"config().customTemplate!; context: config().customTemplateContext\"></ng-container>\n } @else {\n \n @if (config().message) {\n <p class=\"c-popup__text u-text\">\n {{ config().message ?? '' | translate: config().messageParams }}\n </p>\n }\n\n @if (config().inputConfig) {\n <label class=\"c-popup__form c-entry-item\">\n <span class=\"c-entry-text\">\n {{ config().inputConfig?.label ?? '' | translate }}\n @if (!config().inputConfig?.validationValue) {\n <!-- Todo: D\u00F3nde est\u00E1 el .u-text--muted ? -->\n <span class=\"u-text--muted\"> ({{ 'common.optional' | translate }})</span>\n }\n </span>\n <input \n class=\"c-entry-input\"\n type=\"text\"\n [placeholder]=\"config().inputConfig?.placeholder ?? '' | translate\"\n [(ngModel)]=\"inputValue\"\n (ngModelChange)=\"onInputChange($event)\"\n [required]=\"!!config().inputConfig?.validationValue\"\n >\n </label>\n }\n\n }\n\n <div class=\"u-flex u-push-t--xl\">\n @if (config().showCancelButton !== false) {\n <core-generic-button\n [config]=\"cancelButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().showConfirmButton !== false) {\n <core-generic-button\n [config]=\"confirmButtonConfig()\"\n (buttonClick)=\"onConfirm()\">\n </core-generic-button>\n }\n </div>\n </div>\n</div>" }]
6230
+ args: [{ selector: 'core-confirmation-dialog', standalone: true, imports: [CommonModule, TranslateModule, FormsModule, GenericButtonComponent, IconCompatPipe], hostDirectives: [CoreHostDirective], template: "<div class=\"c-popup\" \n [class.c-popup--xl]=\"config().size === 'xl'\" \n [class.is-visible]=\"isOpen()\" \n [ngClass]=\"config().customClass\"\n #popup \n *ngIf=\"isOpen()\">\n <div class=\"c-popup__overlay\" (click)=\"onCancel()\" #overlay></div>\n <div class=\"c-popup__holder\">\n @if(config().showCloseButton) {\n <core-generic-button\n [config]=\"closeButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().icon) {\n <span class=\"c-popup__icon\" [ngClass]=\"config().icon | coreIconCompat\"></span>\n }\n\n <p class=\"c-popup__title u-heading u-fz--600\">\n {{ config().title | translate: config().messageParams }}\n </p>\n\n @if (config().customTemplate) {\n <ng-container *ngTemplateOutlet=\"config().customTemplate!; context: config().customTemplateContext\"></ng-container>\n } @else {\n \n @if (config().message) {\n <p class=\"c-popup__text u-text\">\n {{ config().message ?? '' | translate: config().messageParams }}\n </p>\n }\n\n @if (config().inputConfig) {\n <label class=\"c-popup__form c-entry-item\">\n <span class=\"c-entry-text\">\n {{ config().inputConfig?.label ?? '' | translate }}\n @if (!config().inputConfig?.validationValue) {\n <!-- Todo: D\u00F3nde est\u00E1 el .u-text--muted ? -->\n <span class=\"u-text--muted\"> ({{ 'common.optional' | translate }})</span>\n }\n </span>\n <input \n class=\"c-entry-input\"\n type=\"text\"\n [placeholder]=\"config().inputConfig?.placeholder ?? '' | translate\"\n [(ngModel)]=\"inputValue\"\n (ngModelChange)=\"onInputChange($event)\"\n [required]=\"!!config().inputConfig?.validationValue\"\n >\n </label>\n }\n\n }\n\n <div class=\"c-popup__btns u-flex u-push-t--xl\">\n @if (config().showCancelButton !== false) {\n <core-generic-button\n [config]=\"cancelButtonConfig()\"\n (buttonClick)=\"onCancel()\">\n </core-generic-button>\n }\n @if (config().showConfirmButton !== false) {\n <core-generic-button\n [config]=\"confirmButtonConfig()\"\n (buttonClick)=\"onConfirm()\">\n </core-generic-button>\n }\n </div>\n </div>\n</div>" }]
6145
6231
  }], propDecorators: { popupElement: [{
6146
6232
  type: ViewChild,
6147
6233
  args: ['popup']
@@ -10590,11 +10676,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
10590
10676
  // Este archivo es generado automáticamente por scripts/update-version.js
10591
10677
  // No edites manualmente este archivo
10592
10678
  const VERSION = {
10593
- full: '2.11.36',
10679
+ full: '2.11.38',
10594
10680
  major: 2,
10595
10681
  minor: 11,
10596
- patch: 36,
10597
- timestamp: '2025-09-02T12:41:58.571Z',
10682
+ patch: 38,
10683
+ timestamp: '2025-09-02T15:04:58.415Z',
10598
10684
  buildDate: '2/9/2025'
10599
10685
  };
10600
10686