valtech-components 4.0.5 → 4.0.7

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.
Files changed (72) hide show
  1. package/esm2022/lib/components/atoms/box/box.component.mjs +3 -3
  2. package/esm2022/lib/components/atoms/button/button.component.mjs +15 -5
  3. package/esm2022/lib/components/atoms/fab/fab.component.mjs +12 -18
  4. package/esm2022/lib/components/atoms/fab/types.mjs +1 -1
  5. package/esm2022/lib/components/atoms/horizontal-scroll/horizontal-scroll.component.mjs +5 -7
  6. package/esm2022/lib/components/atoms/progress-bar/progress-bar.component.mjs +3 -1
  7. package/esm2022/lib/components/atoms/progress-bar/types.mjs +1 -1
  8. package/esm2022/lib/components/molecules/accordion/accordion.component.mjs +4 -6
  9. package/esm2022/lib/components/molecules/action-card/action-card.component.mjs +9 -9
  10. package/esm2022/lib/components/molecules/article-card/article-card.component.mjs +5 -5
  11. package/esm2022/lib/components/molecules/breadcrumb/breadcrumb.component.mjs +5 -5
  12. package/esm2022/lib/components/molecules/card/card.component.mjs +19 -9
  13. package/esm2022/lib/components/molecules/chip-group/chip-group.component.mjs +21 -13
  14. package/esm2022/lib/components/molecules/code-display/code-display.component.mjs +5 -5
  15. package/esm2022/lib/components/molecules/comment/comment.component.mjs +31 -58
  16. package/esm2022/lib/components/molecules/content-loader/content-loader.component.mjs +13 -3
  17. package/esm2022/lib/components/molecules/date-picker/date-picker.component.mjs +7 -15
  18. package/esm2022/lib/components/molecules/date-range-input/date-range-input.component.mjs +6 -10
  19. package/esm2022/lib/components/molecules/docs-code-example/docs-code-example.component.mjs +13 -5
  20. package/esm2022/lib/components/molecules/docs-nav-links/docs-nav-links.component.mjs +7 -13
  21. package/esm2022/lib/components/molecules/docs-search/docs-search.component.mjs +12 -28
  22. package/esm2022/lib/components/molecules/expandable-text/expandable-text.component.mjs +16 -4
  23. package/esm2022/lib/components/molecules/features-list/features-list.component.mjs +5 -5
  24. package/esm2022/lib/components/molecules/feedback-form/feedback-form.component.mjs +5 -5
  25. package/esm2022/lib/components/molecules/file-input/file-input.component.mjs +9 -3
  26. package/esm2022/lib/components/molecules/footer-links/footer-links.component.mjs +25 -5
  27. package/esm2022/lib/components/molecules/glow-card/glow-card.component.mjs +17 -5
  28. package/esm2022/lib/components/molecules/language-selector/language-selector.component.mjs +7 -5
  29. package/esm2022/lib/components/molecules/link/link.component.mjs +3 -3
  30. package/esm2022/lib/components/molecules/media-object/media-object.component.mjs +3 -3
  31. package/esm2022/lib/components/molecules/metric-card/metric-card.component.mjs +5 -3
  32. package/esm2022/lib/components/molecules/number-stepper/number-stepper.component.mjs +9 -13
  33. package/esm2022/lib/components/molecules/password-input/password-input.component.mjs +11 -3
  34. package/esm2022/lib/components/molecules/pill/pill.component.mjs +7 -7
  35. package/esm2022/lib/components/molecules/plain-code-box/plain-code-box.component.mjs +17 -5
  36. package/esm2022/lib/components/molecules/popover-selector/popover-selector.component.mjs +7 -7
  37. package/esm2022/lib/components/molecules/segment-control/segment-control.component.mjs +3 -3
  38. package/esm2022/lib/components/molecules/select-search/select-search.component.mjs +15 -3
  39. package/esm2022/lib/components/molecules/share-buttons/share-buttons.component.mjs +3 -1
  40. package/esm2022/lib/components/molecules/stats-card/stats-card.component.mjs +5 -5
  41. package/esm2022/lib/components/molecules/stepper/stepper.component.mjs +11 -13
  42. package/esm2022/lib/components/molecules/tabs/tabs.component.mjs +4 -6
  43. package/esm2022/lib/components/molecules/ticket-card/ticket-card.component.mjs +3 -3
  44. package/esm2022/lib/components/organisms/auth-cta/auth-cta.component.mjs +3 -3
  45. package/esm2022/lib/components/organisms/avatar-upload/avatar-upload.component.mjs +3 -3
  46. package/esm2022/lib/components/organisms/bottom-nav/bottom-nav.component.mjs +5 -5
  47. package/esm2022/lib/components/organisms/cookie-banner/cookie-banner.component.mjs +3 -1
  48. package/esm2022/lib/components/organisms/cookie-banner/types.mjs +1 -1
  49. package/esm2022/lib/components/organisms/data-table/data-table.component.mjs +22 -14
  50. package/esm2022/lib/components/organisms/infinite-list/infinite-list.component.mjs +31 -13
  51. package/esm2022/lib/components/organisms/login/login.component.mjs +3 -3
  52. package/esm2022/lib/components/organisms/toolbar/toolbar.component.mjs +73 -17
  53. package/esm2022/lib/services/page-state/page-state.i18n.mjs +19 -0
  54. package/esm2022/lib/services/page-state/page-state.mjs +101 -0
  55. package/esm2022/lib/version.mjs +2 -2
  56. package/esm2022/public-api.mjs +4 -1
  57. package/fesm2022/valtech-components.mjs +603 -346
  58. package/fesm2022/valtech-components.mjs.map +1 -1
  59. package/lib/components/atoms/fab/types.d.ts +4 -0
  60. package/lib/components/atoms/progress-bar/types.d.ts +2 -0
  61. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +2 -2
  62. package/lib/components/atoms/text/text.component.d.ts +1 -1
  63. package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +1 -1
  64. package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
  65. package/lib/components/organisms/article/article.component.d.ts +4 -4
  66. package/lib/components/organisms/cookie-banner/types.d.ts +2 -0
  67. package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
  68. package/lib/services/page-state/page-state.d.ts +74 -0
  69. package/lib/services/page-state/page-state.i18n.d.ts +6 -0
  70. package/lib/version.d.ts +1 -1
  71. package/package.json +1 -1
  72. package/public-api.d.ts +1 -0
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
56
56
  * Current version of valtech-components.
57
57
  * This is automatically updated during the publish process.
58
58
  */
59
- const VERSION = '4.0.5';
59
+ const VERSION = '4.0.7';
60
60
 
61
61
  // Control de estado de refresco (singleton a nivel de módulo)
62
62
  let isRefreshing = false;
@@ -9774,7 +9774,7 @@ class BoxComponent {
9774
9774
  }"
9775
9775
  >
9776
9776
  @if (props.icon) {
9777
- <ion-icon class="icon" [name]="props.icon" (click)="clickHandler()"></ion-icon>
9777
+ <ion-icon class="icon" [name]="props.icon" (click)="clickHandler()" aria-hidden="true"></ion-icon>
9778
9778
  }
9779
9779
  <div
9780
9780
  [ngStyle]="{
@@ -9801,7 +9801,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
9801
9801
  }"
9802
9802
  >
9803
9803
  @if (props.icon) {
9804
- <ion-icon class="icon" [name]="props.icon" (click)="clickHandler()"></ion-icon>
9804
+ <ion-icon class="icon" [name]="props.icon" (click)="clickHandler()" aria-hidden="true"></ion-icon>
9805
9805
  }
9806
9806
  <div
9807
9807
  [ngStyle]="{
@@ -10576,8 +10576,13 @@ class ButtonComponent {
10576
10576
  [disabled]="resolvedProps.state === states.DISABLED"
10577
10577
  [ngClass]="resolvedProps.size ? [resolvedProps.size] : []"
10578
10578
  >
10579
- <ion-icon *ngIf="resolvedProps.icon" [slot]="resolvedProps.icon.slot" [name]="resolvedProps.icon.name"></ion-icon>
10580
- <ion-spinner *ngIf="resolvedProps.state === states.WORKING" name="circular"></ion-spinner>
10579
+ <ion-icon
10580
+ *ngIf="resolvedProps.icon"
10581
+ [slot]="resolvedProps.icon.slot"
10582
+ [name]="resolvedProps.icon.name"
10583
+ aria-hidden="true"
10584
+ ></ion-icon>
10585
+ <ion-spinner *ngIf="resolvedProps.state === states.WORKING" name="circular" aria-label="Cargando"></ion-spinner>
10581
10586
  <ion-text *ngIf="resolvedProps.state !== states.WORKING">{{ displayText }}</ion-text>
10582
10587
  </ion-button>
10583
10588
  `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif;min-width:6.25rem;margin:0}ion-button.small{--padding-bottom: 12px;--padding-end: 14px;--padding-start: 14px;--padding-top: 12px}ion-button.button-clear{padding:0;margin:0}ion-button ion-spinner{--color: currentColor}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { 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: 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: IonText, selector: "ion-text", inputs: ["color", "mode"] }] }); }
@@ -10600,8 +10605,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
10600
10605
  [disabled]="resolvedProps.state === states.DISABLED"
10601
10606
  [ngClass]="resolvedProps.size ? [resolvedProps.size] : []"
10602
10607
  >
10603
- <ion-icon *ngIf="resolvedProps.icon" [slot]="resolvedProps.icon.slot" [name]="resolvedProps.icon.name"></ion-icon>
10604
- <ion-spinner *ngIf="resolvedProps.state === states.WORKING" name="circular"></ion-spinner>
10608
+ <ion-icon
10609
+ *ngIf="resolvedProps.icon"
10610
+ [slot]="resolvedProps.icon.slot"
10611
+ [name]="resolvedProps.icon.name"
10612
+ aria-hidden="true"
10613
+ ></ion-icon>
10614
+ <ion-spinner *ngIf="resolvedProps.state === states.WORKING" name="circular" aria-label="Cargando"></ion-spinner>
10605
10615
  <ion-text *ngIf="resolvedProps.state !== states.WORKING">{{ displayText }}</ion-text>
10606
10616
  </ion-button>
10607
10617
  `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif;min-width:6.25rem;margin:0}ion-button.small{--padding-bottom: 12px;--padding-end: 14px;--padding-start: 14px;--padding-top: 12px}ion-button.button-clear{padding:0;margin:0}ion-button ion-spinner{--color: currentColor}\n"] }]
@@ -11383,6 +11393,7 @@ class ProgressBarComponent {
11383
11393
  [color]="resolvedProps.color"
11384
11394
  [buffer]="resolvedProps.buffer"
11385
11395
  [type]="resolvedProps.type"
11396
+ [attr.aria-label]="resolvedProps.label || 'Progreso'"
11386
11397
  ></ion-progress-bar>
11387
11398
  `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-progress-bar.rounded{border-radius:.5rem}.medium{height:.25rem}.large{height:.375rem}.xlarge{height:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: IonProgressBar, selector: "ion-progress-bar", inputs: ["buffer", "color", "mode", "reversed", "type", "value"] }] }); }
11388
11399
  }
@@ -11396,6 +11407,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
11396
11407
  [color]="resolvedProps.color"
11397
11408
  [buffer]="resolvedProps.buffer"
11398
11409
  [type]="resolvedProps.type"
11410
+ [attr.aria-label]="resolvedProps.label || 'Progreso'"
11399
11411
  ></ion-progress-bar>
11400
11412
  `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-progress-bar.rounded{border-radius:.5rem}.medium{height:.25rem}.large{height:.375rem}.xlarge{height:.5rem}\n"] }]
11401
11413
  }], propDecorators: { preset: [{
@@ -12348,9 +12360,7 @@ class FabComponent {
12348
12360
  * Explicit props take precedence over preset values.
12349
12361
  */
12350
12362
  resolveProps() {
12351
- const presetProps = this.preset
12352
- ? this.presets.get('fab', this.preset)
12353
- : {};
12363
+ const presetProps = this.preset ? this.presets.get('fab', this.preset) : {};
12354
12364
  this.resolvedProps = {
12355
12365
  ...presetProps,
12356
12366
  ...this.props,
@@ -12394,19 +12404,16 @@ class FabComponent {
12394
12404
  }
12395
12405
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12396
12406
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FabComponent, isStandalone: true, selector: "val-fab", inputs: { preset: "preset", props: "props" }, outputs: { fabClick: "fabClick", actionClick: "actionClick" }, usesOnChanges: true, ngImport: i0, template: `
12397
- <ion-fab
12398
- [vertical]="getVertical()"
12399
- [horizontal]="getHorizontal()"
12400
- [activated]="isActivated"
12401
- >
12407
+ <ion-fab [vertical]="getVertical()" [horizontal]="getHorizontal()" [activated]="isActivated">
12402
12408
  <ion-fab-button
12403
12409
  [color]="resolvedProps.color || 'primary'"
12404
12410
  [size]="resolvedProps.size"
12405
12411
  [disabled]="resolvedProps.disabled"
12406
12412
  [translucent]="resolvedProps.translucent"
12407
12413
  (click)="onMainClick()"
12414
+ [attr.aria-label]="resolvedProps.ariaLabel || resolvedProps.label || 'Acción'"
12408
12415
  >
12409
- <ion-icon [name]="getMainIcon()"></ion-icon>
12416
+ <ion-icon [name]="getMainIcon()" aria-hidden="true"></ion-icon>
12410
12417
  </ion-fab-button>
12411
12418
 
12412
12419
  @if (resolvedProps.actions && resolvedProps.actions.length > 0) {
@@ -12416,8 +12423,9 @@ class FabComponent {
12416
12423
  [color]="action.color || 'light'"
12417
12424
  [disabled]="action.disabled"
12418
12425
  (click)="onActionClick(action)"
12426
+ [attr.aria-label]="action.label || action.token || action.icon"
12419
12427
  >
12420
- <ion-icon [name]="action.icon"></ion-icon>
12428
+ <ion-icon [name]="action.icon" aria-hidden="true"></ion-icon>
12421
12429
  </ion-fab-button>
12422
12430
  }
12423
12431
  </ion-fab-list>
@@ -12428,19 +12436,16 @@ class FabComponent {
12428
12436
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FabComponent, decorators: [{
12429
12437
  type: Component,
12430
12438
  args: [{ selector: 'val-fab', standalone: true, imports: [CommonModule, IonFab, IonFabButton, IonFabList, IonIcon, IonLabel], template: `
12431
- <ion-fab
12432
- [vertical]="getVertical()"
12433
- [horizontal]="getHorizontal()"
12434
- [activated]="isActivated"
12435
- >
12439
+ <ion-fab [vertical]="getVertical()" [horizontal]="getHorizontal()" [activated]="isActivated">
12436
12440
  <ion-fab-button
12437
12441
  [color]="resolvedProps.color || 'primary'"
12438
12442
  [size]="resolvedProps.size"
12439
12443
  [disabled]="resolvedProps.disabled"
12440
12444
  [translucent]="resolvedProps.translucent"
12441
12445
  (click)="onMainClick()"
12446
+ [attr.aria-label]="resolvedProps.ariaLabel || resolvedProps.label || 'Acción'"
12442
12447
  >
12443
- <ion-icon [name]="getMainIcon()"></ion-icon>
12448
+ <ion-icon [name]="getMainIcon()" aria-hidden="true"></ion-icon>
12444
12449
  </ion-fab-button>
12445
12450
 
12446
12451
  @if (resolvedProps.actions && resolvedProps.actions.length > 0) {
@@ -12450,8 +12455,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12450
12455
  [color]="action.color || 'light'"
12451
12456
  [disabled]="action.disabled"
12452
12457
  (click)="onActionClick(action)"
12458
+ [attr.aria-label]="action.label || action.token || action.icon"
12453
12459
  >
12454
- <ion-icon [name]="action.icon"></ion-icon>
12460
+ <ion-icon [name]="action.icon" aria-hidden="true"></ion-icon>
12455
12461
  </ion-fab-button>
12456
12462
  }
12457
12463
  </ion-fab-list>
@@ -13865,13 +13871,12 @@ class HorizontalScrollComponent {
13865
13871
  [class.snap-start]="props?.snapAlign === 'start'"
13866
13872
  [class.snap-center]="props?.snapAlign === 'center'"
13867
13873
  [style.padding]="props?.padding || '0px'"
13874
+ tabindex="0"
13868
13875
  >
13869
13876
  <div class="items-wrapper" [style.gap]="props?.gap || '0px'">
13870
13877
  @for (item of items; track $index) {
13871
13878
  <div class="scroll-item">
13872
- <ng-container
13873
- *ngTemplateOutlet="itemTemplate; context: { $implicit: item, index: $index }"
13874
- ></ng-container>
13879
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, index: $index }"></ng-container>
13875
13880
  </div>
13876
13881
  }
13877
13882
  </div>
@@ -13887,13 +13892,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
13887
13892
  [class.snap-start]="props?.snapAlign === 'start'"
13888
13893
  [class.snap-center]="props?.snapAlign === 'center'"
13889
13894
  [style.padding]="props?.padding || '0px'"
13895
+ tabindex="0"
13890
13896
  >
13891
13897
  <div class="items-wrapper" [style.gap]="props?.gap || '0px'">
13892
13898
  @for (item of items; track $index) {
13893
13899
  <div class="scroll-item">
13894
- <ng-container
13895
- *ngTemplateOutlet="itemTemplate; context: { $implicit: item, index: $index }"
13896
- ></ng-container>
13900
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, index: $index }"></ng-container>
13897
13901
  </div>
13898
13902
  }
13899
13903
  </div>
@@ -15194,9 +15198,10 @@ class CardComponent {
15194
15198
  <ng-container *ngFor="let action of resolvedProps.leftActions">
15195
15199
  <ion-button
15196
15200
  *ngIf="action.type === actionTypes.ICON"
15201
+ [attr.aria-label]="action.description"
15197
15202
  (click)="clickHandler(sections.headerLeft, action.token)"
15198
15203
  >
15199
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15204
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15200
15205
  </ion-button>
15201
15206
  <val-avatar
15202
15207
  style="margin-right: 4px; cursor: pointer"
@@ -15224,9 +15229,10 @@ class CardComponent {
15224
15229
  <ng-container *ngFor="let action of resolvedProps.rightActions">
15225
15230
  <ion-button
15226
15231
  *ngIf="action.type === actionTypes.ICON"
15232
+ [attr.aria-label]="action.description"
15227
15233
  (click)="clickHandler(sections.headerRight, action.token)"
15228
15234
  >
15229
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15235
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15230
15236
  </ion-button>
15231
15237
  <val-avatar
15232
15238
  style="margin-right: 4px; cursor: pointer"
@@ -15268,7 +15274,9 @@ class CardComponent {
15268
15274
  @if (resolvedProps.image) {
15269
15275
  <img [alt]="resolvedProps.title || 'Card image'" [src]="resolvedProps.image" />
15270
15276
  }
15271
- <ion-card-content *ngIf="resolvedProps.content" class="complex-content">{{ resolvedProps.content }}</ion-card-content>
15277
+ <ion-card-content *ngIf="resolvedProps.content" class="complex-content">{{
15278
+ resolvedProps.content
15279
+ }}</ion-card-content>
15272
15280
  </div>
15273
15281
  @if (resolvedProps.footerActions && resolvedProps.footerActions.length > 0) {
15274
15282
  <div class="card-actions">
@@ -15286,9 +15294,10 @@ class CardComponent {
15286
15294
  <ng-container *ngFor="let action of resolvedProps.footerComplexActions">
15287
15295
  <ion-button
15288
15296
  *ngIf="action.type === actionTypes.ICON"
15297
+ [attr.aria-label]="action.description"
15289
15298
  (click)="clickHandler(sections.footerExtra, action.token)"
15290
15299
  >
15291
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15300
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15292
15301
  </ion-button>
15293
15302
  <val-avatar
15294
15303
  style="margin-right: 4px; cursor: pointer"
@@ -15404,9 +15413,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15404
15413
  <ng-container *ngFor="let action of resolvedProps.leftActions">
15405
15414
  <ion-button
15406
15415
  *ngIf="action.type === actionTypes.ICON"
15416
+ [attr.aria-label]="action.description"
15407
15417
  (click)="clickHandler(sections.headerLeft, action.token)"
15408
15418
  >
15409
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15419
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15410
15420
  </ion-button>
15411
15421
  <val-avatar
15412
15422
  style="margin-right: 4px; cursor: pointer"
@@ -15434,9 +15444,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15434
15444
  <ng-container *ngFor="let action of resolvedProps.rightActions">
15435
15445
  <ion-button
15436
15446
  *ngIf="action.type === actionTypes.ICON"
15447
+ [attr.aria-label]="action.description"
15437
15448
  (click)="clickHandler(sections.headerRight, action.token)"
15438
15449
  >
15439
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15450
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15440
15451
  </ion-button>
15441
15452
  <val-avatar
15442
15453
  style="margin-right: 4px; cursor: pointer"
@@ -15478,7 +15489,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15478
15489
  @if (resolvedProps.image) {
15479
15490
  <img [alt]="resolvedProps.title || 'Card image'" [src]="resolvedProps.image" />
15480
15491
  }
15481
- <ion-card-content *ngIf="resolvedProps.content" class="complex-content">{{ resolvedProps.content }}</ion-card-content>
15492
+ <ion-card-content *ngIf="resolvedProps.content" class="complex-content">{{
15493
+ resolvedProps.content
15494
+ }}</ion-card-content>
15482
15495
  </div>
15483
15496
  @if (resolvedProps.footerActions && resolvedProps.footerActions.length > 0) {
15484
15497
  <div class="card-actions">
@@ -15496,9 +15509,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15496
15509
  <ng-container *ngFor="let action of resolvedProps.footerComplexActions">
15497
15510
  <ion-button
15498
15511
  *ngIf="action.type === actionTypes.ICON"
15512
+ [attr.aria-label]="action.description"
15499
15513
  (click)="clickHandler(sections.footerExtra, action.token)"
15500
15514
  >
15501
- <ion-icon slot="icon-only" [name]="action.description" color="dark"></ion-icon>
15515
+ <ion-icon slot="icon-only" [name]="action.description" color="dark" aria-hidden="true"></ion-icon>
15502
15516
  </ion-button>
15503
15517
  <val-avatar
15504
15518
  style="margin-right: 4px; cursor: pointer"
@@ -15720,7 +15734,12 @@ class ContentLoaderComponent {
15720
15734
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
15721
15735
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ContentLoaderComponent, isStandalone: true, selector: "val-content-loader", inputs: { props: "props" }, ngImport: i0, template: `
15722
15736
  <div [ngClass]="['spinner-wrapper', props.size]">
15723
- <ion-spinner [ngClass]="[props.size]" [name]="props.name" [color]="props.color"></ion-spinner>
15737
+ <ion-spinner
15738
+ [ngClass]="[props.size]"
15739
+ [name]="props.name"
15740
+ [color]="props.color"
15741
+ [attr.aria-label]="props.text || 'Cargando'"
15742
+ ></ion-spinner>
15724
15743
  <ion-text [color]="props.color">
15725
15744
  <p>{{ props.text }}</p>
15726
15745
  </ion-text>
@@ -15731,7 +15750,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15731
15750
  type: Component,
15732
15751
  args: [{ selector: 'val-content-loader', standalone: true, imports: [CommonModule, IonSpinner, IonText], template: `
15733
15752
  <div [ngClass]="['spinner-wrapper', props.size]">
15734
- <ion-spinner [ngClass]="[props.size]" [name]="props.name" [color]="props.color"></ion-spinner>
15753
+ <ion-spinner
15754
+ [ngClass]="[props.size]"
15755
+ [name]="props.name"
15756
+ [color]="props.color"
15757
+ [attr.aria-label]="props.text || 'Cargando'"
15758
+ ></ion-spinner>
15735
15759
  <ion-text [color]="props.color">
15736
15760
  <p>{{ props.text }}</p>
15737
15761
  </ion-text>
@@ -16051,7 +16075,7 @@ class ExpandableTextComponent {
16051
16075
  return this.props.content?.length > (this.props.limit || 100);
16052
16076
  }
16053
16077
  getExpandText() {
16054
- return this.props.expandText || this.i18n.t('seeMore');
16078
+ return this.props.expandText || this.i18n.t('seeMore') || 'Ver más';
16055
16079
  }
16056
16080
  toggleExpand() {
16057
16081
  this.expanded = !this.expanded;
@@ -16070,7 +16094,13 @@ class ExpandableTextComponent {
16070
16094
  </ion-text>
16071
16095
  </div>
16072
16096
  @if (!expanded && isTruncated) {
16073
- <button type="button" class="see-more" [style.color]="this.color()" [attr.aria-expanded]="expanded" (click)="toggleExpand()">
16097
+ <button
16098
+ type="button"
16099
+ class="see-more"
16100
+ [style.color]="this.color()"
16101
+ [attr.aria-expanded]="expanded"
16102
+ (click)="toggleExpand()"
16103
+ >
16074
16104
  {{ getExpandText() }}
16075
16105
  </button>
16076
16106
  }
@@ -16089,7 +16119,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16089
16119
  </ion-text>
16090
16120
  </div>
16091
16121
  @if (!expanded && isTruncated) {
16092
- <button type="button" class="see-more" [style.color]="this.color()" [attr.aria-expanded]="expanded" (click)="toggleExpand()">
16122
+ <button
16123
+ type="button"
16124
+ class="see-more"
16125
+ [style.color]="this.color()"
16126
+ [attr.aria-expanded]="expanded"
16127
+ (click)="toggleExpand()"
16128
+ >
16093
16129
  {{ getExpandText() }}
16094
16130
  </button>
16095
16131
  }
@@ -16144,7 +16180,10 @@ class FileInputComponent {
16144
16180
  <div class="file-container">
16145
16181
  <input style="display: none" type="file" (change)="onFileSelected($event)" #fileInput [accept]="props.accept" />
16146
16182
  <div class="name-container">
16147
- <ion-icon [name]="selectedFile ? 'checkmark-circle-outline' : 'alert-circle-outline'"></ion-icon>
16183
+ <ion-icon
16184
+ [name]="selectedFile ? 'checkmark-circle-outline' : 'alert-circle-outline'"
16185
+ aria-hidden="true"
16186
+ ></ion-icon>
16148
16187
  <val-text
16149
16188
  style="margin-left: 4px;"
16150
16189
  [props]="{
@@ -16165,7 +16204,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16165
16204
  <div class="file-container">
16166
16205
  <input style="display: none" type="file" (change)="onFileSelected($event)" #fileInput [accept]="props.accept" />
16167
16206
  <div class="name-container">
16168
- <ion-icon [name]="selectedFile ? 'checkmark-circle-outline' : 'alert-circle-outline'"></ion-icon>
16207
+ <ion-icon
16208
+ [name]="selectedFile ? 'checkmark-circle-outline' : 'alert-circle-outline'"
16209
+ aria-hidden="true"
16210
+ ></ion-icon>
16169
16211
  <val-text
16170
16212
  style="margin-left: 4px;"
16171
16213
  [props]="{
@@ -16411,16 +16453,16 @@ class PopoverSelectorComponent {
16411
16453
  [disabled]="props.disabled || false"
16412
16454
  class="selector-trigger"
16413
16455
  >
16414
- <ion-icon *ngIf="props.icon" [name]="props.icon" slot="start"> </ion-icon>
16456
+ <ion-icon *ngIf="props.icon" [name]="props.icon" slot="start" aria-hidden="true"> </ion-icon>
16415
16457
 
16416
16458
  <span class="trigger-text">{{ getDisplayText() }}</span>
16417
16459
 
16418
- <ion-icon name="chevron-down-outline" slot="end" class="chevron-icon"> </ion-icon>
16460
+ <ion-icon name="chevron-down-outline" slot="end" class="chevron-icon" aria-hidden="true"> </ion-icon>
16419
16461
  </ion-button>
16420
16462
 
16421
16463
  <ion-select-option *ngFor="let option of props.options" [value]="option.value" [disabled]="option.disabled">
16422
16464
  <div class="option-content">
16423
- <ion-icon *ngIf="option.icon" [name]="option.icon" class="option-icon"> </ion-icon>
16465
+ <ion-icon *ngIf="option.icon" [name]="option.icon" class="option-icon" aria-hidden="true"> </ion-icon>
16424
16466
  <span>{{ option.label }}</span>
16425
16467
  </div>
16426
16468
  </ion-select-option>
@@ -16453,16 +16495,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16453
16495
  [disabled]="props.disabled || false"
16454
16496
  class="selector-trigger"
16455
16497
  >
16456
- <ion-icon *ngIf="props.icon" [name]="props.icon" slot="start"> </ion-icon>
16498
+ <ion-icon *ngIf="props.icon" [name]="props.icon" slot="start" aria-hidden="true"> </ion-icon>
16457
16499
 
16458
16500
  <span class="trigger-text">{{ getDisplayText() }}</span>
16459
16501
 
16460
- <ion-icon name="chevron-down-outline" slot="end" class="chevron-icon"> </ion-icon>
16502
+ <ion-icon name="chevron-down-outline" slot="end" class="chevron-icon" aria-hidden="true"> </ion-icon>
16461
16503
  </ion-button>
16462
16504
 
16463
16505
  <ion-select-option *ngFor="let option of props.options" [value]="option.value" [disabled]="option.disabled">
16464
16506
  <div class="option-content">
16465
- <ion-icon *ngIf="option.icon" [name]="option.icon" class="option-icon"> </ion-icon>
16507
+ <ion-icon *ngIf="option.icon" [name]="option.icon" class="option-icon" aria-hidden="true"> </ion-icon>
16466
16508
  <span>{{ option.label }}</span>
16467
16509
  </div>
16468
16510
  </ion-select-option>
@@ -16611,9 +16653,10 @@ class LanguageSelectorComponent {
16611
16653
  [fill]="props.fill || 'clear'"
16612
16654
  [size]="props.size || 'default'"
16613
16655
  [disabled]="props.disabled"
16656
+ [attr.aria-label]="'Cambiar idioma'"
16614
16657
  class="icon-mode-button"
16615
16658
  >
16616
- <ion-icon slot="icon-only" [name]="props.icon || 'globe-outline'"></ion-icon>
16659
+ <ion-icon slot="icon-only" [name]="props.icon || 'globe-outline'" aria-hidden="true"></ion-icon>
16617
16660
  </ion-button>
16618
16661
 
16619
16662
  <ion-popover [trigger]="popoverId" [dismissOnSelect]="true">
@@ -16628,7 +16671,7 @@ class LanguageSelectorComponent {
16628
16671
  >
16629
16672
  <ion-label>{{ getLanguageDisplayName(lang) }}</ion-label>
16630
16673
  @if (lang === currentLanguage) {
16631
- <ion-icon slot="end" name="checkmark" color="primary"></ion-icon>
16674
+ <ion-icon slot="end" name="checkmark" color="primary" aria-hidden="true"></ion-icon>
16632
16675
  }
16633
16676
  </ion-item>
16634
16677
  }
@@ -16654,9 +16697,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16654
16697
  [fill]="props.fill || 'clear'"
16655
16698
  [size]="props.size || 'default'"
16656
16699
  [disabled]="props.disabled"
16700
+ [attr.aria-label]="'Cambiar idioma'"
16657
16701
  class="icon-mode-button"
16658
16702
  >
16659
- <ion-icon slot="icon-only" [name]="props.icon || 'globe-outline'"></ion-icon>
16703
+ <ion-icon slot="icon-only" [name]="props.icon || 'globe-outline'" aria-hidden="true"></ion-icon>
16660
16704
  </ion-button>
16661
16705
 
16662
16706
  <ion-popover [trigger]="popoverId" [dismissOnSelect]="true">
@@ -16671,7 +16715,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16671
16715
  >
16672
16716
  <ion-label>{{ getLanguageDisplayName(lang) }}</ion-label>
16673
16717
  @if (lang === currentLanguage) {
16674
- <ion-icon slot="end" name="checkmark" color="primary"></ion-icon>
16718
+ <ion-icon slot="end" name="checkmark" color="primary" aria-hidden="true"></ion-icon>
16675
16719
  }
16676
16720
  </ion-item>
16677
16721
  }
@@ -17111,7 +17155,7 @@ class LinkComponent {
17111
17155
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: LinkComponent, isStandalone: true, selector: "val-link", inputs: { props: "props" }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
17112
17156
  <div>
17113
17157
  <ion-button type="button" [color]="props.color" fill="clear" [size]="props.size" (click)="onClickHandler()">
17114
- <ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
17158
+ <ion-icon slot="end" name="chevron-forward-outline" aria-hidden="true"></ion-icon>
17115
17159
  <ion-text>{{ props.text }}</ion-text>
17116
17160
  </ion-button>
17117
17161
  </div>
@@ -17122,7 +17166,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17122
17166
  args: [{ selector: 'val-link', standalone: true, imports: [IonButton, IonIcon, IonText], template: `
17123
17167
  <div>
17124
17168
  <ion-button type="button" [color]="props.color" fill="clear" [size]="props.size" (click)="onClickHandler()">
17125
- <ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
17169
+ <ion-icon slot="end" name="chevron-forward-outline" aria-hidden="true"></ion-icon>
17126
17170
  <ion-text>{{ props.text }}</ion-text>
17127
17171
  </ion-button>
17128
17172
  </div>
@@ -17634,7 +17678,11 @@ class PasswordInputComponent {
17634
17678
  [attr.aria-label]="toggleLabel()"
17635
17679
  [attr.aria-pressed]="!hidePassword"
17636
17680
  >
17637
- <ion-icon slot="icon-only" [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"></ion-icon>
17681
+ <ion-icon
17682
+ slot="icon-only"
17683
+ [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"
17684
+ aria-hidden="true"
17685
+ ></ion-icon>
17638
17686
  </ion-button>
17639
17687
  </div>
17640
17688
  `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
@@ -17657,7 +17705,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17657
17705
  [attr.aria-label]="toggleLabel()"
17658
17706
  [attr.aria-pressed]="!hidePassword"
17659
17707
  >
17660
- <ion-icon slot="icon-only" [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"></ion-icon>
17708
+ <ion-icon
17709
+ slot="icon-only"
17710
+ [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"
17711
+ aria-hidden="true"
17712
+ ></ion-icon>
17661
17713
  </ion-button>
17662
17714
  </div>
17663
17715
  `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"] }]
@@ -18818,7 +18870,13 @@ class SelectSearchComponent {
18818
18870
  <ion-list>
18819
18871
  <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
18820
18872
  <ion-label>{{ item[labelProperty] }}</ion-label>
18821
- <ion-icon *ngIf="isItemSelected(item)" name="checkmark-outline" slot="end" color="primary"></ion-icon>
18873
+ <ion-icon
18874
+ *ngIf="isItemSelected(item)"
18875
+ name="checkmark-outline"
18876
+ slot="end"
18877
+ color="primary"
18878
+ aria-hidden="true"
18879
+ ></ion-icon>
18822
18880
  </ion-item>
18823
18881
  <ion-item *ngIf="filteredItems.length === 0" lines="none">
18824
18882
  <ion-label color="dark">{{ getNoResultsText() }}</ion-label>
@@ -18859,7 +18917,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
18859
18917
  <ion-list>
18860
18918
  <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
18861
18919
  <ion-label>{{ item[labelProperty] }}</ion-label>
18862
- <ion-icon *ngIf="isItemSelected(item)" name="checkmark-outline" slot="end" color="primary"></ion-icon>
18920
+ <ion-icon
18921
+ *ngIf="isItemSelected(item)"
18922
+ name="checkmark-outline"
18923
+ slot="end"
18924
+ color="primary"
18925
+ aria-hidden="true"
18926
+ ></ion-icon>
18863
18927
  </ion-item>
18864
18928
  <ion-item *ngIf="filteredItems.length === 0" lines="none">
18865
18929
  <ion-label color="dark">{{ getNoResultsText() }}</ion-label>
@@ -18965,7 +19029,7 @@ class SegmentControlComponent {
18965
19029
  @for (option of resolvedProps.options; track option.value) {
18966
19030
  <ion-segment-button [value]="option.value" [disabled]="option.disabled" [layout]="option.layout || 'icon-top'">
18967
19031
  @if (option.icon) {
18968
- <ion-icon [name]="option.icon"></ion-icon>
19032
+ <ion-icon [name]="option.icon" aria-hidden="true"></ion-icon>
18969
19033
  }
18970
19034
  @if (getOptionLabel(option)) {
18971
19035
  <ion-label>{{ getOptionLabel(option) }}</ion-label>
@@ -18990,7 +19054,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
18990
19054
  @for (option of resolvedProps.options; track option.value) {
18991
19055
  <ion-segment-button [value]="option.value" [disabled]="option.disabled" [layout]="option.layout || 'icon-top'">
18992
19056
  @if (option.icon) {
18993
- <ion-icon [name]="option.icon"></ion-icon>
19057
+ <ion-icon [name]="option.icon" aria-hidden="true"></ion-icon>
18994
19058
  }
18995
19059
  @if (getOptionLabel(option)) {
18996
19060
  <ion-label>{{ getOptionLabel(option) }}</ion-label>
@@ -19309,8 +19373,8 @@ class CodeDisplayComponent {
19309
19373
  </div>
19310
19374
  <div class="code-content">
19311
19375
  <div class="copy-button-wrapper">
19312
- <ion-button fill="clear" class="copy-button" (click)="copyToClipboard()">
19313
- <ion-icon name="copy-outline"></ion-icon>
19376
+ <ion-button fill="clear" class="copy-button" [attr.aria-label]="'Copiar'" (click)="copyToClipboard()">
19377
+ <ion-icon name="copy-outline" aria-hidden="true"></ion-icon>
19314
19378
  </ion-button>
19315
19379
  </div>
19316
19380
  <pre><code [class]="'language-' + (props.tabs[selectedTab]?.language || props.language)" #codeElement></code></pre>
@@ -19334,8 +19398,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19334
19398
  </div>
19335
19399
  <div class="code-content">
19336
19400
  <div class="copy-button-wrapper">
19337
- <ion-button fill="clear" class="copy-button" (click)="copyToClipboard()">
19338
- <ion-icon name="copy-outline"></ion-icon>
19401
+ <ion-button fill="clear" class="copy-button" [attr.aria-label]="'Copiar'" (click)="copyToClipboard()">
19402
+ <ion-icon name="copy-outline" aria-hidden="true"></ion-icon>
19339
19403
  </ion-button>
19340
19404
  </div>
19341
19405
  <pre><code [class]="'language-' + (props.tabs[selectedTab]?.language || props.language)" #codeElement></code></pre>
@@ -19457,7 +19521,7 @@ class PillComponent {
19457
19521
  <div class="notif-pill" [attr.aria-live]="'polite'">
19458
19522
  @if (resolvedProps.notification?.icon) {
19459
19523
  <div class="notif-pill__icon-wrap" [style.color]="getIconColor()">
19460
- <ion-icon [name]="resolvedProps.notification!.icon!" />
19524
+ <ion-icon [name]="resolvedProps.notification!.icon!" aria-hidden="true" />
19461
19525
  </div>
19462
19526
  }
19463
19527
 
@@ -19479,7 +19543,7 @@ class PillComponent {
19479
19543
  [attr.aria-label]="action.ariaLabel || action.token"
19480
19544
  (click)="onActionClick(action.token, $event)"
19481
19545
  >
19482
- <ion-icon [name]="action.icon" />
19546
+ <ion-icon [name]="action.icon" aria-hidden="true" />
19483
19547
  </button>
19484
19548
  }
19485
19549
  </div>
@@ -19508,7 +19572,7 @@ class PillComponent {
19508
19572
  (keydown.space)="onPillClick($event)"
19509
19573
  >
19510
19574
  @if (resolvedProps.icon) {
19511
- <ion-icon class="val-pill__icon" [name]="resolvedProps.icon" />
19575
+ <ion-icon class="val-pill__icon" [name]="resolvedProps.icon" aria-hidden="true" />
19512
19576
  }
19513
19577
  <span class="val-pill__label">{{ resolvedProps.label }}</span>
19514
19578
  </span>
@@ -19523,7 +19587,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19523
19587
  <div class="notif-pill" [attr.aria-live]="'polite'">
19524
19588
  @if (resolvedProps.notification?.icon) {
19525
19589
  <div class="notif-pill__icon-wrap" [style.color]="getIconColor()">
19526
- <ion-icon [name]="resolvedProps.notification!.icon!" />
19590
+ <ion-icon [name]="resolvedProps.notification!.icon!" aria-hidden="true" />
19527
19591
  </div>
19528
19592
  }
19529
19593
 
@@ -19545,7 +19609,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19545
19609
  [attr.aria-label]="action.ariaLabel || action.token"
19546
19610
  (click)="onActionClick(action.token, $event)"
19547
19611
  >
19548
- <ion-icon [name]="action.icon" />
19612
+ <ion-icon [name]="action.icon" aria-hidden="true" />
19549
19613
  </button>
19550
19614
  }
19551
19615
  </div>
@@ -19574,7 +19638,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19574
19638
  (keydown.space)="onPillClick($event)"
19575
19639
  >
19576
19640
  @if (resolvedProps.icon) {
19577
- <ion-icon class="val-pill__icon" [name]="resolvedProps.icon" />
19641
+ <ion-icon class="val-pill__icon" [name]="resolvedProps.icon" aria-hidden="true" />
19578
19642
  }
19579
19643
  <span class="val-pill__label">{{ resolvedProps.label }}</span>
19580
19644
  </span>
@@ -19740,8 +19804,14 @@ class PlainCodeBoxComponent {
19740
19804
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlainCodeBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19741
19805
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PlainCodeBoxComponent, isStandalone: true, selector: "val-plain-code-box", inputs: { props: "props" }, viewQueries: [{ propertyName: "codeBlock", first: true, predicate: ["codeBlock"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
19742
19806
  <div class="code-box-container">
19743
- <ion-button *ngIf="props.showCopyButton !== false" fill="clear" class="copy-button" (click)="copyCode()">
19744
- <ion-icon name="copy-outline"></ion-icon>
19807
+ <ion-button
19808
+ *ngIf="props.showCopyButton !== false"
19809
+ fill="clear"
19810
+ class="copy-button"
19811
+ (click)="copyCode()"
19812
+ aria-label="Copiar"
19813
+ >
19814
+ <ion-icon name="copy-outline" slot="icon-only" aria-hidden="true"></ion-icon>
19745
19815
  </ion-button>
19746
19816
  <pre><code [class]="'language-' + (props.language || 'bash')" #codeBlock><ng-container *ngFor="let line of props.lines; let i = index"><span [class]="line.type ? 'line-' + line.type : 'line-normal'">{{ line.text }}</span><br *ngIf="i < props.lines.length - 1">
19747
19817
  </ng-container></code></pre>
@@ -19752,8 +19822,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19752
19822
  type: Component,
19753
19823
  args: [{ selector: 'val-plain-code-box', standalone: true, imports: [CommonModule, IonIcon, IonButton], template: `
19754
19824
  <div class="code-box-container">
19755
- <ion-button *ngIf="props.showCopyButton !== false" fill="clear" class="copy-button" (click)="copyCode()">
19756
- <ion-icon name="copy-outline"></ion-icon>
19825
+ <ion-button
19826
+ *ngIf="props.showCopyButton !== false"
19827
+ fill="clear"
19828
+ class="copy-button"
19829
+ (click)="copyCode()"
19830
+ aria-label="Copiar"
19831
+ >
19832
+ <ion-icon name="copy-outline" slot="icon-only" aria-hidden="true"></ion-icon>
19757
19833
  </ion-button>
19758
19834
  <pre><code [class]="'language-' + (props.language || 'bash')" #codeBlock><ng-container *ngFor="let line of props.lines; let i = index"><span [class]="line.type ? 'line-' + line.type : 'line-normal'">{{ line.text }}</span><br *ngIf="i < props.lines.length - 1">
19759
19835
  </ng-container></code></pre>
@@ -19804,9 +19880,7 @@ class AccordionComponent {
19804
19880
  }
19805
19881
  }
19806
19882
  resolveProps() {
19807
- const presetProps = this.preset
19808
- ? this.presets.get('accordion', this.preset)
19809
- : {};
19883
+ const presetProps = this.preset ? this.presets.get('accordion', this.preset) : {};
19810
19884
  this.resolvedProps = {
19811
19885
  ...presetProps,
19812
19886
  ...this.props,
@@ -19834,7 +19908,7 @@ class AccordionComponent {
19834
19908
  <ion-accordion [value]="item.value" [disabled]="item.disabled">
19835
19909
  <ion-item slot="header" [color]="resolvedProps.color || 'light'">
19836
19910
  @if (item.icon) {
19837
- <ion-icon [name]="item.icon" slot="start"></ion-icon>
19911
+ <ion-icon [name]="item.icon" slot="start" aria-hidden="true"></ion-icon>
19838
19912
  }
19839
19913
  <ion-label>{{ getItemHeader(item) }}</ion-label>
19840
19914
  </ion-item>
@@ -19860,7 +19934,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19860
19934
  <ion-accordion [value]="item.value" [disabled]="item.disabled">
19861
19935
  <ion-item slot="header" [color]="resolvedProps.color || 'light'">
19862
19936
  @if (item.icon) {
19863
- <ion-icon [name]="item.icon" slot="start"></ion-icon>
19937
+ <ion-icon [name]="item.icon" slot="start" aria-hidden="true"></ion-icon>
19864
19938
  }
19865
19939
  <ion-label>{{ getItemHeader(item) }}</ion-label>
19866
19940
  </ion-item>
@@ -19929,9 +20003,7 @@ class TabsComponent {
19929
20003
  * Explicit props take precedence over preset values.
19930
20004
  */
19931
20005
  resolveProps() {
19932
- const presetProps = this.preset
19933
- ? this.presets.get('tabs', this.preset)
19934
- : {};
20006
+ const presetProps = this.preset ? this.presets.get('tabs', this.preset) : {};
19935
20007
  this.resolvedProps = {
19936
20008
  ...presetProps,
19937
20009
  ...this.props,
@@ -19961,7 +20033,7 @@ class TabsComponent {
19961
20033
  (click)="onTabClick(tab)"
19962
20034
  >
19963
20035
  @if (tab.icon && resolvedProps.layout !== 'icon-hide') {
19964
- <ion-icon [name]="tab.icon"></ion-icon>
20036
+ <ion-icon [name]="tab.icon" aria-hidden="true"></ion-icon>
19965
20037
  }
19966
20038
  @if (getTabLabel(tab) && resolvedProps.layout !== 'label-hide') {
19967
20039
  <ion-label>{{ getTabLabel(tab) }}</ion-label>
@@ -19991,7 +20063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19991
20063
  (click)="onTabClick(tab)"
19992
20064
  >
19993
20065
  @if (tab.icon && resolvedProps.layout !== 'icon-hide') {
19994
- <ion-icon [name]="tab.icon"></ion-icon>
20066
+ <ion-icon [name]="tab.icon" aria-hidden="true"></ion-icon>
19995
20067
  }
19996
20068
  @if (getTabLabel(tab) && resolvedProps.layout !== 'label-hide') {
19997
20069
  <ion-label>{{ getTabLabel(tab) }}</ion-label>
@@ -20085,11 +20157,11 @@ class BreadcrumbComponent {
20085
20157
  (click)="onBreadcrumbClick($event, item, $index)"
20086
20158
  >
20087
20159
  @if (item.icon) {
20088
- <ion-icon [name]="item.icon" slot="start"></ion-icon>
20160
+ <ion-icon [name]="item.icon" slot="start" aria-hidden="true"></ion-icon>
20089
20161
  }
20090
20162
  {{ getItemLabel(item) }}
20091
20163
  @if (!isLast && resolvedProps.separatorIcon) {
20092
- <ion-icon [name]="resolvedProps.separatorIcon" slot="separator"></ion-icon>
20164
+ <ion-icon [name]="resolvedProps.separatorIcon" slot="separator" aria-hidden="true"></ion-icon>
20093
20165
  }
20094
20166
  </ion-breadcrumb>
20095
20167
  }
@@ -20114,11 +20186,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
20114
20186
  (click)="onBreadcrumbClick($event, item, $index)"
20115
20187
  >
20116
20188
  @if (item.icon) {
20117
- <ion-icon [name]="item.icon" slot="start"></ion-icon>
20189
+ <ion-icon [name]="item.icon" slot="start" aria-hidden="true"></ion-icon>
20118
20190
  }
20119
20191
  {{ getItemLabel(item) }}
20120
20192
  @if (!isLast && resolvedProps.separatorIcon) {
20121
- <ion-icon [name]="resolvedProps.separatorIcon" slot="separator"></ion-icon>
20193
+ <ion-icon [name]="resolvedProps.separatorIcon" slot="separator" aria-hidden="true"></ion-icon>
20122
20194
  }
20123
20195
  </ion-breadcrumb>
20124
20196
  }
@@ -20489,9 +20561,7 @@ class StepperComponent {
20489
20561
  }
20490
20562
  }
20491
20563
  resolveProps() {
20492
- const presetProps = this.preset
20493
- ? this.presets.get('stepper', this.preset)
20494
- : {};
20564
+ const presetProps = this.preset ? this.presets.get('stepper', this.preset) : {};
20495
20565
  this.resolvedProps = {
20496
20566
  ...presetProps,
20497
20567
  ...this.props,
@@ -20502,7 +20572,7 @@ class StepperComponent {
20502
20572
  return this.resolvedProps.currentIndex;
20503
20573
  }
20504
20574
  if (this.resolvedProps.currentStep) {
20505
- return this.resolvedProps.steps?.findIndex((s) => s.value === this.resolvedProps.currentStep) ?? 0;
20575
+ return this.resolvedProps.steps?.findIndex(s => s.value === this.resolvedProps.currentStep) ?? 0;
20506
20576
  }
20507
20577
  return 0;
20508
20578
  }
@@ -20577,15 +20647,15 @@ class StepperComponent {
20577
20647
  <div class="step-indicator">
20578
20648
  <div class="step-circle" [style.--step-color]="getStepColor(step, i)">
20579
20649
  @if (getStepStatus(step, i) === 'completed') {
20580
- <ion-icon name="checkmark"></ion-icon>
20650
+ <ion-icon name="checkmark" aria-hidden="true"></ion-icon>
20581
20651
  } @else if (getStepStatus(step, i) === 'error') {
20582
- <ion-icon name="close"></ion-icon>
20652
+ <ion-icon name="close" aria-hidden="true"></ion-icon>
20583
20653
  } @else if (step.icon) {
20584
- <ion-icon [name]="step.icon"></ion-icon>
20654
+ <ion-icon [name]="step.icon" aria-hidden="true"></ion-icon>
20585
20655
  } @else if (resolvedProps.showNumbers !== false) {
20586
20656
  <span class="step-number">{{ i + 1 }}</span>
20587
20657
  } @else {
20588
- <ion-icon name="ellipse"></ion-icon>
20658
+ <ion-icon name="ellipse" aria-hidden="true"></ion-icon>
20589
20659
  }
20590
20660
  </div>
20591
20661
  @if (!isLast && resolvedProps.connectorStyle !== 'none') {
@@ -20637,15 +20707,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
20637
20707
  <div class="step-indicator">
20638
20708
  <div class="step-circle" [style.--step-color]="getStepColor(step, i)">
20639
20709
  @if (getStepStatus(step, i) === 'completed') {
20640
- <ion-icon name="checkmark"></ion-icon>
20710
+ <ion-icon name="checkmark" aria-hidden="true"></ion-icon>
20641
20711
  } @else if (getStepStatus(step, i) === 'error') {
20642
- <ion-icon name="close"></ion-icon>
20712
+ <ion-icon name="close" aria-hidden="true"></ion-icon>
20643
20713
  } @else if (step.icon) {
20644
- <ion-icon [name]="step.icon"></ion-icon>
20714
+ <ion-icon [name]="step.icon" aria-hidden="true"></ion-icon>
20645
20715
  } @else if (resolvedProps.showNumbers !== false) {
20646
20716
  <span class="step-number">{{ i + 1 }}</span>
20647
20717
  } @else {
20648
- <ion-icon name="ellipse"></ion-icon>
20718
+ <ion-icon name="ellipse" aria-hidden="true"></ion-icon>
20649
20719
  }
20650
20720
  </div>
20651
20721
  @if (!isLast && resolvedProps.connectorStyle !== 'none') {
@@ -20746,9 +20816,7 @@ class ChipGroupComponent {
20746
20816
  }
20747
20817
  }
20748
20818
  resolveProps() {
20749
- const presetProps = this.preset
20750
- ? this.presets.get('chipGroup', this.preset)
20751
- : {};
20819
+ const presetProps = this.preset ? this.presets.get('chipGroup', this.preset) : {};
20752
20820
  this.resolvedProps = {
20753
20821
  ...presetProps,
20754
20822
  ...this.props,
@@ -20774,7 +20842,7 @@ class ChipGroupComponent {
20774
20842
  }
20775
20843
  else {
20776
20844
  // Single selection: deselect all others
20777
- this.resolvedProps.chips.forEach((c) => {
20845
+ this.resolvedProps.chips.forEach(c => {
20778
20846
  c.selected = c.value === chip.value ? !c.selected : false;
20779
20847
  });
20780
20848
  }
@@ -20792,8 +20860,8 @@ class ChipGroupComponent {
20792
20860
  }
20793
20861
  }
20794
20862
  emitSelectionChange() {
20795
- const selected = this.resolvedProps.chips.filter((c) => c.selected);
20796
- const values = selected.map((c) => c.value);
20863
+ const selected = this.resolvedProps.chips.filter(c => c.selected);
20864
+ const values = selected.map(c => c.value);
20797
20865
  this.selectionChange.emit({
20798
20866
  selected: this.resolvedProps.multiple ? selected : selected[0],
20799
20867
  values: this.resolvedProps.multiple ? values : values[0],
@@ -20815,14 +20883,19 @@ class ChipGroupComponent {
20815
20883
  (keydown.space)="onChipKey($event, chip)"
20816
20884
  >
20817
20885
  @if (chip.icon) {
20818
- <ion-icon [name]="chip.icon"></ion-icon>
20886
+ <ion-icon [name]="chip.icon" aria-hidden="true"></ion-icon>
20819
20887
  }
20820
20888
  @if (chip.selected && resolvedProps.selectable) {
20821
- <ion-icon name="checkmark" class="selected-icon"></ion-icon>
20889
+ <ion-icon name="checkmark" class="selected-icon" aria-hidden="true"></ion-icon>
20822
20890
  }
20823
20891
  <ion-label>{{ getChipLabel(chip) }}</ion-label>
20824
20892
  @if (resolvedProps.removable && !chip.disabled) {
20825
- <button type="button" class="remove-button" [attr.aria-label]="removeLabel(chip)" (click)="onRemoveChip($event, chip)">
20893
+ <button
20894
+ type="button"
20895
+ class="remove-button"
20896
+ [attr.aria-label]="removeLabel(chip)"
20897
+ (click)="onRemoveChip($event, chip)"
20898
+ >
20826
20899
  <ion-icon name="close" class="remove-icon" aria-hidden="true"></ion-icon>
20827
20900
  </button>
20828
20901
  }
@@ -20848,14 +20921,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
20848
20921
  (keydown.space)="onChipKey($event, chip)"
20849
20922
  >
20850
20923
  @if (chip.icon) {
20851
- <ion-icon [name]="chip.icon"></ion-icon>
20924
+ <ion-icon [name]="chip.icon" aria-hidden="true"></ion-icon>
20852
20925
  }
20853
20926
  @if (chip.selected && resolvedProps.selectable) {
20854
- <ion-icon name="checkmark" class="selected-icon"></ion-icon>
20927
+ <ion-icon name="checkmark" class="selected-icon" aria-hidden="true"></ion-icon>
20855
20928
  }
20856
20929
  <ion-label>{{ getChipLabel(chip) }}</ion-label>
20857
20930
  @if (resolvedProps.removable && !chip.disabled) {
20858
- <button type="button" class="remove-button" [attr.aria-label]="removeLabel(chip)" (click)="onRemoveChip($event, chip)">
20931
+ <button
20932
+ type="button"
20933
+ class="remove-button"
20934
+ [attr.aria-label]="removeLabel(chip)"
20935
+ (click)="onRemoveChip($event, chip)"
20936
+ >
20859
20937
  <ion-icon name="close" class="remove-icon" aria-hidden="true"></ion-icon>
20860
20938
  </button>
20861
20939
  }
@@ -21326,7 +21404,7 @@ class StatsCardComponent {
21326
21404
  <div class="stats-header">
21327
21405
  <span class="stats-title">{{ resolvedProps.title }}</span>
21328
21406
  @if (resolvedProps.icon) {
21329
- <ion-icon [name]="resolvedProps.icon" class="stats-icon"></ion-icon>
21407
+ <ion-icon [name]="resolvedProps.icon" class="stats-icon" aria-hidden="true"></ion-icon>
21330
21408
  }
21331
21409
  </div>
21332
21410
 
@@ -21346,7 +21424,7 @@ class StatsCardComponent {
21346
21424
 
21347
21425
  @if (resolvedProps.trend && !resolvedProps.loading) {
21348
21426
  <div class="stats-trend" [class]="getTrendClass()">
21349
- <ion-icon [name]="getTrendIcon()"></ion-icon>
21427
+ <ion-icon [name]="getTrendIcon()" aria-hidden="true"></ion-icon>
21350
21428
  <span class="trend-value">{{ Math.abs(resolvedProps.trend.value) }}%</span>
21351
21429
  @if (resolvedProps.trend.label) {
21352
21430
  <span class="trend-label">{{ resolvedProps.trend.label }}</span>
@@ -21390,7 +21468,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21390
21468
  <div class="stats-header">
21391
21469
  <span class="stats-title">{{ resolvedProps.title }}</span>
21392
21470
  @if (resolvedProps.icon) {
21393
- <ion-icon [name]="resolvedProps.icon" class="stats-icon"></ion-icon>
21471
+ <ion-icon [name]="resolvedProps.icon" class="stats-icon" aria-hidden="true"></ion-icon>
21394
21472
  }
21395
21473
  </div>
21396
21474
 
@@ -21410,7 +21488,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21410
21488
 
21411
21489
  @if (resolvedProps.trend && !resolvedProps.loading) {
21412
21490
  <div class="stats-trend" [class]="getTrendClass()">
21413
- <ion-icon [name]="getTrendIcon()"></ion-icon>
21491
+ <ion-icon [name]="getTrendIcon()" aria-hidden="true"></ion-icon>
21414
21492
  <span class="trend-value">{{ Math.abs(resolvedProps.trend.value) }}%</span>
21415
21493
  @if (resolvedProps.trend.label) {
21416
21494
  <span class="trend-label">{{ resolvedProps.trend.label }}</span>
@@ -21540,7 +21618,7 @@ class CommentComponent {
21540
21618
  getInitials(name) {
21541
21619
  return name
21542
21620
  .split(' ')
21543
- .map((n) => n[0])
21621
+ .map(n => n[0])
21544
21622
  .join('')
21545
21623
  .substring(0, 2)
21546
21624
  .toUpperCase();
@@ -21625,8 +21703,8 @@ class CommentComponent {
21625
21703
  return item.label || item.contentFallback || '';
21626
21704
  }
21627
21705
  hasChildren() {
21628
- return !!(this.props.children && this.props.children.length > 0) ||
21629
- !!(this.props.replyCount && this.props.replyCount > 0);
21706
+ return (!!(this.props.children && this.props.children.length > 0) ||
21707
+ !!(this.props.replyCount && this.props.replyCount > 0));
21630
21708
  }
21631
21709
  canShowChildren() {
21632
21710
  const maxDepth = this.props.maxDepth ?? 3;
@@ -21699,7 +21777,7 @@ class CommentComponent {
21699
21777
  >
21700
21778
  @if (props.pinned) {
21701
21779
  <div class="pinned-indicator">
21702
- <ion-icon name="pin"></ion-icon>
21780
+ <ion-icon name="pin" aria-hidden="true"></ion-icon>
21703
21781
  <span>{{ i18n.t('pinned') }}</span>
21704
21782
  </div>
21705
21783
  }
@@ -21720,7 +21798,7 @@ class CommentComponent {
21720
21798
  <button type="button" class="author-info" [attr.aria-label]="authorLabel()" (click)="onAuthorClick()">
21721
21799
  <span class="author-name">{{ props.author.name }}</span>
21722
21800
  @if (props.author.verified) {
21723
- <ion-icon name="checkmark-circle" class="verified-badge"></ion-icon>
21801
+ <ion-icon name="checkmark-circle" class="verified-badge" aria-hidden="true"></ion-icon>
21724
21802
  }
21725
21803
  @if (props.author.username) {
21726
21804
  <span class="author-username">&#64;{{ props.author.username }}</span>
@@ -21740,14 +21818,12 @@ class CommentComponent {
21740
21818
  size="small"
21741
21819
  class="more-button"
21742
21820
  [id]="'menu-trigger-' + props.token"
21821
+ [attr.aria-label]="'Más opciones'"
21743
21822
  >
21744
- <ion-icon name="ellipsis-horizontal" slot="icon-only"></ion-icon>
21823
+ <ion-icon name="ellipsis-horizontal" slot="icon-only" aria-hidden="true"></ion-icon>
21745
21824
  </ion-button>
21746
21825
 
21747
- <ion-popover
21748
- [trigger]="'menu-trigger-' + props.token"
21749
- [dismissOnSelect]="true"
21750
- >
21826
+ <ion-popover [trigger]="'menu-trigger-' + props.token" [dismissOnSelect]="true">
21751
21827
  <ng-template>
21752
21828
  <ion-list>
21753
21829
  @for (item of props.menuItems; track item.token) {
@@ -21761,11 +21837,7 @@ class CommentComponent {
21761
21837
  (click)="onMenuItemClick(item)"
21762
21838
  >
21763
21839
  @if (item.icon) {
21764
- <ion-icon
21765
- [name]="item.icon"
21766
- slot="start"
21767
- [color]="item.color"
21768
- ></ion-icon>
21840
+ <ion-icon [name]="item.icon" slot="start" [color]="item.color" aria-hidden="true"></ion-icon>
21769
21841
  }
21770
21842
  <ion-label [color]="item.color">
21771
21843
  {{ getMenuItemLabel(item) }}
@@ -21779,10 +21851,7 @@ class CommentComponent {
21779
21851
  </div>
21780
21852
 
21781
21853
  @if (!props.collapsed) {
21782
- <div
21783
- class="comment-content"
21784
- [innerHTML]="processContent(displayContent)"
21785
- ></div>
21854
+ <div class="comment-content" [innerHTML]="processContent(displayContent)"></div>
21786
21855
 
21787
21856
  @if (props.reactions && props.reactions.length > 0) {
21788
21857
  <div class="comment-reactions">
@@ -21793,7 +21862,7 @@ class CommentComponent {
21793
21862
  [style.--reaction-color]="getReactionColor(reaction)"
21794
21863
  (click)="onReactionClick(reaction)"
21795
21864
  >
21796
- <ion-icon [name]="reaction.icon"></ion-icon>
21865
+ <ion-icon [name]="reaction.icon" aria-hidden="true"></ion-icon>
21797
21866
  @if (reaction.count > 0) {
21798
21867
  <span class="reaction-count">{{ formatCount(reaction.count) }}</span>
21799
21868
  }
@@ -21813,7 +21882,7 @@ class CommentComponent {
21813
21882
  (click)="onActionClick(action)"
21814
21883
  >
21815
21884
  @if (action.icon) {
21816
- <ion-icon [name]="action.icon" slot="start"></ion-icon>
21885
+ <ion-icon [name]="action.icon" slot="start" aria-hidden="true"></ion-icon>
21817
21886
  }
21818
21887
  {{ getActionLabel(action) }}
21819
21888
  </ion-button>
@@ -21822,7 +21891,7 @@ class CommentComponent {
21822
21891
  }
21823
21892
  } @else {
21824
21893
  <button class="expand-button" (click)="onToggleCollapse()">
21825
- <ion-icon name="chevron-down"></ion-icon>
21894
+ <ion-icon name="chevron-down" aria-hidden="true"></ion-icon>
21826
21895
  <span>{{ i18n.t('showComment') }}</span>
21827
21896
  </button>
21828
21897
  }
@@ -21833,7 +21902,7 @@ class CommentComponent {
21833
21902
  <div class="comment-children">
21834
21903
  @if (props.collapsed) {
21835
21904
  <button class="collapse-button" (click)="onToggleCollapse()">
21836
- <ion-icon name="chevron-up"></ion-icon>
21905
+ <ion-icon name="chevron-up" aria-hidden="true"></ion-icon>
21837
21906
  <span>{{ i18n.t('hideReplies') }}</span>
21838
21907
  </button>
21839
21908
  }
@@ -21853,13 +21922,13 @@ class CommentComponent {
21853
21922
 
21854
21923
  @if (hasMoreReplies()) {
21855
21924
  <button class="load-more-button" (click)="onLoadMoreClick()">
21856
- <ion-icon name="chatbubble-outline"></ion-icon>
21925
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
21857
21926
  <span>{{ getLoadMoreRepliesText() }}</span>
21858
21927
  </button>
21859
21928
  }
21860
21929
  } @else {
21861
21930
  <button class="view-replies-button" (click)="onLoadMoreClick()">
21862
- <ion-icon name="chatbubble-outline"></ion-icon>
21931
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
21863
21932
  <span>{{ getViewRepliesText() }}</span>
21864
21933
  </button>
21865
21934
  }
@@ -21870,16 +21939,7 @@ class CommentComponent {
21870
21939
  }
21871
21940
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CommentComponent, decorators: [{
21872
21941
  type: Component,
21873
- args: [{ selector: 'val-comment', standalone: true, imports: [
21874
- CommonModule,
21875
- IonIcon,
21876
- IonButton,
21877
- IonPopover,
21878
- IonList,
21879
- IonItem,
21880
- IonLabel,
21881
- AvatarComponent,
21882
- ], template: `
21942
+ args: [{ selector: 'val-comment', standalone: true, imports: [CommonModule, IonIcon, IonButton, IonPopover, IonList, IonItem, IonLabel, AvatarComponent], template: `
21883
21943
  <div
21884
21944
  class="comment"
21885
21945
  [class.highlighted]="props.highlighted"
@@ -21889,7 +21949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21889
21949
  >
21890
21950
  @if (props.pinned) {
21891
21951
  <div class="pinned-indicator">
21892
- <ion-icon name="pin"></ion-icon>
21952
+ <ion-icon name="pin" aria-hidden="true"></ion-icon>
21893
21953
  <span>{{ i18n.t('pinned') }}</span>
21894
21954
  </div>
21895
21955
  }
@@ -21910,7 +21970,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21910
21970
  <button type="button" class="author-info" [attr.aria-label]="authorLabel()" (click)="onAuthorClick()">
21911
21971
  <span class="author-name">{{ props.author.name }}</span>
21912
21972
  @if (props.author.verified) {
21913
- <ion-icon name="checkmark-circle" class="verified-badge"></ion-icon>
21973
+ <ion-icon name="checkmark-circle" class="verified-badge" aria-hidden="true"></ion-icon>
21914
21974
  }
21915
21975
  @if (props.author.username) {
21916
21976
  <span class="author-username">&#64;{{ props.author.username }}</span>
@@ -21930,14 +21990,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21930
21990
  size="small"
21931
21991
  class="more-button"
21932
21992
  [id]="'menu-trigger-' + props.token"
21993
+ [attr.aria-label]="'Más opciones'"
21933
21994
  >
21934
- <ion-icon name="ellipsis-horizontal" slot="icon-only"></ion-icon>
21995
+ <ion-icon name="ellipsis-horizontal" slot="icon-only" aria-hidden="true"></ion-icon>
21935
21996
  </ion-button>
21936
21997
 
21937
- <ion-popover
21938
- [trigger]="'menu-trigger-' + props.token"
21939
- [dismissOnSelect]="true"
21940
- >
21998
+ <ion-popover [trigger]="'menu-trigger-' + props.token" [dismissOnSelect]="true">
21941
21999
  <ng-template>
21942
22000
  <ion-list>
21943
22001
  @for (item of props.menuItems; track item.token) {
@@ -21951,11 +22009,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21951
22009
  (click)="onMenuItemClick(item)"
21952
22010
  >
21953
22011
  @if (item.icon) {
21954
- <ion-icon
21955
- [name]="item.icon"
21956
- slot="start"
21957
- [color]="item.color"
21958
- ></ion-icon>
22012
+ <ion-icon [name]="item.icon" slot="start" [color]="item.color" aria-hidden="true"></ion-icon>
21959
22013
  }
21960
22014
  <ion-label [color]="item.color">
21961
22015
  {{ getMenuItemLabel(item) }}
@@ -21969,10 +22023,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21969
22023
  </div>
21970
22024
 
21971
22025
  @if (!props.collapsed) {
21972
- <div
21973
- class="comment-content"
21974
- [innerHTML]="processContent(displayContent)"
21975
- ></div>
22026
+ <div class="comment-content" [innerHTML]="processContent(displayContent)"></div>
21976
22027
 
21977
22028
  @if (props.reactions && props.reactions.length > 0) {
21978
22029
  <div class="comment-reactions">
@@ -21983,7 +22034,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21983
22034
  [style.--reaction-color]="getReactionColor(reaction)"
21984
22035
  (click)="onReactionClick(reaction)"
21985
22036
  >
21986
- <ion-icon [name]="reaction.icon"></ion-icon>
22037
+ <ion-icon [name]="reaction.icon" aria-hidden="true"></ion-icon>
21987
22038
  @if (reaction.count > 0) {
21988
22039
  <span class="reaction-count">{{ formatCount(reaction.count) }}</span>
21989
22040
  }
@@ -22003,7 +22054,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22003
22054
  (click)="onActionClick(action)"
22004
22055
  >
22005
22056
  @if (action.icon) {
22006
- <ion-icon [name]="action.icon" slot="start"></ion-icon>
22057
+ <ion-icon [name]="action.icon" slot="start" aria-hidden="true"></ion-icon>
22007
22058
  }
22008
22059
  {{ getActionLabel(action) }}
22009
22060
  </ion-button>
@@ -22012,7 +22063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22012
22063
  }
22013
22064
  } @else {
22014
22065
  <button class="expand-button" (click)="onToggleCollapse()">
22015
- <ion-icon name="chevron-down"></ion-icon>
22066
+ <ion-icon name="chevron-down" aria-hidden="true"></ion-icon>
22016
22067
  <span>{{ i18n.t('showComment') }}</span>
22017
22068
  </button>
22018
22069
  }
@@ -22023,7 +22074,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22023
22074
  <div class="comment-children">
22024
22075
  @if (props.collapsed) {
22025
22076
  <button class="collapse-button" (click)="onToggleCollapse()">
22026
- <ion-icon name="chevron-up"></ion-icon>
22077
+ <ion-icon name="chevron-up" aria-hidden="true"></ion-icon>
22027
22078
  <span>{{ i18n.t('hideReplies') }}</span>
22028
22079
  </button>
22029
22080
  }
@@ -22043,13 +22094,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22043
22094
 
22044
22095
  @if (hasMoreReplies()) {
22045
22096
  <button class="load-more-button" (click)="onLoadMoreClick()">
22046
- <ion-icon name="chatbubble-outline"></ion-icon>
22097
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
22047
22098
  <span>{{ getLoadMoreRepliesText() }}</span>
22048
22099
  </button>
22049
22100
  }
22050
22101
  } @else {
22051
22102
  <button class="view-replies-button" (click)="onLoadMoreClick()">
22052
- <ion-icon name="chatbubble-outline"></ion-icon>
22103
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
22053
22104
  <span>{{ getViewRepliesText() }}</span>
22054
22105
  </button>
22055
22106
  }
@@ -23882,7 +23933,7 @@ class DateRangeInputComponent {
23882
23933
 
23883
23934
  <!-- Separator -->
23884
23935
  <div class="date-separator">
23885
- <ion-icon name="arrow-forward-outline"></ion-icon>
23936
+ <ion-icon name="arrow-forward-outline" aria-hidden="true"></ion-icon>
23886
23937
  </div>
23887
23938
 
23888
23939
  <!-- End Date -->
@@ -23916,9 +23967,7 @@ class DateRangeInputComponent {
23916
23967
  </div>
23917
23968
 
23918
23969
  @if (showDayCount && dayCount !== null) {
23919
- <div class="day-count">
23920
- {{ dayCount }} {{ getDayLabel() }}
23921
- </div>
23970
+ <div class="day-count">{{ dayCount }} {{ getDayLabel() }}</div>
23922
23971
  }
23923
23972
 
23924
23973
  @if (props.hint && !hasError) {
@@ -23980,7 +24029,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
23980
24029
 
23981
24030
  <!-- Separator -->
23982
24031
  <div class="date-separator">
23983
- <ion-icon name="arrow-forward-outline"></ion-icon>
24032
+ <ion-icon name="arrow-forward-outline" aria-hidden="true"></ion-icon>
23984
24033
  </div>
23985
24034
 
23986
24035
  <!-- End Date -->
@@ -24014,9 +24063,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24014
24063
  </div>
24015
24064
 
24016
24065
  @if (showDayCount && dayCount !== null) {
24017
- <div class="day-count">
24018
- {{ dayCount }} {{ getDayLabel() }}
24019
- </div>
24066
+ <div class="day-count">{{ dayCount }} {{ getDayLabel() }}</div>
24020
24067
  }
24021
24068
 
24022
24069
  @if (props.hint && !hasError) {
@@ -24098,11 +24145,11 @@ class NumberStepperComponent {
24098
24145
  }
24099
24146
  /** Get decrement button aria-label with i18n fallback */
24100
24147
  getDecrementLabel() {
24101
- return this.props.decrementLabel || this.i18n.t('decrease');
24148
+ return this.props.decrementLabel || this.i18n.t('decrease') || 'Disminuir';
24102
24149
  }
24103
24150
  /** Get increment button aria-label with i18n fallback */
24104
24151
  getIncrementLabel() {
24105
- return this.props.incrementLabel || this.i18n.t('increase');
24152
+ return this.props.incrementLabel || this.i18n.t('increase') || 'Aumentar';
24106
24153
  }
24107
24154
  ngOnInit() {
24108
24155
  // Ensure initial value is within bounds
@@ -24246,7 +24293,7 @@ class NumberStepperComponent {
24246
24293
  (click)="decrement()"
24247
24294
  [attr.aria-label]="getDecrementLabel()"
24248
24295
  >
24249
- <ion-icon slot="icon-only" name="remove-outline"></ion-icon>
24296
+ <ion-icon slot="icon-only" name="remove-outline" aria-hidden="true"></ion-icon>
24250
24297
  </ion-button>
24251
24298
 
24252
24299
  <div class="value-display">
@@ -24279,16 +24326,14 @@ class NumberStepperComponent {
24279
24326
  (click)="increment()"
24280
24327
  [attr.aria-label]="getIncrementLabel()"
24281
24328
  >
24282
- <ion-icon slot="icon-only" name="add-outline"></ion-icon>
24329
+ <ion-icon slot="icon-only" name="add-outline" aria-hidden="true"></ion-icon>
24283
24330
  </ion-button>
24284
24331
  </div>
24285
24332
 
24286
24333
  <!-- Price display -->
24287
24334
  @if (props.showTotal && props.unitPrice) {
24288
24335
  <div class="price-display">
24289
- <span class="price-calculation">
24290
- {{ currentValue }} × {{ formatPrice(props.unitPrice) }}
24291
- </span>
24336
+ <span class="price-calculation"> {{ currentValue }} × {{ formatPrice(props.unitPrice) }} </span>
24292
24337
  <span class="price-equals">=</span>
24293
24338
  <span class="price-total">{{ formatPrice(totalPrice) }}</span>
24294
24339
  </div>
@@ -24346,7 +24391,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24346
24391
  (click)="decrement()"
24347
24392
  [attr.aria-label]="getDecrementLabel()"
24348
24393
  >
24349
- <ion-icon slot="icon-only" name="remove-outline"></ion-icon>
24394
+ <ion-icon slot="icon-only" name="remove-outline" aria-hidden="true"></ion-icon>
24350
24395
  </ion-button>
24351
24396
 
24352
24397
  <div class="value-display">
@@ -24379,16 +24424,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24379
24424
  (click)="increment()"
24380
24425
  [attr.aria-label]="getIncrementLabel()"
24381
24426
  >
24382
- <ion-icon slot="icon-only" name="add-outline"></ion-icon>
24427
+ <ion-icon slot="icon-only" name="add-outline" aria-hidden="true"></ion-icon>
24383
24428
  </ion-button>
24384
24429
  </div>
24385
24430
 
24386
24431
  <!-- Price display -->
24387
24432
  @if (props.showTotal && props.unitPrice) {
24388
24433
  <div class="price-display">
24389
- <span class="price-calculation">
24390
- {{ currentValue }} × {{ formatPrice(props.unitPrice) }}
24391
- </span>
24434
+ <span class="price-calculation"> {{ currentValue }} × {{ formatPrice(props.unitPrice) }} </span>
24392
24435
  <span class="price-equals">=</span>
24393
24436
  <span class="price-total">{{ formatPrice(totalPrice) }}</span>
24394
24437
  </div>
@@ -24703,6 +24746,7 @@ class ShareButtonsComponent {
24703
24746
  <ion-icon
24704
24747
  [slot]="props.showLabels === false || props.variant === 'icon-only' ? 'icon-only' : 'start'"
24705
24748
  [name]="getButtonIcon(button)"
24749
+ aria-hidden="true"
24706
24750
  ></ion-icon>
24707
24751
  @if (props.showLabels !== false && props.variant !== 'icon-only') {
24708
24752
  {{ getButtonLabel(button) }}
@@ -24744,6 +24788,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24744
24788
  <ion-icon
24745
24789
  [slot]="props.showLabels === false || props.variant === 'icon-only' ? 'icon-only' : 'start'"
24746
24790
  [name]="getButtonIcon(button)"
24791
+ aria-hidden="true"
24747
24792
  ></ion-icon>
24748
24793
  @if (props.showLabels !== false && props.variant !== 'icon-only') {
24749
24794
  {{ getButtonLabel(button) }}
@@ -24794,9 +24839,7 @@ class GlowCardComponent {
24794
24839
  }
24795
24840
  }
24796
24841
  resolveProps() {
24797
- const presetProps = this.preset
24798
- ? this.presets.get('glowCard', this.preset)
24799
- : {};
24842
+ const presetProps = this.preset ? this.presets.get('glowCard', this.preset) : {};
24800
24843
  this.resolvedProps = {
24801
24844
  ...presetProps,
24802
24845
  ...this.props,
@@ -24810,7 +24853,17 @@ class GlowCardComponent {
24810
24853
  this.i18n = inject(I18nService);
24811
24854
  this.navigationService = inject(NavigationService);
24812
24855
  this.themeService = inject(ThemeService);
24813
- this.ionicColors = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
24856
+ this.ionicColors = [
24857
+ 'primary',
24858
+ 'secondary',
24859
+ 'tertiary',
24860
+ 'success',
24861
+ 'warning',
24862
+ 'danger',
24863
+ 'light',
24864
+ 'medium',
24865
+ 'dark',
24866
+ ];
24814
24867
  // RGB values with SPACE separator for CSS rgb(var() / alpha) syntax
24815
24868
  this.colorRgbMap = {
24816
24869
  primary: '112 38 223',
@@ -24980,11 +25033,13 @@ class GlowCardComponent {
24980
25033
  class="glow-card__cta"
24981
25034
  [href]="resolvedProps.cta?.url"
24982
25035
  (click)="onCtaClick($event)"
25036
+ [attr.aria-label]="getCtaText() || resolvedProps.cta?.text || 'Ver más'"
24983
25037
  >
24984
25038
  <span class="glow-card__cta-text">{{ getCtaText() }}</span>
24985
25039
  <ion-icon
24986
25040
  class="glow-card__cta-icon"
24987
25041
  [name]="resolvedProps.cta?.icon || 'arrow-forward-outline'"
25042
+ aria-hidden="true"
24988
25043
  ></ion-icon>
24989
25044
  </a>
24990
25045
  </div>
@@ -25044,11 +25099,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25044
25099
  class="glow-card__cta"
25045
25100
  [href]="resolvedProps.cta?.url"
25046
25101
  (click)="onCtaClick($event)"
25102
+ [attr.aria-label]="getCtaText() || resolvedProps.cta?.text || 'Ver más'"
25047
25103
  >
25048
25104
  <span class="glow-card__cta-text">{{ getCtaText() }}</span>
25049
25105
  <ion-icon
25050
25106
  class="glow-card__cta-icon"
25051
25107
  [name]="resolvedProps.cta?.icon || 'arrow-forward-outline'"
25108
+ aria-hidden="true"
25052
25109
  ></ion-icon>
25053
25110
  </a>
25054
25111
  </div>
@@ -25574,7 +25631,7 @@ class FeaturesListComponent {
25574
25631
  <path [attr.d]="feature.svgPath" />
25575
25632
  </svg>
25576
25633
  } @else if (feature.icon) {
25577
- <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize"></ion-icon>
25634
+ <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize" aria-hidden="true"></ion-icon>
25578
25635
  }
25579
25636
  </div>
25580
25637
  <div class="feature__content">
@@ -25611,7 +25668,7 @@ class FeaturesListComponent {
25611
25668
  <path [attr.d]="feature.svgPath" />
25612
25669
  </svg>
25613
25670
  } @else if (feature.icon) {
25614
- <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize"></ion-icon>
25671
+ <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize" aria-hidden="true"></ion-icon>
25615
25672
  }
25616
25673
  </div>
25617
25674
  <div class="feature__content">
@@ -25683,7 +25740,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25683
25740
  <path [attr.d]="feature.svgPath" />
25684
25741
  </svg>
25685
25742
  } @else if (feature.icon) {
25686
- <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize"></ion-icon>
25743
+ <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize" aria-hidden="true"></ion-icon>
25687
25744
  }
25688
25745
  </div>
25689
25746
  <div class="feature__content">
@@ -25720,7 +25777,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25720
25777
  <path [attr.d]="feature.svgPath" />
25721
25778
  </svg>
25722
25779
  } @else if (feature.icon) {
25723
- <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize"></ion-icon>
25780
+ <ion-icon [name]="feature.icon" [style.font-size.px]="config().iconSize" aria-hidden="true"></ion-icon>
25724
25781
  }
25725
25782
  </div>
25726
25783
  <div class="feature__content">
@@ -25889,7 +25946,12 @@ class FooterLinksComponent {
25889
25946
  class="social-button"
25890
25947
  [attr.aria-label]="social.name"
25891
25948
  >
25892
- <ion-icon [name]="social.icon" slot="icon-only" [color]="props.socialIconColor || 'dark'"></ion-icon>
25949
+ <ion-icon
25950
+ [name]="social.icon"
25951
+ slot="icon-only"
25952
+ [color]="props.socialIconColor || 'dark'"
25953
+ aria-hidden="true"
25954
+ ></ion-icon>
25893
25955
  </ion-button>
25894
25956
  </div>
25895
25957
  </div>
@@ -25952,7 +26014,12 @@ class FooterLinksComponent {
25952
26014
  class="social-button"
25953
26015
  [attr.aria-label]="social.name"
25954
26016
  >
25955
- <ion-icon [name]="social.icon" slot="icon-only" [color]="props.socialIconColor || 'dark'"></ion-icon>
26017
+ <ion-icon
26018
+ [name]="social.icon"
26019
+ slot="icon-only"
26020
+ [color]="props.socialIconColor || 'dark'"
26021
+ aria-hidden="true"
26022
+ ></ion-icon>
25956
26023
  </ion-button>
25957
26024
  </div>
25958
26025
  </div>
@@ -26056,7 +26123,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26056
26123
  class="social-button"
26057
26124
  [attr.aria-label]="social.name"
26058
26125
  >
26059
- <ion-icon [name]="social.icon" slot="icon-only" [color]="props.socialIconColor || 'dark'"></ion-icon>
26126
+ <ion-icon
26127
+ [name]="social.icon"
26128
+ slot="icon-only"
26129
+ [color]="props.socialIconColor || 'dark'"
26130
+ aria-hidden="true"
26131
+ ></ion-icon>
26060
26132
  </ion-button>
26061
26133
  </div>
26062
26134
  </div>
@@ -26119,7 +26191,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26119
26191
  class="social-button"
26120
26192
  [attr.aria-label]="social.name"
26121
26193
  >
26122
- <ion-icon [name]="social.icon" slot="icon-only" [color]="props.socialIconColor || 'dark'"></ion-icon>
26194
+ <ion-icon
26195
+ [name]="social.icon"
26196
+ slot="icon-only"
26197
+ [color]="props.socialIconColor || 'dark'"
26198
+ aria-hidden="true"
26199
+ ></ion-icon>
26123
26200
  </ion-button>
26124
26201
  </div>
26125
26202
  </div>
@@ -27559,7 +27636,7 @@ class ActionCardComponent {
27559
27636
  }
27560
27637
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27561
27638
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ActionCardComponent, isStandalone: true, selector: "val-action-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
27562
- <article
27639
+ <div
27563
27640
  class="action-card"
27564
27641
  [class.action-card--small]="config().size === 'small'"
27565
27642
  [class.action-card--medium]="config().size === 'medium'"
@@ -27592,7 +27669,7 @@ class ActionCardComponent {
27592
27669
  <!-- Icon Container -->
27593
27670
  <div class="action-card__icon" [style.color]="getIconColor()" [style.background-color]="getIconBackgroundColor()">
27594
27671
  @if (config().icon?.ionicon) {
27595
- <ion-icon [name]="config().icon!.ionicon!"></ion-icon>
27672
+ <ion-icon [name]="config().icon!.ionicon!" aria-hidden="true"></ion-icon>
27596
27673
  } @else if (config().icon?.svgPath) {
27597
27674
  <svg
27598
27675
  viewBox="0 0 24 24"
@@ -27619,15 +27696,15 @@ class ActionCardComponent {
27619
27696
 
27620
27697
  <!-- Chevron (optional) -->
27621
27698
  @if (config().showChevron && !config().disabled) {
27622
- <ion-icon name="chevron-forward-outline" class="action-card__chevron"></ion-icon>
27699
+ <ion-icon name="chevron-forward-outline" class="action-card__chevron" aria-hidden="true"></ion-icon>
27623
27700
  }
27624
- </article>
27701
+ </div>
27625
27702
  `, isInline: true, styles: [":host{display:flex;flex-direction:column}.action-card{position:relative;display:flex;align-items:center;flex:1;gap:1rem;padding:1rem;background:var(--card-bg, var(--ion-card-background, var(--ion-background-color)));border-radius:12px;cursor:pointer;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease;text-decoration:none;overflow:hidden;--ripple-color: var(--ion-color-primary)}.action-card--small{padding:.75rem;gap:.75rem}.action-card--small .action-card__icon{width:36px;height:36px;font-size:1.125rem;border-radius:8px}.action-card--small .action-card__icon svg{width:18px;height:18px}.action-card--small .action-card__title{font-size:.9rem}.action-card--small .action-card__description{font-size:.8rem}.action-card--medium{padding:1rem;gap:1rem}.action-card--medium .action-card__icon{width:48px;height:48px;font-size:1.5rem;border-radius:10px}.action-card--medium .action-card__icon svg{width:24px;height:24px}.action-card--medium .action-card__title{font-size:1rem}.action-card--medium .action-card__description{font-size:.875rem}.action-card--large{padding:1.25rem;gap:1.25rem}.action-card--large .action-card__icon{width:56px;height:56px;font-size:1.75rem;border-radius:12px}.action-card--large .action-card__icon svg{width:28px;height:28px}.action-card--large .action-card__title{font-size:1.1rem}.action-card--large .action-card__description{font-size:.9rem}.action-card--bordered{border:1px solid var(--card-border-color, var(--ion-color-light-shade))}.action-card--shadowed{box-shadow:0 2px 8px #00000014}.action-card--clickable:hover{transform:translateY(-2px);box-shadow:0 4px 16px #0000001f}.action-card--clickable:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.action-card--clickable:active{transform:translateY(0)}.action-card--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.action-card__badge{position:absolute;top:8px;right:8px;padding:2px 8px;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;border-radius:10px;z-index:1}.action-card__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center}.action-card__icon ion-icon{font-size:inherit}.action-card__icon svg{display:block}.action-card__icon-image{width:100%;height:100%;object-fit:cover;border-radius:8px}.action-card__content{flex:1;min-width:0}.action-card__title{margin:0 0 .25rem;font-weight:600;color:var(--ion-text-color);line-height:1.3}.action-card__description{margin:0;color:var(--ion-color-medium);line-height:1.4}.action-card__chevron{flex-shrink:0;font-size:1.25rem;color:var(--ion-color-medium);transition:transform .2s ease}.action-card--clickable:hover .action-card__chevron{transform:translate(4px)}:host-context(.dark) .action-card--shadowed,:host-context(.ion-palette-dark) .action-card--shadowed,:host-context(html.ion-palette-dark) .action-card--shadowed,:host-context(body.dark) .action-card--shadowed,:host-context([data-theme=dark]) .action-card--shadowed{box-shadow:0 2px 8px #0000004d}:host-context(.dark) .action-card--clickable:hover,:host-context(.ion-palette-dark) .action-card--clickable:hover,:host-context(html.ion-palette-dark) .action-card--clickable:hover,:host-context(body.dark) .action-card--clickable:hover,:host-context([data-theme=dark]) .action-card--clickable:hover{box-shadow:0 4px 16px #0006}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonRippleEffect, selector: "ion-ripple-effect", inputs: ["type"] }] }); }
27626
27703
  }
27627
27704
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionCardComponent, decorators: [{
27628
27705
  type: Component,
27629
27706
  args: [{ selector: 'val-action-card', standalone: true, imports: [CommonModule, RouterLink, IonIcon, IonRippleEffect], template: `
27630
- <article
27707
+ <div
27631
27708
  class="action-card"
27632
27709
  [class.action-card--small]="config().size === 'small'"
27633
27710
  [class.action-card--medium]="config().size === 'medium'"
@@ -27660,7 +27737,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
27660
27737
  <!-- Icon Container -->
27661
27738
  <div class="action-card__icon" [style.color]="getIconColor()" [style.background-color]="getIconBackgroundColor()">
27662
27739
  @if (config().icon?.ionicon) {
27663
- <ion-icon [name]="config().icon!.ionicon!"></ion-icon>
27740
+ <ion-icon [name]="config().icon!.ionicon!" aria-hidden="true"></ion-icon>
27664
27741
  } @else if (config().icon?.svgPath) {
27665
27742
  <svg
27666
27743
  viewBox="0 0 24 24"
@@ -27687,9 +27764,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
27687
27764
 
27688
27765
  <!-- Chevron (optional) -->
27689
27766
  @if (config().showChevron && !config().disabled) {
27690
- <ion-icon name="chevron-forward-outline" class="action-card__chevron"></ion-icon>
27767
+ <ion-icon name="chevron-forward-outline" class="action-card__chevron" aria-hidden="true"></ion-icon>
27691
27768
  }
27692
- </article>
27769
+ </div>
27693
27770
  `, styles: [":host{display:flex;flex-direction:column}.action-card{position:relative;display:flex;align-items:center;flex:1;gap:1rem;padding:1rem;background:var(--card-bg, var(--ion-card-background, var(--ion-background-color)));border-radius:12px;cursor:pointer;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease;text-decoration:none;overflow:hidden;--ripple-color: var(--ion-color-primary)}.action-card--small{padding:.75rem;gap:.75rem}.action-card--small .action-card__icon{width:36px;height:36px;font-size:1.125rem;border-radius:8px}.action-card--small .action-card__icon svg{width:18px;height:18px}.action-card--small .action-card__title{font-size:.9rem}.action-card--small .action-card__description{font-size:.8rem}.action-card--medium{padding:1rem;gap:1rem}.action-card--medium .action-card__icon{width:48px;height:48px;font-size:1.5rem;border-radius:10px}.action-card--medium .action-card__icon svg{width:24px;height:24px}.action-card--medium .action-card__title{font-size:1rem}.action-card--medium .action-card__description{font-size:.875rem}.action-card--large{padding:1.25rem;gap:1.25rem}.action-card--large .action-card__icon{width:56px;height:56px;font-size:1.75rem;border-radius:12px}.action-card--large .action-card__icon svg{width:28px;height:28px}.action-card--large .action-card__title{font-size:1.1rem}.action-card--large .action-card__description{font-size:.9rem}.action-card--bordered{border:1px solid var(--card-border-color, var(--ion-color-light-shade))}.action-card--shadowed{box-shadow:0 2px 8px #00000014}.action-card--clickable:hover{transform:translateY(-2px);box-shadow:0 4px 16px #0000001f}.action-card--clickable:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.action-card--clickable:active{transform:translateY(0)}.action-card--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.action-card__badge{position:absolute;top:8px;right:8px;padding:2px 8px;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;border-radius:10px;z-index:1}.action-card__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center}.action-card__icon ion-icon{font-size:inherit}.action-card__icon svg{display:block}.action-card__icon-image{width:100%;height:100%;object-fit:cover;border-radius:8px}.action-card__content{flex:1;min-width:0}.action-card__title{margin:0 0 .25rem;font-weight:600;color:var(--ion-text-color);line-height:1.3}.action-card__description{margin:0;color:var(--ion-color-medium);line-height:1.4}.action-card__chevron{flex-shrink:0;font-size:1.25rem;color:var(--ion-color-medium);transition:transform .2s ease}.action-card--clickable:hover .action-card__chevron{transform:translate(4px)}:host-context(.dark) .action-card--shadowed,:host-context(.ion-palette-dark) .action-card--shadowed,:host-context(html.ion-palette-dark) .action-card--shadowed,:host-context(body.dark) .action-card--shadowed,:host-context([data-theme=dark]) .action-card--shadowed{box-shadow:0 2px 8px #0000004d}:host-context(.dark) .action-card--clickable:hover,:host-context(.ion-palette-dark) .action-card--clickable:hover,:host-context(html.ion-palette-dark) .action-card--clickable:hover,:host-context(body.dark) .action-card--clickable:hover,:host-context([data-theme=dark]) .action-card--clickable:hover{box-shadow:0 4px 16px #0006}\n"] }]
27694
27771
  }], propDecorators: { onClick: [{
27695
27772
  type: Output
@@ -27774,7 +27851,7 @@ class MediaObjectComponent {
27774
27851
  @if (config().image) {
27775
27852
  <img [src]="config().image" [alt]="config().imageAlt || config().title" />
27776
27853
  } @else if (config().icon) {
27777
- <ion-icon [name]="config().icon!"></ion-icon>
27854
+ <ion-icon [name]="config().icon!" aria-hidden="true"></ion-icon>
27778
27855
  }
27779
27856
  </div>
27780
27857
 
@@ -27815,7 +27892,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
27815
27892
  @if (config().image) {
27816
27893
  <img [src]="config().image" [alt]="config().imageAlt || config().title" />
27817
27894
  } @else if (config().icon) {
27818
- <ion-icon [name]="config().icon!"></ion-icon>
27895
+ <ion-icon [name]="config().icon!" aria-hidden="true"></ion-icon>
27819
27896
  }
27820
27897
  </div>
27821
27898
 
@@ -28010,7 +28087,7 @@ class ArticleCardComponent {
28010
28087
  }
28011
28088
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28012
28089
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ArticleCardComponent, isStandalone: true, selector: "val-article-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
28013
- <article
28090
+ <div
28014
28091
  class="article-card"
28015
28092
  [class.article-card--bordered]="config().bordered"
28016
28093
  [class.article-card--shadowed]="config().shadowed"
@@ -28050,13 +28127,13 @@ class ArticleCardComponent {
28050
28127
  </p>
28051
28128
  }
28052
28129
  </div>
28053
- </article>
28130
+ </div>
28054
28131
  `, isInline: true, styles: [":host{display:flex;flex-direction:column}.article-card{position:relative;display:flex;flex:1;flex-direction:column;background:var(--ion-card-background, var(--ion-background-color));border-radius:14px;overflow:hidden;text-decoration:none;transition:transform .2s ease,box-shadow .2s ease;--ripple-color: var(--ion-color-primary)}.article-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.article-card--shadowed{box-shadow:0 2px 8px #00000014}.article-card--clickable{cursor:pointer}.article-card--clickable:hover{transform:translateY(-3px);box-shadow:0 6px 20px #0000001f}.article-card--clickable:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.article-card__media{width:100%;overflow:hidden;background:var(--ion-color-light, #f4f5f8)}.article-card__media img{width:100%;height:100%;object-fit:cover;display:block}.article-card__body{display:flex;flex-direction:column;gap:.5rem;padding:1rem 1.1rem 1.25rem}.article-card__meta{display:flex;align-items:center;gap:.75rem;font-size:.8rem}.article-card__date{color:var(--ion-color-medium)}.article-card__topic{font-weight:600;color:var(--ion-color-primary)}.article-card__title{margin:0;font-size:1.05rem;font-weight:700;line-height:1.35;color:var(--ion-text-color)}.article-card__excerpt{margin:0;font-size:.9rem;line-height:1.5;color:var(--ion-color-medium-shade);display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}:host-context(.dark) .article-card--bordered,:host-context(.ion-palette-dark) .article-card--bordered,:host-context(html.ion-palette-dark) .article-card--bordered,:host-context(body.dark) .article-card--bordered,:host-context([data-theme=dark]) .article-card--bordered{border-color:#ffffff1f}:host-context(.dark) .article-card--shadowed,:host-context(.ion-palette-dark) .article-card--shadowed,:host-context(html.ion-palette-dark) .article-card--shadowed,:host-context(body.dark) .article-card--shadowed,:host-context([data-theme=dark]) .article-card--shadowed{box-shadow:0 2px 8px #0000004d}:host-context(.dark) .article-card--clickable:hover,:host-context(.ion-palette-dark) .article-card--clickable:hover,:host-context(html.ion-palette-dark) .article-card--clickable:hover,:host-context(body.dark) .article-card--clickable:hover,:host-context([data-theme=dark]) .article-card--clickable:hover{box-shadow:0 6px 20px #0006}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonRippleEffect, selector: "ion-ripple-effect", inputs: ["type"] }] }); }
28055
28132
  }
28056
28133
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleCardComponent, decorators: [{
28057
28134
  type: Component,
28058
28135
  args: [{ selector: 'val-article-card', standalone: true, imports: [CommonModule, RouterLink, IonRippleEffect], template: `
28059
- <article
28136
+ <div
28060
28137
  class="article-card"
28061
28138
  [class.article-card--bordered]="config().bordered"
28062
28139
  [class.article-card--shadowed]="config().shadowed"
@@ -28096,7 +28173,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
28096
28173
  </p>
28097
28174
  }
28098
28175
  </div>
28099
- </article>
28176
+ </div>
28100
28177
  `, styles: [":host{display:flex;flex-direction:column}.article-card{position:relative;display:flex;flex:1;flex-direction:column;background:var(--ion-card-background, var(--ion-background-color));border-radius:14px;overflow:hidden;text-decoration:none;transition:transform .2s ease,box-shadow .2s ease;--ripple-color: var(--ion-color-primary)}.article-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.article-card--shadowed{box-shadow:0 2px 8px #00000014}.article-card--clickable{cursor:pointer}.article-card--clickable:hover{transform:translateY(-3px);box-shadow:0 6px 20px #0000001f}.article-card--clickable:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.article-card__media{width:100%;overflow:hidden;background:var(--ion-color-light, #f4f5f8)}.article-card__media img{width:100%;height:100%;object-fit:cover;display:block}.article-card__body{display:flex;flex-direction:column;gap:.5rem;padding:1rem 1.1rem 1.25rem}.article-card__meta{display:flex;align-items:center;gap:.75rem;font-size:.8rem}.article-card__date{color:var(--ion-color-medium)}.article-card__topic{font-weight:600;color:var(--ion-color-primary)}.article-card__title{margin:0;font-size:1.05rem;font-weight:700;line-height:1.35;color:var(--ion-text-color)}.article-card__excerpt{margin:0;font-size:.9rem;line-height:1.5;color:var(--ion-color-medium-shade);display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}:host-context(.dark) .article-card--bordered,:host-context(.ion-palette-dark) .article-card--bordered,:host-context(html.ion-palette-dark) .article-card--bordered,:host-context(body.dark) .article-card--bordered,:host-context([data-theme=dark]) .article-card--bordered{border-color:#ffffff1f}:host-context(.dark) .article-card--shadowed,:host-context(.ion-palette-dark) .article-card--shadowed,:host-context(html.ion-palette-dark) .article-card--shadowed,:host-context(body.dark) .article-card--shadowed,:host-context([data-theme=dark]) .article-card--shadowed{box-shadow:0 2px 8px #0000004d}:host-context(.dark) .article-card--clickable:hover,:host-context(.ion-palette-dark) .article-card--clickable:hover,:host-context(html.ion-palette-dark) .article-card--clickable:hover,:host-context(body.dark) .article-card--clickable:hover,:host-context([data-theme=dark]) .article-card--clickable:hover{box-shadow:0 6px 20px #0006}\n"] }]
28101
28178
  }], propDecorators: { onClick: [{
28102
28179
  type: Output
@@ -33766,6 +33843,7 @@ class CookieBannerComponent {
33766
33843
  role="dialog"
33767
33844
  aria-modal="false"
33768
33845
  aria-live="polite"
33846
+ [attr.aria-label]="props.ariaLabel || 'Aviso de cookies'"
33769
33847
  >
33770
33848
  <div class="val-cookie-banner__inner" [style.max-width]="props.maxWidth || '1200px'">
33771
33849
  @if (props.dismissible) {
@@ -33842,6 +33920,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
33842
33920
  role="dialog"
33843
33921
  aria-modal="false"
33844
33922
  aria-live="polite"
33923
+ [attr.aria-label]="props.ariaLabel || 'Aviso de cookies'"
33845
33924
  >
33846
33925
  <div class="val-cookie-banner__inner" [style.max-width]="props.maxWidth || '1200px'">
33847
33926
  @if (props.dismissible) {
@@ -34289,17 +34368,36 @@ class ToolbarComponent {
34289
34368
  <ion-toolbar [color]="props.color" [class.background]="props.color === 'background'">
34290
34369
  <ng-container *ngIf="props.withBack">
34291
34370
  <ion-buttons class="left-buttons" slot="start" *ngIf="props.withBack">
34292
- <ion-button fill="clear" (click)="goBack()" [color]="props.textColor" style="margin-left: 8px;">
34293
- <ion-icon name="chevron-back-outline" [slot]="props.backText ? 'start' : 'icon-only'"></ion-icon>
34294
- <ion-text *ngIf="props.backText">{{ props.backText }}</ion-text>
34371
+ <ion-button
34372
+ fill="clear"
34373
+ (click)="goBack()"
34374
+ [color]="props.textColor"
34375
+ style="margin-left: 8px;"
34376
+ [attr.aria-label]="props.backText || 'Volver'"
34377
+ >
34378
+ <ion-icon
34379
+ name="chevron-back-outline"
34380
+ [slot]="props.backText ? 'start' : 'icon-only'"
34381
+ aria-hidden="true"
34382
+ ></ion-icon>
34383
+ <ion-text *ngIf="props.backText" aria-hidden="true">{{ props.backText }}</ion-text>
34295
34384
  </ion-button>
34296
34385
  </ion-buttons>
34297
34386
  </ng-container>
34298
34387
  <ng-container *ngIf="props.withActions">
34299
34388
  <ion-buttons slot="end" *ngIf="someInRight() || props.withMenu || props.languageSelector">
34300
34389
  <ng-container *ngFor="let action of rightActions()">
34301
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34302
- <ion-icon slot="icon-only" [name]="action.description" [color]="props.textColor"></ion-icon>
34390
+ <ion-button
34391
+ *ngIf="action.type === actionTypes.ICON"
34392
+ (click)="clickHandler(action.token)"
34393
+ [attr.aria-label]="action.token"
34394
+ >
34395
+ <ion-icon
34396
+ slot="icon-only"
34397
+ [name]="action.description"
34398
+ [color]="props.textColor"
34399
+ aria-hidden="true"
34400
+ ></ion-icon>
34303
34401
  </ion-button>
34304
34402
  <val-user-avatar
34305
34403
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34331,8 +34429,17 @@ class ToolbarComponent {
34331
34429
  </ion-buttons>
34332
34430
  <ion-buttons slot="start" *ngIf="someInLeft()" style="padding-left: 4px;">
34333
34431
  <ng-container *ngFor="let action of leftActions()">
34334
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34335
- <ion-icon slot="icon-only" [name]="action.description" [color]="props.textColor"></ion-icon>
34432
+ <ion-button
34433
+ *ngIf="action.type === actionTypes.ICON"
34434
+ (click)="clickHandler(action.token)"
34435
+ [attr.aria-label]="action.token"
34436
+ >
34437
+ <ion-icon
34438
+ slot="icon-only"
34439
+ [name]="action.description"
34440
+ [color]="props.textColor"
34441
+ aria-hidden="true"
34442
+ ></ion-icon>
34336
34443
  </ion-button>
34337
34444
  <val-user-avatar
34338
34445
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34358,7 +34465,7 @@ class ToolbarComponent {
34358
34465
  <!-- experimental -->
34359
34466
  <ng-content select="[toolbar-bottom]"></ng-content>
34360
34467
  </ion-toolbar>
34361
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif}.left-buttons{margin-left:-1rem}.background{background:var(--ion-background-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: UserAvatarComponent, selector: "val-user-avatar", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: LanguageSelectorComponent, selector: "val-language-selector", inputs: ["props"], outputs: ["languageChange"] }] }); }
34468
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif}.left-buttons{margin-left:-1rem}.background{background:var(--ion-background-color)}:host ion-title{--color: var(--ion-text-color)}:host ion-button{--color: var(--ion-text-color)}:host ion-icon{color:var(--ion-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: UserAvatarComponent, selector: "val-user-avatar", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: IonMenuButton, selector: "ion-menu-button", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] }, { kind: "component", type: LanguageSelectorComponent, selector: "val-language-selector", inputs: ["props"], outputs: ["languageChange"] }] }); }
34362
34469
  }
34363
34470
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ToolbarComponent, decorators: [{
34364
34471
  type: Component,
@@ -34379,17 +34486,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34379
34486
  <ion-toolbar [color]="props.color" [class.background]="props.color === 'background'">
34380
34487
  <ng-container *ngIf="props.withBack">
34381
34488
  <ion-buttons class="left-buttons" slot="start" *ngIf="props.withBack">
34382
- <ion-button fill="clear" (click)="goBack()" [color]="props.textColor" style="margin-left: 8px;">
34383
- <ion-icon name="chevron-back-outline" [slot]="props.backText ? 'start' : 'icon-only'"></ion-icon>
34384
- <ion-text *ngIf="props.backText">{{ props.backText }}</ion-text>
34489
+ <ion-button
34490
+ fill="clear"
34491
+ (click)="goBack()"
34492
+ [color]="props.textColor"
34493
+ style="margin-left: 8px;"
34494
+ [attr.aria-label]="props.backText || 'Volver'"
34495
+ >
34496
+ <ion-icon
34497
+ name="chevron-back-outline"
34498
+ [slot]="props.backText ? 'start' : 'icon-only'"
34499
+ aria-hidden="true"
34500
+ ></ion-icon>
34501
+ <ion-text *ngIf="props.backText" aria-hidden="true">{{ props.backText }}</ion-text>
34385
34502
  </ion-button>
34386
34503
  </ion-buttons>
34387
34504
  </ng-container>
34388
34505
  <ng-container *ngIf="props.withActions">
34389
34506
  <ion-buttons slot="end" *ngIf="someInRight() || props.withMenu || props.languageSelector">
34390
34507
  <ng-container *ngFor="let action of rightActions()">
34391
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34392
- <ion-icon slot="icon-only" [name]="action.description" [color]="props.textColor"></ion-icon>
34508
+ <ion-button
34509
+ *ngIf="action.type === actionTypes.ICON"
34510
+ (click)="clickHandler(action.token)"
34511
+ [attr.aria-label]="action.token"
34512
+ >
34513
+ <ion-icon
34514
+ slot="icon-only"
34515
+ [name]="action.description"
34516
+ [color]="props.textColor"
34517
+ aria-hidden="true"
34518
+ ></ion-icon>
34393
34519
  </ion-button>
34394
34520
  <val-user-avatar
34395
34521
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34421,8 +34547,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34421
34547
  </ion-buttons>
34422
34548
  <ion-buttons slot="start" *ngIf="someInLeft()" style="padding-left: 4px;">
34423
34549
  <ng-container *ngFor="let action of leftActions()">
34424
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34425
- <ion-icon slot="icon-only" [name]="action.description" [color]="props.textColor"></ion-icon>
34550
+ <ion-button
34551
+ *ngIf="action.type === actionTypes.ICON"
34552
+ (click)="clickHandler(action.token)"
34553
+ [attr.aria-label]="action.token"
34554
+ >
34555
+ <ion-icon
34556
+ slot="icon-only"
34557
+ [name]="action.description"
34558
+ [color]="props.textColor"
34559
+ aria-hidden="true"
34560
+ ></ion-icon>
34426
34561
  </ion-button>
34427
34562
  <val-user-avatar
34428
34563
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34448,7 +34583,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34448
34583
  <!-- experimental -->
34449
34584
  <ng-content select="[toolbar-bottom]"></ng-content>
34450
34585
  </ion-toolbar>
34451
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif}.left-buttons{margin-left:-1rem}.background{background:var(--ion-background-color)}\n"] }]
34586
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif}.left-buttons{margin-left:-1rem}.background{background:var(--ion-background-color)}:host ion-title{--color: var(--ion-text-color)}:host ion-button{--color: var(--ion-text-color)}:host ion-icon{color:var(--ion-text-color)}\n"] }]
34452
34587
  }], ctorParameters: () => [{ type: IconService }], propDecorators: { props: [{
34453
34588
  type: Input
34454
34589
  }], onClick: [{
@@ -36654,7 +36789,7 @@ class DataTableComponent {
36654
36789
  }
36655
36790
  /** Get actions column label */
36656
36791
  getActionsLabel() {
36657
- return this.props.actionsLabel || this.i18n.t('actions');
36792
+ return this.props.actionsLabel || this.i18n.t('actions') || 'Acciones';
36658
36793
  }
36659
36794
  /** Get pagination info text */
36660
36795
  getPaginationInfoText() {
@@ -36666,19 +36801,19 @@ class DataTableComponent {
36666
36801
  }
36667
36802
  /** Get first page aria label */
36668
36803
  getFirstPageLabel() {
36669
- return this.i18n.t('firstPage');
36804
+ return this.i18n.t('firstPage') || 'Primera página';
36670
36805
  }
36671
36806
  /** Get previous page aria label */
36672
36807
  getPreviousPageLabel() {
36673
- return this.i18n.t('previousPage');
36808
+ return this.i18n.t('previousPage') || 'Página anterior';
36674
36809
  }
36675
36810
  /** Get next page aria label */
36676
36811
  getNextPageLabel() {
36677
- return this.i18n.t('nextPage');
36812
+ return this.i18n.t('nextPage') || 'Página siguiente';
36678
36813
  }
36679
36814
  /** Get last page aria label */
36680
36815
  getLastPageLabel() {
36681
- return this.i18n.t('lastPage');
36816
+ return this.i18n.t('lastPage') || 'Última página';
36682
36817
  }
36683
36818
  get pageSizeOptions() {
36684
36819
  return this.props.pagination?.pageSizeOptions || DEFAULT_PAGE_SIZE_OPTIONS;
@@ -36899,9 +37034,9 @@ class DataTableComponent {
36899
37034
  <!-- Loading overlay -->
36900
37035
  @if (props.loadingState?.loading) {
36901
37036
  <div class="loading-overlay">
36902
- <ion-spinner name="circular"></ion-spinner>
37037
+ <ion-spinner name="circular" [attr.aria-label]="props.loadingState?.message || 'Cargando'"></ion-spinner>
36903
37038
  @if (props.loadingState?.message) {
36904
- <span class="loading-message">{{ props.loadingState.message }}</span>
37039
+ <span class="loading-message" aria-hidden="true">{{ props.loadingState.message }}</span>
36905
37040
  }
36906
37041
  </div>
36907
37042
  }
@@ -36920,16 +37055,17 @@ class DataTableComponent {
36920
37055
  <tr>
36921
37056
  <!-- Selection column -->
36922
37057
  @if (props.showSelectionColumn && props.selection?.mode === 'multiple') {
36923
- <th class="selection-cell">
37058
+ <th class="selection-cell" scope="col" aria-label="Selección">
36924
37059
  <ion-checkbox
36925
37060
  [checked]="isAllSelected"
36926
37061
  [indeterminate]="isIndeterminate"
36927
37062
  (ionChange)="toggleSelectAll($event)"
37063
+ aria-label="Seleccionar todo"
36928
37064
  ></ion-checkbox>
36929
37065
  </th>
36930
37066
  }
36931
37067
  @if (props.showSelectionColumn && props.selection?.mode === 'single') {
36932
- <th class="selection-cell"></th>
37068
+ <th class="selection-cell" scope="col" aria-label="Selección"></th>
36933
37069
  }
36934
37070
 
36935
37071
  <!-- Row number column -->
@@ -36958,10 +37094,12 @@ class DataTableComponent {
36958
37094
  <span class="sort-icons">
36959
37095
  <ion-icon
36960
37096
  name="chevron-up-outline"
37097
+ aria-hidden="true"
36961
37098
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
36962
37099
  ></ion-icon>
36963
37100
  <ion-icon
36964
37101
  name="chevron-down-outline"
37102
+ aria-hidden="true"
36965
37103
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
36966
37104
  ></ion-icon>
36967
37105
  </span>
@@ -37016,6 +37154,7 @@ class DataTableComponent {
37016
37154
  [checked]="isRowSelected(row)"
37017
37155
  (ionChange)="toggleRowSelection(row, $event)"
37018
37156
  (click)="$event.stopPropagation()"
37157
+ aria-label="Seleccionar fila"
37019
37158
  ></ion-checkbox>
37020
37159
  } @else if (props.selection?.mode === 'single') {
37021
37160
  <input
@@ -37254,9 +37393,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37254
37393
  <!-- Loading overlay -->
37255
37394
  @if (props.loadingState?.loading) {
37256
37395
  <div class="loading-overlay">
37257
- <ion-spinner name="circular"></ion-spinner>
37396
+ <ion-spinner name="circular" [attr.aria-label]="props.loadingState?.message || 'Cargando'"></ion-spinner>
37258
37397
  @if (props.loadingState?.message) {
37259
- <span class="loading-message">{{ props.loadingState.message }}</span>
37398
+ <span class="loading-message" aria-hidden="true">{{ props.loadingState.message }}</span>
37260
37399
  }
37261
37400
  </div>
37262
37401
  }
@@ -37275,16 +37414,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37275
37414
  <tr>
37276
37415
  <!-- Selection column -->
37277
37416
  @if (props.showSelectionColumn && props.selection?.mode === 'multiple') {
37278
- <th class="selection-cell">
37417
+ <th class="selection-cell" scope="col" aria-label="Selección">
37279
37418
  <ion-checkbox
37280
37419
  [checked]="isAllSelected"
37281
37420
  [indeterminate]="isIndeterminate"
37282
37421
  (ionChange)="toggleSelectAll($event)"
37422
+ aria-label="Seleccionar todo"
37283
37423
  ></ion-checkbox>
37284
37424
  </th>
37285
37425
  }
37286
37426
  @if (props.showSelectionColumn && props.selection?.mode === 'single') {
37287
- <th class="selection-cell"></th>
37427
+ <th class="selection-cell" scope="col" aria-label="Selección"></th>
37288
37428
  }
37289
37429
 
37290
37430
  <!-- Row number column -->
@@ -37313,10 +37453,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37313
37453
  <span class="sort-icons">
37314
37454
  <ion-icon
37315
37455
  name="chevron-up-outline"
37456
+ aria-hidden="true"
37316
37457
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
37317
37458
  ></ion-icon>
37318
37459
  <ion-icon
37319
37460
  name="chevron-down-outline"
37461
+ aria-hidden="true"
37320
37462
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
37321
37463
  ></ion-icon>
37322
37464
  </span>
@@ -37371,6 +37513,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37371
37513
  [checked]="isRowSelected(row)"
37372
37514
  (ionChange)="toggleRowSelection(row, $event)"
37373
37515
  (click)="$event.stopPropagation()"
37516
+ aria-label="Seleccionar fila"
37374
37517
  ></ion-checkbox>
37375
37518
  } @else if (props.selection?.mode === 'single') {
37376
37519
  <input
@@ -39021,7 +39164,7 @@ class InfiniteListComponent {
39021
39164
  lastItem: this.items()[this.items().length - 1],
39022
39165
  };
39023
39166
  const result = await this.executeLoad(params);
39024
- this.items.update((current) => [...current, ...result.items]);
39167
+ this.items.update(current => [...current, ...result.items]);
39025
39168
  this.hasMoreBottom.set(result.hasMore);
39026
39169
  this.currentPage++;
39027
39170
  this.currentCursor = result.cursor;
@@ -39048,7 +39191,7 @@ class InfiniteListComponent {
39048
39191
  firstItem: this.items()[0],
39049
39192
  };
39050
39193
  const result = await this.executeLoad(params);
39051
- this.items.update((current) => [...result.items, ...current]);
39194
+ this.items.update(current => [...result.items, ...current]);
39052
39195
  this.hasMoreTop.set(result.hasMore);
39053
39196
  this.state.set('idle');
39054
39197
  this.itemsChange.emit(this.items());
@@ -39091,17 +39234,17 @@ class InfiniteListComponent {
39091
39234
  }
39092
39235
  /** Agregar items al inicio */
39093
39236
  prependItems(newItems) {
39094
- this.items.update((current) => [...newItems, ...current]);
39237
+ this.items.update(current => [...newItems, ...current]);
39095
39238
  this.itemsChange.emit(this.items());
39096
39239
  }
39097
39240
  /** Agregar items al final */
39098
39241
  appendItems(newItems) {
39099
- this.items.update((current) => [...current, ...newItems]);
39242
+ this.items.update(current => [...current, ...newItems]);
39100
39243
  this.itemsChange.emit(this.items());
39101
39244
  }
39102
39245
  /** Actualizar un item por indice */
39103
39246
  updateItem(index, item) {
39104
- this.items.update((current) => {
39247
+ this.items.update(current => {
39105
39248
  const updated = [...current];
39106
39249
  updated[index] = item;
39107
39250
  return updated;
@@ -39110,7 +39253,7 @@ class InfiniteListComponent {
39110
39253
  }
39111
39254
  /** Remover un item por indice */
39112
39255
  removeItem(index) {
39113
- this.items.update((current) => current.filter((_, i) => i !== index));
39256
+ this.items.update(current => current.filter((_, i) => i !== index));
39114
39257
  this.itemsChange.emit(this.items());
39115
39258
  }
39116
39259
  /** Handler para evento de infinite scroll */
@@ -39197,7 +39340,10 @@ class InfiniteListComponent {
39197
39340
  <div class="infinite-list-error">
39198
39341
  @if (mergedProps.errorState?.template) {
39199
39342
  <ng-container
39200
- *ngTemplateOutlet="mergedProps.errorState.template; context: { error: error(), retry: retry.bind(this) }"
39343
+ *ngTemplateOutlet="
39344
+ mergedProps.errorState.template;
39345
+ context: { error: error(), retry: retry.bind(this) }
39346
+ "
39201
39347
  ></ng-container>
39202
39348
  } @else {
39203
39349
  @if (mergedProps.errorState?.icon) {
@@ -39218,8 +39364,14 @@ class InfiniteListComponent {
39218
39364
 
39219
39365
  <!-- Items list -->
39220
39366
  @if (items().length > 0) {
39221
- <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
39222
- @for (item of items(); track trackByFn($index, item); let i = $index; let first = $first; let last = $last) {
39367
+ <div class="infinite-list-items" role="presentation" [class.with-dividers]="mergedProps.showDividers">
39368
+ @for (
39369
+ item of items();
39370
+ track trackByFn($index, item);
39371
+ let i = $index;
39372
+ let first = $first;
39373
+ let last = $last
39374
+ ) {
39223
39375
  <article
39224
39376
  class="infinite-list-item"
39225
39377
  [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
@@ -39355,7 +39507,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39355
39507
  <div class="infinite-list-error">
39356
39508
  @if (mergedProps.errorState?.template) {
39357
39509
  <ng-container
39358
- *ngTemplateOutlet="mergedProps.errorState.template; context: { error: error(), retry: retry.bind(this) }"
39510
+ *ngTemplateOutlet="
39511
+ mergedProps.errorState.template;
39512
+ context: { error: error(), retry: retry.bind(this) }
39513
+ "
39359
39514
  ></ng-container>
39360
39515
  } @else {
39361
39516
  @if (mergedProps.errorState?.icon) {
@@ -39376,8 +39531,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39376
39531
 
39377
39532
  <!-- Items list -->
39378
39533
  @if (items().length > 0) {
39379
- <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
39380
- @for (item of items(); track trackByFn($index, item); let i = $index; let first = $first; let last = $last) {
39534
+ <div class="infinite-list-items" role="presentation" [class.with-dividers]="mergedProps.showDividers">
39535
+ @for (
39536
+ item of items();
39537
+ track trackByFn($index, item);
39538
+ let i = $index;
39539
+ let first = $first;
39540
+ let last = $last
39541
+ ) {
39381
39542
  <article
39382
39543
  class="infinite-list-item"
39383
39544
  [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
@@ -40352,7 +40513,7 @@ class LoginComponent {
40352
40513
  this.stopResetResendCooldown();
40353
40514
  }
40354
40515
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
40355
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
40516
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
40356
40517
  }
40357
40518
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, decorators: [{
40358
40519
  type: Component,
@@ -40368,7 +40529,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
40368
40529
  IonToolbar,
40369
40530
  FormComponent,
40370
40531
  ImageComponent,
40371
- ], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
40532
+ ], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\" aria-hidden=\"true\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" [attr.aria-label]=\"t('close')\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
40372
40533
  }], propDecorators: { props: [{
40373
40534
  type: Input
40374
40535
  }], onSuccess: [{
@@ -41025,7 +41186,7 @@ class BottomNavComponent {
41025
41186
  type="button"
41026
41187
  >
41027
41188
  <ion-ripple-effect></ion-ripple-effect>
41028
- <ion-icon [name]="config().fab!.icon"></ion-icon>
41189
+ <ion-icon [name]="config().fab!.icon" aria-hidden="true"></ion-icon>
41029
41190
  </button>
41030
41191
  } @else if (item) {
41031
41192
  <!-- Tab Item -->
@@ -41043,7 +41204,7 @@ class BottomNavComponent {
41043
41204
  <ion-ripple-effect></ion-ripple-effect>
41044
41205
 
41045
41206
  <div class="bottom-nav__tab-icon">
41046
- <ion-icon [name]="getIcon(item)"></ion-icon>
41207
+ <ion-icon [name]="getIcon(item)" aria-hidden="true"></ion-icon>
41047
41208
 
41048
41209
  <!-- Badge -->
41049
41210
  @if (item.badge) {
@@ -41099,7 +41260,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41099
41260
  type="button"
41100
41261
  >
41101
41262
  <ion-ripple-effect></ion-ripple-effect>
41102
- <ion-icon [name]="config().fab!.icon"></ion-icon>
41263
+ <ion-icon [name]="config().fab!.icon" aria-hidden="true"></ion-icon>
41103
41264
  </button>
41104
41265
  } @else if (item) {
41105
41266
  <!-- Tab Item -->
@@ -41117,7 +41278,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41117
41278
  <ion-ripple-effect></ion-ripple-effect>
41118
41279
 
41119
41280
  <div class="bottom-nav__tab-icon">
41120
- <ion-icon [name]="getIcon(item)"></ion-icon>
41281
+ <ion-icon [name]="getIcon(item)" aria-hidden="true"></ion-icon>
41121
41282
 
41122
41283
  <!-- Badge -->
41123
41284
  @if (item.badge) {
@@ -41639,7 +41800,7 @@ class AvatarUploadComponent {
41639
41800
  <!-- Edit Button -->
41640
41801
  @if (config().editable && !loading()) {
41641
41802
  <button class="edit-button" type="button" (click)="openFilePicker()" [attr.aria-label]="editButtonLabel()">
41642
- <ion-icon name="camera-outline"></ion-icon>
41803
+ <ion-icon name="camera-outline" aria-hidden="true"></ion-icon>
41643
41804
  </button>
41644
41805
  }
41645
41806
 
@@ -41746,7 +41907,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41746
41907
  <!-- Edit Button -->
41747
41908
  @if (config().editable && !loading()) {
41748
41909
  <button class="edit-button" type="button" (click)="openFilePicker()" [attr.aria-label]="editButtonLabel()">
41749
- <ion-icon name="camera-outline"></ion-icon>
41910
+ <ion-icon name="camera-outline" aria-hidden="true"></ion-icon>
41750
41911
  </button>
41751
41912
  }
41752
41913
 
@@ -55401,7 +55562,7 @@ const FIELD_LIST_I18N = {
55401
55562
  };
55402
55563
 
55403
55564
  addIcons({ addOutline, trashOutline });
55404
- const I18N_NS$1 = 'FieldList';
55565
+ const I18N_NS$2 = 'FieldList';
55405
55566
  /**
55406
55567
  * `val-field-list` — editor de listas de campos repetibles (premios, rondas,
55407
55568
  * integrantes, etc.). Cada ítem es una **card** con sus campos apilados y un botón
@@ -55455,8 +55616,8 @@ class FieldListComponent {
55455
55616
  const max = this.props.max;
55456
55617
  return max == null || this.rowsSig().length < max;
55457
55618
  });
55458
- if (!this.i18n.hasNamespace(I18N_NS$1)) {
55459
- this.i18n.registerContent(I18N_NS$1, FIELD_LIST_I18N);
55619
+ if (!this.i18n.hasNamespace(I18N_NS$2)) {
55620
+ this.i18n.registerContent(I18N_NS$2, FIELD_LIST_I18N);
55460
55621
  }
55461
55622
  }
55462
55623
  ngOnChanges(changes) {
@@ -55472,7 +55633,7 @@ class FieldListComponent {
55472
55633
  }
55473
55634
  }
55474
55635
  t(key) {
55475
- return this.i18n.t(key, I18N_NS$1);
55636
+ return this.i18n.t(key, I18N_NS$2);
55476
55637
  }
55477
55638
  /** Reemplaza `{n}` por el número de fila (1-based) en el rótulo de la card. */
55478
55639
  rowLabel(template, index) {
@@ -55644,7 +55805,7 @@ const DATE_PICKER_I18N = {
55644
55805
  };
55645
55806
 
55646
55807
  addIcons({ calendarOutline, closeOutline });
55647
- const I18N_NS = 'DatePicker';
55808
+ const I18N_NS$1 = 'DatePicker';
55648
55809
  /**
55649
55810
  * `val-date-picker` — selector de fecha con calendario vanilla-calendar-pro v3
55650
55811
  * (NO ion-datetime). Se presenta como **sheet modal** (bottom sheet), igual que
@@ -55666,8 +55827,8 @@ class DatePickerComponent {
55666
55827
  this.sheetOpen = signal(false);
55667
55828
  /** true cuando el calendario ya se construyó y es visible (fade-in). */
55668
55829
  this.calReady = signal(false);
55669
- if (!this.i18n.hasNamespace(I18N_NS)) {
55670
- this.i18n.registerContent(I18N_NS, DATE_PICKER_I18N);
55830
+ if (!this.i18n.hasNamespace(I18N_NS$1)) {
55831
+ this.i18n.registerContent(I18N_NS$1, DATE_PICKER_I18N);
55671
55832
  }
55672
55833
  }
55673
55834
  get triggerId() {
@@ -55710,7 +55871,7 @@ class DatePickerComponent {
55710
55871
  this.destroyCalendar();
55711
55872
  }
55712
55873
  t(key) {
55713
- return this.i18n.t(key, I18N_NS);
55874
+ return this.i18n.t(key, I18N_NS$1);
55714
55875
  }
55715
55876
  onSheetPresent() {
55716
55877
  this.calReady.set(false);
@@ -55736,7 +55897,7 @@ class DatePickerComponent {
55736
55897
  selectedDates: value ? [value] : [],
55737
55898
  displayDateMin: (this.props.min ?? undefined),
55738
55899
  displayDateMax: (this.props.max ?? undefined),
55739
- onClickDate: (self) => {
55900
+ onClickDate: self => {
55740
55901
  const picked = self.context.selectedDates[0] ?? null;
55741
55902
  if (picked)
55742
55903
  this.apply(picked);
@@ -55801,7 +55962,7 @@ class DatePickerComponent {
55801
55962
  [class.is-placeholder]="!displayValue"
55802
55963
  (click)="sheetOpen.set(true)"
55803
55964
  >
55804
- <ion-icon name="calendar-outline" slot="start" />
55965
+ <ion-icon name="calendar-outline" slot="start" aria-hidden="true" />
55805
55966
  {{ displayValue || placeholderText }}
55806
55967
  </ion-button>
55807
55968
  </div>
@@ -55840,11 +56001,7 @@ class DatePickerComponent {
55840
56001
  }
55841
56002
 
55842
56003
  <!-- Calendario: siempre en el DOM para que #cal exista; fade-in al estar listo -->
55843
- <div
55844
- #cal
55845
- class="vdp-sheet__cal"
55846
- [class.is-ready]="calReady()"
55847
- ></div>
56004
+ <div #cal class="vdp-sheet__cal" [class.is-ready]="calReady()"></div>
55848
56005
 
55849
56006
  @if (props.clearable && displayValue) {
55850
56007
  <ion-button expand="block" fill="clear" color="medium" (click)="clear()">
@@ -55886,7 +56043,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
55886
56043
  [class.is-placeholder]="!displayValue"
55887
56044
  (click)="sheetOpen.set(true)"
55888
56045
  >
55889
- <ion-icon name="calendar-outline" slot="start" />
56046
+ <ion-icon name="calendar-outline" slot="start" aria-hidden="true" />
55890
56047
  {{ displayValue || placeholderText }}
55891
56048
  </ion-button>
55892
56049
  </div>
@@ -55925,11 +56082,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
55925
56082
  }
55926
56083
 
55927
56084
  <!-- Calendario: siempre en el DOM para que #cal exista; fade-in al estar listo -->
55928
- <div
55929
- #cal
55930
- class="vdp-sheet__cal"
55931
- [class.is-ready]="calReady()"
55932
- ></div>
56085
+ <div #cal class="vdp-sheet__cal" [class.is-ready]="calReady()"></div>
55933
56086
 
55934
56087
  @if (props.clearable && displayValue) {
55935
56088
  <ion-button expand="block" fill="clear" color="medium" (click)="clear()">
@@ -58434,6 +58587,122 @@ function beautifyLegalArticle(article) {
58434
58587
  * Soporta modo one-shot y real-time, con gate de `firebaseAuthReady`.
58435
58588
  */
58436
58589
 
58590
+ /**
58591
+ * Defaults i18n embebidos en `createPageState`. Namespace `PageState`.
58592
+ * Auto-registrados la primera vez que se llama al helper.
58593
+ */
58594
+ const PAGE_STATE_I18N = {
58595
+ es: {
58596
+ errorTitle: 'No pudimos cargar la página',
58597
+ offlineTitle: 'Sin conexión',
58598
+ offlineHint: 'Revisá tu conexión e intentá de nuevo.',
58599
+ retry: 'Reintentar',
58600
+ },
58601
+ en: {
58602
+ errorTitle: "We couldn't load the page",
58603
+ offlineTitle: "You're offline",
58604
+ offlineHint: 'Check your connection and try again.',
58605
+ retry: 'Retry',
58606
+ },
58607
+ };
58608
+
58609
+ /**
58610
+ * createPageState — helper estándar para el patrón loading/error/data de una
58611
+ * página con datos remotos (HTTP o Firestore one-shot).
58612
+ *
58613
+ * Encapsula el boilerplate repetido en cada vista:
58614
+ * - `loading` signal (true mientras carga o recarga).
58615
+ * - `loadError` signal (el error crudo o null).
58616
+ * - `errorState` computed que convierte el error a `EmptyStateMetadata` listo
58617
+ * para `<val-empty-state>`, reactivo al idioma.
58618
+ * - `reload()` function que re-ejecuta el `loader` async.
58619
+ *
58620
+ * El caller controla el template; `createPageState` solo maneja el estado:
58621
+ *
58622
+ * ```ts
58623
+ * readonly page = createPageState(
58624
+ * this.i18n,
58625
+ * async () => {
58626
+ * const res = await firstValueFrom(this.svc.getData());
58627
+ * this.items.set(res.items);
58628
+ * },
58629
+ * { errorTitle: () => this.t('errorTitle'), retryLabel: () => this.t('retry') }
58630
+ * );
58631
+ * ```
58632
+ *
58633
+ * Template:
58634
+ * ```html
58635
+ * @if (page.loading()) { <val-skeleton-layout [props]="{ preset: 'list' }" /> }
58636
+ * @else if (page.errorState(); as e) { <val-empty-state [props]="e" /> }
58637
+ * @else { <!-- content --> }
58638
+ * ```
58639
+ *
58640
+ * El helper llama a `reload()` automáticamente al construirse (carga inicial),
58641
+ * igual que el patrón clásico `void this.load()` en el constructor.
58642
+ * Para deshabilitar la carga automática, pasar `{ autoLoad: false }`.
58643
+ *
58644
+ * Para pull-to-refresh usar `connectPageRefresh(() => page.reload())` como siempre.
58645
+ */
58646
+ const I18N_NS = 'PageState';
58647
+ /**
58648
+ * Crea el estado de carga de una página.
58649
+ *
58650
+ * @param i18n - `I18nService` inyectado en la page (para reactividad al idioma).
58651
+ * @param loader - función async que carga los datos y los siembra en signals
58652
+ * propias de la page. Si lanza, el error se captura en `loadError`.
58653
+ * @param labels - labels i18n opcionales. Si se omiten usa defaults genéricos.
58654
+ * @param options - `autoLoad`: si false no carga al construirse (default true).
58655
+ */
58656
+ function createPageState(i18n, loader, labels, options) {
58657
+ if (!i18n.hasNamespace(I18N_NS)) {
58658
+ i18n.registerContent(I18N_NS, PAGE_STATE_I18N);
58659
+ }
58660
+ const loading = signal(false);
58661
+ const loadError = signal(null);
58662
+ const errorState = computed(() => {
58663
+ i18n.lang(); // reactividad al cambiar idioma
58664
+ const err = loadError();
58665
+ if (!err)
58666
+ return null;
58667
+ const interpreted = interpretError(err);
58668
+ return createErrorStateProps(err, {
58669
+ title: {
58670
+ error: labels?.errorTitle?.() ?? i18n.t('errorTitle', 'PageState'),
58671
+ offline: labels?.offlineTitle?.() ?? i18n.t('offlineTitle', 'PageState'),
58672
+ },
58673
+ description: {
58674
+ error: labels?.errorDescription?.(err) ?? interpreted.message,
58675
+ offline: labels?.offlineHint?.() ?? i18n.t('offlineHint', 'PageState'),
58676
+ },
58677
+ retryLabel: labels?.retryLabel?.() ?? i18n.t('retry', 'PageState'),
58678
+ onRetry: () => void reload(),
58679
+ retrying: loading(),
58680
+ });
58681
+ });
58682
+ async function reload() {
58683
+ loading.set(true);
58684
+ try {
58685
+ await loader();
58686
+ loadError.set(null);
58687
+ }
58688
+ catch (err) {
58689
+ loadError.set(err);
58690
+ }
58691
+ finally {
58692
+ loading.set(false);
58693
+ }
58694
+ }
58695
+ if (options?.autoLoad !== false) {
58696
+ void reload();
58697
+ }
58698
+ return {
58699
+ loading: loading.asReadonly(),
58700
+ loadError: loadError.asReadonly(),
58701
+ errorState,
58702
+ reload,
58703
+ };
58704
+ }
58705
+
58437
58706
  /**
58438
58707
  * Cross-Platform Version Helpers
58439
58708
  *
@@ -62419,14 +62688,14 @@ class FeedbackFormComponent {
62419
62688
 
62420
62689
  @if (error()) {
62421
62690
  <div class="feedback-alert error">
62422
- <ion-icon name="close-circle-outline"></ion-icon>
62691
+ <ion-icon name="close-circle-outline" aria-hidden="true"></ion-icon>
62423
62692
  <span>{{ error() }}</span>
62424
62693
  </div>
62425
62694
  }
62426
62695
 
62427
62696
  @if (isSuccess()) {
62428
62697
  <div class="feedback-alert success">
62429
- <ion-icon name="checkmark-circle-outline"></ion-icon>
62698
+ <ion-icon name="checkmark-circle-outline" aria-hidden="true"></ion-icon>
62430
62699
  <span>{{ props.successMessage || i18n.t('feedbackSuccess') }}</span>
62431
62700
  </div>
62432
62701
  }
@@ -62454,14 +62723,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
62454
62723
 
62455
62724
  @if (error()) {
62456
62725
  <div class="feedback-alert error">
62457
- <ion-icon name="close-circle-outline"></ion-icon>
62726
+ <ion-icon name="close-circle-outline" aria-hidden="true"></ion-icon>
62458
62727
  <span>{{ error() }}</span>
62459
62728
  </div>
62460
62729
  }
62461
62730
 
62462
62731
  @if (isSuccess()) {
62463
62732
  <div class="feedback-alert success">
62464
- <ion-icon name="checkmark-circle-outline"></ion-icon>
62733
+ <ion-icon name="checkmark-circle-outline" aria-hidden="true"></ion-icon>
62465
62734
  <span>{{ props.successMessage || i18n.t('feedbackSuccess') }}</span>
62466
62735
  </div>
62467
62736
  }
@@ -63495,7 +63764,7 @@ class DocsNavLinksComponent {
63495
63764
  [href]="getHref(props.previous.route)"
63496
63765
  (click)="onNavigate($event, props.previous.route)"
63497
63766
  >
63498
- <ion-icon name="arrow-back-outline" class="docs-nav-links__icon"></ion-icon>
63767
+ <ion-icon name="arrow-back-outline" class="docs-nav-links__icon" aria-hidden="true"></ion-icon>
63499
63768
  <div class="docs-nav-links__text">
63500
63769
  <span class="docs-nav-links__label">{{ props.previous.label || previousLabel() }}</span>
63501
63770
  <span class="docs-nav-links__title">{{ props.previous.title }}</span>
@@ -63505,10 +63774,7 @@ class DocsNavLinksComponent {
63505
63774
  </div>
63506
63775
 
63507
63776
  <!-- Next -->
63508
- <div
63509
- class="docs-nav-links__item docs-nav-links__item--next"
63510
- [class.docs-nav-links__item--empty]="!props.next"
63511
- >
63777
+ <div class="docs-nav-links__item docs-nav-links__item--next" [class.docs-nav-links__item--empty]="!props.next">
63512
63778
  @if (props.next) {
63513
63779
  <a
63514
63780
  class="docs-nav-links__link"
@@ -63519,7 +63785,7 @@ class DocsNavLinksComponent {
63519
63785
  <span class="docs-nav-links__label">{{ props.next.label || nextLabel() }}</span>
63520
63786
  <span class="docs-nav-links__title">{{ props.next.title }}</span>
63521
63787
  </div>
63522
- <ion-icon name="arrow-forward-outline" class="docs-nav-links__icon"></ion-icon>
63788
+ <ion-icon name="arrow-forward-outline" class="docs-nav-links__icon" aria-hidden="true"></ion-icon>
63523
63789
  </a>
63524
63790
  }
63525
63791
  </div>
@@ -63541,7 +63807,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
63541
63807
  [href]="getHref(props.previous.route)"
63542
63808
  (click)="onNavigate($event, props.previous.route)"
63543
63809
  >
63544
- <ion-icon name="arrow-back-outline" class="docs-nav-links__icon"></ion-icon>
63810
+ <ion-icon name="arrow-back-outline" class="docs-nav-links__icon" aria-hidden="true"></ion-icon>
63545
63811
  <div class="docs-nav-links__text">
63546
63812
  <span class="docs-nav-links__label">{{ props.previous.label || previousLabel() }}</span>
63547
63813
  <span class="docs-nav-links__title">{{ props.previous.title }}</span>
@@ -63551,10 +63817,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
63551
63817
  </div>
63552
63818
 
63553
63819
  <!-- Next -->
63554
- <div
63555
- class="docs-nav-links__item docs-nav-links__item--next"
63556
- [class.docs-nav-links__item--empty]="!props.next"
63557
- >
63820
+ <div class="docs-nav-links__item docs-nav-links__item--next" [class.docs-nav-links__item--empty]="!props.next">
63558
63821
  @if (props.next) {
63559
63822
  <a
63560
63823
  class="docs-nav-links__link"
@@ -63565,7 +63828,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
63565
63828
  <span class="docs-nav-links__label">{{ props.next.label || nextLabel() }}</span>
63566
63829
  <span class="docs-nav-links__title">{{ props.next.title }}</span>
63567
63830
  </div>
63568
- <ion-icon name="arrow-forward-outline" class="docs-nav-links__icon"></ion-icon>
63831
+ <ion-icon name="arrow-forward-outline" class="docs-nav-links__icon" aria-hidden="true"></ion-icon>
63569
63832
  </a>
63570
63833
  }
63571
63834
  </div>
@@ -63894,7 +64157,7 @@ class DocsCodeExampleComponent {
63894
64157
  rel="noopener noreferrer"
63895
64158
  >
63896
64159
  {{ props.externalLink.label || 'Open in StackBlitz' }}
63897
- <ion-icon name="open-outline"></ion-icon>
64160
+ <ion-icon name="open-outline" aria-hidden="true"></ion-icon>
63898
64161
  </a>
63899
64162
  }
63900
64163
  </div>
@@ -63935,7 +64198,11 @@ class DocsCodeExampleComponent {
63935
64198
  [attr.aria-label]="copied() ? 'Code copied' : 'Copy code'"
63936
64199
  (click)="copyCode()"
63937
64200
  >
63938
- <ion-icon slot="icon-only" [name]="copied() ? 'checkmark-outline' : 'copy-outline'"></ion-icon>
64201
+ <ion-icon
64202
+ slot="icon-only"
64203
+ [name]="copied() ? 'checkmark-outline' : 'copy-outline'"
64204
+ aria-hidden="true"
64205
+ ></ion-icon>
63939
64206
  </ion-button>
63940
64207
  }
63941
64208
  </div>
@@ -63974,7 +64241,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
63974
64241
  rel="noopener noreferrer"
63975
64242
  >
63976
64243
  {{ props.externalLink.label || 'Open in StackBlitz' }}
63977
- <ion-icon name="open-outline"></ion-icon>
64244
+ <ion-icon name="open-outline" aria-hidden="true"></ion-icon>
63978
64245
  </a>
63979
64246
  }
63980
64247
  </div>
@@ -64015,7 +64282,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64015
64282
  [attr.aria-label]="copied() ? 'Code copied' : 'Copy code'"
64016
64283
  (click)="copyCode()"
64017
64284
  >
64018
- <ion-icon slot="icon-only" [name]="copied() ? 'checkmark-outline' : 'copy-outline'"></ion-icon>
64285
+ <ion-icon
64286
+ slot="icon-only"
64287
+ [name]="copied() ? 'checkmark-outline' : 'copy-outline'"
64288
+ aria-hidden="true"
64289
+ ></ion-icon>
64019
64290
  </ion-button>
64020
64291
  }
64021
64292
  </div>
@@ -64095,9 +64366,7 @@ class DocsSearchComponent {
64095
64366
  });
64096
64367
  return results.slice(0, 10); // Limit results
64097
64368
  });
64098
- this.searchSubject
64099
- .pipe(debounceTime$1(this.props.debounceMs || 150), takeUntil$1(this.destroy$))
64100
- .subscribe((query) => {
64369
+ this.searchSubject.pipe(debounceTime$1(this.props.debounceMs || 150), takeUntil$1(this.destroy$)).subscribe(query => {
64101
64370
  this.search.emit(query);
64102
64371
  });
64103
64372
  }
@@ -64129,11 +64398,11 @@ class DocsSearchComponent {
64129
64398
  switch (event.key) {
64130
64399
  case 'ArrowDown':
64131
64400
  event.preventDefault();
64132
- this.selectedIndex.update((i) => Math.min(i + 1, resultsArray.length - 1));
64401
+ this.selectedIndex.update(i => Math.min(i + 1, resultsArray.length - 1));
64133
64402
  break;
64134
64403
  case 'ArrowUp':
64135
64404
  event.preventDefault();
64136
- this.selectedIndex.update((i) => Math.max(i - 1, 0));
64405
+ this.selectedIndex.update(i => Math.max(i - 1, 0));
64137
64406
  break;
64138
64407
  case 'Enter':
64139
64408
  event.preventDefault();
@@ -64162,7 +64431,7 @@ class DocsSearchComponent {
64162
64431
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: DocsSearchComponent, isStandalone: true, selector: "val-docs-search", inputs: { props: "props" }, outputs: { navigate: "navigate", search: "search" }, host: { listeners: { "document:keydown": "onGlobalKeydown($event)" } }, viewQueries: [{ propertyName: "searchInputEl", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: `
64163
64432
  <div class="docs-search" [class]="props.cssClass">
64164
64433
  <div class="docs-search__input-wrapper">
64165
- <ion-icon name="search-outline" class="docs-search__icon"></ion-icon>
64434
+ <ion-icon name="search-outline" class="docs-search__icon" aria-hidden="true"></ion-icon>
64166
64435
  <input
64167
64436
  #searchInput
64168
64437
  type="text"
@@ -64177,13 +64446,8 @@ class DocsSearchComponent {
64177
64446
  autocomplete="off"
64178
64447
  />
64179
64448
  @if (searchQuery()) {
64180
- <button
64181
- type="button"
64182
- class="docs-search__clear"
64183
- (click)="clearSearch()"
64184
- aria-label="Clear search"
64185
- >
64186
- <ion-icon name="close-outline"></ion-icon>
64449
+ <button type="button" class="docs-search__clear" (click)="clearSearch()" aria-label="Clear search">
64450
+ <ion-icon name="close-outline" aria-hidden="true"></ion-icon>
64187
64451
  </button>
64188
64452
  } @else if (props.showShortcut) {
64189
64453
  <span class="docs-search__shortcut">{{ isMac ? '⌘' : 'Ctrl' }}+K</span>
@@ -64213,9 +64477,7 @@ class DocsSearchComponent {
64213
64477
  }
64214
64478
 
64215
64479
  @if (showResults() && searchQuery() && results().length === 0) {
64216
- <div class="docs-search__no-results">
64217
- No results found for "{{ searchQuery() }}"
64218
- </div>
64480
+ <div class="docs-search__no-results">No results found for "{{ searchQuery() }}"</div>
64219
64481
  }
64220
64482
  </div>
64221
64483
  `, isInline: true, styles: [".docs-search{--search-bg: var(--ion-background-color, #fff);--search-border: var(--ion-border-color, #e0e0e0);--search-text: var(--ion-text-color, #1a1a1a);--search-placeholder: var(--ion-color-medium, #666);--search-hover-bg: rgba(0, 0, 0, .03);--search-active-bg: rgba(0, 0, 0, .05);position:relative;font-family:var(--ion-font-family, system-ui, sans-serif)}.docs-search__input-wrapper{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;transition:all .15s ease}.docs-search__input-wrapper:focus-within{border-color:#1a1a1a;box-shadow:0 0 0 3px #0000000d}.docs-search__icon{font-size:1rem;color:var(--search-placeholder);flex-shrink:0}.docs-search__input{flex:1;border:none;outline:none;background:transparent;font-size:.875rem;color:var(--search-text);min-width:0}.docs-search__input::placeholder{color:var(--search-placeholder)}.docs-search__clear{display:flex;align-items:center;justify-content:center;padding:.25rem;border:none;background:transparent;color:var(--search-placeholder);cursor:pointer;border-radius:4px;transition:all .15s ease}.docs-search__clear:hover{background:var(--search-hover-bg);color:var(--search-text)}.docs-search__clear:focus-visible{outline:2px solid #1a1a1a;outline-offset:2px}.docs-search__clear ion-icon{font-size:.875rem}.docs-search__shortcut{font-size:.6875rem;font-weight:500;color:var(--search-placeholder);background:var(--search-hover-bg);padding:.125rem .375rem;border-radius:4px;white-space:nowrap}.docs-search__results{position:absolute;top:calc(100% + 4px);left:0;right:0;max-height:400px;overflow-y:auto;background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;box-shadow:0 4px 16px #0000001a;z-index:100}.docs-search__result{display:flex;flex-direction:column;gap:.125rem;width:100%;padding:.75rem 1rem;border:none;background:transparent;text-align:left;cursor:pointer;transition:background .15s ease;border-bottom:1px solid var(--search-border)}.docs-search__result:last-child{border-bottom:none}.docs-search__result:hover,.docs-search__result--active{background:var(--search-hover-bg)}.docs-search__result:focus-visible{outline:2px solid #1a1a1a;outline-offset:-2px}.docs-search__result-section{font-size:.625rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--search-placeholder)}.docs-search__result-label{font-size:.875rem;font-weight:500;color:var(--search-text)}.docs-search__result-description{font-size:.75rem;color:var(--search-placeholder);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-search__no-results{padding:1.5rem 1rem;text-align:center;font-size:.875rem;color:var(--search-placeholder);background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;box-shadow:0 4px 16px #0000001a;position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:100}:host-context(.dark) .docs-search,:host-context([color-scheme=dark]) .docs-search{--search-bg: #1e1e1e;--search-border: #3a3a3a;--search-text: #f4f5f8;--search-placeholder: #a0a0a0;--search-hover-bg: rgba(255, 255, 255, .05);--search-active-bg: rgba(255, 255, 255, .08)}:host-context(.dark) .docs-search__input-wrapper:focus-within,:host-context([color-scheme=dark]) .docs-search__input-wrapper:focus-within{border-color:#f4f5f8;box-shadow:0 0 0 3px #ffffff0d}:host-context(.dark) .docs-search__results,:host-context(.dark) .docs-search__no-results,:host-context([color-scheme=dark]) .docs-search__results,:host-context([color-scheme=dark]) .docs-search__no-results{box-shadow:0 4px 16px #0000004d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$7.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: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
@@ -64225,7 +64487,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64225
64487
  args: [{ selector: 'val-docs-search', standalone: true, imports: [CommonModule, FormsModule, IonIcon], template: `
64226
64488
  <div class="docs-search" [class]="props.cssClass">
64227
64489
  <div class="docs-search__input-wrapper">
64228
- <ion-icon name="search-outline" class="docs-search__icon"></ion-icon>
64490
+ <ion-icon name="search-outline" class="docs-search__icon" aria-hidden="true"></ion-icon>
64229
64491
  <input
64230
64492
  #searchInput
64231
64493
  type="text"
@@ -64240,13 +64502,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64240
64502
  autocomplete="off"
64241
64503
  />
64242
64504
  @if (searchQuery()) {
64243
- <button
64244
- type="button"
64245
- class="docs-search__clear"
64246
- (click)="clearSearch()"
64247
- aria-label="Clear search"
64248
- >
64249
- <ion-icon name="close-outline"></ion-icon>
64505
+ <button type="button" class="docs-search__clear" (click)="clearSearch()" aria-label="Clear search">
64506
+ <ion-icon name="close-outline" aria-hidden="true"></ion-icon>
64250
64507
  </button>
64251
64508
  } @else if (props.showShortcut) {
64252
64509
  <span class="docs-search__shortcut">{{ isMac ? '⌘' : 'Ctrl' }}+K</span>
@@ -64276,9 +64533,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
64276
64533
  }
64277
64534
 
64278
64535
  @if (showResults() && searchQuery() && results().length === 0) {
64279
- <div class="docs-search__no-results">
64280
- No results found for "{{ searchQuery() }}"
64281
- </div>
64536
+ <div class="docs-search__no-results">No results found for "{{ searchQuery() }}"</div>
64282
64537
  }
64283
64538
  </div>
64284
64539
  `, styles: [".docs-search{--search-bg: var(--ion-background-color, #fff);--search-border: var(--ion-border-color, #e0e0e0);--search-text: var(--ion-text-color, #1a1a1a);--search-placeholder: var(--ion-color-medium, #666);--search-hover-bg: rgba(0, 0, 0, .03);--search-active-bg: rgba(0, 0, 0, .05);position:relative;font-family:var(--ion-font-family, system-ui, sans-serif)}.docs-search__input-wrapper{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;transition:all .15s ease}.docs-search__input-wrapper:focus-within{border-color:#1a1a1a;box-shadow:0 0 0 3px #0000000d}.docs-search__icon{font-size:1rem;color:var(--search-placeholder);flex-shrink:0}.docs-search__input{flex:1;border:none;outline:none;background:transparent;font-size:.875rem;color:var(--search-text);min-width:0}.docs-search__input::placeholder{color:var(--search-placeholder)}.docs-search__clear{display:flex;align-items:center;justify-content:center;padding:.25rem;border:none;background:transparent;color:var(--search-placeholder);cursor:pointer;border-radius:4px;transition:all .15s ease}.docs-search__clear:hover{background:var(--search-hover-bg);color:var(--search-text)}.docs-search__clear:focus-visible{outline:2px solid #1a1a1a;outline-offset:2px}.docs-search__clear ion-icon{font-size:.875rem}.docs-search__shortcut{font-size:.6875rem;font-weight:500;color:var(--search-placeholder);background:var(--search-hover-bg);padding:.125rem .375rem;border-radius:4px;white-space:nowrap}.docs-search__results{position:absolute;top:calc(100% + 4px);left:0;right:0;max-height:400px;overflow-y:auto;background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;box-shadow:0 4px 16px #0000001a;z-index:100}.docs-search__result{display:flex;flex-direction:column;gap:.125rem;width:100%;padding:.75rem 1rem;border:none;background:transparent;text-align:left;cursor:pointer;transition:background .15s ease;border-bottom:1px solid var(--search-border)}.docs-search__result:last-child{border-bottom:none}.docs-search__result:hover,.docs-search__result--active{background:var(--search-hover-bg)}.docs-search__result:focus-visible{outline:2px solid #1a1a1a;outline-offset:-2px}.docs-search__result-section{font-size:.625rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--search-placeholder)}.docs-search__result-label{font-size:.875rem;font-weight:500;color:var(--search-text)}.docs-search__result-description{font-size:.75rem;color:var(--search-placeholder);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-search__no-results{padding:1.5rem 1rem;text-align:center;font-size:.875rem;color:var(--search-placeholder);background:var(--search-bg);border:1px solid var(--search-border);border-radius:8px;box-shadow:0 4px 16px #0000001a;position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:100}:host-context(.dark) .docs-search,:host-context([color-scheme=dark]) .docs-search{--search-bg: #1e1e1e;--search-border: #3a3a3a;--search-text: #f4f5f8;--search-placeholder: #a0a0a0;--search-hover-bg: rgba(255, 255, 255, .05);--search-active-bg: rgba(255, 255, 255, .08)}:host-context(.dark) .docs-search__input-wrapper:focus-within,:host-context([color-scheme=dark]) .docs-search__input-wrapper:focus-within{border-color:#f4f5f8;box-shadow:0 0 0 3px #ffffff0d}:host-context(.dark) .docs-search__results,:host-context(.dark) .docs-search__no-results,:host-context([color-scheme=dark]) .docs-search__results,:host-context([color-scheme=dark]) .docs-search__no-results{box-shadow:0 4px 16px #0000004d}\n"] }]
@@ -65849,9 +66104,10 @@ class MetricCardComponent {
65849
66104
  fill="clear"
65850
66105
  size="small"
65851
66106
  [disabled]="action.disabled ?? false"
66107
+ [attr.aria-label]="action.token"
65852
66108
  (click)="onAction.emit(action.token)"
65853
66109
  >
65854
- <ion-icon [name]="action.icon" slot="icon-only"></ion-icon>
66110
+ <ion-icon [name]="action.icon" slot="icon-only" aria-hidden="true"></ion-icon>
65855
66111
  </ion-button>
65856
66112
  }
65857
66113
  </div>
@@ -65901,9 +66157,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
65901
66157
  fill="clear"
65902
66158
  size="small"
65903
66159
  [disabled]="action.disabled ?? false"
66160
+ [attr.aria-label]="action.token"
65904
66161
  (click)="onAction.emit(action.token)"
65905
66162
  >
65906
- <ion-icon [name]="action.icon" slot="icon-only"></ion-icon>
66163
+ <ion-icon [name]="action.icon" slot="icon-only" aria-hidden="true"></ion-icon>
65907
66164
  </ion-button>
65908
66165
  }
65909
66166
  </div>
@@ -65975,8 +66232,8 @@ class AuthCtaComponent {
65975
66232
  ...AUTH_CTA_DEFAULTS,
65976
66233
  ...this.props(),
65977
66234
  }));
65978
- this.loginLabel = computed(() => this.config().loginLabel ?? this.i18n.t('AuthCta.login'));
65979
- this.registerLabel = computed(() => this.config().registerLabel ?? this.i18n.t('AuthCta.register'));
66235
+ this.loginLabel = computed(() => (this.config().loginLabel ?? this.i18n.t('AuthCta.login')) || 'Iniciar sesión');
66236
+ this.registerLabel = computed(() => (this.config().registerLabel ?? this.i18n.t('AuthCta.register')) || 'Registrarse');
65980
66237
  this.resolvedBg = computed(() => {
65981
66238
  const bg = this.config().backgroundColor;
65982
66239
  if (!bg)
@@ -66249,7 +66506,7 @@ class TicketCardComponent {
66249
66506
  <div class="ticket-card__qr-fallback">{{ tokenShort() }}</div>
66250
66507
  } @else {
66251
66508
  <div class="ticket-card__qr-loading">
66252
- <ion-spinner name="crescent" />
66509
+ <ion-spinner name="crescent" aria-label="Generando QR" />
66253
66510
  </div>
66254
66511
  }
66255
66512
  </div>
@@ -66283,7 +66540,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
66283
66540
  <div class="ticket-card__qr-fallback">{{ tokenShort() }}</div>
66284
66541
  } @else {
66285
66542
  <div class="ticket-card__qr-loading">
66286
- <ion-spinner name="crescent" />
66543
+ <ion-spinner name="crescent" aria-label="Generando QR" />
66287
66544
  </div>
66288
66545
  }
66289
66546
  </div>
@@ -66641,5 +66898,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
66641
66898
  * Generated bundle index. Do not edit.
66642
66899
  */
66643
66900
 
66644
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionSelectorComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketCardComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPermissionLabeler, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
66901
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PermissionCatalogService, PermissionSelectorComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketCardComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
66645
66902
  //# sourceMappingURL=valtech-components.mjs.map