valtech-components 2.0.807 → 2.0.809

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.
@@ -3,7 +3,7 @@ import { signal, Injectable, makeEnvironmentProviders, APP_INITIALIZER, inject,
3
3
  import * as i2$1 from '@ionic/angular/standalone';
4
4
  import { IonAvatar, IonCard, IonIcon, IonButton, IonSpinner, IonText, IonModal, IonHeader, IonToolbar, IonContent, IonButtons, IonTitle, IonProgressBar, IonSkeletonText, IonFab, IonFabButton, IonFabList, IonLabel, IonCardContent, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCheckbox, IonTextarea, IonDatetime, IonDatetimeButton, IonInput, IonSelect, IonSelectOption, IonPopover, IonList, IonItem, IonRadioGroup, IonRadio, IonRange, IonSearchbar, IonSegment, IonSegmentButton, IonToggle, IonAccordion, IonAccordionGroup, IonTabBar, IonTabButton, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonChip, IonNote, ToastController as ToastController$1, IonCol, IonRow, IonRefresher, IonRefresherContent, IonRippleEffect, AlertController, IonMenuButton, IonFooter, IonListHeader, IonInfiniteScroll, IonInfiniteScrollContent, IonGrid, MenuController, IonMenu, IonMenuToggle, IonSplitPane } from '@ionic/angular/standalone';
5
5
  import * as i1 from '@angular/common';
6
- import { CommonModule, NgStyle, NgFor, isPlatformBrowser, NgClass } from '@angular/common';
6
+ import { CommonModule, NgStyle, NgFor, isPlatformBrowser, DOCUMENT, NgClass } from '@angular/common';
7
7
  import { addIcons } from 'ionicons';
8
8
  import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, settings, settingsOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notifications, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, home, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, logoGoogle, createOutline, trashOutline, playOutline, phonePortraitOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, removeOutline, optionsOutline, personOutline, shieldCheckmarkOutline, keyOutline, desktopOutline, logOutOutline, add, close, share, create, trash, star, camera, mic, send, downloadOutline, chevronDown, language, globeOutline, checkmark, list, grid, apps, menu, search, person, helpCircle, informationCircle, documentText, mail, calendar, folder, chevronForward, ellipsisHorizontal, chevronBack, playBack, playForward, ellipse, starOutline, starHalf, heartHalf, checkmarkCircle, timeOutline, flag, trendingUp, trendingDown, remove, analytics, people, cash, cart, eye, chatbubbleOutline, thumbsUpOutline, thumbsUp, happyOutline, happy, sadOutline, sad, chevronUp, pin, pencil, callOutline, logoWhatsapp, paperPlaneOutline, mailOutline, closeCircle, alertCircle, logoApple, logoMicrosoft, linkOutline, unlinkOutline, chevronBackOutline, sendOutline, chatbubbleEllipsesOutline, swapVerticalOutline, chevronUpOutline, documentOutline, searchOutline, cartOutline, chatbubble, compass, compassOutline, gridOutline, listOutline, folderOutline, documents, documentsOutline, statsChart, statsChartOutline, cameraOutline, bugOutline, bulbOutline, closeCircleOutline, menuOutline } from 'ionicons/icons';
9
9
  import * as i1$1 from '@angular/router';
@@ -14,7 +14,7 @@ import { DomSanitizer, Meta, Title } from '@angular/platform-browser';
14
14
  import QRCodeStyling from 'qr-code-styling';
15
15
  import * as i1$3 from '@angular/forms';
16
16
  import { ReactiveFormsModule, FormsModule, FormControl, Validators, FormBuilder } from '@angular/forms';
17
- import { BehaviorSubject, map, throwError, Subject, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, shareReplay, race, timer } from 'rxjs';
17
+ import { BehaviorSubject, map, filter as filter$1, interval, throwError, Subject, distinctUntilChanged, take as take$1, firstValueFrom, of, from, EMPTY, Observable, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, shareReplay, race, timer } from 'rxjs';
18
18
  import * as i1$4 from 'ng-otp-input';
19
19
  import { NgOtpInputComponent, NgOtpInputModule } from 'ng-otp-input';
20
20
  import * as i2 from '@ionic/angular';
@@ -28,6 +28,8 @@ import 'prismjs/components/prism-typescript';
28
28
  import 'prismjs/components/prism-bash';
29
29
  import Swiper from 'swiper';
30
30
  import { Navigation, Pagination, EffectFade, EffectCube, EffectCoverflow, EffectFlip, Autoplay } from 'swiper/modules';
31
+ import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
32
+ import { SwUpdate } from '@angular/service-worker';
31
33
  import * as i1$5 from '@angular/fire/firestore';
32
34
  import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexedDbPersistence, doc, getDoc, collection, query as query$1, getDocs, getCountFromServer, limit, docData, collectionData, serverTimestamp, addDoc, setDoc, updateDoc, deleteDoc, writeBatch, arrayUnion, arrayRemove, increment, where, orderBy, startAfter, startAt, endBefore, endAt, Timestamp } from '@angular/fire/firestore';
33
35
  import { Analytics, logEvent, setUserId, setUserProperties, provideAnalytics, getAnalytics } from '@angular/fire/analytics';
@@ -37,7 +39,6 @@ import { provideAuth, getAuth, connectAuthEmulator, authState, signInWithCustomT
37
39
  import { provideMessaging, getMessaging, getToken, deleteToken, onMessage } from '@angular/fire/messaging';
38
40
  import * as i1$7 from '@angular/fire/storage';
39
41
  import { provideStorage, getStorage, connectStorageEmulator, ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, listAll } from '@angular/fire/storage';
40
- import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
41
42
  import { filter, catchError, switchMap, finalize, take, map as map$1, tap, retry, timeout, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
42
43
  import * as i1$8 from '@angular/common/http';
43
44
  import { provideHttpClient, withInterceptors, HttpErrorResponse, HttpClient } from '@angular/common/http';
@@ -52,7 +53,7 @@ import 'prismjs/components/prism-json';
52
53
  * Current version of valtech-components.
53
54
  * This is automatically updated during the publish process.
54
55
  */
55
- const VERSION = '2.0.807';
56
+ const VERSION = '2.0.809';
56
57
 
57
58
  /**
58
59
  * Servicio para gestionar presets de componentes.
@@ -17546,110 +17547,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
17546
17547
  type: Output
17547
17548
  }] } });
17548
17549
 
17549
- /**
17550
- * val-banner
17551
- *
17552
- * Displays a banner with title block, actions, and optional close button.
17553
- *
17554
- * @example
17555
- * <val-banner [props]="{ content: {...}, actions: {...}, closable: true, bordered: true, mode: 'center', alignment: 'center', padding: '8px' }" (onClick)="handler($event)" (onClose)="closeHandler()"></val-banner>
17556
- *
17557
- * @input props: BannerMetadata - Configuration for the banner (content, actions, closable, bordered, mode, alignment, padding)
17558
- * @output onClick - Emits when an action is clicked
17559
- * @output onClose - Emits when the banner is closed
17560
- */
17561
- class BannerComponent {
17562
- constructor(cdr) {
17563
- this.cdr = cdr;
17564
- this.onClick = new EventEmitter();
17565
- this.onClose = new EventEmitter();
17566
- }
17567
- ngOnInit() { }
17568
- ngOnChanges(changes) {
17569
- if (changes['props']) {
17570
- // Forzar detección de cambios múltiple
17571
- this.cdr.detectChanges();
17572
- setTimeout(() => {
17573
- this.cdr.detectChanges();
17574
- }, 0);
17575
- }
17576
- }
17577
- clickHandler(token) {
17578
- this.onClick.emit(token);
17579
- }
17580
- closeHandler() {
17581
- this.onClose.emit();
17582
- }
17583
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BannerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
17584
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: BannerComponent, isStandalone: true, selector: "val-banner", inputs: { props: "props" }, outputs: { onClick: "onClick", onClose: "onClose" }, usesOnChanges: true, ngImport: i0, template: `
17585
- <val-box
17586
- [props]="{
17587
- icon: props.closable ? 'close-outline' : '',
17588
- bordered: props.bordered,
17589
- color: '',
17590
- padding: props.padding,
17591
- }"
17592
- (onClick)="closeHandler()"
17593
- >
17594
- <div [ngClass]="['content-container', props.mode, props.alignment]" body>
17595
- <val-title-block
17596
- [props]="{
17597
- position: props.content.position,
17598
- aboveTitle: props.content.aboveTitle,
17599
- title: props.content.title,
17600
- bellowTitle: props.content.bellowTitle,
17601
- }"
17602
- ></val-title-block>
17603
- @if (props.actions) {
17604
- <val-button-group
17605
- [ngClass]="['buttons-container', props.mode, props.alignment]"
17606
- [props]="props.actions"
17607
- (onClick)="clickHandler($event)"
17608
- ></val-button-group>
17609
- }
17610
- </div>
17611
- </val-box>
17612
- `, 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)}.content-container{display:flex;justify-content:space-between}.content-container.center{flex-direction:column}.content-container.column{flex-direction:row}.content-container.row{flex-direction:column}.content-container.middle{align-items:center}.content-container.top{align-items:flex-start}.content-container.bottom{align-items:flex-end}.content-container.hybrid{flex-direction:column;align-items:flex-start}@media (min-width: 768px){.content-container.hybrid{flex-direction:row;align-items:center}}.buttons-container{align-items:center;display:flex;margin-top:1rem;margin-bottom:.0625rem}.buttons-container.column{margin-top:0rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: BoxComponent, selector: "val-box", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: TitleBlockComponent, selector: "val-title-block", inputs: ["props"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }] }); }
17613
- }
17614
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BannerComponent, decorators: [{
17615
- type: Component,
17616
- args: [{ selector: 'val-banner', standalone: true, imports: [CommonModule, BoxComponent, TitleBlockComponent, ButtonGroupComponent], template: `
17617
- <val-box
17618
- [props]="{
17619
- icon: props.closable ? 'close-outline' : '',
17620
- bordered: props.bordered,
17621
- color: '',
17622
- padding: props.padding,
17623
- }"
17624
- (onClick)="closeHandler()"
17625
- >
17626
- <div [ngClass]="['content-container', props.mode, props.alignment]" body>
17627
- <val-title-block
17628
- [props]="{
17629
- position: props.content.position,
17630
- aboveTitle: props.content.aboveTitle,
17631
- title: props.content.title,
17632
- bellowTitle: props.content.bellowTitle,
17633
- }"
17634
- ></val-title-block>
17635
- @if (props.actions) {
17636
- <val-button-group
17637
- [ngClass]="['buttons-container', props.mode, props.alignment]"
17638
- [props]="props.actions"
17639
- (onClick)="clickHandler($event)"
17640
- ></val-button-group>
17641
- }
17642
- </div>
17643
- </val-box>
17644
- `, 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)}.content-container{display:flex;justify-content:space-between}.content-container.center{flex-direction:column}.content-container.column{flex-direction:row}.content-container.row{flex-direction:column}.content-container.middle{align-items:center}.content-container.top{align-items:flex-start}.content-container.bottom{align-items:flex-end}.content-container.hybrid{flex-direction:column;align-items:flex-start}@media (min-width: 768px){.content-container.hybrid{flex-direction:row;align-items:center}}.buttons-container{align-items:center;display:flex;margin-top:1rem;margin-bottom:.0625rem}.buttons-container.column{margin-top:0rem}\n"] }]
17645
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { props: [{
17646
- type: Input
17647
- }], onClick: [{
17648
- type: Output
17649
- }], onClose: [{
17650
- type: Output
17651
- }] } });
17652
-
17653
17550
  /**
17654
17551
  * Analytics Service (Firebase GA4)
17655
17552
  *
@@ -19638,110 +19535,515 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19638
19535
  args: [{ providedIn: 'root' }]
19639
19536
  }] });
19640
19537
 
19538
+ /**
19539
+ * AppVersion Types
19540
+ *
19541
+ * Tipos para el servicio de verificación de versión de la aplicación.
19542
+ */
19543
+ /**
19544
+ * Intervalo por defecto de chequeo de actualizaciones: 30 minutos.
19545
+ */
19546
+ const DEFAULT_CHECK_INTERVAL_MS = 30 * 60 * 1000;
19547
+ /**
19548
+ * Configuración por defecto del servicio.
19549
+ */
19550
+ const DEFAULT_APP_VERSION_SERVICE_CONFIG = {
19551
+ currentVersion: '0.0.0',
19552
+ checkIntervalMs: DEFAULT_CHECK_INTERVAL_MS,
19553
+ };
19554
+
19555
+ /**
19556
+ * AppVersion Provider
19557
+ *
19558
+ * Provider e injection token para el servicio de verificación de versión.
19559
+ */
19560
+ /**
19561
+ * Token de inyección para la configuración de AppVersionService.
19562
+ */
19563
+ const VALTECH_APP_VERSION = new InjectionToken('ValtechAppVersion');
19564
+ /**
19565
+ * Provee el servicio de verificación de versión a la aplicación Angular.
19566
+ *
19567
+ * Detecta cuándo hay una versión nueva de la app combinando dos señales:
19568
+ * - `SwUpdate` (PWA service worker) — bundle nuevo descargado y listo.
19569
+ * - `AppConfigService` (config remoto en Firestore) — `version` / `minVersion`.
19570
+ *
19571
+ * @param config - Configuración del servicio. `currentVersion` es obligatorio.
19572
+ * @returns EnvironmentProviders para usar en bootstrapApplication.
19573
+ *
19574
+ * @example
19575
+ * ```typescript
19576
+ * // main.ts
19577
+ * import { provideValtechAppVersion } from 'valtech-components';
19578
+ * import pkg from '../package.json';
19579
+ *
19580
+ * bootstrapApplication(AppComponent, {
19581
+ * providers: [
19582
+ * provideValtechAppVersion({ currentVersion: pkg.version }),
19583
+ * ],
19584
+ * });
19585
+ * ```
19586
+ */
19587
+ function provideValtechAppVersion(config) {
19588
+ const mergedConfig = {
19589
+ ...DEFAULT_APP_VERSION_SERVICE_CONFIG,
19590
+ ...config,
19591
+ };
19592
+ return makeEnvironmentProviders([{ provide: VALTECH_APP_VERSION, useValue: mergedConfig }]);
19593
+ }
19594
+
19595
+ /**
19596
+ * AppVersionService
19597
+ *
19598
+ * Verificación de versión de la app para PWA / web.
19599
+ *
19600
+ * Unifica dos señales para detectar actualizaciones:
19601
+ *
19602
+ * 1. `SwUpdate` (`@angular/service-worker`) — el evento `VERSION_READY` indica
19603
+ * que un bundle nuevo fue descargado y está listo para activarse. Solo está
19604
+ * disponible cuando el service worker está registrado (build de producción).
19605
+ * Además se chequea proactivamente cada `checkIntervalMs` y cada vez que la
19606
+ * app vuelve a foreground (`visibilitychange`).
19607
+ *
19608
+ * 2. `AppConfigService` (config remoto en Firestore) — expone `version`
19609
+ * (última versión publicada) y `minVersion` (versión mínima soportada).
19610
+ * Se usa para la política de actualización obligatoria (hard gate).
19611
+ *
19612
+ * Ambas dependencias se inyectan como opcionales: el servicio degrada con
19613
+ * gracia si el SW no está habilitado (dev mode) o si `AppConfigService` no
19614
+ * está wireado en la app.
19615
+ */
19616
+ /**
19617
+ * Compara dos versiones semver. Retorna true si `a` es estrictamente menor
19618
+ * que `b`. Tolerante a longitudes distintas y a partes no numéricas.
19619
+ */
19620
+ function isVersionLower(a, b) {
19621
+ const pa = a.split('.').map(n => Number(n) || 0);
19622
+ const pb = b.split('.').map(n => Number(n) || 0);
19623
+ const len = Math.max(pa.length, pb.length);
19624
+ for (let i = 0; i < len; i++) {
19625
+ const x = pa[i] || 0;
19626
+ const y = pb[i] || 0;
19627
+ if (x < y)
19628
+ return true;
19629
+ if (x > y)
19630
+ return false;
19631
+ }
19632
+ return false;
19633
+ }
19634
+ class AppVersionService {
19635
+ constructor() {
19636
+ /** SwUpdate solo existe si el SW está registrado (prod build). */
19637
+ this.swUpdate = inject(SwUpdate, { optional: true });
19638
+ /** AppConfigService es opcional: la app puede no wirearlo. */
19639
+ this.appConfig = inject(AppConfigService, { optional: true });
19640
+ this.serviceConfig = inject(VALTECH_APP_VERSION, {
19641
+ optional: true,
19642
+ });
19643
+ this.document = inject(DOCUMENT);
19644
+ this.destroyRef = inject(DestroyRef);
19645
+ /** True cuando el SW reportó un bundle nuevo listo (`VERSION_READY`). */
19646
+ this.swUpdateReady = signal(false);
19647
+ /**
19648
+ * True cuando el usuario descartó el banner de actualización opcional.
19649
+ * El banner obligatorio (`update-required`) ignora este flag.
19650
+ */
19651
+ this._dismissed = signal(false);
19652
+ this.dismissed = this._dismissed.asReadonly();
19653
+ // ===========================================================================
19654
+ // SIGNALS PÚBLICOS
19655
+ // ===========================================================================
19656
+ /**
19657
+ * Versión local del build actual de la app.
19658
+ * Proviene del provider `provideValtechAppVersion({ currentVersion })`.
19659
+ */
19660
+ this.currentVersion = computed(() => this.serviceConfig?.currentVersion ?? '0.0.0');
19661
+ /**
19662
+ * Última versión publicada según el config remoto.
19663
+ * `null` si `AppConfigService` no está disponible o aún no cargó.
19664
+ */
19665
+ this.latestVersion = computed(() => this.appConfig?.remoteVersion() ?? null);
19666
+ /**
19667
+ * Estado de la versión:
19668
+ * - `update-required` — la versión local quedó por debajo de `minVersion`
19669
+ * del config remoto. Hard gate. Solo si `AppConfigService` tiene datos.
19670
+ * - `update-available` — el SW descargó un bundle nuevo (`VERSION_READY`)
19671
+ * o `AppConfigService.hasUpdate` es true.
19672
+ * - `up-to-date` — en cualquier otro caso.
19673
+ */
19674
+ this.status = computed(() => {
19675
+ // 1. Hard gate — minVersion del config remoto.
19676
+ if (this.appConfig) {
19677
+ const minVersion = this.appConfig.appConfig()?.minVersion;
19678
+ if (minVersion && isVersionLower(this.currentVersion(), minVersion)) {
19679
+ return 'update-required';
19680
+ }
19681
+ }
19682
+ // 2. Update opcional — SW bundle listo o config remoto más nuevo.
19683
+ if (this.swUpdateReady() || this.appConfig?.hasUpdate()) {
19684
+ return 'update-available';
19685
+ }
19686
+ return 'up-to-date';
19687
+ });
19688
+ this.wireServiceWorker();
19689
+ }
19690
+ // ===========================================================================
19691
+ // MÉTODOS PÚBLICOS
19692
+ // ===========================================================================
19693
+ /**
19694
+ * Aplica la actualización pendiente.
19695
+ *
19696
+ * Si el SW está habilitado, activa la versión descargada y recarga; si no,
19697
+ * solo recarga la página (la web obtiene el bundle nuevo del servidor).
19698
+ */
19699
+ async applyUpdate() {
19700
+ try {
19701
+ if (this.swUpdate?.isEnabled) {
19702
+ await this.swUpdate.activateUpdate();
19703
+ }
19704
+ }
19705
+ catch (err) {
19706
+ console.warn('[AppVersionService] activateUpdate failed:', err);
19707
+ }
19708
+ finally {
19709
+ this.document.defaultView?.location.reload();
19710
+ }
19711
+ }
19712
+ /**
19713
+ * Descarta el banner de actualización opcional.
19714
+ * No tiene efecto sobre el estado `update-required` (hard gate).
19715
+ */
19716
+ dismiss() {
19717
+ this._dismissed.set(true);
19718
+ }
19719
+ /**
19720
+ * Fuerza un chequeo de actualización del service worker.
19721
+ * No-op si el SW no está habilitado.
19722
+ */
19723
+ async checkNow() {
19724
+ if (!this.swUpdate?.isEnabled)
19725
+ return;
19726
+ try {
19727
+ await this.swUpdate.checkForUpdate();
19728
+ }
19729
+ catch (err) {
19730
+ console.warn('[AppVersionService] checkForUpdate failed:', err);
19731
+ }
19732
+ }
19733
+ // ===========================================================================
19734
+ // PRIVADO
19735
+ // ===========================================================================
19736
+ /**
19737
+ * Suscribe `versionUpdates`, programa chequeos periódicos y reacciona al
19738
+ * volver la app a foreground. Solo actúa si el SW está habilitado.
19739
+ */
19740
+ wireServiceWorker() {
19741
+ if (!this.swUpdate?.isEnabled)
19742
+ return;
19743
+ // Bundle nuevo descargado y listo.
19744
+ this.swUpdate.versionUpdates
19745
+ .pipe(filter$1(evt => evt.type === 'VERSION_READY'), takeUntilDestroyed(this.destroyRef))
19746
+ .subscribe(() => this.swUpdateReady.set(true));
19747
+ // Chequeo periódico.
19748
+ const intervalMs = this.serviceConfig?.checkIntervalMs ?? DEFAULT_APP_VERSION_SERVICE_CONFIG.checkIntervalMs;
19749
+ interval(intervalMs)
19750
+ .pipe(takeUntilDestroyed(this.destroyRef))
19751
+ .subscribe(() => void this.checkNow());
19752
+ // Chequeo al volver la app a foreground.
19753
+ const onVisible = () => {
19754
+ if (this.document.visibilityState === 'visible') {
19755
+ void this.checkNow();
19756
+ }
19757
+ };
19758
+ this.document.addEventListener('visibilitychange', onVisible);
19759
+ this.destroyRef.onDestroy(() => {
19760
+ this.document.removeEventListener('visibilitychange', onVisible);
19761
+ });
19762
+ // Chequeo inicial.
19763
+ void this.checkNow();
19764
+ }
19765
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppVersionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
19766
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppVersionService, providedIn: 'root' }); }
19767
+ }
19768
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppVersionService, decorators: [{
19769
+ type: Injectable,
19770
+ args: [{ providedIn: 'root' }]
19771
+ }], ctorParameters: () => [] });
19772
+
19773
+ /**
19774
+ * UpdateBanner Types
19775
+ *
19776
+ * Contenido i18n del banner de actualización de la app.
19777
+ */
19778
+ /**
19779
+ * Namespace i18n usado por `val-update-banner`.
19780
+ * Las apps consumidoras pueden sobreescribir estas keys registrando
19781
+ * contenido bajo este namespace en `I18nService`.
19782
+ */
19783
+ const UPDATE_BANNER_I18N_NAMESPACE = 'UpdateBanner';
19784
+ /**
19785
+ * Textos por defecto del banner (fallback si la app no registra el namespace).
19786
+ * Soporta es / en / pt.
19787
+ */
19788
+ const UPDATE_BANNER_DEFAULT_CONTENT = {
19789
+ es: {
19790
+ availableTitle: 'Hay una versión nueva disponible',
19791
+ availableMessage: 'Actualiza para obtener las últimas mejoras.',
19792
+ requiredTitle: 'Debes actualizar para continuar',
19793
+ requiredMessage: 'Esta versión ya no es compatible. Actualiza para seguir.',
19794
+ updateAction: 'Actualizar',
19795
+ dismissAction: 'Cerrar',
19796
+ },
19797
+ en: {
19798
+ availableTitle: 'A new version is available',
19799
+ availableMessage: 'Update to get the latest improvements.',
19800
+ requiredTitle: 'You must update to continue',
19801
+ requiredMessage: 'This version is no longer supported. Please update.',
19802
+ updateAction: 'Update',
19803
+ dismissAction: 'Close',
19804
+ },
19805
+ pt: {
19806
+ availableTitle: 'Há uma nova versão disponível',
19807
+ availableMessage: 'Atualize para obter as últimas melhorias.',
19808
+ requiredTitle: 'Você precisa atualizar para continuar',
19809
+ requiredMessage: 'Esta versão não é mais compatível. Atualize para seguir.',
19810
+ updateAction: 'Atualizar',
19811
+ dismissAction: 'Fechar',
19812
+ },
19813
+ };
19814
+
19641
19815
  /**
19642
19816
  * UpdateBannerComponent
19643
19817
  *
19644
- * Componente que muestra un banner cuando hay una nueva versión de la aplicación disponible.
19645
- * Se integra automáticamente con AppConfigService para detectar actualizaciones.
19818
+ * Banner que avisa al usuario cuando hay una versión nueva de la app.
19819
+ * Consume `AppVersionService` (no toca `SwUpdate` ni `AppConfigService`
19820
+ * directamente) y soporta dos modos:
19821
+ *
19822
+ * - `update-available` — banner descartable: mensaje + botón "Actualizar"
19823
+ * + botón cerrar.
19824
+ * - `update-required` — overlay bloqueante no-descartable (hard gate):
19825
+ * mensaje + botón "Actualizar". Sin botón cerrar.
19826
+ *
19827
+ * Cuando el estado es `up-to-date` (o el usuario descartó el banner opcional)
19828
+ * no renderiza nada.
19646
19829
  */
19647
19830
  /**
19648
19831
  * val-update-banner
19649
19832
  *
19650
- * Banner de actualización que aparece cuando hay una nueva versión disponible.
19651
- * Se cierra automáticamente cuando el usuario hace clic en "Actualizar" o en cerrar.
19833
+ * Avisa al usuario de una versión nueva. Colócalo una sola vez, alto en el
19834
+ * árbol de la app (p.ej. en `app.component` por encima del router outlet)
19835
+ * para que sea visible en cualquier ruta.
19652
19836
  *
19653
19837
  * @example
19654
19838
  * ```html
19655
- * <!-- Uso básico -->
19656
19839
  * <val-update-banner />
19657
- *
19658
- * <!-- El banner solo aparece si hay actualización disponible -->
19659
19840
  * ```
19660
19841
  */
19661
19842
  class UpdateBannerComponent {
19662
19843
  constructor() {
19663
- this.appConfig = inject(AppConfigService);
19844
+ this.version = inject(AppVersionService);
19664
19845
  this.i18n = inject(I18nService);
19665
19846
  /**
19666
- * Signal para controlar si el banner fue descartado por el usuario.
19847
+ * True cuando el banner está en modo obligatorio (hard gate, no descartable).
19667
19848
  */
19668
- this.dismissed = signal(false);
19849
+ this.required = computed(() => this.version.status() === 'update-required');
19669
19850
  /**
19670
- * Indica si el banner debe mostrarse.
19851
+ * True cuando el banner debe renderizarse:
19852
+ * - siempre que el estado sea `update-required`, o
19853
+ * - si es `update-available` y el usuario no lo descartó.
19671
19854
  */
19672
- this.show = computed(() => this.appConfig.hasUpdate() && !this.dismissed());
19855
+ this.visible = computed(() => {
19856
+ const status = this.version.status();
19857
+ if (status === 'update-required')
19858
+ return true;
19859
+ if (status === 'update-available')
19860
+ return !this.version.dismissed();
19861
+ return false;
19862
+ });
19673
19863
  /**
19674
- * Props del banner calculadas reactivamente.
19864
+ * Textos resolvidos del banner. Reactivo a idioma y al estado required.
19865
+ * Usa el namespace `UpdateBanner` de `I18nService` con fallback embebido.
19675
19866
  */
19676
- this.bannerProps = computed(() => ({
19677
- color: 'primary',
19678
- bordered: false,
19679
- closable: true,
19680
- mode: 'center',
19681
- alignment: 'center',
19682
- padding: '0.5rem 1rem',
19683
- content: {
19684
- position: 'center',
19685
- title: {
19686
- content: this.i18n.t('clickToUpdate', 'AppConfig'),
19687
- size: 'small',
19688
- color: 'light',
19689
- bold: false,
19690
- },
19691
- },
19692
- actions: {
19693
- position: 'center',
19694
- columned: false,
19695
- buttons: [
19696
- {
19697
- token: 'update',
19698
- text: this.i18n.t('updateNow', 'AppConfig'),
19699
- color: 'light',
19700
- fill: 'outline',
19701
- size: 'small',
19702
- state: 'ENABLED',
19703
- type: 'button',
19704
- },
19705
- ],
19706
- },
19707
- }));
19867
+ this.t = computed(() => {
19868
+ this.i18n.lang(); // track para reactividad
19869
+ const isRequired = this.required();
19870
+ return {
19871
+ title: this.tr(isRequired ? 'requiredTitle' : 'availableTitle'),
19872
+ message: this.tr(isRequired ? 'requiredMessage' : 'availableMessage'),
19873
+ updateAction: this.tr('updateAction'),
19874
+ dismissAction: this.tr('dismissAction'),
19875
+ };
19876
+ });
19708
19877
  }
19709
- /**
19710
- * Maneja el clic en acciones del banner.
19711
- */
19712
- onAction(token) {
19713
- if (token === 'update') {
19714
- window.location.reload();
19715
- }
19878
+ /** Aplica la actualización (activa el SW si existe + recarga). */
19879
+ onUpdate() {
19880
+ void this.version.applyUpdate();
19881
+ }
19882
+ /** Descarta el banner opcional. No-op en modo obligatorio. */
19883
+ onDismiss() {
19884
+ this.version.dismiss();
19716
19885
  }
19717
19886
  /**
19718
- * Descarta el banner temporalmente (hasta que se recargue la página).
19887
+ * Resuelve una key i18n del namespace `UpdateBanner` con fallback al
19888
+ * contenido por defecto embebido (es / en / pt).
19719
19889
  */
19720
- dismiss() {
19721
- this.dismissed.set(true);
19890
+ tr(key) {
19891
+ const value = this.i18n.t(key, UPDATE_BANNER_I18N_NAMESPACE);
19892
+ if (value && !value.startsWith('['))
19893
+ return value;
19894
+ const lang = this.i18n.lang();
19895
+ const pack = UPDATE_BANNER_DEFAULT_CONTENT[lang] ??
19896
+ UPDATE_BANNER_DEFAULT_CONTENT.es;
19897
+ return pack[key];
19722
19898
  }
19723
19899
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UpdateBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19724
19900
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UpdateBannerComponent, isStandalone: true, selector: "val-update-banner", ngImport: i0, template: `
19725
- @if (show()) {
19726
- <val-banner
19727
- [props]="bannerProps()"
19728
- (onClick)="onAction($event)"
19729
- (onClose)="dismiss()"
19730
- />
19901
+ @if (visible()) {
19902
+ <div
19903
+ class="val-update-banner"
19904
+ [class.val-update-banner--required]="required()"
19905
+ role="alert"
19906
+ [attr.aria-live]="required() ? 'assertive' : 'polite'"
19907
+ >
19908
+ @if (required()) {
19909
+ <div class="val-update-banner__backdrop"></div>
19910
+ }
19911
+
19912
+ <div class="val-update-banner__panel">
19913
+ <div class="val-update-banner__icon">
19914
+ <val-icon
19915
+ [props]="{
19916
+ name: required() ? 'warning-outline' : 'cloud-download-outline',
19917
+ size: 'large',
19918
+ color: required() ? 'warning' : 'primary',
19919
+ }"
19920
+ />
19921
+ </div>
19922
+
19923
+ <div class="val-update-banner__body">
19924
+ <val-text
19925
+ [props]="{
19926
+ content: t().title,
19927
+ size: 'medium',
19928
+ bold: true,
19929
+ color: 'dark',
19930
+ }"
19931
+ />
19932
+ <val-text
19933
+ [props]="{
19934
+ content: t().message,
19935
+ size: 'small',
19936
+ bold: false,
19937
+ color: 'medium',
19938
+ }"
19939
+ />
19940
+ </div>
19941
+
19942
+ <div class="val-update-banner__actions">
19943
+ <val-button
19944
+ [props]="{
19945
+ text: t().updateAction,
19946
+ color: 'primary',
19947
+ fill: 'solid',
19948
+ size: 'small',
19949
+ state: 'ENABLED',
19950
+ type: 'button',
19951
+ }"
19952
+ (onClick)="onUpdate()"
19953
+ />
19954
+ @if (!required()) {
19955
+ <val-button
19956
+ [props]="{
19957
+ text: t().dismissAction,
19958
+ color: 'medium',
19959
+ fill: 'clear',
19960
+ size: 'small',
19961
+ state: 'ENABLED',
19962
+ type: 'button',
19963
+ }"
19964
+ (onClick)="onDismiss()"
19965
+ />
19966
+ }
19967
+ </div>
19968
+ </div>
19969
+ </div>
19731
19970
  }
19732
- `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BannerComponent, selector: "val-banner", inputs: ["props"], outputs: ["onClick", "onClose"] }] }); }
19971
+ `, isInline: true, styles: [":host{display:contents}.val-update-banner{position:fixed;top:0;left:0;right:0;z-index:1100;display:flex;justify-content:center;padding:calc(12px + env(safe-area-inset-top,0px)) 16px 12px;pointer-events:none}.val-update-banner__backdrop{position:fixed;inset:0;z-index:-1;background:#0000008c;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);pointer-events:auto}.val-update-banner__panel{pointer-events:auto;display:flex;flex-direction:row;align-items:center;gap:12px;width:100%;max-width:640px;padding:12px 16px;background:var(--ion-background-color, #fff);border:1px solid var(--val-border-color, rgba(0, 0, 0, .08));border-radius:var(--val-border-radius, 12px);box-shadow:0 4px 24px #0000001f;animation:val-update-banner-in .25s ease-out}.val-update-banner--required{align-items:center;height:100%}.val-update-banner--required .val-update-banner__panel{flex-direction:column;text-align:center;max-width:420px}.val-update-banner__icon{flex:0 0 auto;display:inline-flex;align-items:center}.val-update-banner__body{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;min-width:0}.val-update-banner__actions{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:4px}.val-update-banner--required .val-update-banner__actions{margin-top:8px}@keyframes val-update-banner-in{0%{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:translateY(0)}}@media (max-width: 540px){.val-update-banner__panel{flex-direction:column;text-align:center}.val-update-banner__actions{width:100%;justify-content:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: IconComponent, selector: "val-icon", inputs: ["props"] }] }); }
19733
19972
  }
19734
19973
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UpdateBannerComponent, decorators: [{
19735
19974
  type: Component,
19736
- args: [{ selector: 'val-update-banner', standalone: true, imports: [CommonModule, BannerComponent], template: `
19737
- @if (show()) {
19738
- <val-banner
19739
- [props]="bannerProps()"
19740
- (onClick)="onAction($event)"
19741
- (onClose)="dismiss()"
19742
- />
19975
+ args: [{ selector: 'val-update-banner', standalone: true, imports: [CommonModule, TextComponent, ButtonComponent, IconComponent], template: `
19976
+ @if (visible()) {
19977
+ <div
19978
+ class="val-update-banner"
19979
+ [class.val-update-banner--required]="required()"
19980
+ role="alert"
19981
+ [attr.aria-live]="required() ? 'assertive' : 'polite'"
19982
+ >
19983
+ @if (required()) {
19984
+ <div class="val-update-banner__backdrop"></div>
19985
+ }
19986
+
19987
+ <div class="val-update-banner__panel">
19988
+ <div class="val-update-banner__icon">
19989
+ <val-icon
19990
+ [props]="{
19991
+ name: required() ? 'warning-outline' : 'cloud-download-outline',
19992
+ size: 'large',
19993
+ color: required() ? 'warning' : 'primary',
19994
+ }"
19995
+ />
19996
+ </div>
19997
+
19998
+ <div class="val-update-banner__body">
19999
+ <val-text
20000
+ [props]="{
20001
+ content: t().title,
20002
+ size: 'medium',
20003
+ bold: true,
20004
+ color: 'dark',
20005
+ }"
20006
+ />
20007
+ <val-text
20008
+ [props]="{
20009
+ content: t().message,
20010
+ size: 'small',
20011
+ bold: false,
20012
+ color: 'medium',
20013
+ }"
20014
+ />
20015
+ </div>
20016
+
20017
+ <div class="val-update-banner__actions">
20018
+ <val-button
20019
+ [props]="{
20020
+ text: t().updateAction,
20021
+ color: 'primary',
20022
+ fill: 'solid',
20023
+ size: 'small',
20024
+ state: 'ENABLED',
20025
+ type: 'button',
20026
+ }"
20027
+ (onClick)="onUpdate()"
20028
+ />
20029
+ @if (!required()) {
20030
+ <val-button
20031
+ [props]="{
20032
+ text: t().dismissAction,
20033
+ color: 'medium',
20034
+ fill: 'clear',
20035
+ size: 'small',
20036
+ state: 'ENABLED',
20037
+ type: 'button',
20038
+ }"
20039
+ (onClick)="onDismiss()"
20040
+ />
20041
+ }
20042
+ </div>
20043
+ </div>
20044
+ </div>
19743
20045
  }
19744
- `, styles: [":host{display:block}\n"] }]
20046
+ `, styles: [":host{display:contents}.val-update-banner{position:fixed;top:0;left:0;right:0;z-index:1100;display:flex;justify-content:center;padding:calc(12px + env(safe-area-inset-top,0px)) 16px 12px;pointer-events:none}.val-update-banner__backdrop{position:fixed;inset:0;z-index:-1;background:#0000008c;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);pointer-events:auto}.val-update-banner__panel{pointer-events:auto;display:flex;flex-direction:row;align-items:center;gap:12px;width:100%;max-width:640px;padding:12px 16px;background:var(--ion-background-color, #fff);border:1px solid var(--val-border-color, rgba(0, 0, 0, .08));border-radius:var(--val-border-radius, 12px);box-shadow:0 4px 24px #0000001f;animation:val-update-banner-in .25s ease-out}.val-update-banner--required{align-items:center;height:100%}.val-update-banner--required .val-update-banner__panel{flex-direction:column;text-align:center;max-width:420px}.val-update-banner__icon{flex:0 0 auto;display:inline-flex;align-items:center}.val-update-banner__body{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;min-width:0}.val-update-banner__actions{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:4px}.val-update-banner--required .val-update-banner__actions{margin-top:8px}@keyframes val-update-banner-in{0%{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:translateY(0)}}@media (max-width: 540px){.val-update-banner__panel{flex-direction:column;text-align:center}.val-update-banner__actions{width:100%;justify-content:center}}\n"] }]
19745
20047
  }] });
19746
20048
 
19747
20049
  /**
@@ -26707,6 +27009,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26707
27009
  type: Input
26708
27010
  }] } });
26709
27011
 
27012
+ /**
27013
+ * val-banner
27014
+ *
27015
+ * Displays a banner with title block, actions, and optional close button.
27016
+ *
27017
+ * @example
27018
+ * <val-banner [props]="{ content: {...}, actions: {...}, closable: true, bordered: true, mode: 'center', alignment: 'center', padding: '8px' }" (onClick)="handler($event)" (onClose)="closeHandler()"></val-banner>
27019
+ *
27020
+ * @input props: BannerMetadata - Configuration for the banner (content, actions, closable, bordered, mode, alignment, padding)
27021
+ * @output onClick - Emits when an action is clicked
27022
+ * @output onClose - Emits when the banner is closed
27023
+ */
27024
+ class BannerComponent {
27025
+ constructor(cdr) {
27026
+ this.cdr = cdr;
27027
+ this.onClick = new EventEmitter();
27028
+ this.onClose = new EventEmitter();
27029
+ }
27030
+ ngOnInit() { }
27031
+ ngOnChanges(changes) {
27032
+ if (changes['props']) {
27033
+ // Forzar detección de cambios múltiple
27034
+ this.cdr.detectChanges();
27035
+ setTimeout(() => {
27036
+ this.cdr.detectChanges();
27037
+ }, 0);
27038
+ }
27039
+ }
27040
+ clickHandler(token) {
27041
+ this.onClick.emit(token);
27042
+ }
27043
+ closeHandler() {
27044
+ this.onClose.emit();
27045
+ }
27046
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BannerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
27047
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: BannerComponent, isStandalone: true, selector: "val-banner", inputs: { props: "props" }, outputs: { onClick: "onClick", onClose: "onClose" }, usesOnChanges: true, ngImport: i0, template: `
27048
+ <val-box
27049
+ [props]="{
27050
+ icon: props.closable ? 'close-outline' : '',
27051
+ bordered: props.bordered,
27052
+ color: '',
27053
+ padding: props.padding,
27054
+ }"
27055
+ (onClick)="closeHandler()"
27056
+ >
27057
+ <div [ngClass]="['content-container', props.mode, props.alignment]" body>
27058
+ <val-title-block
27059
+ [props]="{
27060
+ position: props.content.position,
27061
+ aboveTitle: props.content.aboveTitle,
27062
+ title: props.content.title,
27063
+ bellowTitle: props.content.bellowTitle,
27064
+ }"
27065
+ ></val-title-block>
27066
+ @if (props.actions) {
27067
+ <val-button-group
27068
+ [ngClass]="['buttons-container', props.mode, props.alignment]"
27069
+ [props]="props.actions"
27070
+ (onClick)="clickHandler($event)"
27071
+ ></val-button-group>
27072
+ }
27073
+ </div>
27074
+ </val-box>
27075
+ `, 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)}.content-container{display:flex;justify-content:space-between}.content-container.center{flex-direction:column}.content-container.column{flex-direction:row}.content-container.row{flex-direction:column}.content-container.middle{align-items:center}.content-container.top{align-items:flex-start}.content-container.bottom{align-items:flex-end}.content-container.hybrid{flex-direction:column;align-items:flex-start}@media (min-width: 768px){.content-container.hybrid{flex-direction:row;align-items:center}}.buttons-container{align-items:center;display:flex;margin-top:1rem;margin-bottom:.0625rem}.buttons-container.column{margin-top:0rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: BoxComponent, selector: "val-box", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: TitleBlockComponent, selector: "val-title-block", inputs: ["props"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }] }); }
27076
+ }
27077
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BannerComponent, decorators: [{
27078
+ type: Component,
27079
+ args: [{ selector: 'val-banner', standalone: true, imports: [CommonModule, BoxComponent, TitleBlockComponent, ButtonGroupComponent], template: `
27080
+ <val-box
27081
+ [props]="{
27082
+ icon: props.closable ? 'close-outline' : '',
27083
+ bordered: props.bordered,
27084
+ color: '',
27085
+ padding: props.padding,
27086
+ }"
27087
+ (onClick)="closeHandler()"
27088
+ >
27089
+ <div [ngClass]="['content-container', props.mode, props.alignment]" body>
27090
+ <val-title-block
27091
+ [props]="{
27092
+ position: props.content.position,
27093
+ aboveTitle: props.content.aboveTitle,
27094
+ title: props.content.title,
27095
+ bellowTitle: props.content.bellowTitle,
27096
+ }"
27097
+ ></val-title-block>
27098
+ @if (props.actions) {
27099
+ <val-button-group
27100
+ [ngClass]="['buttons-container', props.mode, props.alignment]"
27101
+ [props]="props.actions"
27102
+ (onClick)="clickHandler($event)"
27103
+ ></val-button-group>
27104
+ }
27105
+ </div>
27106
+ </val-box>
27107
+ `, 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)}.content-container{display:flex;justify-content:space-between}.content-container.center{flex-direction:column}.content-container.column{flex-direction:row}.content-container.row{flex-direction:column}.content-container.middle{align-items:center}.content-container.top{align-items:flex-start}.content-container.bottom{align-items:flex-end}.content-container.hybrid{flex-direction:column;align-items:flex-start}@media (min-width: 768px){.content-container.hybrid{flex-direction:row;align-items:center}}.buttons-container{align-items:center;display:flex;margin-top:1rem;margin-bottom:.0625rem}.buttons-container.column{margin-top:0rem}\n"] }]
27108
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { props: [{
27109
+ type: Input
27110
+ }], onClick: [{
27111
+ type: Output
27112
+ }], onClose: [{
27113
+ type: Output
27114
+ }] } });
27115
+
26710
27116
  /**
26711
27117
  * `val-cookie-banner` — bottom/top fixed banner asking the user to choose
26712
27118
  * a cookie consent option. Presentational only: emits events on each
@@ -37950,6 +38356,27 @@ async function getAppInfo() {
37950
38356
  * ```
37951
38357
  */
37952
38358
 
38359
+ /**
38360
+ * AppVersion Service Module
38361
+ *
38362
+ * Verificación de versión de la app para PWA / web. Detecta cuándo hay una
38363
+ * versión nueva combinando el service worker (`SwUpdate`) y el config remoto
38364
+ * (`AppConfigService`), con soporte para actualización obligatoria (hard gate).
38365
+ *
38366
+ * @example
38367
+ * ```typescript
38368
+ * // main.ts
38369
+ * import { provideValtechAppVersion } from 'valtech-components';
38370
+ * import pkg from '../package.json';
38371
+ *
38372
+ * bootstrapApplication(AppComponent, {
38373
+ * providers: [
38374
+ * provideValtechAppVersion({ currentVersion: pkg.version }),
38375
+ * ],
38376
+ * });
38377
+ * ```
38378
+ */
38379
+
37953
38380
  /**
37954
38381
  * Directiva estructural simplificada para estados de carga.
37955
38382
  *
@@ -45121,5 +45548,5 @@ function buildFooterLinks(links, t, resolver) {
45121
45548
  * Generated bundle index. Do not edit.
45122
45549
  */
45123
45550
 
45124
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentTransformer, CookieBannerComponent, CountdownComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, 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, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, 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, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SHAPE_KEYS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, 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, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, 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, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, 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_SOCIAL_LINKS, VERSION, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, blogPost, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideValtechAds, provideValtechAppConfig, provideValtechAuth, provideValtechAuthInterceptor, provideValtechDonations, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPresets, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard, toArticle };
45551
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, AppVersionService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentTransformer, CookieBannerComponent, CountdownComponent, 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_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, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, 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, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SHAPE_KEYS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, 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, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, 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_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_SOCIAL_LINKS, VERSION, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, blogPost, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechDonations, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPresets, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard, toArticle };
45125
45552
  //# sourceMappingURL=valtech-components.mjs.map