valtech-components 4.0.6 → 4.0.9

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 (24) hide show
  1. package/esm2022/lib/components/atoms/box/box.component.mjs +3 -3
  2. package/esm2022/lib/components/atoms/fab/fab.component.mjs +5 -1
  3. package/esm2022/lib/components/atoms/fab/types.mjs +1 -1
  4. package/esm2022/lib/components/molecules/action-card/action-card.component.mjs +5 -5
  5. package/esm2022/lib/components/molecules/article-card/article-card.component.mjs +5 -5
  6. package/esm2022/lib/components/molecules/comment/comment.component.mjs +3 -3
  7. package/esm2022/lib/components/molecules/expandable-text/expandable-text.component.mjs +16 -4
  8. package/esm2022/lib/components/molecules/footer-links/footer-links.component.mjs +25 -5
  9. package/esm2022/lib/components/molecules/glow-card/glow-card.component.mjs +13 -3
  10. package/esm2022/lib/components/molecules/number-stepper/number-stepper.component.mjs +9 -13
  11. package/esm2022/lib/components/molecules/plain-code-box/plain-code-box.component.mjs +17 -5
  12. package/esm2022/lib/components/organisms/auth-cta/auth-cta.component.mjs +3 -3
  13. package/esm2022/lib/components/organisms/avatar-upload/avatar-upload.component.mjs +3 -3
  14. package/esm2022/lib/components/organisms/bottom-nav/bottom-nav.component.mjs +5 -5
  15. package/esm2022/lib/components/organisms/data-table/data-table.component.mjs +12 -8
  16. package/esm2022/lib/components/organisms/infinite-list/infinite-list.component.mjs +31 -13
  17. package/esm2022/lib/components/organisms/login/login.component.mjs +3 -3
  18. package/esm2022/lib/components/organisms/toolbar/toolbar.component.mjs +73 -17
  19. package/esm2022/lib/version.mjs +2 -2
  20. package/fesm2022/valtech-components.mjs +215 -83
  21. package/fesm2022/valtech-components.mjs.map +1 -1
  22. package/lib/components/atoms/fab/types.d.ts +4 -0
  23. package/lib/version.d.ts +1 -1
  24. package/package.json +1 -1
@@ -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.6';
59
+ const VERSION = '4.0.9';
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]="{
@@ -12411,6 +12411,7 @@ class FabComponent {
12411
12411
  [disabled]="resolvedProps.disabled"
12412
12412
  [translucent]="resolvedProps.translucent"
12413
12413
  (click)="onMainClick()"
12414
+ [attr.aria-label]="resolvedProps.ariaLabel || resolvedProps.label || 'Acción'"
12414
12415
  >
12415
12416
  <ion-icon [name]="getMainIcon()" aria-hidden="true"></ion-icon>
12416
12417
  </ion-fab-button>
@@ -12422,6 +12423,7 @@ class FabComponent {
12422
12423
  [color]="action.color || 'light'"
12423
12424
  [disabled]="action.disabled"
12424
12425
  (click)="onActionClick(action)"
12426
+ [attr.aria-label]="action.label || action.token || action.icon"
12425
12427
  >
12426
12428
  <ion-icon [name]="action.icon" aria-hidden="true"></ion-icon>
12427
12429
  </ion-fab-button>
@@ -12441,6 +12443,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12441
12443
  [disabled]="resolvedProps.disabled"
12442
12444
  [translucent]="resolvedProps.translucent"
12443
12445
  (click)="onMainClick()"
12446
+ [attr.aria-label]="resolvedProps.ariaLabel || resolvedProps.label || 'Acción'"
12444
12447
  >
12445
12448
  <ion-icon [name]="getMainIcon()" aria-hidden="true"></ion-icon>
12446
12449
  </ion-fab-button>
@@ -12452,6 +12455,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12452
12455
  [color]="action.color || 'light'"
12453
12456
  [disabled]="action.disabled"
12454
12457
  (click)="onActionClick(action)"
12458
+ [attr.aria-label]="action.label || action.token || action.icon"
12455
12459
  >
12456
12460
  <ion-icon [name]="action.icon" aria-hidden="true"></ion-icon>
12457
12461
  </ion-fab-button>
@@ -16071,7 +16075,7 @@ class ExpandableTextComponent {
16071
16075
  return this.props.content?.length > (this.props.limit || 100);
16072
16076
  }
16073
16077
  getExpandText() {
16074
- return this.props.expandText || this.i18n.t('seeMore');
16078
+ return this.props.expandText || this.i18n.t('seeMore') || 'Ver más';
16075
16079
  }
16076
16080
  toggleExpand() {
16077
16081
  this.expanded = !this.expanded;
@@ -16090,7 +16094,13 @@ class ExpandableTextComponent {
16090
16094
  </ion-text>
16091
16095
  </div>
16092
16096
  @if (!expanded && isTruncated) {
16093
- <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
+ >
16094
16104
  {{ getExpandText() }}
16095
16105
  </button>
16096
16106
  }
@@ -16109,7 +16119,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16109
16119
  </ion-text>
16110
16120
  </div>
16111
16121
  @if (!expanded && isTruncated) {
16112
- <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
+ >
16113
16129
  {{ getExpandText() }}
16114
16130
  </button>
16115
16131
  }
@@ -19788,8 +19804,14 @@ class PlainCodeBoxComponent {
19788
19804
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlainCodeBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19789
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: `
19790
19806
  <div class="code-box-container">
19791
- <ion-button *ngIf="props.showCopyButton !== false" fill="clear" class="copy-button" (click)="copyCode()">
19792
- <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>
19793
19815
  </ion-button>
19794
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">
19795
19817
  </ng-container></code></pre>
@@ -19800,8 +19822,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19800
19822
  type: Component,
19801
19823
  args: [{ selector: 'val-plain-code-box', standalone: true, imports: [CommonModule, IonIcon, IonButton], template: `
19802
19824
  <div class="code-box-container">
19803
- <ion-button *ngIf="props.showCopyButton !== false" fill="clear" class="copy-button" (click)="copyCode()">
19804
- <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>
19805
19833
  </ion-button>
19806
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">
19807
19835
  </ng-container></code></pre>
@@ -21900,7 +21928,7 @@ class CommentComponent {
21900
21928
  }
21901
21929
  } @else {
21902
21930
  <button class="view-replies-button" (click)="onLoadMoreClick()">
21903
- <ion-icon name="chatbubble-outline"></ion-icon>
21931
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
21904
21932
  <span>{{ getViewRepliesText() }}</span>
21905
21933
  </button>
21906
21934
  }
@@ -22072,7 +22100,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
22072
22100
  }
22073
22101
  } @else {
22074
22102
  <button class="view-replies-button" (click)="onLoadMoreClick()">
22075
- <ion-icon name="chatbubble-outline"></ion-icon>
22103
+ <ion-icon name="chatbubble-outline" aria-hidden="true"></ion-icon>
22076
22104
  <span>{{ getViewRepliesText() }}</span>
22077
22105
  </button>
22078
22106
  }
@@ -24117,11 +24145,11 @@ class NumberStepperComponent {
24117
24145
  }
24118
24146
  /** Get decrement button aria-label with i18n fallback */
24119
24147
  getDecrementLabel() {
24120
- return this.props.decrementLabel || this.i18n.t('decrease');
24148
+ return this.props.decrementLabel || this.i18n.t('decrease') || 'Disminuir';
24121
24149
  }
24122
24150
  /** Get increment button aria-label with i18n fallback */
24123
24151
  getIncrementLabel() {
24124
- return this.props.incrementLabel || this.i18n.t('increase');
24152
+ return this.props.incrementLabel || this.i18n.t('increase') || 'Aumentar';
24125
24153
  }
24126
24154
  ngOnInit() {
24127
24155
  // Ensure initial value is within bounds
@@ -24265,7 +24293,7 @@ class NumberStepperComponent {
24265
24293
  (click)="decrement()"
24266
24294
  [attr.aria-label]="getDecrementLabel()"
24267
24295
  >
24268
- <ion-icon slot="icon-only" name="remove-outline"></ion-icon>
24296
+ <ion-icon slot="icon-only" name="remove-outline" aria-hidden="true"></ion-icon>
24269
24297
  </ion-button>
24270
24298
 
24271
24299
  <div class="value-display">
@@ -24298,16 +24326,14 @@ class NumberStepperComponent {
24298
24326
  (click)="increment()"
24299
24327
  [attr.aria-label]="getIncrementLabel()"
24300
24328
  >
24301
- <ion-icon slot="icon-only" name="add-outline"></ion-icon>
24329
+ <ion-icon slot="icon-only" name="add-outline" aria-hidden="true"></ion-icon>
24302
24330
  </ion-button>
24303
24331
  </div>
24304
24332
 
24305
24333
  <!-- Price display -->
24306
24334
  @if (props.showTotal && props.unitPrice) {
24307
24335
  <div class="price-display">
24308
- <span class="price-calculation">
24309
- {{ currentValue }} × {{ formatPrice(props.unitPrice) }}
24310
- </span>
24336
+ <span class="price-calculation"> {{ currentValue }} × {{ formatPrice(props.unitPrice) }} </span>
24311
24337
  <span class="price-equals">=</span>
24312
24338
  <span class="price-total">{{ formatPrice(totalPrice) }}</span>
24313
24339
  </div>
@@ -24365,7 +24391,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24365
24391
  (click)="decrement()"
24366
24392
  [attr.aria-label]="getDecrementLabel()"
24367
24393
  >
24368
- <ion-icon slot="icon-only" name="remove-outline"></ion-icon>
24394
+ <ion-icon slot="icon-only" name="remove-outline" aria-hidden="true"></ion-icon>
24369
24395
  </ion-button>
24370
24396
 
24371
24397
  <div class="value-display">
@@ -24398,16 +24424,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
24398
24424
  (click)="increment()"
24399
24425
  [attr.aria-label]="getIncrementLabel()"
24400
24426
  >
24401
- <ion-icon slot="icon-only" name="add-outline"></ion-icon>
24427
+ <ion-icon slot="icon-only" name="add-outline" aria-hidden="true"></ion-icon>
24402
24428
  </ion-button>
24403
24429
  </div>
24404
24430
 
24405
24431
  <!-- Price display -->
24406
24432
  @if (props.showTotal && props.unitPrice) {
24407
24433
  <div class="price-display">
24408
- <span class="price-calculation">
24409
- {{ currentValue }} × {{ formatPrice(props.unitPrice) }}
24410
- </span>
24434
+ <span class="price-calculation"> {{ currentValue }} × {{ formatPrice(props.unitPrice) }} </span>
24411
24435
  <span class="price-equals">=</span>
24412
24436
  <span class="price-total">{{ formatPrice(totalPrice) }}</span>
24413
24437
  </div>
@@ -25005,7 +25029,12 @@ class GlowCardComponent {
25005
25029
  </p>
25006
25030
 
25007
25031
  <!-- CTA Link with expanding animation -->
25008
- <a class="glow-card__cta" [href]="resolvedProps.cta?.url" (click)="onCtaClick($event)">
25032
+ <a
25033
+ class="glow-card__cta"
25034
+ [href]="resolvedProps.cta?.url"
25035
+ (click)="onCtaClick($event)"
25036
+ [attr.aria-label]="getCtaText() || resolvedProps.cta?.text || 'Ver más'"
25037
+ >
25009
25038
  <span class="glow-card__cta-text">{{ getCtaText() }}</span>
25010
25039
  <ion-icon
25011
25040
  class="glow-card__cta-icon"
@@ -25066,7 +25095,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25066
25095
  </p>
25067
25096
 
25068
25097
  <!-- CTA Link with expanding animation -->
25069
- <a class="glow-card__cta" [href]="resolvedProps.cta?.url" (click)="onCtaClick($event)">
25098
+ <a
25099
+ class="glow-card__cta"
25100
+ [href]="resolvedProps.cta?.url"
25101
+ (click)="onCtaClick($event)"
25102
+ [attr.aria-label]="getCtaText() || resolvedProps.cta?.text || 'Ver más'"
25103
+ >
25070
25104
  <span class="glow-card__cta-text">{{ getCtaText() }}</span>
25071
25105
  <ion-icon
25072
25106
  class="glow-card__cta-icon"
@@ -25912,7 +25946,12 @@ class FooterLinksComponent {
25912
25946
  class="social-button"
25913
25947
  [attr.aria-label]="social.name"
25914
25948
  >
25915
- <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>
25916
25955
  </ion-button>
25917
25956
  </div>
25918
25957
  </div>
@@ -25975,7 +26014,12 @@ class FooterLinksComponent {
25975
26014
  class="social-button"
25976
26015
  [attr.aria-label]="social.name"
25977
26016
  >
25978
- <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>
25979
26023
  </ion-button>
25980
26024
  </div>
25981
26025
  </div>
@@ -26079,7 +26123,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26079
26123
  class="social-button"
26080
26124
  [attr.aria-label]="social.name"
26081
26125
  >
26082
- <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>
26083
26132
  </ion-button>
26084
26133
  </div>
26085
26134
  </div>
@@ -26142,7 +26191,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26142
26191
  class="social-button"
26143
26192
  [attr.aria-label]="social.name"
26144
26193
  >
26145
- <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>
26146
26200
  </ion-button>
26147
26201
  </div>
26148
26202
  </div>
@@ -27582,7 +27636,7 @@ class ActionCardComponent {
27582
27636
  }
27583
27637
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27584
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: `
27585
- <article
27639
+ <div
27586
27640
  class="action-card"
27587
27641
  [class.action-card--small]="config().size === 'small'"
27588
27642
  [class.action-card--medium]="config().size === 'medium'"
@@ -27644,13 +27698,13 @@ class ActionCardComponent {
27644
27698
  @if (config().showChevron && !config().disabled) {
27645
27699
  <ion-icon name="chevron-forward-outline" class="action-card__chevron" aria-hidden="true"></ion-icon>
27646
27700
  }
27647
- </article>
27701
+ </div>
27648
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"] }] }); }
27649
27703
  }
27650
27704
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ActionCardComponent, decorators: [{
27651
27705
  type: Component,
27652
27706
  args: [{ selector: 'val-action-card', standalone: true, imports: [CommonModule, RouterLink, IonIcon, IonRippleEffect], template: `
27653
- <article
27707
+ <div
27654
27708
  class="action-card"
27655
27709
  [class.action-card--small]="config().size === 'small'"
27656
27710
  [class.action-card--medium]="config().size === 'medium'"
@@ -27712,7 +27766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
27712
27766
  @if (config().showChevron && !config().disabled) {
27713
27767
  <ion-icon name="chevron-forward-outline" class="action-card__chevron" aria-hidden="true"></ion-icon>
27714
27768
  }
27715
- </article>
27769
+ </div>
27716
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"] }]
27717
27771
  }], propDecorators: { onClick: [{
27718
27772
  type: Output
@@ -28033,7 +28087,7 @@ class ArticleCardComponent {
28033
28087
  }
28034
28088
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
28035
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: `
28036
- <article
28090
+ <div
28037
28091
  class="article-card"
28038
28092
  [class.article-card--bordered]="config().bordered"
28039
28093
  [class.article-card--shadowed]="config().shadowed"
@@ -28073,13 +28127,13 @@ class ArticleCardComponent {
28073
28127
  </p>
28074
28128
  }
28075
28129
  </div>
28076
- </article>
28130
+ </div>
28077
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"] }] }); }
28078
28132
  }
28079
28133
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleCardComponent, decorators: [{
28080
28134
  type: Component,
28081
28135
  args: [{ selector: 'val-article-card', standalone: true, imports: [CommonModule, RouterLink, IonRippleEffect], template: `
28082
- <article
28136
+ <div
28083
28137
  class="article-card"
28084
28138
  [class.article-card--bordered]="config().bordered"
28085
28139
  [class.article-card--shadowed]="config().shadowed"
@@ -28119,7 +28173,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
28119
28173
  </p>
28120
28174
  }
28121
28175
  </div>
28122
- </article>
28176
+ </div>
28123
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"] }]
28124
28178
  }], propDecorators: { onClick: [{
28125
28179
  type: Output
@@ -34314,17 +34368,36 @@ class ToolbarComponent {
34314
34368
  <ion-toolbar [color]="props.color" [class.background]="props.color === 'background'">
34315
34369
  <ng-container *ngIf="props.withBack">
34316
34370
  <ion-buttons class="left-buttons" slot="start" *ngIf="props.withBack">
34317
- <ion-button fill="clear" (click)="goBack()" [color]="props.textColor" style="margin-left: 8px;">
34318
- <ion-icon name="chevron-back-outline" [slot]="props.backText ? 'start' : 'icon-only'"></ion-icon>
34319
- <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>
34320
34384
  </ion-button>
34321
34385
  </ion-buttons>
34322
34386
  </ng-container>
34323
34387
  <ng-container *ngIf="props.withActions">
34324
34388
  <ion-buttons slot="end" *ngIf="someInRight() || props.withMenu || props.languageSelector">
34325
34389
  <ng-container *ngFor="let action of rightActions()">
34326
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34327
- <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>
34328
34401
  </ion-button>
34329
34402
  <val-user-avatar
34330
34403
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34356,8 +34429,17 @@ class ToolbarComponent {
34356
34429
  </ion-buttons>
34357
34430
  <ion-buttons slot="start" *ngIf="someInLeft()" style="padding-left: 4px;">
34358
34431
  <ng-container *ngFor="let action of leftActions()">
34359
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34360
- <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>
34361
34443
  </ion-button>
34362
34444
  <val-user-avatar
34363
34445
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34383,7 +34465,7 @@ class ToolbarComponent {
34383
34465
  <!-- experimental -->
34384
34466
  <ng-content select="[toolbar-bottom]"></ng-content>
34385
34467
  </ion-toolbar>
34386
- `, 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"] }] }); }
34387
34469
  }
34388
34470
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ToolbarComponent, decorators: [{
34389
34471
  type: Component,
@@ -34404,17 +34486,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34404
34486
  <ion-toolbar [color]="props.color" [class.background]="props.color === 'background'">
34405
34487
  <ng-container *ngIf="props.withBack">
34406
34488
  <ion-buttons class="left-buttons" slot="start" *ngIf="props.withBack">
34407
- <ion-button fill="clear" (click)="goBack()" [color]="props.textColor" style="margin-left: 8px;">
34408
- <ion-icon name="chevron-back-outline" [slot]="props.backText ? 'start' : 'icon-only'"></ion-icon>
34409
- <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>
34410
34502
  </ion-button>
34411
34503
  </ion-buttons>
34412
34504
  </ng-container>
34413
34505
  <ng-container *ngIf="props.withActions">
34414
34506
  <ion-buttons slot="end" *ngIf="someInRight() || props.withMenu || props.languageSelector">
34415
34507
  <ng-container *ngFor="let action of rightActions()">
34416
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34417
- <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>
34418
34519
  </ion-button>
34419
34520
  <val-user-avatar
34420
34521
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34446,8 +34547,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34446
34547
  </ion-buttons>
34447
34548
  <ion-buttons slot="start" *ngIf="someInLeft()" style="padding-left: 4px;">
34448
34549
  <ng-container *ngFor="let action of leftActions()">
34449
- <ion-button *ngIf="action.type === actionTypes.ICON" (click)="clickHandler(action.token)">
34450
- <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>
34451
34561
  </ion-button>
34452
34562
  <val-user-avatar
34453
34563
  *ngIf="action.type === actionTypes.AVATAR"
@@ -34473,7 +34583,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
34473
34583
  <!-- experimental -->
34474
34584
  <ng-content select="[toolbar-bottom]"></ng-content>
34475
34585
  </ion-toolbar>
34476
- `, 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"] }]
34477
34587
  }], ctorParameters: () => [{ type: IconService }], propDecorators: { props: [{
34478
34588
  type: Input
34479
34589
  }], onClick: [{
@@ -36679,7 +36789,7 @@ class DataTableComponent {
36679
36789
  }
36680
36790
  /** Get actions column label */
36681
36791
  getActionsLabel() {
36682
- return this.props.actionsLabel || this.i18n.t('actions');
36792
+ return this.props.actionsLabel || this.i18n.t('actions') || 'Acciones';
36683
36793
  }
36684
36794
  /** Get pagination info text */
36685
36795
  getPaginationInfoText() {
@@ -36691,19 +36801,19 @@ class DataTableComponent {
36691
36801
  }
36692
36802
  /** Get first page aria label */
36693
36803
  getFirstPageLabel() {
36694
- return this.i18n.t('firstPage');
36804
+ return this.i18n.t('firstPage') || 'Primera página';
36695
36805
  }
36696
36806
  /** Get previous page aria label */
36697
36807
  getPreviousPageLabel() {
36698
- return this.i18n.t('previousPage');
36808
+ return this.i18n.t('previousPage') || 'Página anterior';
36699
36809
  }
36700
36810
  /** Get next page aria label */
36701
36811
  getNextPageLabel() {
36702
- return this.i18n.t('nextPage');
36812
+ return this.i18n.t('nextPage') || 'Página siguiente';
36703
36813
  }
36704
36814
  /** Get last page aria label */
36705
36815
  getLastPageLabel() {
36706
- return this.i18n.t('lastPage');
36816
+ return this.i18n.t('lastPage') || 'Última página';
36707
36817
  }
36708
36818
  get pageSizeOptions() {
36709
36819
  return this.props.pagination?.pageSizeOptions || DEFAULT_PAGE_SIZE_OPTIONS;
@@ -36955,7 +37065,7 @@ class DataTableComponent {
36955
37065
  </th>
36956
37066
  }
36957
37067
  @if (props.showSelectionColumn && props.selection?.mode === 'single') {
36958
- <th class="selection-cell"></th>
37068
+ <th class="selection-cell" scope="col" aria-label="Selección"></th>
36959
37069
  }
36960
37070
 
36961
37071
  <!-- Row number column -->
@@ -36984,10 +37094,12 @@ class DataTableComponent {
36984
37094
  <span class="sort-icons">
36985
37095
  <ion-icon
36986
37096
  name="chevron-up-outline"
37097
+ aria-hidden="true"
36987
37098
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
36988
37099
  ></ion-icon>
36989
37100
  <ion-icon
36990
37101
  name="chevron-down-outline"
37102
+ aria-hidden="true"
36991
37103
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
36992
37104
  ></ion-icon>
36993
37105
  </span>
@@ -37312,7 +37424,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37312
37424
  </th>
37313
37425
  }
37314
37426
  @if (props.showSelectionColumn && props.selection?.mode === 'single') {
37315
- <th class="selection-cell"></th>
37427
+ <th class="selection-cell" scope="col" aria-label="Selección"></th>
37316
37428
  }
37317
37429
 
37318
37430
  <!-- Row number column -->
@@ -37341,10 +37453,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
37341
37453
  <span class="sort-icons">
37342
37454
  <ion-icon
37343
37455
  name="chevron-up-outline"
37456
+ aria-hidden="true"
37344
37457
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'asc'"
37345
37458
  ></ion-icon>
37346
37459
  <ion-icon
37347
37460
  name="chevron-down-outline"
37461
+ aria-hidden="true"
37348
37462
  [class.active]="currentSort?.column === column.key && currentSort?.direction === 'desc'"
37349
37463
  ></ion-icon>
37350
37464
  </span>
@@ -39050,7 +39164,7 @@ class InfiniteListComponent {
39050
39164
  lastItem: this.items()[this.items().length - 1],
39051
39165
  };
39052
39166
  const result = await this.executeLoad(params);
39053
- this.items.update((current) => [...current, ...result.items]);
39167
+ this.items.update(current => [...current, ...result.items]);
39054
39168
  this.hasMoreBottom.set(result.hasMore);
39055
39169
  this.currentPage++;
39056
39170
  this.currentCursor = result.cursor;
@@ -39077,7 +39191,7 @@ class InfiniteListComponent {
39077
39191
  firstItem: this.items()[0],
39078
39192
  };
39079
39193
  const result = await this.executeLoad(params);
39080
- this.items.update((current) => [...result.items, ...current]);
39194
+ this.items.update(current => [...result.items, ...current]);
39081
39195
  this.hasMoreTop.set(result.hasMore);
39082
39196
  this.state.set('idle');
39083
39197
  this.itemsChange.emit(this.items());
@@ -39120,17 +39234,17 @@ class InfiniteListComponent {
39120
39234
  }
39121
39235
  /** Agregar items al inicio */
39122
39236
  prependItems(newItems) {
39123
- this.items.update((current) => [...newItems, ...current]);
39237
+ this.items.update(current => [...newItems, ...current]);
39124
39238
  this.itemsChange.emit(this.items());
39125
39239
  }
39126
39240
  /** Agregar items al final */
39127
39241
  appendItems(newItems) {
39128
- this.items.update((current) => [...current, ...newItems]);
39242
+ this.items.update(current => [...current, ...newItems]);
39129
39243
  this.itemsChange.emit(this.items());
39130
39244
  }
39131
39245
  /** Actualizar un item por indice */
39132
39246
  updateItem(index, item) {
39133
- this.items.update((current) => {
39247
+ this.items.update(current => {
39134
39248
  const updated = [...current];
39135
39249
  updated[index] = item;
39136
39250
  return updated;
@@ -39139,7 +39253,7 @@ class InfiniteListComponent {
39139
39253
  }
39140
39254
  /** Remover un item por indice */
39141
39255
  removeItem(index) {
39142
- this.items.update((current) => current.filter((_, i) => i !== index));
39256
+ this.items.update(current => current.filter((_, i) => i !== index));
39143
39257
  this.itemsChange.emit(this.items());
39144
39258
  }
39145
39259
  /** Handler para evento de infinite scroll */
@@ -39226,7 +39340,10 @@ class InfiniteListComponent {
39226
39340
  <div class="infinite-list-error">
39227
39341
  @if (mergedProps.errorState?.template) {
39228
39342
  <ng-container
39229
- *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
+ "
39230
39347
  ></ng-container>
39231
39348
  } @else {
39232
39349
  @if (mergedProps.errorState?.icon) {
@@ -39247,8 +39364,14 @@ class InfiniteListComponent {
39247
39364
 
39248
39365
  <!-- Items list -->
39249
39366
  @if (items().length > 0) {
39250
- <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
39251
- @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
+ ) {
39252
39375
  <article
39253
39376
  class="infinite-list-item"
39254
39377
  [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
@@ -39384,7 +39507,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39384
39507
  <div class="infinite-list-error">
39385
39508
  @if (mergedProps.errorState?.template) {
39386
39509
  <ng-container
39387
- *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
+ "
39388
39514
  ></ng-container>
39389
39515
  } @else {
39390
39516
  @if (mergedProps.errorState?.icon) {
@@ -39405,8 +39531,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
39405
39531
 
39406
39532
  <!-- Items list -->
39407
39533
  @if (items().length > 0) {
39408
- <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
39409
- @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
+ ) {
39410
39542
  <article
39411
39543
  class="infinite-list-item"
39412
39544
  [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
@@ -40381,7 +40513,7 @@ class LoginComponent {
40381
40513
  this.stopResetResendCooldown();
40382
40514
  }
40383
40515
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
40384
- 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\" [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\" (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"] }] }); }
40385
40517
  }
40386
40518
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, decorators: [{
40387
40519
  type: Component,
@@ -40397,7 +40529,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
40397
40529
  IonToolbar,
40398
40530
  FormComponent,
40399
40531
  ImageComponent,
40400
- ], 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\" [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\" (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"] }]
40401
40533
  }], propDecorators: { props: [{
40402
40534
  type: Input
40403
40535
  }], onSuccess: [{
@@ -41054,7 +41186,7 @@ class BottomNavComponent {
41054
41186
  type="button"
41055
41187
  >
41056
41188
  <ion-ripple-effect></ion-ripple-effect>
41057
- <ion-icon [name]="config().fab!.icon"></ion-icon>
41189
+ <ion-icon [name]="config().fab!.icon" aria-hidden="true"></ion-icon>
41058
41190
  </button>
41059
41191
  } @else if (item) {
41060
41192
  <!-- Tab Item -->
@@ -41072,7 +41204,7 @@ class BottomNavComponent {
41072
41204
  <ion-ripple-effect></ion-ripple-effect>
41073
41205
 
41074
41206
  <div class="bottom-nav__tab-icon">
41075
- <ion-icon [name]="getIcon(item)"></ion-icon>
41207
+ <ion-icon [name]="getIcon(item)" aria-hidden="true"></ion-icon>
41076
41208
 
41077
41209
  <!-- Badge -->
41078
41210
  @if (item.badge) {
@@ -41128,7 +41260,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41128
41260
  type="button"
41129
41261
  >
41130
41262
  <ion-ripple-effect></ion-ripple-effect>
41131
- <ion-icon [name]="config().fab!.icon"></ion-icon>
41263
+ <ion-icon [name]="config().fab!.icon" aria-hidden="true"></ion-icon>
41132
41264
  </button>
41133
41265
  } @else if (item) {
41134
41266
  <!-- Tab Item -->
@@ -41146,7 +41278,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41146
41278
  <ion-ripple-effect></ion-ripple-effect>
41147
41279
 
41148
41280
  <div class="bottom-nav__tab-icon">
41149
- <ion-icon [name]="getIcon(item)"></ion-icon>
41281
+ <ion-icon [name]="getIcon(item)" aria-hidden="true"></ion-icon>
41150
41282
 
41151
41283
  <!-- Badge -->
41152
41284
  @if (item.badge) {
@@ -41668,7 +41800,7 @@ class AvatarUploadComponent {
41668
41800
  <!-- Edit Button -->
41669
41801
  @if (config().editable && !loading()) {
41670
41802
  <button class="edit-button" type="button" (click)="openFilePicker()" [attr.aria-label]="editButtonLabel()">
41671
- <ion-icon name="camera-outline"></ion-icon>
41803
+ <ion-icon name="camera-outline" aria-hidden="true"></ion-icon>
41672
41804
  </button>
41673
41805
  }
41674
41806
 
@@ -41775,7 +41907,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41775
41907
  <!-- Edit Button -->
41776
41908
  @if (config().editable && !loading()) {
41777
41909
  <button class="edit-button" type="button" (click)="openFilePicker()" [attr.aria-label]="editButtonLabel()">
41778
- <ion-icon name="camera-outline"></ion-icon>
41910
+ <ion-icon name="camera-outline" aria-hidden="true"></ion-icon>
41779
41911
  </button>
41780
41912
  }
41781
41913
 
@@ -66100,8 +66232,8 @@ class AuthCtaComponent {
66100
66232
  ...AUTH_CTA_DEFAULTS,
66101
66233
  ...this.props(),
66102
66234
  }));
66103
- this.loginLabel = computed(() => this.config().loginLabel ?? this.i18n.t('AuthCta.login'));
66104
- 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');
66105
66237
  this.resolvedBg = computed(() => {
66106
66238
  const bg = this.config().backgroundColor;
66107
66239
  if (!bg)