valtech-components 2.0.970 → 2.0.972

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 (36) hide show
  1. package/esm2022/lib/components/molecules/date-input/date-input.component.mjs +3 -3
  2. package/esm2022/lib/components/molecules/file-input/file-input.component.mjs +3 -3
  3. package/esm2022/lib/components/molecules/hint/hint.component.mjs +3 -3
  4. package/esm2022/lib/components/molecules/password-input/password-input.component.mjs +3 -3
  5. package/esm2022/lib/components/molecules/pin-input/pin-input.component.mjs +3 -3
  6. package/esm2022/lib/components/molecules/text-input/text-input.component.mjs +3 -3
  7. package/esm2022/lib/components/organisms/form/form.component.mjs +54 -12
  8. package/esm2022/lib/components/organisms/preferences-view/preferences-view.component.mjs +263 -0
  9. package/esm2022/lib/components/organisms/preferences-view/preferences-view.i18n.mjs +37 -0
  10. package/esm2022/lib/components/organisms/preferences-view/preferences.routes.mjs +29 -0
  11. package/esm2022/lib/components/organisms/preferences-view/types.mjs +2 -0
  12. package/esm2022/lib/components/organisms/profile-view/profile-view.component.mjs +601 -0
  13. package/esm2022/lib/components/organisms/profile-view/profile-view.i18n.mjs +75 -0
  14. package/esm2022/lib/components/organisms/profile-view/profile.routes.mjs +28 -0
  15. package/esm2022/lib/components/organisms/profile-view/types.mjs +2 -0
  16. package/esm2022/lib/components/types.mjs +1 -1
  17. package/esm2022/lib/version.mjs +2 -2
  18. package/esm2022/public-api.mjs +7 -2
  19. package/fesm2022/valtech-components.mjs +1351 -395
  20. package/fesm2022/valtech-components.mjs.map +1 -1
  21. package/lib/components/organisms/article/article.component.d.ts +4 -1
  22. package/lib/components/organisms/form/form.component.d.ts +23 -0
  23. package/lib/components/organisms/preferences-view/preferences-view.component.d.ts +53 -0
  24. package/lib/components/organisms/preferences-view/preferences-view.i18n.d.ts +12 -0
  25. package/lib/components/organisms/preferences-view/preferences.routes.d.ts +24 -0
  26. package/lib/components/organisms/preferences-view/types.d.ts +35 -0
  27. package/lib/components/organisms/profile-view/profile-view.component.d.ts +84 -0
  28. package/lib/components/organisms/profile-view/profile-view.i18n.d.ts +12 -0
  29. package/lib/components/organisms/profile-view/profile.routes.d.ts +23 -0
  30. package/lib/components/organisms/profile-view/types.d.ts +32 -0
  31. package/lib/components/types.d.ts +14 -0
  32. package/lib/version.d.ts +1 -1
  33. package/package.json +1 -1
  34. package/public-api.d.ts +6 -1
  35. package/esm2022/lib/components/organisms/form/form-footer/form-footer.component.mjs +0 -83
  36. package/lib/components/organisms/form/form-footer/form-footer.component.d.ts +0 -17
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, NgZone, ViewChild, ChangeDetectorRef, output, ContentChild, ElementRef, Injector, isSignal, ViewEncapsulation } from '@angular/core';
2
+ import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, NgZone, ViewChild, ChangeDetectorRef, output, ContentChild, ElementRef, viewChild, Injector, isSignal, ViewEncapsulation } from '@angular/core';
3
3
  import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, shareReplay, race, timer, forkJoin } from 'rxjs';
4
4
  import { catchError, switchMap, finalize, filter, take, map as map$1, tap, retry, timeout, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
5
5
  import * as i1$3 from '@angular/common/http';
@@ -17,7 +17,7 @@ import * as i1$2 from '@angular/fire/storage';
17
17
  import { provideStorage, getStorage, connectStorageEmulator, ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, listAll } from '@angular/fire/storage';
18
18
  import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
19
19
  import * as i1$4 from '@angular/router';
20
- import { Router, NavigationEnd, RouterLink, RouterOutlet, RouterModule } from '@angular/router';
20
+ import { Router, NavigationEnd, RouterLink, ActivatedRoute, RouterOutlet, RouterModule } from '@angular/router';
21
21
  import * as i2 from '@ionic/angular';
22
22
  import { IonicModule, ToastController, NavController } from '@ionic/angular';
23
23
  import { isSupported, getMessaging as getMessaging$1 } from 'firebase/messaging';
@@ -54,7 +54,7 @@ import 'prismjs/components/prism-json';
54
54
  * Current version of valtech-components.
55
55
  * This is automatically updated during the publish process.
56
56
  */
57
- const VERSION = '2.0.970';
57
+ const VERSION = '2.0.972';
58
58
 
59
59
  // Control de estado de refresco (singleton a nivel de módulo)
60
60
  let isRefreshing = false;
@@ -15901,7 +15901,7 @@ class DateInputComponent {
15901
15901
  </ion-datetime>
15902
15902
  </ng-template>
15903
15903
  </ion-modal>
15904
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.button-container{display:flex;flex-direction:column;align-items:flex-start}.action{margin-top:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonDatetimeButton, selector: "ion-datetime-button", inputs: ["color", "datetime", "disabled", "mode"] }, { kind: "component", type: IonModal, selector: "ion-modal" }] }); }
15904
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.button-container{display:flex;flex-direction:column;align-items:flex-start}.action{margin-top:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonDatetimeButton, selector: "ion-datetime-button", inputs: ["color", "datetime", "disabled", "mode"] }, { kind: "component", type: IonModal, selector: "ion-modal" }] }); }
15905
15905
  }
15906
15906
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DateInputComponent, decorators: [{
15907
15907
  type: Component,
@@ -15929,7 +15929,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
15929
15929
  </ion-datetime>
15930
15930
  </ng-template>
15931
15931
  </ion-modal>
15932
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.button-container{display:flex;flex-direction:column;align-items:flex-start}.action{margin-top:.25rem}\n"] }]
15932
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.button-container{display:flex;flex-direction:column;align-items:flex-start}.action{margin-top:.25rem}\n"] }]
15933
15933
  }], propDecorators: { preset: [{
15934
15934
  type: Input
15935
15935
  }], props: [{
@@ -16160,7 +16160,7 @@ class FileInputComponent {
16160
16160
  </div>
16161
16161
  <val-button [props]="contrastButton" (onClick)="fileInput.click()"></val-button>
16162
16162
  </div>
16163
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.file-container{margin-top:.25rem}.name-container{display:flex;flex-direction:row;align-items:center}\n"], dependencies: [{ kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }] }); }
16163
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.file-container{margin-top:.25rem}.name-container{display:flex;flex-direction:row;align-items:center}\n"], dependencies: [{ kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }] }); }
16164
16164
  }
16165
16165
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FileInputComponent, decorators: [{
16166
16166
  type: Component,
@@ -16181,7 +16181,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16181
16181
  </div>
16182
16182
  <val-button [props]="contrastButton" (onClick)="fileInput.click()"></val-button>
16183
16183
  </div>
16184
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.file-container{margin-top:.25rem}.name-container{display:flex;flex-direction:row;align-items:center}\n"] }]
16184
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.file-container{margin-top:.25rem}.name-container{display:flex;flex-direction:row;align-items:center}\n"] }]
16185
16185
  }], ctorParameters: () => [], propDecorators: { props: [{
16186
16186
  type: Input
16187
16187
  }], fileInput: [{
@@ -16252,7 +16252,7 @@ class HintComponent {
16252
16252
  }"
16253
16253
  ></val-text>
16254
16254
  </div>
16255
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.hint-container{margin-top:.25rem}\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: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
16255
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.hint-container{margin-top:.25rem}\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: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
16256
16256
  }
16257
16257
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HintComponent, decorators: [{
16258
16258
  type: Component,
@@ -16268,7 +16268,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16268
16268
  }"
16269
16269
  ></val-text>
16270
16270
  </div>
16271
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.hint-container{margin-top:.25rem}\n"] }]
16271
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.hint-container{margin-top:.25rem}\n"] }]
16272
16272
  }], ctorParameters: () => [], propDecorators: { props: [{
16273
16273
  type: Input
16274
16274
  }] } });
@@ -17750,7 +17750,7 @@ class PasswordInputComponent {
17750
17750
  <ion-icon slot="icon-only" [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"></ion-icon>
17751
17751
  </ion-button>
17752
17752
  </div>
17753
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
17753
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
17754
17754
  }
17755
17755
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PasswordInputComponent, decorators: [{
17756
17756
  type: Component,
@@ -17766,7 +17766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17766
17766
  <ion-icon slot="icon-only" [name]="hidePassword ? 'eye-off-outline' : 'eye-outline'"></ion-icon>
17767
17767
  </ion-button>
17768
17768
  </div>
17769
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"] }]
17769
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.input-container{display:flex;align-items:center;flex-direction:row}\n"] }]
17770
17770
  }], ctorParameters: () => [{ type: IconService }], propDecorators: { preset: [{
17771
17771
  type: Input
17772
17772
  }], props: [{
@@ -17839,7 +17839,7 @@ class PinInputComponent {
17839
17839
  <div class="otp">
17840
17840
  <ng-otp-input [formCtrl]="props.control" [config]="otpInputConfig"></ng-otp-input>
17841
17841
  </div>
17842
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.otp{text-align:center;margin-top:.25rem;font-family:var(--ion-default-font),Arial,sans-serif}@media (max-width: 480px){.otp ::ng-deep .otp-input{width:40px!important;height:44px!important;font-size:24px!important}}.otp-input-box:focus{border-color:#0ff}\n"], dependencies: [{ kind: "ngmodule", type: NgOtpInputModule }, { kind: "component", type: i1$8.NgOtpInputComponent, selector: "ng-otp-input", inputs: ["config", "formCtrl"], outputs: ["onInputChange"] }] }); }
17842
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.otp{text-align:center;margin-top:.25rem;font-family:var(--ion-default-font),Arial,sans-serif}@media (max-width: 480px){.otp ::ng-deep .otp-input{width:40px!important;height:44px!important;font-size:24px!important}}.otp-input-box:focus{border-color:#0ff}\n"], dependencies: [{ kind: "ngmodule", type: NgOtpInputModule }, { kind: "component", type: i1$8.NgOtpInputComponent, selector: "ng-otp-input", inputs: ["config", "formCtrl"], outputs: ["onInputChange"] }] }); }
17843
17843
  }
17844
17844
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PinInputComponent, decorators: [{
17845
17845
  type: Component,
@@ -17847,7 +17847,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17847
17847
  <div class="otp">
17848
17848
  <ng-otp-input [formCtrl]="props.control" [config]="otpInputConfig"></ng-otp-input>
17849
17849
  </div>
17850
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.otp{text-align:center;margin-top:.25rem;font-family:var(--ion-default-font),Arial,sans-serif}@media (max-width: 480px){.otp ::ng-deep .otp-input{width:40px!important;height:44px!important;font-size:24px!important}}.otp-input-box:focus{border-color:#0ff}\n"] }]
17850
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}.otp{text-align:center;margin-top:.25rem;font-family:var(--ion-default-font),Arial,sans-serif}@media (max-width: 480px){.otp ::ng-deep .otp-input{width:40px!important;height:44px!important;font-size:24px!important}}.otp-input-box:focus{border-color:#0ff}\n"] }]
17851
17851
  }], ctorParameters: () => [], propDecorators: { pinCode: [{
17852
17852
  type: ViewChild,
17853
17853
  args: [NgOtpInputComponent, { static: false }]
@@ -19072,11 +19072,11 @@ class TextInputComponent {
19072
19072
  };
19073
19073
  }
19074
19074
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TextInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19075
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: TextInputComponent, isStandalone: true, selector: "val-text-input", inputs: { preset: "preset", props: "props" }, usesOnChanges: true, ngImport: i0, template: ` <ion-input [formControl]="resolvedProps.control" type="text" [placeholder]="resolvedProps.placeholder" /> `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }] }); }
19075
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: TextInputComponent, isStandalone: true, selector: "val-text-input", inputs: { preset: "preset", props: "props" }, usesOnChanges: true, ngImport: i0, template: ` <ion-input [formControl]="resolvedProps.control" type="text" [placeholder]="resolvedProps.placeholder" /> `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$7.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }] }); }
19076
19076
  }
19077
19077
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TextInputComponent, decorators: [{
19078
19078
  type: Component,
19079
- args: [{ selector: 'val-text-input', standalone: true, imports: [ReactiveFormsModule, IonInput], template: ` <ion-input [formControl]="resolvedProps.control" type="text" [placeholder]="resolvedProps.placeholder" /> `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"] }]
19079
+ args: [{ selector: 'val-text-input', standalone: true, imports: [ReactiveFormsModule, IonInput], template: ` <ion-input [formControl]="resolvedProps.control" type="text" [placeholder]="resolvedProps.placeholder" /> `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"] }]
19080
19080
  }], propDecorators: { preset: [{
19081
19081
  type: Input
19082
19082
  }], props: [{
@@ -30598,6 +30598,18 @@ class FormComponent {
30598
30598
  this.onSelectChange = new EventEmitter();
30599
30599
  this.types = InputType;
30600
30600
  this.states = ComponentStates;
30601
+ /**
30602
+ * Valor actual del form (`form.getRawValue()`), actualizado en cada
30603
+ * `valueChanges`. Pensado para el modo `controlled`: el host lo lee vía
30604
+ * `@ViewChild(FormComponent)` sin tocar el FormGroup directo. En modo normal
30605
+ * también está disponible.
30606
+ */
30607
+ this.value = signal({});
30608
+ /**
30609
+ * Estado de validez del form, actualizado en cada `statusChanges`. Para que
30610
+ * el host (wizard) habilite/deshabilite su botón "Siguiente".
30611
+ */
30612
+ this.valid = signal(false);
30601
30613
  this.subscriptions = [];
30602
30614
  this.actionsCache = [];
30603
30615
  // Memo de getFieldProp/getUsernameProp por referencia de field — evita
@@ -30647,6 +30659,12 @@ class FormComponent {
30647
30659
  this.trackSelectChanges(field.name);
30648
30660
  });
30649
30661
  });
30662
+ // Estado reactivo público (value/valid) — actualizado por suscripción RxJS,
30663
+ // NO dentro de un effect: setear signals acá es seguro (no dispara NG0600).
30664
+ this.value.set(this.form.getRawValue());
30665
+ this.valid.set(this.form.valid);
30666
+ this.subscriptions.push(this.form.valueChanges.subscribe(() => this.value.set(this.form.getRawValue())));
30667
+ this.subscriptions.push(this.form.statusChanges.subscribe(() => this.valid.set(this.form.valid)));
30650
30668
  this.syncFieldControlStates();
30651
30669
  this.updateActionsCache();
30652
30670
  this.previousState = this.props.state;
@@ -30849,6 +30867,22 @@ class FormComponent {
30849
30867
  get isAtEndOfForm() {
30850
30868
  return isAtEnd(this.elementRef);
30851
30869
  }
30870
+ /**
30871
+ * Fuerza mostrar los errores de validación (marca todos los controles como
30872
+ * touched) y devuelve si el form es válido. Pensado para el modo `controlled`:
30873
+ * el host lo invoca en su "Siguiente" para gatear la navegación del wizard.
30874
+ */
30875
+ validate() {
30876
+ this.form.markAllAsTouched();
30877
+ return this.form.valid;
30878
+ }
30879
+ /**
30880
+ * Marca todos los controles como touched (muestra errores) sin devolver nada.
30881
+ * Alias semántico de la primera mitad de `validate()`.
30882
+ */
30883
+ markAllTouched() {
30884
+ this.form.markAllAsTouched();
30885
+ }
30852
30886
  get Form() {
30853
30887
  return this.form;
30854
30888
  }
@@ -30966,13 +31000,17 @@ class FormComponent {
30966
31000
  <ng-content></ng-content>
30967
31001
  </div>
30968
31002
  }
30969
- <val-button-group
30970
- [props]="{ buttons: actions, position: 'center', columned: false }"
30971
- (onClick)="submitHandler($event)"
30972
- ></val-button-group>
31003
+ @if (!props.controlled) {
31004
+ <div class="submit-actions" [class.submit-actions--sticky]="props.stickyFooter">
31005
+ <val-button-group
31006
+ [props]="{ buttons: actions, position: 'center', columned: false }"
31007
+ (onClick)="submitHandler($event)"
31008
+ ></val-button-group>
31009
+ </div>
31010
+ }
30973
31011
  </form>
30974
31012
  </div>
30975
- `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: HintComponent, selector: "val-hint", inputs: ["props"] }, { kind: "component", type: CommentInputComponent, selector: "val-comment-input", inputs: ["props"] }, { kind: "component", type: DateInputComponent, selector: "val-date-input", inputs: ["preset", "props"] }, { kind: "component", type: FileInputComponent, selector: "val-file-input", inputs: ["props"] }, { kind: "component", type: HourInputComponent, selector: "val-hour-input", inputs: ["props"] }, { kind: "component", type: EmailInputComponent, selector: "val-email-input", inputs: ["preset", "props"] }, { kind: "component", type: NumberInputComponent, selector: "val-number-input", inputs: ["props"] }, { kind: "component", type: NumberFromToComponent, selector: "val-number-from-to", inputs: ["props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: PasswordInputComponent, selector: "val-password-input", inputs: ["preset", "props"] }, { kind: "component", type: PinInputComponent, selector: "val-pin-input", inputs: ["props"] }, { kind: "component", type: SelectSearchComponent, selector: "val-select-search", inputs: ["label", "labelProperty", "valueProperty", "multiple", "placeholder", "props"] }, { kind: "component", type: MultiSelectSearchComponent, selector: "val-multi-select-search", inputs: ["label", "labelProperty", "valueProperty", "placeholder", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: PhoneInputComponent, selector: "val-phone-input", inputs: ["preset", "props"], outputs: ["phoneChange"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: CheckboxRadioInputComponent, selector: "val-checkbox-radio-input", inputs: ["props"] }, { kind: "component", type: UsernameInputComponent, selector: "val-username-input", inputs: ["props"] }, { kind: "component", type: AttachmentUploaderComponent, selector: "val-attachment-uploader", inputs: ["props"], outputs: ["attachmentsChange"] }] }); }
31013
+ `, isInline: true, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["preset", "props"] }, { kind: "component", type: TextareaInputComponent, selector: "val-textarea-input", inputs: ["preset", "props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: HintComponent, selector: "val-hint", inputs: ["props"] }, { kind: "component", type: CommentInputComponent, selector: "val-comment-input", inputs: ["props"] }, { kind: "component", type: DateInputComponent, selector: "val-date-input", inputs: ["preset", "props"] }, { kind: "component", type: FileInputComponent, selector: "val-file-input", inputs: ["props"] }, { kind: "component", type: HourInputComponent, selector: "val-hour-input", inputs: ["props"] }, { kind: "component", type: EmailInputComponent, selector: "val-email-input", inputs: ["preset", "props"] }, { kind: "component", type: NumberInputComponent, selector: "val-number-input", inputs: ["props"] }, { kind: "component", type: NumberFromToComponent, selector: "val-number-from-to", inputs: ["props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: PasswordInputComponent, selector: "val-password-input", inputs: ["preset", "props"] }, { kind: "component", type: PinInputComponent, selector: "val-pin-input", inputs: ["props"] }, { kind: "component", type: SelectSearchComponent, selector: "val-select-search", inputs: ["label", "labelProperty", "valueProperty", "multiple", "placeholder", "props"] }, { kind: "component", type: MultiSelectSearchComponent, selector: "val-multi-select-search", inputs: ["label", "labelProperty", "valueProperty", "placeholder", "props"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["preset", "props"] }, { kind: "component", type: PhoneInputComponent, selector: "val-phone-input", inputs: ["preset", "props"], outputs: ["phoneChange"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: CheckboxRadioInputComponent, selector: "val-checkbox-radio-input", inputs: ["props"] }, { kind: "component", type: UsernameInputComponent, selector: "val-username-input", inputs: ["props"] }, { kind: "component", type: AttachmentUploaderComponent, selector: "val-attachment-uploader", inputs: ["props"], outputs: ["attachmentsChange"] }] }); }
30976
31014
  }
30977
31015
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormComponent, decorators: [{
30978
31016
  type: Component,
@@ -31108,13 +31146,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
31108
31146
  <ng-content></ng-content>
31109
31147
  </div>
31110
31148
  }
31111
- <val-button-group
31112
- [props]="{ buttons: actions, position: 'center', columned: false }"
31113
- (onClick)="submitHandler($event)"
31114
- ></val-button-group>
31149
+ @if (!props.controlled) {
31150
+ <div class="submit-actions" [class.submit-actions--sticky]="props.stickyFooter">
31151
+ <val-button-group
31152
+ [props]="{ buttons: actions, position: 'center', columned: false }"
31153
+ (onClick)="submitHandler($event)"
31154
+ ></val-button-group>
31155
+ </div>
31156
+ }
31115
31157
  </form>
31116
31158
  </div>
31117
- `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"] }]
31159
+ `, styles: ["@charset \"UTF-8\";:root{--val-container-sm: 540px;--val-container-md: 720px;--val-container-lg: 880px;--val-container-xl: 1100px;--val-container-padding: 16px;--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}body.dark,html.ion-palette-dark,body[data-theme=dark]{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:var(--val-form-field-gap, .5rem) 0}@media (min-width: 768px){.input{margin:var(--val-form-field-gap, .75rem) 0}}.submit-actions--sticky{position:sticky;bottom:0;z-index:1;background:var(--ion-background-color);border-top:1px solid var(--ion-color-step-150, rgba(0, 0, 0, .08));padding:.75rem 0 calc(.75rem + env(safe-area-inset-bottom))}.field-description{display:block;font-size:.75rem;color:var(--ion-color-dark);margin-bottom:.25rem;line-height:1.4}\n"] }]
31118
31160
  }], ctorParameters: () => [{ type: i1$7.FormBuilder }, { type: i0.ElementRef }], propDecorators: { props: [{
31119
31161
  type: Input
31120
31162
  }], onSubmit: [{
@@ -33870,84 +33912,6 @@ const createNumberFromToField = (name, label, fromLabel, toLabel, options) => {
33870
33912
  };
33871
33913
  };
33872
33914
 
33873
- class FormFooterComponent {
33874
- constructor() {
33875
- this.onSubmit = new EventEmitter();
33876
- }
33877
- ngOnInit() { }
33878
- async submitHandler(token) {
33879
- this.onSubmit.emit({ fields: this.props.form.value, token });
33880
- }
33881
- get actions() {
33882
- if (!this.props.form) {
33883
- return [];
33884
- }
33885
- if (this.props.form.valid) {
33886
- this.props.data.actions.state = ComponentStates.ENABLED;
33887
- }
33888
- if (this.props.data.state === ComponentStates.WORKING) {
33889
- this.props.data.actions.state = ComponentStates.WORKING;
33890
- }
33891
- if (this.props.data.state === ComponentStates.ENABLED) {
33892
- this.props.data.actions.state = ComponentStates.ENABLED;
33893
- }
33894
- if (this.props.data.state === ComponentStates.DISABLED) {
33895
- this.props.data.actions.state = ComponentStates.DISABLED;
33896
- }
33897
- return [this.props.data.actions];
33898
- }
33899
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
33900
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: FormFooterComponent, isStandalone: true, selector: "val-form-footer", inputs: { props: "props" }, outputs: { onSubmit: "onSubmit" }, ngImport: i0, template: `
33901
- <val-footer
33902
- [props]="{
33903
- bordered: false,
33904
- translucent: false,
33905
- toolbar: {
33906
- title: '',
33907
- actions: [],
33908
- color: 'background',
33909
- withBack: false,
33910
- withActions: false,
33911
- },
33912
- }"
33913
- >
33914
- <val-button-group
33915
- extra
33916
- [props]="{ buttons: actions, position: 'center', columned: false }"
33917
- (onClick)="submitHandler($event)"
33918
- ></val-button-group>
33919
- </val-footer>
33920
- `, isInline: true, styles: [""], dependencies: [{ kind: "component", type: FooterComponent, selector: "val-footer", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }] }); }
33921
- }
33922
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormFooterComponent, decorators: [{
33923
- type: Component,
33924
- args: [{ selector: 'val-form-footer', standalone: true, imports: [FooterComponent, ButtonGroupComponent], template: `
33925
- <val-footer
33926
- [props]="{
33927
- bordered: false,
33928
- translucent: false,
33929
- toolbar: {
33930
- title: '',
33931
- actions: [],
33932
- color: 'background',
33933
- withBack: false,
33934
- withActions: false,
33935
- },
33936
- }"
33937
- >
33938
- <val-button-group
33939
- extra
33940
- [props]="{ buttons: actions, position: 'center', columned: false }"
33941
- (onClick)="submitHandler($event)"
33942
- ></val-button-group>
33943
- </val-footer>
33944
- ` }]
33945
- }], ctorParameters: () => [], propDecorators: { props: [{
33946
- type: Input
33947
- }], onSubmit: [{
33948
- type: Output
33949
- }] } });
33950
-
33951
33915
  /**
33952
33916
  * HeaderComponent
33953
33917
  *
@@ -41489,6 +41453,1289 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
41489
41453
  type: Input
41490
41454
  }] } });
41491
41455
 
41456
+ /**
41457
+ * PageRefreshService — bus del pull-to-refresh estándar del factory.
41458
+ *
41459
+ * **Por qué existe:** `val-page-wrapper` posee un único `<ion-content>` y todas
41460
+ * las páginas se renderizan dentro vía `<router-outlet>`. Un `<ion-refresher>`
41461
+ * tiene que vivir dentro de ese `ion-content`, así que el refresher NO puede
41462
+ * declararse en el template de cada página — vive una sola vez en
41463
+ * `val-page-wrapper`. Este servicio es el puente: la página activa registra
41464
+ * *qué hacer* al refrescar; el page-wrapper dispara el gesto y cierra el spinner.
41465
+ *
41466
+ * **Uso en una página** (ver `frontend/CLAUDE.md` — es el patrón estándar):
41467
+ *
41468
+ * ```ts
41469
+ * export class MiPage implements ViewWillEnter, ViewWillLeave {
41470
+ * private pageRefresh = inject(PageRefreshService);
41471
+ *
41472
+ * ionViewWillEnter(): void {
41473
+ * this.pageRefresh.register(() => this.reload());
41474
+ * }
41475
+ * ionViewWillLeave(): void {
41476
+ * this.pageRefresh.unregister();
41477
+ * }
41478
+ *
41479
+ * private async reload(): Promise<void> {
41480
+ * // re-fetch / re-suscribir streams / etc.
41481
+ * }
41482
+ * }
41483
+ * ```
41484
+ *
41485
+ * Páginas que no llaman `register()` simplemente no muestran refresher —
41486
+ * opt-in, sin impacto.
41487
+ */
41488
+ class PageRefreshService {
41489
+ constructor() {
41490
+ this.handler = null;
41491
+ /**
41492
+ * `true` cuando hay una página con handler registrado. `val-page-wrapper`
41493
+ * renderiza el `<val-refresher>` sólo cuando esto es `true`.
41494
+ */
41495
+ this.hasHandler = signal(false);
41496
+ }
41497
+ /**
41498
+ * Registra el handler de refresh de la página activa. Llamar en
41499
+ * `ionViewWillEnter`. Si ya había uno, lo reemplaza (sólo hay una página
41500
+ * activa a la vez en el router-outlet de Ionic).
41501
+ */
41502
+ register(handler) {
41503
+ this.handler = handler;
41504
+ this.hasHandler.set(true);
41505
+ }
41506
+ /**
41507
+ * Quita el handler. Llamar en `ionViewWillLeave` para que el refresher
41508
+ * desaparezca al salir de la vista.
41509
+ */
41510
+ unregister() {
41511
+ this.handler = null;
41512
+ this.hasHandler.set(false);
41513
+ }
41514
+ /**
41515
+ * Ejecuta el handler registrado y espera a que termine. Lo invoca
41516
+ * `val-page-wrapper` al detectar el gesto de pull. No-op si no hay handler.
41517
+ */
41518
+ async run() {
41519
+ if (!this.handler)
41520
+ return;
41521
+ await this.handler();
41522
+ }
41523
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
41524
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, providedIn: 'root' }); }
41525
+ }
41526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, decorators: [{
41527
+ type: Injectable,
41528
+ args: [{ providedIn: 'root' }]
41529
+ }] });
41530
+ /**
41531
+ * Conecta una página al pull-to-refresh estándar en UNA línea, sin lifecycle
41532
+ * hooks manuales: registra el handler y lo desregistra al destruir la página
41533
+ * (vía `DestroyRef`).
41534
+ *
41535
+ * DEBE llamarse en un injection context (constructor o field initializer).
41536
+ *
41537
+ * @example
41538
+ * ```ts
41539
+ * export class MiPage {
41540
+ * private data = createRefreshableStream(() => this.svc.getX());
41541
+ * readonly items = this.data.data;
41542
+ *
41543
+ * constructor() {
41544
+ * connectPageRefresh(() => this.data.reload());
41545
+ * }
41546
+ * }
41547
+ * ```
41548
+ *
41549
+ * Reemplaza el patrón `ngOnInit`→`register` / `ngOnDestroy`→`unregister`.
41550
+ */
41551
+ function connectPageRefresh(handler) {
41552
+ const svc = inject(PageRefreshService);
41553
+ const destroyRef = inject(DestroyRef);
41554
+ svc.register(handler);
41555
+ destroyRef.onDestroy(() => svc.unregister());
41556
+ }
41557
+
41558
+ /**
41559
+ * Defaults i18n (es/en) embebidos en `val-profile-view`. Auto-registrados en el
41560
+ * constructor del componente si el consumer no proveyó el namespace
41561
+ * (`Settings.Profile` por default). Garantiza que nunca haya una key faltante
41562
+ * evaluada por cada change-detection (ver nota en valtech-components/CLAUDE.md
41563
+ * sobre el storm de CD con `val-debug-console`). El consumer puede override
41564
+ * registrando el mismo namespace antes de que el componente monte.
41565
+ *
41566
+ * SOLO incluye las keys que la vista realmente usa.
41567
+ */
41568
+ const PROFILE_VIEW_I18N = {
41569
+ es: {
41570
+ pageTitle: 'Perfil',
41571
+ pageDescription: 'Administra tu informacion personal',
41572
+ name: 'Nombre completo',
41573
+ namePlaceholder: 'Tu nombre completo',
41574
+ nameHint: 'Tu nombre real que se mostrara en tu perfil.',
41575
+ email: 'Correo electronico',
41576
+ handle: 'Nombre de usuario',
41577
+ handlePlaceholder: 'usuario',
41578
+ handleHint: 'Tu identificador unico (@usuario). Otros pueden buscarte con este nombre.',
41579
+ handleInUse: 'Ese nombre de usuario ya está tomado',
41580
+ handleError: 'Error al actualizar el nombre de usuario',
41581
+ phoneInUse: 'Ese teléfono ya está en uso por otra cuenta',
41582
+ phoneInvalid: 'Formato de teléfono inválido (usa E.164: +56...)',
41583
+ phone: 'Telefono',
41584
+ phonePlaceholder: '+1 234 567 8900',
41585
+ phoneHint: 'Opcional. Para recuperacion de cuenta y notificaciones.',
41586
+ save: 'Guardar cambios',
41587
+ saving: 'Guardando...',
41588
+ saveSuccess: 'Perfil actualizado',
41589
+ saveError: 'Error al actualizar el perfil',
41590
+ usernameInvalid: 'Solo letras, numeros y guion bajo',
41591
+ avatarSuccess: 'Foto actualizada',
41592
+ avatarError: 'Error al actualizar la foto',
41593
+ changePhoto: 'Cambiar foto',
41594
+ viewPhoto: 'Ver foto',
41595
+ errorTitle: 'No pudimos cargar tu perfil',
41596
+ offlineTitle: 'Sin conexión',
41597
+ offlineHint: 'Revisa tu conexión a internet e intenta nuevamente.',
41598
+ retry: 'Reintentar',
41599
+ },
41600
+ en: {
41601
+ pageTitle: 'Profile',
41602
+ pageDescription: 'Manage your personal information',
41603
+ name: 'Full name',
41604
+ namePlaceholder: 'Your full name',
41605
+ nameHint: 'Your real name that will be displayed on your profile.',
41606
+ email: 'Email',
41607
+ handle: 'Username',
41608
+ handlePlaceholder: 'username',
41609
+ handleHint: 'Your unique identifier (@username). Others can search for you with this name.',
41610
+ handleInUse: 'That username is already taken',
41611
+ handleError: 'Failed to update username',
41612
+ phoneInUse: 'That phone is already in use by another account',
41613
+ phoneInvalid: 'Invalid phone format (use E.164: +1...)',
41614
+ phone: 'Phone',
41615
+ phonePlaceholder: '+1 234 567 8900',
41616
+ phoneHint: 'Optional. For account recovery and notifications.',
41617
+ save: 'Save changes',
41618
+ saving: 'Saving...',
41619
+ saveSuccess: 'Profile updated',
41620
+ saveError: 'Failed to update profile',
41621
+ usernameInvalid: 'Only letters, numbers and underscore',
41622
+ avatarSuccess: 'Photo updated',
41623
+ avatarError: 'Failed to update photo',
41624
+ changePhoto: 'Change photo',
41625
+ viewPhoto: 'View photo',
41626
+ errorTitle: "We couldn't load your profile",
41627
+ offlineTitle: 'Offline',
41628
+ offlineHint: 'Check your internet connection and try again.',
41629
+ retry: 'Retry',
41630
+ },
41631
+ };
41632
+
41633
+ /** Patrón sincronizado con backend handleRegex: lowercase alfanum + underscore. */
41634
+ const HANDLE_PATTERN = /^[a-z_][a-z0-9_]*$/;
41635
+ const HANDLE_MIN = 3;
41636
+ const HANDLE_MAX = 20;
41637
+ const DEFAULT_NAMESPACE$1 = 'Settings.Profile';
41638
+ /**
41639
+ * `val-profile-view` — vista Perfil full-feature autocontenida (organism).
41640
+ *
41641
+ * Edita los campos públicos del usuario en UN solo formulario con UN solo botón
41642
+ * "Guardar". Wireup:
41643
+ * - Avatar — val-avatar-upload (Firebase Storage + backend sync). Separado del
41644
+ * form porque es upload sync independiente.
41645
+ * - Handle (@usuario) — InputType.HANDLE (val-username-input con check de
41646
+ * disponibilidad async resuelto vía AuthService inyectado).
41647
+ * - Nombre — InputType.TEXT.
41648
+ * - Teléfono — InputType.PHONE.
41649
+ *
41650
+ * Submit handler dispatcha:
41651
+ * 1. Si handle cambió → updateHandle PRIMERO (uniqueness).
41652
+ * 2. Si name o phone cambió → updateProfile con ambos.
41653
+ *
41654
+ * Lectura del perfil: suscribe al doc Firestore /users/{uid} (mirror que mantiene
41655
+ * el backend). Reactivo cross-tab + auto-refresca tras save. Fallback REST
41656
+ * (auth.getProfile) si el doc no existe o el listener falla.
41657
+ *
41658
+ * NO renderiza ion-content — vive dentro de val-page-wrapper.
41659
+ *
41660
+ * Auto-registra sus defaults i18n (es/en) en el constructor si el consumer no
41661
+ * proveyó el namespace configurado (default `Settings.Profile`).
41662
+ */
41663
+ class ProfileViewComponent {
41664
+ /** Namespace i18n resuelto (capturado una vez para llamadas no-reactivas). */
41665
+ get ns() {
41666
+ return this.resolvedConfig().i18nNamespace;
41667
+ }
41668
+ constructor() {
41669
+ this.nav = inject(NavigationService);
41670
+ this.auth = inject(AuthService);
41671
+ this.i18n = inject(I18nService);
41672
+ this.toast = inject(ToastService);
41673
+ this.errors = inject(ValtechErrorService);
41674
+ this.firebase = inject(FirebaseService);
41675
+ this.collections = inject(FirestoreCollectionFactory);
41676
+ this.route = inject(ActivatedRoute, { optional: true });
41677
+ /** Config mergeada con defaults. @Input gana sobre route data. */
41678
+ this.resolvedConfig = computed(() => {
41679
+ const fromRoute = (this.route?.snapshot.data['profileConfig'] ?? {});
41680
+ const merged = { ...fromRoute, ...(this.config ?? {}) };
41681
+ return {
41682
+ showAvatar: merged.showAvatar ?? true,
41683
+ showHandle: merged.showHandle ?? true,
41684
+ showPhone: merged.showPhone ?? true,
41685
+ i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE$1,
41686
+ onSaved: merged.onSaved,
41687
+ onAvatarUploaded: merged.onAvatarUploaded,
41688
+ };
41689
+ });
41690
+ /**
41691
+ * Colección global /users/{uid} (skipAppPrefix: true — el doc vive fuera de
41692
+ * apps/{appId}/... porque es cross-app, ver firestore.rules).
41693
+ */
41694
+ this.usersCol = this.collections.create('users', {
41695
+ skipAppPrefix: true,
41696
+ });
41697
+ this.formCmp = viewChild('form');
41698
+ this.profile = signal(null);
41699
+ this.loading = signal(true);
41700
+ this.saving = signal(false);
41701
+ this.loadError = signal(null);
41702
+ this._userId = computed(() => this.auth.user()?.userId ?? null);
41703
+ this.errorState = computed(() => {
41704
+ this.i18n.lang();
41705
+ const err = this.loadError();
41706
+ if (!err)
41707
+ return null;
41708
+ return createErrorStateProps(err, {
41709
+ title: {
41710
+ offline: this.t('offlineTitle'),
41711
+ error: this.t('errorTitle'),
41712
+ },
41713
+ description: {
41714
+ offline: this.t('offlineHint'),
41715
+ error: interpretError(err).message,
41716
+ },
41717
+ retryLabel: this.t('retry'),
41718
+ onRetry: () => this.loadFromApi(),
41719
+ retrying: this.loading(),
41720
+ });
41721
+ });
41722
+ this.avatarProps = computed(() => {
41723
+ this.i18n.lang();
41724
+ const p = this.profile();
41725
+ return {
41726
+ currentUrl: p?.avatarUrl,
41727
+ initials: this.initialsFromName(p?.name),
41728
+ size: 96,
41729
+ editable: true,
41730
+ showViewButton: true,
41731
+ i18nNamespace: this.ns,
41732
+ };
41733
+ });
41734
+ this.formMeta = this.buildFormMeta();
41735
+ // Auto-registro i18n — respeta override del consumer. El namespace puede
41736
+ // venir de @Input.config o del route data; lo resolvemos acá.
41737
+ const ns = this.ns;
41738
+ if (!this.i18n.hasNamespace(ns)) {
41739
+ this.i18n.registerContent(ns, PROFILE_VIEW_I18N);
41740
+ }
41741
+ this.nav.setBackHeader('pageTitle', ns, { withMenu: true });
41742
+ connectPageRefresh(() => this.loadFromApi());
41743
+ effect(onCleanup => {
41744
+ const uid = this._userId();
41745
+ if (!uid) {
41746
+ this.profile.set(null);
41747
+ this.loading.set(false);
41748
+ return;
41749
+ }
41750
+ this.loading.set(true);
41751
+ let sub = null;
41752
+ let cancelled = false;
41753
+ let apiFallbackUsed = false;
41754
+ void this.firebase.whenFirebaseAuthReady().then(() => {
41755
+ if (cancelled)
41756
+ return;
41757
+ sub = this.usersCol.watch(uid).subscribe({
41758
+ next: doc => {
41759
+ if (doc) {
41760
+ this.profile.set(this.mapMirrorToProfile(doc));
41761
+ this.loadError.set(null);
41762
+ this.loading.set(false);
41763
+ }
41764
+ else if (!apiFallbackUsed) {
41765
+ apiFallbackUsed = true;
41766
+ void this.loadFromApi();
41767
+ }
41768
+ },
41769
+ error: () => {
41770
+ if (!apiFallbackUsed) {
41771
+ apiFallbackUsed = true;
41772
+ void this.loadFromApi();
41773
+ }
41774
+ },
41775
+ });
41776
+ });
41777
+ onCleanup(() => {
41778
+ cancelled = true;
41779
+ sub?.unsubscribe();
41780
+ });
41781
+ }, { allowSignalWrites: true });
41782
+ // saving → mutar state (val-form.ngDoCheck lo detecta).
41783
+ effect(() => {
41784
+ const isSaving = this.saving();
41785
+ const state = isSaving ? ComponentStates.WORKING : ComponentStates.ENABLED;
41786
+ this.formMeta.state = state;
41787
+ this.formMeta.actions.state = state;
41788
+ this.formMeta.actions.text = isSaving ? this.t('saving') : this.t('save');
41789
+ });
41790
+ // profile loaded + form mounted → patchValue al FormGroup.
41791
+ effect(() => {
41792
+ const p = this.profile();
41793
+ const form = this.formCmp()?.Form;
41794
+ if (!p || !form)
41795
+ return;
41796
+ form.patchValue({
41797
+ handle: p.handle || '',
41798
+ name: p.name || '',
41799
+ phone: p.phone || '',
41800
+ }, { emitEvent: false });
41801
+ });
41802
+ // i18n.lang change → mutar labels (rare, no afecta typing).
41803
+ effect(() => {
41804
+ this.i18n.lang();
41805
+ this.applyI18nLabels();
41806
+ });
41807
+ }
41808
+ /** Construcción inicial — UNA vez. Gatea handle/phone según config. */
41809
+ buildFormMeta() {
41810
+ const cfg = this.resolvedConfig();
41811
+ const handleField = {
41812
+ token: 'profile-handle',
41813
+ name: 'handle',
41814
+ label: this.t('handle'),
41815
+ hint: this.t('handleHint'),
41816
+ placeholder: this.t('handlePlaceholder'),
41817
+ type: InputType.HANDLE,
41818
+ order: 1,
41819
+ validators: [
41820
+ Validators.required,
41821
+ Validators.minLength(HANDLE_MIN),
41822
+ Validators.maxLength(HANDLE_MAX),
41823
+ Validators.pattern(HANDLE_PATTERN),
41824
+ ],
41825
+ errors: {
41826
+ required: this.t('usernameInvalid'),
41827
+ minlength: this.t('usernameInvalid'),
41828
+ maxlength: this.t('usernameInvalid'),
41829
+ pattern: this.t('usernameInvalid'),
41830
+ },
41831
+ value: '',
41832
+ range: { min: HANDLE_MIN, max: HANDLE_MAX },
41833
+ state: ComponentStates.ENABLED,
41834
+ };
41835
+ const nameField = {
41836
+ token: 'profile-name',
41837
+ name: 'name',
41838
+ label: this.t('name'),
41839
+ hint: this.t('nameHint'),
41840
+ placeholder: this.t('namePlaceholder'),
41841
+ type: InputType.TEXT,
41842
+ order: 2,
41843
+ validators: [Validators.required, Validators.minLength(2), Validators.maxLength(100)],
41844
+ errors: {},
41845
+ value: '',
41846
+ state: ComponentStates.ENABLED,
41847
+ };
41848
+ const phoneField = {
41849
+ token: 'profile-phone',
41850
+ name: 'phone',
41851
+ label: this.t('phone'),
41852
+ hint: this.t('phoneHint'),
41853
+ placeholder: this.t('phonePlaceholder'),
41854
+ type: InputType.PHONE,
41855
+ order: 3,
41856
+ validators: [],
41857
+ errors: {},
41858
+ value: '',
41859
+ state: ComponentStates.ENABLED,
41860
+ };
41861
+ // Filtrado por config: el name siempre va; handle/phone son opt-out.
41862
+ const fields = [];
41863
+ if (cfg.showHandle)
41864
+ fields.push(handleField);
41865
+ fields.push(nameField);
41866
+ if (cfg.showPhone)
41867
+ fields.push(phoneField);
41868
+ const submitButton = {
41869
+ text: this.t('save'),
41870
+ color: 'dark',
41871
+ type: 'submit',
41872
+ fill: 'solid',
41873
+ size: 'default',
41874
+ shape: 'round',
41875
+ expand: 'block',
41876
+ state: ComponentStates.ENABLED,
41877
+ token: 'profile-save',
41878
+ };
41879
+ return {
41880
+ name: '',
41881
+ state: ComponentStates.ENABLED,
41882
+ sections: [
41883
+ {
41884
+ name: '',
41885
+ order: 1,
41886
+ fields,
41887
+ },
41888
+ ],
41889
+ actions: submitButton,
41890
+ };
41891
+ }
41892
+ /** Re-aplica labels/hints/placeholders en cambio de idioma. */
41893
+ applyI18nLabels() {
41894
+ const section = this.formMeta.sections[0];
41895
+ for (const field of section.fields) {
41896
+ switch (field.name) {
41897
+ case 'handle':
41898
+ field.label = this.t('handle');
41899
+ field.hint = this.t('handleHint');
41900
+ field.placeholder = this.t('handlePlaceholder');
41901
+ field.errors = {
41902
+ required: this.t('usernameInvalid'),
41903
+ minlength: this.t('usernameInvalid'),
41904
+ maxlength: this.t('usernameInvalid'),
41905
+ pattern: this.t('usernameInvalid'),
41906
+ };
41907
+ break;
41908
+ case 'name':
41909
+ field.label = this.t('name');
41910
+ field.hint = this.t('nameHint');
41911
+ field.placeholder = this.t('namePlaceholder');
41912
+ break;
41913
+ case 'phone':
41914
+ field.label = this.t('phone');
41915
+ field.hint = this.t('phoneHint');
41916
+ field.placeholder = this.t('phonePlaceholder');
41917
+ break;
41918
+ }
41919
+ }
41920
+ const button = this.formMeta.actions;
41921
+ button.text = this.saving() ? this.t('saving') : this.t('save');
41922
+ }
41923
+ /**
41924
+ * Fallback REST. Capa 4 (UI declarativa): NO toasteamos acá — el
41925
+ * val-empty-state ES la UI del error.
41926
+ */
41927
+ async loadFromApi() {
41928
+ this.loading.set(true);
41929
+ try {
41930
+ const p = await firstValueFrom(this.auth.getProfile());
41931
+ this.profile.set(p);
41932
+ this.loadError.set(null);
41933
+ }
41934
+ catch (err) {
41935
+ this.loadError.set(err);
41936
+ }
41937
+ finally {
41938
+ this.loading.set(false);
41939
+ }
41940
+ }
41941
+ mapMirrorToProfile(doc) {
41942
+ return {
41943
+ operationId: '',
41944
+ userId: doc.userId,
41945
+ email: doc.email,
41946
+ name: doc.name ?? '',
41947
+ handle: doc.handle,
41948
+ phone: doc.phone,
41949
+ avatarUrl: doc.avatarUrl,
41950
+ emailVerified: false,
41951
+ phoneVerified: false,
41952
+ mfaEnabled: false,
41953
+ createdAt: '',
41954
+ updatedAt: '',
41955
+ };
41956
+ }
41957
+ async onSubmit(event) {
41958
+ if (this.saving())
41959
+ return;
41960
+ const current = this.profile();
41961
+ if (!current)
41962
+ return;
41963
+ const cfg = this.resolvedConfig();
41964
+ const fields = event.fields || {};
41965
+ const nextHandle = String(fields['handle'] || '')
41966
+ .trim()
41967
+ .toLowerCase();
41968
+ const nextName = String(fields['name'] || '').trim();
41969
+ const nextPhone = String(fields['phone'] || '').trim();
41970
+ const handleChanged = cfg.showHandle && !!nextHandle && nextHandle !== (current.handle || '').toLowerCase();
41971
+ const nameChanged = !!nextName && nextName !== (current.name || '');
41972
+ const phoneChanged = cfg.showPhone && nextPhone !== (current.phone || '');
41973
+ if (!handleChanged && !nameChanged && !phoneChanged) {
41974
+ this.toast.show({
41975
+ message: this.t('saveSuccess'),
41976
+ duration: 2000,
41977
+ color: 'dark',
41978
+ position: 'top',
41979
+ });
41980
+ return;
41981
+ }
41982
+ this.saving.set(true);
41983
+ try {
41984
+ if (handleChanged) {
41985
+ try {
41986
+ await firstValueFrom(this.auth.updateHandle(nextHandle));
41987
+ }
41988
+ catch (err) {
41989
+ this.errors.handle(err, {
41990
+ context: 'profile.updateHandle',
41991
+ i18nMap: { AUTH_USERNAME_EXISTS: 'handleInUse' },
41992
+ fallbackKey: 'handleError',
41993
+ i18nNamespace: this.ns,
41994
+ });
41995
+ await this.loadFromApi();
41996
+ return;
41997
+ }
41998
+ }
41999
+ if (nameChanged || phoneChanged) {
42000
+ const payload = {};
42001
+ if (nameChanged)
42002
+ payload.name = nextName;
42003
+ if (phoneChanged)
42004
+ payload.phone = nextPhone;
42005
+ try {
42006
+ await firstValueFrom(this.auth.updateProfile(payload));
42007
+ }
42008
+ catch (err) {
42009
+ this.errors.handle(err, {
42010
+ context: 'profile.updateProfile',
42011
+ i18nMap: {
42012
+ AUTHV2_PHONE_EXISTS: 'phoneInUse',
42013
+ AUTHV2_INVALID_PHONE: 'phoneInvalid',
42014
+ },
42015
+ fallbackKey: 'saveError',
42016
+ i18nNamespace: this.ns,
42017
+ });
42018
+ await this.loadFromApi();
42019
+ return;
42020
+ }
42021
+ }
42022
+ this.toast.show({
42023
+ message: this.t('saveSuccess'),
42024
+ duration: 2500,
42025
+ color: 'dark',
42026
+ position: 'top',
42027
+ });
42028
+ cfg.onSaved?.(this.profile() ?? current);
42029
+ }
42030
+ finally {
42031
+ this.saving.set(false);
42032
+ }
42033
+ }
42034
+ onAvatarUploaded(result) {
42035
+ this.toast.show({
42036
+ message: this.t('avatarSuccess'),
42037
+ duration: 2500,
42038
+ color: 'dark',
42039
+ position: 'top',
42040
+ });
42041
+ this.resolvedConfig().onAvatarUploaded?.(result);
42042
+ }
42043
+ onAvatarError(_err) {
42044
+ this.toast.show({
42045
+ message: this.t('avatarError'),
42046
+ duration: 3000,
42047
+ color: 'dark',
42048
+ position: 'top',
42049
+ });
42050
+ }
42051
+ /** Lee del namespace configurado. */
42052
+ t(key) {
42053
+ return this.i18n.t(key, this.ns);
42054
+ }
42055
+ initialsFromName(name) {
42056
+ if (!name)
42057
+ return '?';
42058
+ const parts = name.trim().split(/\s+/).filter(Boolean);
42059
+ if (parts.length === 0)
42060
+ return '?';
42061
+ const first = parts[0]?.[0] ?? '';
42062
+ const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? '') : '';
42063
+ return (first + last).toUpperCase() || '?';
42064
+ }
42065
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfileViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
42066
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ProfileViewComponent, isStandalone: true, selector: "val-profile-view", inputs: { config: "config" }, viewQueries: [{ propertyName: "formCmp", first: true, predicate: ["form"], descendants: true, isSignal: true }], ngImport: i0, template: `
42067
+ <div class="page">
42068
+ <header class="page-header">
42069
+ <val-display [props]="{ size: 'small', color: 'dark', content: t('pageTitle') }" />
42070
+ <val-title
42071
+ [props]="{
42072
+ size: 'large',
42073
+ color: 'dark',
42074
+ bold: false,
42075
+ content: t('pageDescription'),
42076
+ }"
42077
+ />
42078
+ </header>
42079
+
42080
+ @if (loading()) {
42081
+ <val-skeleton-layout [props]="{ preset: 'form', rows: 3, showAvatar: true }" />
42082
+ } @else if (errorState()) {
42083
+ <val-empty-state [props]="errorState()!" />
42084
+ } @else {
42085
+ @if (profile(); as p) {
42086
+ @if (resolvedConfig().showAvatar) {
42087
+ <section class="settings-section avatar-section">
42088
+ <val-avatar-upload
42089
+ [props]="avatarProps()"
42090
+ (uploaded)="onAvatarUploaded($event)"
42091
+ (error)="onAvatarError($event)"
42092
+ />
42093
+ <div class="avatar-meta">
42094
+ <val-title
42095
+ [props]="{
42096
+ size: 'medium',
42097
+ color: 'dark',
42098
+ bold: true,
42099
+ content: p.name || '—',
42100
+ }"
42101
+ />
42102
+ <val-text
42103
+ [props]="{
42104
+ size: 'small',
42105
+ color: 'dark',
42106
+ bold: false,
42107
+ content: p.email,
42108
+ }"
42109
+ />
42110
+ @if (p.handle) {
42111
+ <val-text
42112
+ [props]="{
42113
+ size: 'small',
42114
+ color: 'dark',
42115
+ bold: true,
42116
+ content: '@' + p.handle,
42117
+ }"
42118
+ />
42119
+ }
42120
+ </div>
42121
+ </section>
42122
+ }
42123
+
42124
+ <val-form #form [props]="formMeta" (onSubmit)="onSubmit($event)" />
42125
+ }
42126
+ }
42127
+ </div>
42128
+ `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.page-header h1{font-size:22px;font-weight:700;margin:0 0 4px}.hint{font-size:13px;opacity:.7;margin:0 0 12px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.avatar-section{display:flex;align-items:center;gap:16px}.avatar-meta{display:flex;flex-direction:column;gap:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: AvatarUploadComponent, selector: "val-avatar-upload", inputs: ["props"], outputs: ["uploaded", "error", "uploadStart"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }] }); }
42129
+ }
42130
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfileViewComponent, decorators: [{
42131
+ type: Component,
42132
+ args: [{ selector: 'val-profile-view', standalone: true, imports: [
42133
+ CommonModule,
42134
+ ReactiveFormsModule,
42135
+ AvatarUploadComponent,
42136
+ EmptyStateComponent,
42137
+ FormComponent,
42138
+ DisplayComponent,
42139
+ TextComponent,
42140
+ TitleComponent,
42141
+ SkeletonLayoutComponent,
42142
+ ], template: `
42143
+ <div class="page">
42144
+ <header class="page-header">
42145
+ <val-display [props]="{ size: 'small', color: 'dark', content: t('pageTitle') }" />
42146
+ <val-title
42147
+ [props]="{
42148
+ size: 'large',
42149
+ color: 'dark',
42150
+ bold: false,
42151
+ content: t('pageDescription'),
42152
+ }"
42153
+ />
42154
+ </header>
42155
+
42156
+ @if (loading()) {
42157
+ <val-skeleton-layout [props]="{ preset: 'form', rows: 3, showAvatar: true }" />
42158
+ } @else if (errorState()) {
42159
+ <val-empty-state [props]="errorState()!" />
42160
+ } @else {
42161
+ @if (profile(); as p) {
42162
+ @if (resolvedConfig().showAvatar) {
42163
+ <section class="settings-section avatar-section">
42164
+ <val-avatar-upload
42165
+ [props]="avatarProps()"
42166
+ (uploaded)="onAvatarUploaded($event)"
42167
+ (error)="onAvatarError($event)"
42168
+ />
42169
+ <div class="avatar-meta">
42170
+ <val-title
42171
+ [props]="{
42172
+ size: 'medium',
42173
+ color: 'dark',
42174
+ bold: true,
42175
+ content: p.name || '—',
42176
+ }"
42177
+ />
42178
+ <val-text
42179
+ [props]="{
42180
+ size: 'small',
42181
+ color: 'dark',
42182
+ bold: false,
42183
+ content: p.email,
42184
+ }"
42185
+ />
42186
+ @if (p.handle) {
42187
+ <val-text
42188
+ [props]="{
42189
+ size: 'small',
42190
+ color: 'dark',
42191
+ bold: true,
42192
+ content: '@' + p.handle,
42193
+ }"
42194
+ />
42195
+ }
42196
+ </div>
42197
+ </section>
42198
+ }
42199
+
42200
+ <val-form #form [props]="formMeta" (onSubmit)="onSubmit($event)" />
42201
+ }
42202
+ }
42203
+ </div>
42204
+ `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.page-header h1{font-size:22px;font-weight:700;margin:0 0 4px}.hint{font-size:13px;opacity:.7;margin:0 0 12px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.avatar-section{display:flex;align-items:center;gap:16px}.avatar-meta{display:flex;flex-direction:column;gap:2px}\n"] }]
42205
+ }], ctorParameters: () => [], propDecorators: { config: [{
42206
+ type: Input
42207
+ }] } });
42208
+
42209
+ /**
42210
+ * Helper para montar la vista Perfil (`val-profile-view`) como ruta en una app
42211
+ * del factory. El `config` se pasa por route `data` (`profileConfig`) y el
42212
+ * componente lo lee como fallback de su `@Input() config`.
42213
+ *
42214
+ * @example
42215
+ * ```ts
42216
+ * // settings.routes.ts
42217
+ * export const settingsRoutes: Routes = [
42218
+ * ...provideValtechProfileRoutes(),
42219
+ * { path: 'preferences', loadComponent: () => ... },
42220
+ * ];
42221
+ *
42222
+ * // con config acotada:
42223
+ * ...provideValtechProfileRoutes({ config: { showPhone: false } }),
42224
+ * ```
42225
+ */
42226
+ function provideValtechProfileRoutes(opts) {
42227
+ return [
42228
+ {
42229
+ path: opts?.path ?? 'profile',
42230
+ component: ProfileViewComponent,
42231
+ data: { profileConfig: opts?.config },
42232
+ },
42233
+ ];
42234
+ }
42235
+
42236
+ /**
42237
+ * PreferencesService — preferencias del user en el doc canónico Firestore
42238
+ * `/apps/{appId}/users/{uid}/preferences/main`.
42239
+ *
42240
+ * Read reactivo (signals) via listener Firestore.
42241
+ * Write via `PUT /v2/auth/preferences` (cliente NUNCA escribe Firestore directo —
42242
+ * ver memoria `feedback_no_direct_firestore_writes`).
42243
+ *
42244
+ * Side-effects automáticos:
42245
+ * - Cuando `theme()` cambia → `ThemeService.Theme = ...`
42246
+ * - Cuando `language()` cambia → `I18nService.setLanguage(...)`
42247
+ *
42248
+ * Auto-bind al user actual via `AuthService.user()`. Sin user (logout) → unbind.
42249
+ */
42250
+ class PreferencesService {
42251
+ constructor(config, firestore, auth, http, themeService, i18n) {
42252
+ this.config = config;
42253
+ this.firestore = firestore;
42254
+ this.auth = auth;
42255
+ this.http = http;
42256
+ this.themeService = themeService;
42257
+ this.i18n = i18n;
42258
+ this._theme = signal('auto');
42259
+ this._language = signal('es');
42260
+ // Default `false` (opt-in). El user debe activar explícitamente las notificaciones;
42261
+ // no asumimos consentimiento implícito. Backend debe coincidir.
42262
+ this._notificationsMaster = signal(false);
42263
+ /** `true` después del primer snapshot Firestore. Antes, defaults sin side-effects. */
42264
+ this._synced = signal(false);
42265
+ this.theme = this._theme.asReadonly();
42266
+ this.language = this._language.asReadonly();
42267
+ this.notificationsMaster = this._notificationsMaster.asReadonly();
42268
+ this.synced = this._synced.asReadonly();
42269
+ /**
42270
+ * `true` mientras un `update()` está en vuelo (PUT al backend).
42271
+ *
42272
+ * El listener Firestore (`bindToUser`) es real-time y puede emitir un snapshot
42273
+ * *stale* — anterior al sync del backend — que pisaría el valor optimista de
42274
+ * `_notificationsMaster` y revertiría el toggle. Mientras este flag esté `true`
42275
+ * el listener ignora las emisiones; el `update()` ya alinea las señales con la
42276
+ * respuesta del backend al terminar.
42277
+ */
42278
+ this._updateInFlight = false;
42279
+ const destroyRef = inject(DestroyRef);
42280
+ destroyRef.onDestroy(() => this.unbind());
42281
+ // Auto-bind al user actual. effect() corre en injection context (constructor OK).
42282
+ // allowSignalWrites: bindToUser/unbind escriben `_synced` (señal interna sin
42283
+ // dependencias del propio effect) → seguro y necesario.
42284
+ effect(() => {
42285
+ const user = this.auth.user();
42286
+ if (user?.userId) {
42287
+ this.bindToUser(user.userId);
42288
+ }
42289
+ else {
42290
+ this.unbind();
42291
+ }
42292
+ }, { allowSignalWrites: true });
42293
+ // Side-effect: aplicar theme local cuando llega snapshot real.
42294
+ // OJO: usar `toggleUserPreference()` y NO el setter `Theme =`. El setter
42295
+ // solo persiste localStorage + emite el BehaviorSubject; no aplica las
42296
+ // clases `body.dark`/`body.light` que el palette `dark.class.css` de
42297
+ // Ionic necesita para conmutar el tema visible.
42298
+ effect(() => {
42299
+ if (!this._synced())
42300
+ return;
42301
+ const t = this._theme();
42302
+ if (this.themeService) {
42303
+ this.themeService.toggleUserPreference(t);
42304
+ }
42305
+ });
42306
+ // Side-effect: aplicar language local cuando llega snapshot real.
42307
+ effect(() => {
42308
+ if (!this._synced())
42309
+ return;
42310
+ const l = this._language();
42311
+ if (this.i18n && this.i18n.lang() !== l) {
42312
+ this.i18n.setLanguage(l);
42313
+ }
42314
+ });
42315
+ }
42316
+ /** Actualiza preferencias via backend. Optimistic UI: aplica local, revierte si falla. */
42317
+ async update(partial) {
42318
+ const url = `${this.config.apiUrl}/v2/auth/preferences`;
42319
+ const prev = {
42320
+ theme: this._theme(),
42321
+ language: this._language(),
42322
+ master: this._notificationsMaster(),
42323
+ };
42324
+ if (partial.theme)
42325
+ this._theme.set(partial.theme);
42326
+ if (partial.language)
42327
+ this._language.set(partial.language);
42328
+ if (partial.notifications && typeof partial.notifications.master === 'boolean') {
42329
+ this._notificationsMaster.set(partial.notifications.master);
42330
+ }
42331
+ // Bloquear el listener Firestore mientras el PUT está en vuelo: un snapshot
42332
+ // stale no debe pisar el valor optimista recién aplicado.
42333
+ this._updateInFlight = true;
42334
+ try {
42335
+ // Enviar appId explícito — el backend lo usa para escribir el mirror
42336
+ // Firestore en apps/{appId}/... correcto, sin depender del header Origin
42337
+ // (que en PWA iOS puede no resolver al AppID esperado).
42338
+ const body = { ...partial, appId: this.config.appId };
42339
+ const res = await firstValueFrom(this.http.put(url, body));
42340
+ // El listener Firestore es la fuente final, pero alinear ya con la
42341
+ // respuesta del backend acelera UX (especialmente si el listener
42342
+ // tarda en propagar).
42343
+ if (res.theme)
42344
+ this._theme.set(res.theme);
42345
+ if (res.language)
42346
+ this._language.set(res.language);
42347
+ if (typeof res.notifications?.master === 'boolean') {
42348
+ this._notificationsMaster.set(res.notifications.master);
42349
+ }
42350
+ return res;
42351
+ }
42352
+ catch (err) {
42353
+ // Revert optimistic.
42354
+ this._theme.set(prev.theme);
42355
+ this._language.set(prev.language);
42356
+ this._notificationsMaster.set(prev.master);
42357
+ throw err;
42358
+ }
42359
+ finally {
42360
+ this._updateInFlight = false;
42361
+ }
42362
+ }
42363
+ setTheme(theme) {
42364
+ return this.update({ theme });
42365
+ }
42366
+ setLanguage(language) {
42367
+ return this.update({ language });
42368
+ }
42369
+ setNotificationsMaster(enabled) {
42370
+ return this.update({ notifications: { master: enabled } });
42371
+ }
42372
+ bindToUser(userId) {
42373
+ if (this.currentUserId === userId && this.subscription)
42374
+ return;
42375
+ this.unbind();
42376
+ this.currentUserId = userId;
42377
+ // FirestoreService.docChanges prefija automáticamente `apps/{appId}/`
42378
+ // cuando `config.appId` está seteado en ValtechAuthConfig.
42379
+ this.subscription = this.firestore
42380
+ .docChanges(`users/${userId}/preferences`, 'main')
42381
+ .subscribe(doc => {
42382
+ if (!doc) {
42383
+ // Doc no existe aún (user nuevo, sin primer sync). Mantenemos
42384
+ // defaults locales pero NO marcamos synced — los side-effects no
42385
+ // pisan el theme/lang locales con valores arbitrarios.
42386
+ return;
42387
+ }
42388
+ // Ignorar emisiones del listener mientras hay un update() en vuelo: un
42389
+ // snapshot stale (anterior al sync del backend) revertiría el valor
42390
+ // optimista. El update() ya alinea las señales con la respuesta real.
42391
+ if (this._updateInFlight) {
42392
+ return;
42393
+ }
42394
+ if (doc.theme)
42395
+ this._theme.set(doc.theme);
42396
+ if (doc.language)
42397
+ this._language.set(doc.language);
42398
+ if (doc.notifications && typeof doc.notifications.master === 'boolean') {
42399
+ this._notificationsMaster.set(doc.notifications.master);
42400
+ }
42401
+ this._synced.set(true);
42402
+ });
42403
+ }
42404
+ unbind() {
42405
+ this.subscription?.unsubscribe();
42406
+ this.subscription = undefined;
42407
+ this.currentUserId = undefined;
42408
+ this._synced.set(false);
42409
+ }
42410
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: FirestoreService }, { token: AuthService }, { token: i1$3.HttpClient }, { token: ThemeService, optional: true }, { token: I18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
42411
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, providedIn: 'root' }); }
42412
+ }
42413
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, decorators: [{
42414
+ type: Injectable,
42415
+ args: [{ providedIn: 'root' }]
42416
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
42417
+ type: Inject,
42418
+ args: [VALTECH_AUTH_CONFIG]
42419
+ }] }, { type: FirestoreService }, { type: AuthService }, { type: i1$3.HttpClient }, { type: ThemeService, decorators: [{
42420
+ type: Optional
42421
+ }] }, { type: I18nService, decorators: [{
42422
+ type: Optional
42423
+ }] }] });
42424
+
42425
+ /**
42426
+ * Defaults i18n (es/en) embebidos en `val-preferences-view`. Auto-registrados
42427
+ * en el constructor del componente si el consumer no proveyó el namespace
42428
+ * (`Settings.General` por default). Garantiza que nunca haya una key faltante
42429
+ * evaluada por cada change-detection (ver nota en valtech-components/CLAUDE.md
42430
+ * sobre el storm de CD con `val-debug-console`). El consumer puede override
42431
+ * registrando el mismo namespace antes de que el componente monte.
42432
+ *
42433
+ * SOLO incluye las keys que la vista realmente usa.
42434
+ */
42435
+ const PREFERENCES_VIEW_I18N = {
42436
+ es: {
42437
+ pageTitle: 'General',
42438
+ pageDescription: 'Apariencia e idioma',
42439
+ themeTitle: 'Tema',
42440
+ themeHint: 'Cómo se ve la app: claro, oscuro o según tu sistema.',
42441
+ themeLight: 'Claro',
42442
+ themeDark: 'Oscuro',
42443
+ themeAuto: 'Auto',
42444
+ languageTitle: 'Idioma',
42445
+ languageHint: 'Idioma de la interfaz y de los correos que recibes.',
42446
+ saveError: 'No se pudo guardar la preferencia.',
42447
+ },
42448
+ en: {
42449
+ pageTitle: 'General',
42450
+ pageDescription: 'Appearance and language',
42451
+ themeTitle: 'Theme',
42452
+ themeHint: 'How the app looks: light, dark, or matching your system.',
42453
+ themeLight: 'Light',
42454
+ themeDark: 'Dark',
42455
+ themeAuto: 'Auto',
42456
+ languageTitle: 'Language',
42457
+ languageHint: 'Language of the interface and of the emails you receive.',
42458
+ saveError: 'Could not save preference.',
42459
+ },
42460
+ };
42461
+
42462
+ const DEFAULT_NAMESPACE = 'Settings.General';
42463
+ const DEFAULT_LANGUAGES = ['es', 'en'];
42464
+ /**
42465
+ * `val-preferences-view` — vista de preferencias de UI cross-app (tema +
42466
+ * idioma) full-feature autocontenida (organism). Promovida desde `showcase`
42467
+ * bajo el proceso de ADR-021.
42468
+ *
42469
+ * Backend integration 100% en `PreferencesService`:
42470
+ * - Read: listener Firestore reactivo (`prefs.theme()` / `prefs.language()`).
42471
+ * - Write: `PUT /v2/auth/preferences` (`prefs.setTheme` / `prefs.setLanguage`).
42472
+ * El cliente NUNCA escribe Firestore directo.
42473
+ *
42474
+ * NO renderiza ion-content — vive dentro de val-page-wrapper.
42475
+ *
42476
+ * Auto-registra sus defaults i18n (es/en) en el constructor si el consumer no
42477
+ * proveyó el namespace configurado (default `Settings.General`).
42478
+ */
42479
+ class PreferencesViewComponent {
42480
+ /** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
42481
+ get ns() {
42482
+ return this.resolvedConfig().i18nNamespace;
42483
+ }
42484
+ constructor() {
42485
+ this.nav = inject(NavigationService);
42486
+ this.prefs = inject(PreferencesService);
42487
+ this.i18n = inject(I18nService);
42488
+ this.errors = inject(ValtechErrorService);
42489
+ this.route = inject(ActivatedRoute, { optional: true });
42490
+ /** Config mergeada con defaults. @Input gana sobre route data. */
42491
+ this.resolvedConfig = computed(() => {
42492
+ const fromRoute = (this.route?.snapshot.data['preferencesConfig'] ?? {});
42493
+ const merged = { ...fromRoute, ...(this.config ?? {}) };
42494
+ return {
42495
+ showTheme: merged.showTheme ?? true,
42496
+ showLanguage: merged.showLanguage ?? true,
42497
+ supportedLanguages: merged.supportedLanguages ?? DEFAULT_LANGUAGES,
42498
+ i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE,
42499
+ onThemeChanged: merged.onThemeChanged,
42500
+ onLanguageChanged: merged.onLanguageChanged,
42501
+ };
42502
+ });
42503
+ this.saving = signal(false);
42504
+ this.pageTitle = computed(() => this.t('pageTitle'));
42505
+ this.pageDescription = computed(() => this.t('pageDescription'));
42506
+ this.themeTitle = computed(() => this.t('themeTitle'));
42507
+ this.themeHint = computed(() => this.t('themeHint'));
42508
+ this.langTitle = computed(() => this.t('languageTitle'));
42509
+ this.langHint = computed(() => this.t('languageHint'));
42510
+ this.themeProps = computed(() => ({
42511
+ value: this.prefs.theme(),
42512
+ disabled: this.saving(),
42513
+ options: [
42514
+ { value: 'light', label: this.t('themeLight') },
42515
+ { value: 'dark', label: this.t('themeDark') },
42516
+ { value: 'auto', label: this.t('themeAuto') },
42517
+ ],
42518
+ }));
42519
+ this.langProps = computed(() => ({
42520
+ currentLanguage: this.prefs.language(),
42521
+ availableLanguages: this.resolvedConfig().supportedLanguages,
42522
+ showLabel: false,
42523
+ disabled: this.saving(),
42524
+ expand: 'block',
42525
+ fill: 'outline',
42526
+ }));
42527
+ // Auto-registro i18n — respeta override del consumer. El namespace puede
42528
+ // venir de @Input.config o del route data; lo resolvemos acá.
42529
+ const ns = this.ns;
42530
+ if (!this.i18n.hasNamespace(ns)) {
42531
+ this.i18n.registerContent(ns, PREFERENCES_VIEW_I18N);
42532
+ }
42533
+ this.nav.setBackHeader('pageTitle', ns, { withMenu: true });
42534
+ }
42535
+ async onThemeChange(value) {
42536
+ if (this.saving() || value === this.prefs.theme())
42537
+ return;
42538
+ const theme = value;
42539
+ await this.dispatch(() => this.prefs.setTheme(theme), () => this.resolvedConfig().onThemeChanged?.(theme));
42540
+ }
42541
+ async onLanguageChange(value) {
42542
+ const lang = value;
42543
+ if (!this.resolvedConfig().supportedLanguages.includes(lang))
42544
+ return;
42545
+ if (this.saving() || value === this.prefs.language())
42546
+ return;
42547
+ await this.dispatch(() => this.prefs.setLanguage(lang), () => this.resolvedConfig().onLanguageChanged?.(lang));
42548
+ }
42549
+ async dispatch(fn, onSuccess) {
42550
+ this.saving.set(true);
42551
+ try {
42552
+ await fn();
42553
+ onSuccess?.();
42554
+ }
42555
+ catch (err) {
42556
+ this.errors.handle(err, {
42557
+ context: 'settings.preferences.save',
42558
+ fallbackKey: 'saveError',
42559
+ i18nNamespace: this.ns,
42560
+ });
42561
+ }
42562
+ finally {
42563
+ this.saving.set(false);
42564
+ }
42565
+ }
42566
+ /** Lee del namespace configurado. */
42567
+ t(key) {
42568
+ return this.i18n.t(key, this.ns);
42569
+ }
42570
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
42571
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PreferencesViewComponent, isStandalone: true, selector: "val-preferences-view", inputs: { config: "config" }, ngImport: i0, template: `
42572
+ <div class="page">
42573
+ <header class="page-header">
42574
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
42575
+ <val-title
42576
+ [props]="{
42577
+ size: 'large',
42578
+ color: 'dark',
42579
+ bold: false,
42580
+ content: pageDescription(),
42581
+ }"
42582
+ />
42583
+ </header>
42584
+
42585
+ @if (resolvedConfig().showTheme) {
42586
+ <section class="settings-section">
42587
+ <val-title
42588
+ [props]="{
42589
+ size: 'medium',
42590
+ color: 'dark',
42591
+ bold: true,
42592
+ content: themeTitle(),
42593
+ }"
42594
+ />
42595
+ <div class="section-body">
42596
+ <val-text
42597
+ [props]="{
42598
+ size: 'medium',
42599
+ color: 'dark',
42600
+ bold: false,
42601
+ content: themeHint(),
42602
+ }"
42603
+ />
42604
+ <val-segment-control [props]="themeProps()" (segmentChange)="onThemeChange($event)" />
42605
+ </div>
42606
+ </section>
42607
+ }
42608
+
42609
+ @if (resolvedConfig().showLanguage) {
42610
+ <section class="settings-section">
42611
+ <val-title
42612
+ [props]="{
42613
+ size: 'medium',
42614
+ color: 'dark',
42615
+ bold: true,
42616
+ content: langTitle(),
42617
+ }"
42618
+ />
42619
+ <div class="section-body">
42620
+ <val-text
42621
+ [props]="{
42622
+ size: 'medium',
42623
+ color: 'dark',
42624
+ bold: false,
42625
+ content: langHint(),
42626
+ }"
42627
+ />
42628
+ <val-language-selector [props]="langProps()" (languageChange)="onLanguageChange($event)" />
42629
+ </div>
42630
+ </section>
42631
+ }
42632
+ </div>
42633
+ `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-body{display:flex;flex-direction:column;gap:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: SegmentControlComponent, selector: "val-segment-control", inputs: ["preset", "props"], outputs: ["segmentChange"] }, { kind: "component", type: LanguageSelectorComponent, selector: "val-language-selector", inputs: ["props"], outputs: ["languageChange"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }] }); }
42634
+ }
42635
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesViewComponent, decorators: [{
42636
+ type: Component,
42637
+ args: [{ selector: 'val-preferences-view', standalone: true, imports: [
42638
+ CommonModule,
42639
+ SegmentControlComponent,
42640
+ LanguageSelectorComponent,
42641
+ DisplayComponent,
42642
+ TitleComponent,
42643
+ TextComponent,
42644
+ ], template: `
42645
+ <div class="page">
42646
+ <header class="page-header">
42647
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
42648
+ <val-title
42649
+ [props]="{
42650
+ size: 'large',
42651
+ color: 'dark',
42652
+ bold: false,
42653
+ content: pageDescription(),
42654
+ }"
42655
+ />
42656
+ </header>
42657
+
42658
+ @if (resolvedConfig().showTheme) {
42659
+ <section class="settings-section">
42660
+ <val-title
42661
+ [props]="{
42662
+ size: 'medium',
42663
+ color: 'dark',
42664
+ bold: true,
42665
+ content: themeTitle(),
42666
+ }"
42667
+ />
42668
+ <div class="section-body">
42669
+ <val-text
42670
+ [props]="{
42671
+ size: 'medium',
42672
+ color: 'dark',
42673
+ bold: false,
42674
+ content: themeHint(),
42675
+ }"
42676
+ />
42677
+ <val-segment-control [props]="themeProps()" (segmentChange)="onThemeChange($event)" />
42678
+ </div>
42679
+ </section>
42680
+ }
42681
+
42682
+ @if (resolvedConfig().showLanguage) {
42683
+ <section class="settings-section">
42684
+ <val-title
42685
+ [props]="{
42686
+ size: 'medium',
42687
+ color: 'dark',
42688
+ bold: true,
42689
+ content: langTitle(),
42690
+ }"
42691
+ />
42692
+ <div class="section-body">
42693
+ <val-text
42694
+ [props]="{
42695
+ size: 'medium',
42696
+ color: 'dark',
42697
+ bold: false,
42698
+ content: langHint(),
42699
+ }"
42700
+ />
42701
+ <val-language-selector [props]="langProps()" (languageChange)="onLanguageChange($event)" />
42702
+ </div>
42703
+ </section>
42704
+ }
42705
+ </div>
42706
+ `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-body{display:flex;flex-direction:column;gap:10px}\n"] }]
42707
+ }], ctorParameters: () => [], propDecorators: { config: [{
42708
+ type: Input
42709
+ }] } });
42710
+
42711
+ /**
42712
+ * Helper para montar la vista de preferencias (`val-preferences-view`) como
42713
+ * ruta en una app del factory. El `config` se pasa por route `data`
42714
+ * (`preferencesConfig`) y el componente lo lee como fallback de su
42715
+ * `@Input() config`.
42716
+ *
42717
+ * @example
42718
+ * ```ts
42719
+ * // settings.routes.ts
42720
+ * export const settingsRoutes: Routes = [
42721
+ * ...provideValtechPreferencesRoutes(),
42722
+ * { path: 'profile', loadComponent: () => ... },
42723
+ * ];
42724
+ *
42725
+ * // con config acotada:
42726
+ * ...provideValtechPreferencesRoutes({ config: { showLanguage: false } }),
42727
+ * ```
42728
+ */
42729
+ function provideValtechPreferencesRoutes(opts) {
42730
+ return [
42731
+ {
42732
+ path: opts?.path ?? 'preferences',
42733
+ component: PreferencesViewComponent,
42734
+ data: { preferencesConfig: opts?.config },
42735
+ },
42736
+ ];
42737
+ }
42738
+
41492
42739
  /** Built-in label sets for the three platform locales. */
41493
42740
  const CALLOUT_LABELS = {
41494
42741
  es: {
@@ -42451,108 +43698,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
42451
43698
  type: Output
42452
43699
  }] } });
42453
43700
 
42454
- /**
42455
- * PageRefreshService — bus del pull-to-refresh estándar del factory.
42456
- *
42457
- * **Por qué existe:** `val-page-wrapper` posee un único `<ion-content>` y todas
42458
- * las páginas se renderizan dentro vía `<router-outlet>`. Un `<ion-refresher>`
42459
- * tiene que vivir dentro de ese `ion-content`, así que el refresher NO puede
42460
- * declararse en el template de cada página — vive una sola vez en
42461
- * `val-page-wrapper`. Este servicio es el puente: la página activa registra
42462
- * *qué hacer* al refrescar; el page-wrapper dispara el gesto y cierra el spinner.
42463
- *
42464
- * **Uso en una página** (ver `frontend/CLAUDE.md` — es el patrón estándar):
42465
- *
42466
- * ```ts
42467
- * export class MiPage implements ViewWillEnter, ViewWillLeave {
42468
- * private pageRefresh = inject(PageRefreshService);
42469
- *
42470
- * ionViewWillEnter(): void {
42471
- * this.pageRefresh.register(() => this.reload());
42472
- * }
42473
- * ionViewWillLeave(): void {
42474
- * this.pageRefresh.unregister();
42475
- * }
42476
- *
42477
- * private async reload(): Promise<void> {
42478
- * // re-fetch / re-suscribir streams / etc.
42479
- * }
42480
- * }
42481
- * ```
42482
- *
42483
- * Páginas que no llaman `register()` simplemente no muestran refresher —
42484
- * opt-in, sin impacto.
42485
- */
42486
- class PageRefreshService {
42487
- constructor() {
42488
- this.handler = null;
42489
- /**
42490
- * `true` cuando hay una página con handler registrado. `val-page-wrapper`
42491
- * renderiza el `<val-refresher>` sólo cuando esto es `true`.
42492
- */
42493
- this.hasHandler = signal(false);
42494
- }
42495
- /**
42496
- * Registra el handler de refresh de la página activa. Llamar en
42497
- * `ionViewWillEnter`. Si ya había uno, lo reemplaza (sólo hay una página
42498
- * activa a la vez en el router-outlet de Ionic).
42499
- */
42500
- register(handler) {
42501
- this.handler = handler;
42502
- this.hasHandler.set(true);
42503
- }
42504
- /**
42505
- * Quita el handler. Llamar en `ionViewWillLeave` para que el refresher
42506
- * desaparezca al salir de la vista.
42507
- */
42508
- unregister() {
42509
- this.handler = null;
42510
- this.hasHandler.set(false);
42511
- }
42512
- /**
42513
- * Ejecuta el handler registrado y espera a que termine. Lo invoca
42514
- * `val-page-wrapper` al detectar el gesto de pull. No-op si no hay handler.
42515
- */
42516
- async run() {
42517
- if (!this.handler)
42518
- return;
42519
- await this.handler();
42520
- }
42521
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
42522
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, providedIn: 'root' }); }
42523
- }
42524
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PageRefreshService, decorators: [{
42525
- type: Injectable,
42526
- args: [{ providedIn: 'root' }]
42527
- }] });
42528
- /**
42529
- * Conecta una página al pull-to-refresh estándar en UNA línea, sin lifecycle
42530
- * hooks manuales: registra el handler y lo desregistra al destruir la página
42531
- * (vía `DestroyRef`).
42532
- *
42533
- * DEBE llamarse en un injection context (constructor o field initializer).
42534
- *
42535
- * @example
42536
- * ```ts
42537
- * export class MiPage {
42538
- * private data = createRefreshableStream(() => this.svc.getX());
42539
- * readonly items = this.data.data;
42540
- *
42541
- * constructor() {
42542
- * connectPageRefresh(() => this.data.reload());
42543
- * }
42544
- * }
42545
- * ```
42546
- *
42547
- * Reemplaza el patrón `ngOnInit`→`register` / `ngOnDestroy`→`unregister`.
42548
- */
42549
- function connectPageRefresh(handler) {
42550
- const svc = inject(PageRefreshService);
42551
- const destroyRef = inject(DestroyRef);
42552
- svc.register(handler);
42553
- destroyRef.onDestroy(() => svc.unregister());
42554
- }
42555
-
42556
43701
  class NetworkStatusService {
42557
43702
  constructor() {
42558
43703
  this._isOnline = signal(typeof navigator !== 'undefined' ? navigator.onLine : true);
@@ -44237,195 +45382,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
44237
45382
  args: [VALTECH_AUTH_CONFIG]
44238
45383
  }] }, { type: i1$3.HttpClient }] });
44239
45384
 
44240
- /**
44241
- * PreferencesService — preferencias del user en el doc canónico Firestore
44242
- * `/apps/{appId}/users/{uid}/preferences/main`.
44243
- *
44244
- * Read reactivo (signals) via listener Firestore.
44245
- * Write via `PUT /v2/auth/preferences` (cliente NUNCA escribe Firestore directo —
44246
- * ver memoria `feedback_no_direct_firestore_writes`).
44247
- *
44248
- * Side-effects automáticos:
44249
- * - Cuando `theme()` cambia → `ThemeService.Theme = ...`
44250
- * - Cuando `language()` cambia → `I18nService.setLanguage(...)`
44251
- *
44252
- * Auto-bind al user actual via `AuthService.user()`. Sin user (logout) → unbind.
44253
- */
44254
- class PreferencesService {
44255
- constructor(config, firestore, auth, http, themeService, i18n) {
44256
- this.config = config;
44257
- this.firestore = firestore;
44258
- this.auth = auth;
44259
- this.http = http;
44260
- this.themeService = themeService;
44261
- this.i18n = i18n;
44262
- this._theme = signal('auto');
44263
- this._language = signal('es');
44264
- // Default `false` (opt-in). El user debe activar explícitamente las notificaciones;
44265
- // no asumimos consentimiento implícito. Backend debe coincidir.
44266
- this._notificationsMaster = signal(false);
44267
- /** `true` después del primer snapshot Firestore. Antes, defaults sin side-effects. */
44268
- this._synced = signal(false);
44269
- this.theme = this._theme.asReadonly();
44270
- this.language = this._language.asReadonly();
44271
- this.notificationsMaster = this._notificationsMaster.asReadonly();
44272
- this.synced = this._synced.asReadonly();
44273
- /**
44274
- * `true` mientras un `update()` está en vuelo (PUT al backend).
44275
- *
44276
- * El listener Firestore (`bindToUser`) es real-time y puede emitir un snapshot
44277
- * *stale* — anterior al sync del backend — que pisaría el valor optimista de
44278
- * `_notificationsMaster` y revertiría el toggle. Mientras este flag esté `true`
44279
- * el listener ignora las emisiones; el `update()` ya alinea las señales con la
44280
- * respuesta del backend al terminar.
44281
- */
44282
- this._updateInFlight = false;
44283
- const destroyRef = inject(DestroyRef);
44284
- destroyRef.onDestroy(() => this.unbind());
44285
- // Auto-bind al user actual. effect() corre en injection context (constructor OK).
44286
- // allowSignalWrites: bindToUser/unbind escriben `_synced` (señal interna sin
44287
- // dependencias del propio effect) → seguro y necesario.
44288
- effect(() => {
44289
- const user = this.auth.user();
44290
- if (user?.userId) {
44291
- this.bindToUser(user.userId);
44292
- }
44293
- else {
44294
- this.unbind();
44295
- }
44296
- }, { allowSignalWrites: true });
44297
- // Side-effect: aplicar theme local cuando llega snapshot real.
44298
- // OJO: usar `toggleUserPreference()` y NO el setter `Theme =`. El setter
44299
- // solo persiste localStorage + emite el BehaviorSubject; no aplica las
44300
- // clases `body.dark`/`body.light` que el palette `dark.class.css` de
44301
- // Ionic necesita para conmutar el tema visible.
44302
- effect(() => {
44303
- if (!this._synced())
44304
- return;
44305
- const t = this._theme();
44306
- if (this.themeService) {
44307
- this.themeService.toggleUserPreference(t);
44308
- }
44309
- });
44310
- // Side-effect: aplicar language local cuando llega snapshot real.
44311
- effect(() => {
44312
- if (!this._synced())
44313
- return;
44314
- const l = this._language();
44315
- if (this.i18n && this.i18n.lang() !== l) {
44316
- this.i18n.setLanguage(l);
44317
- }
44318
- });
44319
- }
44320
- /** Actualiza preferencias via backend. Optimistic UI: aplica local, revierte si falla. */
44321
- async update(partial) {
44322
- const url = `${this.config.apiUrl}/v2/auth/preferences`;
44323
- const prev = {
44324
- theme: this._theme(),
44325
- language: this._language(),
44326
- master: this._notificationsMaster(),
44327
- };
44328
- if (partial.theme)
44329
- this._theme.set(partial.theme);
44330
- if (partial.language)
44331
- this._language.set(partial.language);
44332
- if (partial.notifications && typeof partial.notifications.master === 'boolean') {
44333
- this._notificationsMaster.set(partial.notifications.master);
44334
- }
44335
- // Bloquear el listener Firestore mientras el PUT está en vuelo: un snapshot
44336
- // stale no debe pisar el valor optimista recién aplicado.
44337
- this._updateInFlight = true;
44338
- try {
44339
- // Enviar appId explícito — el backend lo usa para escribir el mirror
44340
- // Firestore en apps/{appId}/... correcto, sin depender del header Origin
44341
- // (que en PWA iOS puede no resolver al AppID esperado).
44342
- const body = { ...partial, appId: this.config.appId };
44343
- const res = await firstValueFrom(this.http.put(url, body));
44344
- // El listener Firestore es la fuente final, pero alinear ya con la
44345
- // respuesta del backend acelera UX (especialmente si el listener
44346
- // tarda en propagar).
44347
- if (res.theme)
44348
- this._theme.set(res.theme);
44349
- if (res.language)
44350
- this._language.set(res.language);
44351
- if (typeof res.notifications?.master === 'boolean') {
44352
- this._notificationsMaster.set(res.notifications.master);
44353
- }
44354
- return res;
44355
- }
44356
- catch (err) {
44357
- // Revert optimistic.
44358
- this._theme.set(prev.theme);
44359
- this._language.set(prev.language);
44360
- this._notificationsMaster.set(prev.master);
44361
- throw err;
44362
- }
44363
- finally {
44364
- this._updateInFlight = false;
44365
- }
44366
- }
44367
- setTheme(theme) {
44368
- return this.update({ theme });
44369
- }
44370
- setLanguage(language) {
44371
- return this.update({ language });
44372
- }
44373
- setNotificationsMaster(enabled) {
44374
- return this.update({ notifications: { master: enabled } });
44375
- }
44376
- bindToUser(userId) {
44377
- if (this.currentUserId === userId && this.subscription)
44378
- return;
44379
- this.unbind();
44380
- this.currentUserId = userId;
44381
- // FirestoreService.docChanges prefija automáticamente `apps/{appId}/`
44382
- // cuando `config.appId` está seteado en ValtechAuthConfig.
44383
- this.subscription = this.firestore
44384
- .docChanges(`users/${userId}/preferences`, 'main')
44385
- .subscribe(doc => {
44386
- if (!doc) {
44387
- // Doc no existe aún (user nuevo, sin primer sync). Mantenemos
44388
- // defaults locales pero NO marcamos synced — los side-effects no
44389
- // pisan el theme/lang locales con valores arbitrarios.
44390
- return;
44391
- }
44392
- // Ignorar emisiones del listener mientras hay un update() en vuelo: un
44393
- // snapshot stale (anterior al sync del backend) revertiría el valor
44394
- // optimista. El update() ya alinea las señales con la respuesta real.
44395
- if (this._updateInFlight) {
44396
- return;
44397
- }
44398
- if (doc.theme)
44399
- this._theme.set(doc.theme);
44400
- if (doc.language)
44401
- this._language.set(doc.language);
44402
- if (doc.notifications && typeof doc.notifications.master === 'boolean') {
44403
- this._notificationsMaster.set(doc.notifications.master);
44404
- }
44405
- this._synced.set(true);
44406
- });
44407
- }
44408
- unbind() {
44409
- this.subscription?.unsubscribe();
44410
- this.subscription = undefined;
44411
- this.currentUserId = undefined;
44412
- this._synced.set(false);
44413
- }
44414
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: FirestoreService }, { token: AuthService }, { token: i1$3.HttpClient }, { token: ThemeService, optional: true }, { token: I18nService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
44415
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, providedIn: 'root' }); }
44416
- }
44417
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PreferencesService, decorators: [{
44418
- type: Injectable,
44419
- args: [{ providedIn: 'root' }]
44420
- }], ctorParameters: () => [{ type: undefined, decorators: [{
44421
- type: Inject,
44422
- args: [VALTECH_AUTH_CONFIG]
44423
- }] }, { type: FirestoreService }, { type: AuthService }, { type: i1$3.HttpClient }, { type: ThemeService, decorators: [{
44424
- type: Optional
44425
- }] }, { type: I18nService, decorators: [{
44426
- type: Optional
44427
- }] }] });
44428
-
44429
45385
  /**
44430
45386
  * Preferences types — Fase 1 schema simple (theme + language + notifications.master).
44431
45387
  * Doc canónico: /apps/{appId}/users/{uid}/preferences/main
@@ -52655,5 +53611,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
52655
53611
  * Generated bundle index. Do not edit.
52656
53612
  */
52657
53613
 
52658
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildFooterLinks, buildPath, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPresets, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
53614
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildFooterLinks, buildPath, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
52659
53615
  //# sourceMappingURL=valtech-components.mjs.map