valtech-components 2.0.907 → 2.0.910

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.
@@ -45,6 +45,7 @@ import { provideHttpClient, withInterceptors, HttpClient, HttpErrorResponse } fr
45
45
  import { isSupported, getMessaging as getMessaging$1 } from 'firebase/messaging';
46
46
  import { getApps, getApp, initializeApp as initializeApp$1 } from 'firebase/app';
47
47
  import { ImageCropperComponent } from 'ngx-image-cropper';
48
+ import Compressor from 'compressorjs';
48
49
  import { Capacitor } from '@capacitor/core';
49
50
  import 'prismjs/components/prism-scss';
50
51
  import 'prismjs/components/prism-json';
@@ -53,7 +54,7 @@ import 'prismjs/components/prism-json';
53
54
  * Current version of valtech-components.
54
55
  * This is automatically updated during the publish process.
55
56
  */
56
- const VERSION = '2.0.907';
57
+ const VERSION = '2.0.910';
57
58
 
58
59
  /**
59
60
  * Servicio para gestionar presets de componentes.
@@ -28593,9 +28594,25 @@ class AttachmentUploaderComponent {
28593
28594
  this.uploadFile(id, file);
28594
28595
  }
28595
28596
  }
28597
+ compressImage(file) {
28598
+ return new Promise((resolve, reject) => {
28599
+ new Compressor(file, {
28600
+ quality: 0.8,
28601
+ maxWidth: 1920,
28602
+ maxHeight: 1920,
28603
+ convertSize: 2 * 1024 * 1024, // PNG > 2 MB → JPEG
28604
+ success(result) {
28605
+ resolve(new File([result], file.name, { type: result.type }));
28606
+ },
28607
+ error: reject,
28608
+ });
28609
+ });
28610
+ }
28596
28611
  async uploadFile(id, file) {
28597
28612
  try {
28598
- const url = await this.feedbackService.uploadAttachment(file);
28613
+ const shouldCompress = this.props().compressImages !== false && file.type.startsWith('image/');
28614
+ const fileToUpload = shouldCompress ? await this.compressImage(file) : file;
28615
+ const url = await this.feedbackService.uploadAttachment(fileToUpload);
28599
28616
  this.attachments.update(list => list.map(a => (a.id === id ? { ...a, status: 'ready', url } : a)));
28600
28617
  }
28601
28618
  catch {
@@ -38695,6 +38712,7 @@ const AVATAR_UPLOAD_DEFAULTS = {
38695
38712
  maxWidth: 800,
38696
38713
  thumbnailSize: 150,
38697
38714
  backgroundColor: '#6366f1', // Indigo
38715
+ showViewButton: false,
38698
38716
  };
38699
38717
 
38700
38718
  addIcons({ cameraOutline });
@@ -38738,6 +38756,7 @@ class AvatarUploadComponent {
38738
38756
  // Internal state
38739
38757
  this.loading = signal(false);
38740
38758
  this.showCropModal = signal(false);
38759
+ this.showViewModal = signal(false);
38741
38760
  this.selectedFile = signal(null);
38742
38761
  this.previewUrl = signal(null);
38743
38762
  this.imageLoadError = signal(false);
@@ -38757,6 +38776,11 @@ class AvatarUploadComponent {
38757
38776
  this.i18n.lang();
38758
38777
  return this.i18n.t('changePhoto', this.config().i18nNamespace) || 'Cambiar foto';
38759
38778
  });
38779
+ /** Label for view photo button */
38780
+ this.viewPhotoLabel = computed(() => {
38781
+ this.i18n.lang();
38782
+ return this.i18n.t('viewPhoto', this.config().i18nNamespace) || 'Ver foto';
38783
+ });
38760
38784
  }
38761
38785
  /** Open file picker dialog */
38762
38786
  openFilePicker() {
@@ -38926,6 +38950,13 @@ class AvatarUploadComponent {
38926
38950
  hidden
38927
38951
  />
38928
38952
 
38953
+ <!-- View Photo Button -->
38954
+ @if (config().showViewButton && displayUrl()) {
38955
+ <button class="view-photo-btn" type="button" (click)="showViewModal.set(true)">
38956
+ {{ viewPhotoLabel() }}
38957
+ </button>
38958
+ }
38959
+
38929
38960
  <!-- Crop Modal -->
38930
38961
  <ion-modal
38931
38962
  [isOpen]="showCropModal()"
@@ -38947,12 +38978,29 @@ class AvatarUploadComponent {
38947
38978
  }
38948
38979
  </ng-template>
38949
38980
  </ion-modal>
38981
+
38982
+ <!-- Photo Viewer Modal -->
38983
+ <ion-modal
38984
+ [isOpen]="showViewModal()"
38985
+ (didDismiss)="showViewModal.set(false)"
38986
+ [breakpoints]="[0, 0.92]"
38987
+ [initialBreakpoint]="0.92"
38988
+ [handle]="true"
38989
+ >
38990
+ <ng-template>
38991
+ <ion-content class="ion-padding photo-viewer-content">
38992
+ <div class="photo-viewer">
38993
+ <img class="photo-viewer__img" [src]="displayUrl()" alt="Photo" />
38994
+ </div>
38995
+ </ion-content>
38996
+ </ng-template>
38997
+ </ion-modal>
38950
38998
  </div>
38951
- `, isInline: true, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ImageCropComponent, selector: "val-image-crop", inputs: ["image", "aspectRatio", "roundCropper", "resizeToWidth", "i18nNamespace"], outputs: ["cropComplete", "cancel", "loadFailed"] }] }); }
38999
+ `, isInline: true, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}.view-photo-btn{display:block;background:none;border:none;padding:0;margin-top:6px;font-size:.8rem;color:var(--ion-color-primary);cursor:pointer;font-family:inherit;text-decoration:underline;text-underline-offset:2px;text-align:center;width:var(--avatar-size)}.view-photo-btn:active{opacity:.7}.photo-viewer-content{--background: transparent}.photo-viewer{display:flex;align-items:center;justify-content:center;padding:24px 16px 32px;min-height:200px}.photo-viewer__img{max-width:100%;max-height:65vh;border-radius:16px;object-fit:contain;box-shadow:0 8px 32px #0000002e}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: ImageCropComponent, selector: "val-image-crop", inputs: ["image", "aspectRatio", "roundCropper", "resizeToWidth", "i18nNamespace"], outputs: ["cropComplete", "cancel", "loadFailed"] }] }); }
38952
39000
  }
38953
39001
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarUploadComponent, decorators: [{
38954
39002
  type: Component,
38955
- args: [{ selector: 'val-avatar-upload', standalone: true, imports: [CommonModule, IonIcon, IonSpinner, IonModal, ImageCropComponent], template: `
39003
+ args: [{ selector: 'val-avatar-upload', standalone: true, imports: [CommonModule, IonIcon, IonSpinner, IonModal, IonContent, ImageCropComponent], template: `
38956
39004
  <div class="avatar-upload" [style.--avatar-size.px]="config().size" [class.avatar-upload--loading]="loading()">
38957
39005
  <div class="avatar-container">
38958
39006
  <!-- Avatar Image or Initials -->
@@ -38989,6 +39037,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
38989
39037
  hidden
38990
39038
  />
38991
39039
 
39040
+ <!-- View Photo Button -->
39041
+ @if (config().showViewButton && displayUrl()) {
39042
+ <button class="view-photo-btn" type="button" (click)="showViewModal.set(true)">
39043
+ {{ viewPhotoLabel() }}
39044
+ </button>
39045
+ }
39046
+
38992
39047
  <!-- Crop Modal -->
38993
39048
  <ion-modal
38994
39049
  [isOpen]="showCropModal()"
@@ -39010,8 +39065,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39010
39065
  }
39011
39066
  </ng-template>
39012
39067
  </ion-modal>
39068
+
39069
+ <!-- Photo Viewer Modal -->
39070
+ <ion-modal
39071
+ [isOpen]="showViewModal()"
39072
+ (didDismiss)="showViewModal.set(false)"
39073
+ [breakpoints]="[0, 0.92]"
39074
+ [initialBreakpoint]="0.92"
39075
+ [handle]="true"
39076
+ >
39077
+ <ng-template>
39078
+ <ion-content class="ion-padding photo-viewer-content">
39079
+ <div class="photo-viewer">
39080
+ <img class="photo-viewer__img" [src]="displayUrl()" alt="Photo" />
39081
+ </div>
39082
+ </ion-content>
39083
+ </ng-template>
39084
+ </ion-modal>
39013
39085
  </div>
39014
- `, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"] }]
39086
+ `, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}.view-photo-btn{display:block;background:none;border:none;padding:0;margin-top:6px;font-size:.8rem;color:var(--ion-color-primary);cursor:pointer;font-family:inherit;text-decoration:underline;text-underline-offset:2px;text-align:center;width:var(--avatar-size)}.view-photo-btn:active{opacity:.7}.photo-viewer-content{--background: transparent}.photo-viewer{display:flex;align-items:center;justify-content:center;padding:24px 16px 32px;min-height:200px}.photo-viewer__img{max-width:100%;max-height:65vh;border-radius:16px;object-fit:contain;box-shadow:0 8px 32px #0000002e}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"] }]
39015
39087
  }], propDecorators: { fileInput: [{
39016
39088
  type: ViewChild,
39017
39089
  args: ['fileInput']
@@ -46281,11 +46353,11 @@ class ContentReactionComponent {
46281
46353
  return this.i18n.t(key, 'ContentReaction') || translations[key] || key;
46282
46354
  }
46283
46355
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentReactionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
46284
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ContentReactionComponent, isStandalone: true, selector: "val-content-reaction", inputs: { props: "props" }, outputs: { reactionSubmit: "reactionSubmit", reactionChange: "reactionChange" }, usesOnChanges: true, ngImport: i0, template: "@if (isConfigured()) {\n<div class=\"content-reaction\" [class.disabled]=\"resolvedProps().disabled\" [class.readonly]=\"resolvedProps().readonly\">\n <!-- Loading inicial -->\n @if (state().isLoading && !state().selectedValue) {\n <div class=\"loading-container\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else {\n <!-- Pregunta -->\n <p class=\"question\">{{ resolvedProps().question }}</p>\n\n <!-- Emojis -->\n <div class=\"emoji-container\">\n @for (value of activeReactionValues(); track value; let i = $index) {\n <button\n type=\"button\"\n class=\"emoji-button\"\n [class.selected]=\"isSelected(value)\"\n [class.negative]=\"value === 'negative' && isSelected(value)\"\n [class.neutral]=\"value === 'neutral' && isSelected(value)\"\n [class.positive]=\"value === 'positive' && isSelected(value)\"\n [attr.aria-label]=\"getEmojiLabel(i)\"\n [attr.aria-pressed]=\"isSelected(value)\"\n [disabled]=\"resolvedProps().disabled || resolvedProps().readonly\"\n (click)=\"selectReaction(value)\"\n >\n <span class=\"emoji\">{{ getEmoji(i) }}</span>\n </button>\n }\n </div>\n\n <!-- Campo de comentario (solo si hay selecci\u00F3n) -->\n @if (showCommentField()) {\n <div class=\"comment-section\">\n <ion-textarea\n [value]=\"state().comment\"\n [placeholder]=\"resolvedProps().commentPlaceholder\"\n [maxlength]=\"resolvedProps().maxCommentLength\"\n [disabled]=\"resolvedProps().disabled\"\n [rows]=\"3\"\n class=\"comment-textarea\"\n (ionInput)=\"updateComment($event)\"\n ></ion-textarea>\n <span class=\"char-count\"> {{ state().comment.length }}/{{ resolvedProps().maxCommentLength }} </span>\n </div>\n }\n\n <!-- Bot\u00F3n de env\u00EDo -->\n @if (state().selectedValue && !state().isSubmitted) {\n <ion-button expand=\"block\" [disabled]=\"!canSubmit()\" (click)=\"submitReaction()\" class=\"submit-button\">\n @if (state().isLoading) {\n <ion-spinner name=\"crescent\"></ion-spinner>\n } @else { {{ state().hadPreviousReaction ? t('update') : t('submit') }} }\n </ion-button>\n }\n\n <!-- Mensaje de confirmaci\u00F3n -->\n @if (state().isSubmitted) {\n <p class=\"submitted-message\">{{ t('thankYou') }}</p>\n }\n\n <!-- Error -->\n @if (state().error) {\n <p class=\"error-message\">{{ state().error }}</p>\n } }\n</div>\n}\n", styles: [":host{display:block}.content-reaction{padding:16px;text-align:center}.content-reaction.disabled{opacity:.6;pointer-events:none}.content-reaction.readonly{pointer-events:none}.question{font-size:16px;font-weight:500;color:var(--ion-color-dark);margin:0 0 16px}.emoji-container{display:flex;justify-content:center;gap:24px;margin-bottom:20px}.emoji-button{background:transparent;border:2px solid var(--ion-color-light-shade);border-radius:50%;width:64px;height:64px;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;padding:0}.emoji-button .emoji{font-size:32px;transition:transform .3s cubic-bezier(.4,0,.2,1);line-height:1}.emoji-button:hover:not(:disabled){transform:scale(1.1);border-color:var(--ion-color-medium)}.emoji-button:focus{outline:2px solid var(--ion-color-primary);outline-offset:2px}.emoji-button.selected{transform:scale(1.2)}.emoji-button.selected .emoji{transform:scale(1.1)}.emoji-button.selected.negative{border-color:var(--ion-color-danger);background:var(--ion-color-danger-tint);box-shadow:0 4px 12px rgba(var(--ion-color-danger-rgb),.3)}.emoji-button.selected.neutral{border-color:var(--ion-color-warning);background:var(--ion-color-warning-tint);box-shadow:0 4px 12px rgba(var(--ion-color-warning-rgb),.3)}.emoji-button.selected.positive{border-color:var(--ion-color-success);background:var(--ion-color-success-tint);box-shadow:0 4px 12px rgba(var(--ion-color-success-rgb),.3)}.emoji-button:disabled{cursor:not-allowed;opacity:.5}.comment-section{margin-top:16px;animation:slideIn .3s ease-out}.comment-section .comment-textarea{--background: var(--ion-color-light);--border-radius: 8px;--padding-start: 12px;--padding-end: 12px;width:100%}.comment-section .char-count{display:block;text-align:right;font-size:12px;color:var(--ion-color-medium);margin-top:4px}.submit-button{margin-top:16px;--border-radius: 8px}.submitted-message{margin-top:16px;color:var(--ion-color-success);font-weight:500;animation:fadeIn .3s ease-out}.error-message{margin-top:8px;color:var(--ion-color-danger);font-size:14px}.loading-container{display:flex;justify-content:center;padding:20px}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }] }); }
46356
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ContentReactionComponent, isStandalone: true, selector: "val-content-reaction", inputs: { props: "props" }, outputs: { reactionSubmit: "reactionSubmit", reactionChange: "reactionChange" }, usesOnChanges: true, ngImport: i0, template: "@if (isConfigured()) {\n<div class=\"content-reaction\" [class.disabled]=\"resolvedProps().disabled\" [class.readonly]=\"resolvedProps().readonly\">\n <!-- Loading inicial -->\n @if (state().isLoading && !state().selectedValue) {\n <div class=\"loading-container\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else {\n <!-- Pregunta -->\n <p class=\"question\">{{ resolvedProps().question }}</p>\n\n <!-- Emojis -->\n <div class=\"emoji-container\">\n @for (value of activeReactionValues(); track value; let i = $index) {\n <button\n type=\"button\"\n class=\"emoji-button\"\n [class.selected]=\"isSelected(value)\"\n [class.negative]=\"value === 'negative' && isSelected(value)\"\n [class.neutral]=\"value === 'neutral' && isSelected(value)\"\n [class.positive]=\"value === 'positive' && isSelected(value)\"\n [attr.aria-label]=\"getEmojiLabel(i)\"\n [attr.aria-pressed]=\"isSelected(value)\"\n [disabled]=\"resolvedProps().disabled || resolvedProps().readonly\"\n (click)=\"selectReaction(value)\"\n >\n <span class=\"emoji\">{{ getEmoji(i) }}</span>\n </button>\n }\n </div>\n\n <!-- Campo de comentario (solo si hay selecci\u00F3n) -->\n @if (showCommentField()) {\n <div class=\"comment-section\">\n <ion-textarea\n [value]=\"state().comment\"\n [placeholder]=\"resolvedProps().commentPlaceholder\"\n [maxlength]=\"resolvedProps().maxCommentLength\"\n [disabled]=\"resolvedProps().disabled\"\n [rows]=\"3\"\n class=\"comment-textarea\"\n (ionInput)=\"updateComment($event)\"\n ></ion-textarea>\n <span class=\"char-count\"> {{ state().comment.length }}/{{ resolvedProps().maxCommentLength }} </span>\n </div>\n }\n\n <!-- Bot\u00F3n de env\u00EDo -->\n @if (state().selectedValue && !state().isSubmitted) {\n <ion-button expand=\"block\" [disabled]=\"!canSubmit()\" (click)=\"submitReaction()\" class=\"submit-button\">\n @if (state().isLoading) {\n <ion-spinner name=\"crescent\"></ion-spinner>\n } @else { {{ state().hadPreviousReaction ? t('update') : t('submit') }} }\n </ion-button>\n }\n\n <!-- Mensaje de confirmaci\u00F3n -->\n @if (state().isSubmitted) {\n <p class=\"submitted-message\">{{ t('thankYou') }}</p>\n }\n\n <!-- Error -->\n @if (state().error) {\n <p class=\"error-message\">{{ state().error }}</p>\n } }\n</div>\n}\n", styles: [":host{display:block}.content-reaction{padding:16px;text-align:center}.content-reaction.disabled{opacity:.6;pointer-events:none}.content-reaction.readonly{pointer-events:none}.question{font-size:17px;font-weight:700;color:var(--ion-color-dark);margin:0 0 16px}.emoji-container{display:flex;justify-content:center;gap:24px;margin-bottom:20px}.emoji-button{background:transparent;border:2px solid var(--ion-color-light-shade);border-radius:50%;width:48px;height:48px;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;padding:0}.emoji-button .emoji{font-size:22px;transition:transform .3s cubic-bezier(.4,0,.2,1);line-height:1}.emoji-button:hover:not(:disabled){transform:scale(1.1);border-color:var(--ion-color-medium)}.emoji-button:focus{outline:2px solid var(--ion-color-primary);outline-offset:2px}.emoji-button.selected{transform:scale(1.2)}.emoji-button.selected .emoji{transform:scale(1.1)}.emoji-button.selected.negative{border-color:var(--ion-color-danger);background:var(--ion-color-danger-tint);box-shadow:0 4px 12px rgba(var(--ion-color-danger-rgb),.3)}.emoji-button.selected.neutral{border-color:var(--ion-color-warning);background:var(--ion-color-warning-tint);box-shadow:0 4px 12px rgba(var(--ion-color-warning-rgb),.3)}.emoji-button.selected.positive{border-color:var(--ion-color-success);background:var(--ion-color-success-tint);box-shadow:0 4px 12px rgba(var(--ion-color-success-rgb),.3)}.emoji-button:disabled{cursor:not-allowed;opacity:.5}.comment-section{margin-top:16px;animation:slideIn .3s ease-out}.comment-section .comment-textarea{--background: transparent;--border-radius: 8px;--padding-start: 12px;--padding-end: 12px;width:100%}.comment-section .char-count{display:block;text-align:right;font-size:12px;color:var(--ion-color-medium);margin-top:4px}.submit-button{margin-top:16px;--border-radius: 8px}.submitted-message{margin-top:16px;color:var(--ion-color-success);font-weight:500;animation:fadeIn .3s ease-out}.error-message{margin-top:8px;color:var(--ion-color-danger);font-size:14px}.loading-container{display:flex;justify-content:center;padding:20px}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }] }); }
46285
46357
  }
46286
46358
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentReactionComponent, decorators: [{
46287
46359
  type: Component,
46288
- args: [{ selector: 'val-content-reaction', standalone: true, imports: [CommonModule, FormsModule, IonButton, IonSpinner, IonTextarea], template: "@if (isConfigured()) {\n<div class=\"content-reaction\" [class.disabled]=\"resolvedProps().disabled\" [class.readonly]=\"resolvedProps().readonly\">\n <!-- Loading inicial -->\n @if (state().isLoading && !state().selectedValue) {\n <div class=\"loading-container\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else {\n <!-- Pregunta -->\n <p class=\"question\">{{ resolvedProps().question }}</p>\n\n <!-- Emojis -->\n <div class=\"emoji-container\">\n @for (value of activeReactionValues(); track value; let i = $index) {\n <button\n type=\"button\"\n class=\"emoji-button\"\n [class.selected]=\"isSelected(value)\"\n [class.negative]=\"value === 'negative' && isSelected(value)\"\n [class.neutral]=\"value === 'neutral' && isSelected(value)\"\n [class.positive]=\"value === 'positive' && isSelected(value)\"\n [attr.aria-label]=\"getEmojiLabel(i)\"\n [attr.aria-pressed]=\"isSelected(value)\"\n [disabled]=\"resolvedProps().disabled || resolvedProps().readonly\"\n (click)=\"selectReaction(value)\"\n >\n <span class=\"emoji\">{{ getEmoji(i) }}</span>\n </button>\n }\n </div>\n\n <!-- Campo de comentario (solo si hay selecci\u00F3n) -->\n @if (showCommentField()) {\n <div class=\"comment-section\">\n <ion-textarea\n [value]=\"state().comment\"\n [placeholder]=\"resolvedProps().commentPlaceholder\"\n [maxlength]=\"resolvedProps().maxCommentLength\"\n [disabled]=\"resolvedProps().disabled\"\n [rows]=\"3\"\n class=\"comment-textarea\"\n (ionInput)=\"updateComment($event)\"\n ></ion-textarea>\n <span class=\"char-count\"> {{ state().comment.length }}/{{ resolvedProps().maxCommentLength }} </span>\n </div>\n }\n\n <!-- Bot\u00F3n de env\u00EDo -->\n @if (state().selectedValue && !state().isSubmitted) {\n <ion-button expand=\"block\" [disabled]=\"!canSubmit()\" (click)=\"submitReaction()\" class=\"submit-button\">\n @if (state().isLoading) {\n <ion-spinner name=\"crescent\"></ion-spinner>\n } @else { {{ state().hadPreviousReaction ? t('update') : t('submit') }} }\n </ion-button>\n }\n\n <!-- Mensaje de confirmaci\u00F3n -->\n @if (state().isSubmitted) {\n <p class=\"submitted-message\">{{ t('thankYou') }}</p>\n }\n\n <!-- Error -->\n @if (state().error) {\n <p class=\"error-message\">{{ state().error }}</p>\n } }\n</div>\n}\n", styles: [":host{display:block}.content-reaction{padding:16px;text-align:center}.content-reaction.disabled{opacity:.6;pointer-events:none}.content-reaction.readonly{pointer-events:none}.question{font-size:16px;font-weight:500;color:var(--ion-color-dark);margin:0 0 16px}.emoji-container{display:flex;justify-content:center;gap:24px;margin-bottom:20px}.emoji-button{background:transparent;border:2px solid var(--ion-color-light-shade);border-radius:50%;width:64px;height:64px;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;padding:0}.emoji-button .emoji{font-size:32px;transition:transform .3s cubic-bezier(.4,0,.2,1);line-height:1}.emoji-button:hover:not(:disabled){transform:scale(1.1);border-color:var(--ion-color-medium)}.emoji-button:focus{outline:2px solid var(--ion-color-primary);outline-offset:2px}.emoji-button.selected{transform:scale(1.2)}.emoji-button.selected .emoji{transform:scale(1.1)}.emoji-button.selected.negative{border-color:var(--ion-color-danger);background:var(--ion-color-danger-tint);box-shadow:0 4px 12px rgba(var(--ion-color-danger-rgb),.3)}.emoji-button.selected.neutral{border-color:var(--ion-color-warning);background:var(--ion-color-warning-tint);box-shadow:0 4px 12px rgba(var(--ion-color-warning-rgb),.3)}.emoji-button.selected.positive{border-color:var(--ion-color-success);background:var(--ion-color-success-tint);box-shadow:0 4px 12px rgba(var(--ion-color-success-rgb),.3)}.emoji-button:disabled{cursor:not-allowed;opacity:.5}.comment-section{margin-top:16px;animation:slideIn .3s ease-out}.comment-section .comment-textarea{--background: var(--ion-color-light);--border-radius: 8px;--padding-start: 12px;--padding-end: 12px;width:100%}.comment-section .char-count{display:block;text-align:right;font-size:12px;color:var(--ion-color-medium);margin-top:4px}.submit-button{margin-top:16px;--border-radius: 8px}.submitted-message{margin-top:16px;color:var(--ion-color-success);font-weight:500;animation:fadeIn .3s ease-out}.error-message{margin-top:8px;color:var(--ion-color-danger);font-size:14px}.loading-container{display:flex;justify-content:center;padding:20px}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"] }]
46360
+ args: [{ selector: 'val-content-reaction', standalone: true, imports: [CommonModule, FormsModule, IonButton, IonSpinner, IonTextarea], template: "@if (isConfigured()) {\n<div class=\"content-reaction\" [class.disabled]=\"resolvedProps().disabled\" [class.readonly]=\"resolvedProps().readonly\">\n <!-- Loading inicial -->\n @if (state().isLoading && !state().selectedValue) {\n <div class=\"loading-container\">\n <ion-spinner name=\"crescent\"></ion-spinner>\n </div>\n } @else {\n <!-- Pregunta -->\n <p class=\"question\">{{ resolvedProps().question }}</p>\n\n <!-- Emojis -->\n <div class=\"emoji-container\">\n @for (value of activeReactionValues(); track value; let i = $index) {\n <button\n type=\"button\"\n class=\"emoji-button\"\n [class.selected]=\"isSelected(value)\"\n [class.negative]=\"value === 'negative' && isSelected(value)\"\n [class.neutral]=\"value === 'neutral' && isSelected(value)\"\n [class.positive]=\"value === 'positive' && isSelected(value)\"\n [attr.aria-label]=\"getEmojiLabel(i)\"\n [attr.aria-pressed]=\"isSelected(value)\"\n [disabled]=\"resolvedProps().disabled || resolvedProps().readonly\"\n (click)=\"selectReaction(value)\"\n >\n <span class=\"emoji\">{{ getEmoji(i) }}</span>\n </button>\n }\n </div>\n\n <!-- Campo de comentario (solo si hay selecci\u00F3n) -->\n @if (showCommentField()) {\n <div class=\"comment-section\">\n <ion-textarea\n [value]=\"state().comment\"\n [placeholder]=\"resolvedProps().commentPlaceholder\"\n [maxlength]=\"resolvedProps().maxCommentLength\"\n [disabled]=\"resolvedProps().disabled\"\n [rows]=\"3\"\n class=\"comment-textarea\"\n (ionInput)=\"updateComment($event)\"\n ></ion-textarea>\n <span class=\"char-count\"> {{ state().comment.length }}/{{ resolvedProps().maxCommentLength }} </span>\n </div>\n }\n\n <!-- Bot\u00F3n de env\u00EDo -->\n @if (state().selectedValue && !state().isSubmitted) {\n <ion-button expand=\"block\" [disabled]=\"!canSubmit()\" (click)=\"submitReaction()\" class=\"submit-button\">\n @if (state().isLoading) {\n <ion-spinner name=\"crescent\"></ion-spinner>\n } @else { {{ state().hadPreviousReaction ? t('update') : t('submit') }} }\n </ion-button>\n }\n\n <!-- Mensaje de confirmaci\u00F3n -->\n @if (state().isSubmitted) {\n <p class=\"submitted-message\">{{ t('thankYou') }}</p>\n }\n\n <!-- Error -->\n @if (state().error) {\n <p class=\"error-message\">{{ state().error }}</p>\n } }\n</div>\n}\n", styles: [":host{display:block}.content-reaction{padding:16px;text-align:center}.content-reaction.disabled{opacity:.6;pointer-events:none}.content-reaction.readonly{pointer-events:none}.question{font-size:17px;font-weight:700;color:var(--ion-color-dark);margin:0 0 16px}.emoji-container{display:flex;justify-content:center;gap:24px;margin-bottom:20px}.emoji-button{background:transparent;border:2px solid var(--ion-color-light-shade);border-radius:50%;width:48px;height:48px;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center;padding:0}.emoji-button .emoji{font-size:22px;transition:transform .3s cubic-bezier(.4,0,.2,1);line-height:1}.emoji-button:hover:not(:disabled){transform:scale(1.1);border-color:var(--ion-color-medium)}.emoji-button:focus{outline:2px solid var(--ion-color-primary);outline-offset:2px}.emoji-button.selected{transform:scale(1.2)}.emoji-button.selected .emoji{transform:scale(1.1)}.emoji-button.selected.negative{border-color:var(--ion-color-danger);background:var(--ion-color-danger-tint);box-shadow:0 4px 12px rgba(var(--ion-color-danger-rgb),.3)}.emoji-button.selected.neutral{border-color:var(--ion-color-warning);background:var(--ion-color-warning-tint);box-shadow:0 4px 12px rgba(var(--ion-color-warning-rgb),.3)}.emoji-button.selected.positive{border-color:var(--ion-color-success);background:var(--ion-color-success-tint);box-shadow:0 4px 12px rgba(var(--ion-color-success-rgb),.3)}.emoji-button:disabled{cursor:not-allowed;opacity:.5}.comment-section{margin-top:16px;animation:slideIn .3s ease-out}.comment-section .comment-textarea{--background: transparent;--border-radius: 8px;--padding-start: 12px;--padding-end: 12px;width:100%}.comment-section .char-count{display:block;text-align:right;font-size:12px;color:var(--ion-color-medium);margin-top:4px}.submit-button{margin-top:16px;--border-radius: 8px}.submitted-message{margin-top:16px;color:var(--ion-color-success);font-weight:500;animation:fadeIn .3s ease-out}.error-message{margin-top:8px;color:var(--ion-color-danger);font-size:14px}.loading-container{display:flex;justify-content:center;padding:20px}@keyframes slideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"] }]
46289
46361
  }], propDecorators: { props: [{
46290
46362
  type: Input
46291
46363
  }], reactionSubmit: [{