valtech-components 2.0.946 → 2.0.947

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 (25) hide show
  1. package/esm2022/lib/components/organisms/fun-modal/fun-modal.component.mjs +135 -0
  2. package/esm2022/lib/components/organisms/fun-modal/types.mjs +8 -0
  3. package/esm2022/lib/components/organisms/share-profile-modal/share-profile-modal.component.mjs +221 -0
  4. package/esm2022/lib/components/organisms/share-profile-modal/types.mjs +10 -0
  5. package/esm2022/lib/services/content/index.mjs +1 -1
  6. package/esm2022/lib/services/content-platform/config.mjs +40 -0
  7. package/esm2022/lib/services/content-platform/content.service.mjs +138 -0
  8. package/esm2022/lib/services/content-platform/index.mjs +10 -0
  9. package/esm2022/lib/services/content-platform/types.mjs +19 -0
  10. package/esm2022/lib/version.mjs +2 -2
  11. package/esm2022/public-api.mjs +9 -1
  12. package/fesm2022/valtech-components.mjs +545 -13
  13. package/fesm2022/valtech-components.mjs.map +1 -1
  14. package/lib/components/organisms/fun-modal/fun-modal.component.d.ts +44 -0
  15. package/lib/components/organisms/fun-modal/types.d.ts +37 -0
  16. package/lib/components/organisms/share-profile-modal/share-profile-modal.component.d.ts +49 -0
  17. package/lib/components/organisms/share-profile-modal/types.d.ts +45 -0
  18. package/lib/services/content/index.d.ts +1 -1
  19. package/lib/services/content-platform/config.d.ts +38 -0
  20. package/lib/services/content-platform/content.service.d.ts +70 -0
  21. package/lib/services/content-platform/index.d.ts +10 -0
  22. package/lib/services/content-platform/types.d.ts +117 -0
  23. package/lib/version.d.ts +1 -1
  24. package/package.json +1 -1
  25. package/public-api.d.ts +5 -0
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
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, ContentChild, output, Injector, isSignal, ElementRef, ViewEncapsulation } from '@angular/core';
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 } from 'rxjs';
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';
6
6
  import { provideHttpClient, withInterceptors, HttpClient, HttpErrorResponse } from '@angular/common/http';
@@ -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.946';
57
+ const VERSION = '2.0.947';
58
58
 
59
59
  // Control de estado de refresco (singleton a nivel de módulo)
60
60
  let isRefreshing = false;
@@ -26952,7 +26952,7 @@ const ACTION_CARD_DEFAULTS = {
26952
26952
  };
26953
26953
 
26954
26954
  addIcons({ chevronForwardOutline });
26955
- const IONIC_COLORS$4 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
26955
+ const IONIC_COLORS$5 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
26956
26956
  /**
26957
26957
  * val-action-card
26958
26958
  *
@@ -27032,7 +27032,7 @@ class ActionCardComponent {
27032
27032
  resolveColor(color) {
27033
27033
  if (!color)
27034
27034
  return null;
27035
- if (IONIC_COLORS$4.includes(color)) {
27035
+ if (IONIC_COLORS$5.includes(color)) {
27036
27036
  return `var(--ion-color-${color})`;
27037
27037
  }
27038
27038
  return color;
@@ -27225,7 +27225,7 @@ const MEDIA_OBJECT_DEFAULTS = {
27225
27225
  circle: false,
27226
27226
  };
27227
27227
 
27228
- const IONIC_COLORS$3 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27228
+ const IONIC_COLORS$4 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27229
27229
  /**
27230
27230
  * val-media-object
27231
27231
  *
@@ -27265,7 +27265,7 @@ class MediaObjectComponent {
27265
27265
  const color = this.config().color;
27266
27266
  if (!color)
27267
27267
  return 'var(--ion-color-primary)';
27268
- return IONIC_COLORS$3.includes(color) ? `var(--ion-color-${color})` : color;
27268
+ return IONIC_COLORS$4.includes(color) ? `var(--ion-color-${color})` : color;
27269
27269
  }
27270
27270
  handleLinkClick(event) {
27271
27271
  const link = this.config().link;
@@ -27369,7 +27369,7 @@ const STATS_BAR_DEFAULTS = {
27369
27369
  stackOnMobile: true,
27370
27370
  };
27371
27371
 
27372
- const IONIC_COLORS$2 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27372
+ const IONIC_COLORS$3 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27373
27373
  /**
27374
27374
  * val-stats-bar
27375
27375
  *
@@ -27406,7 +27406,7 @@ class StatsBarComponent {
27406
27406
  const color = stat.color;
27407
27407
  if (!color)
27408
27408
  return null;
27409
- return IONIC_COLORS$2.includes(color) ? `var(--ion-color-${color})` : color;
27409
+ return IONIC_COLORS$3.includes(color) ? `var(--ion-color-${color})` : color;
27410
27410
  }
27411
27411
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatsBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27412
27412
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: StatsBarComponent, isStandalone: true, selector: "val-stats-bar", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
@@ -27474,7 +27474,7 @@ const ARTICLE_CARD_DEFAULTS = {
27474
27474
  excerptLines: 3,
27475
27475
  };
27476
27476
 
27477
- const IONIC_COLORS$1 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27477
+ const IONIC_COLORS$2 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27478
27478
  /**
27479
27479
  * val-article-card
27480
27480
  *
@@ -27517,7 +27517,7 @@ class ArticleCardComponent {
27517
27517
  const color = this.config().topicColor;
27518
27518
  if (!color)
27519
27519
  return 'var(--ion-color-primary)';
27520
- return IONIC_COLORS$1.includes(color) ? `var(--ion-color-${color})` : color;
27520
+ return IONIC_COLORS$2.includes(color) ? `var(--ion-color-${color})` : color;
27521
27521
  }
27522
27522
  handleClick(event) {
27523
27523
  const cfg = this.config();
@@ -27632,7 +27632,7 @@ const CTA_CARD_DEFAULTS = {
27632
27632
  shadowed: false,
27633
27633
  };
27634
27634
 
27635
- const IONIC_COLORS = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27635
+ const IONIC_COLORS$1 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27636
27636
  /**
27637
27637
  * val-cta-card
27638
27638
  *
@@ -27676,7 +27676,7 @@ class CtaCardComponent {
27676
27676
  resolveColor(color) {
27677
27677
  if (!color)
27678
27678
  return null;
27679
- return IONIC_COLORS.includes(color) ? `var(--ion-color-${color})` : color;
27679
+ return IONIC_COLORS$1.includes(color) ? `var(--ion-color-${color})` : color;
27680
27680
  }
27681
27681
  getBackground() {
27682
27682
  return this.resolveColor(this.config().backgroundColor) || 'var(--ion-color-light, #f4f5f8)';
@@ -32583,6 +32583,359 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
32583
32583
  type: Output
32584
32584
  }] } });
32585
32585
 
32586
+ /**
32587
+ * Default values for ShareProfileModalMetadata.
32588
+ */
32589
+ const SHARE_PROFILE_MODAL_DEFAULTS = {
32590
+ platforms: ['copy', 'native', 'whatsapp'],
32591
+ qrTheme: 'default',
32592
+ qrSize: 220,
32593
+ borderRadius: 24,
32594
+ };
32595
+
32596
+ /**
32597
+ * Defaults i18n (es/en). Auto-registrados en el constructor si el consumer no
32598
+ * proveyó el namespace `ShareProfileModal`. Garantiza que nunca haya una key
32599
+ * faltante (ver nota en valtech-components/CLAUDE.md sobre el storm de CD).
32600
+ */
32601
+ const SHARE_PROFILE_MODAL_I18N = {
32602
+ es: {
32603
+ title: 'Compartir perfil',
32604
+ caption: 'Escanea el código QR para añadirme como contacto',
32605
+ },
32606
+ en: {
32607
+ title: 'Share profile',
32608
+ caption: 'Scan the QR code to add me as a contact',
32609
+ },
32610
+ };
32611
+ /**
32612
+ * `val-share-profile-modal` — modal reutilizable para compartir un perfil (o
32613
+ * cualquier entidad) vía QR + URL. Sigue la Regla #5 (header canónico vía
32614
+ * `val-modal-shell`).
32615
+ *
32616
+ * Self-contained: genera el QR con `QrGeneratorService` a partir de `url` al
32617
+ * abrirse. El padre solo controla `[isOpen]` y reacciona a `(dismissed)`.
32618
+ *
32619
+ * @example
32620
+ * ```html
32621
+ * <val-share-profile-modal
32622
+ * [isOpen]="isOpen()"
32623
+ * [props]="{ name: 'Víctor Valenzuela', url: 'https://app.myvaltech.com/u/victor', avatarUrl: '/me.jpg' }"
32624
+ * (dismissed)="isOpen.set(false)"
32625
+ * />
32626
+ * ```
32627
+ */
32628
+ class ShareProfileModalComponent {
32629
+ /** Controla la visibilidad. Al pasar de cerrado a abierto genera el QR. */
32630
+ set isOpen(value) {
32631
+ const opening = value && !this._isOpen;
32632
+ this._isOpen = value;
32633
+ if (opening) {
32634
+ this.generateQr();
32635
+ }
32636
+ }
32637
+ get isOpen() {
32638
+ return this._isOpen;
32639
+ }
32640
+ constructor() {
32641
+ this.qrGenerator = inject(QrGeneratorService);
32642
+ this.i18n = inject(I18nService);
32643
+ this._isOpen = false;
32644
+ /** Configuración del modal. */
32645
+ this.props = {};
32646
+ /** Emite cuando el user cierra el modal (botón Cerrar o backdrop). */
32647
+ this.dismissed = new EventEmitter();
32648
+ /** Emite al completar una acción de compartir. */
32649
+ this.shared = new EventEmitter();
32650
+ this._qr = signal(null);
32651
+ this.qr = this._qr.asReadonly();
32652
+ this._qrError = signal(false);
32653
+ this.qrError = this._qrError.asReadonly();
32654
+ this.config = computed(() => ({
32655
+ ...SHARE_PROFILE_MODAL_DEFAULTS,
32656
+ ...this.props,
32657
+ }));
32658
+ this.displayName = computed(() => this.config().title || this.config().name || this.t('title'));
32659
+ this.caption = computed(() => this.config().caption || this.t('caption'));
32660
+ if (!this.i18n.hasNamespace('ShareProfileModal')) {
32661
+ this.i18n.registerContent('ShareProfileModal', SHARE_PROFILE_MODAL_I18N);
32662
+ }
32663
+ }
32664
+ t(key) {
32665
+ this.i18n.lang();
32666
+ return this.i18n.t(key, 'ShareProfileModal');
32667
+ }
32668
+ async generateQr() {
32669
+ const url = this.config().url;
32670
+ if (!url)
32671
+ return;
32672
+ this._qr.set(null);
32673
+ this._qrError.set(false);
32674
+ try {
32675
+ // Formato SVG: lo genera qr-code-styling sin canvas.toBlob (que cuelga en
32676
+ // algunos contextos de bundler/Storybook). Renderiza igual de nítido.
32677
+ const result = await this.qrGenerator.generate({ data: url, width: this.config().qrSize, format: 'svg' });
32678
+ this._qr.set(result);
32679
+ }
32680
+ catch {
32681
+ // QR opcional — si falla, mostramos la URL como fallback (no spinner eterno).
32682
+ this._qr.set(null);
32683
+ this._qrError.set(true);
32684
+ }
32685
+ }
32686
+ close() {
32687
+ this._isOpen = false;
32688
+ this.dismissed.emit();
32689
+ }
32690
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ShareProfileModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32691
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ShareProfileModalComponent, isStandalone: true, selector: "val-share-profile-modal", inputs: { isOpen: "isOpen", props: "props" }, outputs: { dismissed: "dismissed", shared: "shared" }, ngImport: i0, template: `
32692
+ <ion-modal [isOpen]="isOpen" [style.--border-radius.px]="config().borderRadius" (didDismiss)="close()">
32693
+ <ng-template>
32694
+ <val-modal-shell [title]="''" [closeLabel]="config().closeLabel || ''" (close)="close()">
32695
+ <div class="share-profile">
32696
+ <val-user-avatar
32697
+ [props]="{ name: config().name, avatarUrl: config().avatarUrl, email: config().email, size: 'xlarge' }"
32698
+ />
32699
+ <val-display [props]="{ content: displayName(), size: 'small', color: 'dark' }" />
32700
+
32701
+ <div class="share-profile__qr">
32702
+ @if (qr(); as qrResult) {
32703
+ <val-qr-code
32704
+ [props]="{
32705
+ qr: qrResult,
32706
+ theme: config().qrTheme,
32707
+ displaySize: config().qrSize,
32708
+ alt: config().name,
32709
+ }"
32710
+ />
32711
+ } @else if (qrError()) {
32712
+ <p class="share-profile__qr-error">{{ config().url }}</p>
32713
+ } @else {
32714
+ <div class="share-profile__qr-loading" [style.height.px]="config().qrSize">
32715
+ <ion-spinner name="crescent"></ion-spinner>
32716
+ </div>
32717
+ }
32718
+ </div>
32719
+
32720
+ <p class="share-profile__caption">{{ caption() }}</p>
32721
+
32722
+ <val-share-buttons
32723
+ [props]="{
32724
+ shareData: { title: config().shareTitle || config().name, text: config().shareText, url: config().url },
32725
+ platforms: config().platforms,
32726
+ layout: 'horizontal',
32727
+ variant: 'icon-only',
32728
+ usePlatformColors: false,
32729
+ }"
32730
+ (shareComplete)="shared.emit($event)"
32731
+ />
32732
+ </div>
32733
+ </val-modal-shell>
32734
+ </ng-template>
32735
+ </ion-modal>
32736
+ `, isInline: true, styles: [".share-profile{display:flex;flex-direction:column;align-items:center;gap:1rem;padding:.5rem 0 1rem;text-align:center}.share-profile__name{margin:0;font-size:1.5rem;font-weight:700;line-height:1.2;color:var(--ion-text-color)}.share-profile__qr{display:flex;justify-content:center}.share-profile__qr-loading{display:flex;align-items:center;justify-content:center;min-width:120px}.share-profile__qr-error{margin:0;padding:1rem;max-width:28ch;word-break:break-all;font-size:.9rem;font-weight:600;color:var(--ion-color-medium-shade)}.share-profile__caption{margin:0;max-width:32ch;font-size:.95rem;line-height:1.45;color:var(--ion-color-medium-shade)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: ModalShellComponent, selector: "val-modal-shell", inputs: ["title", "subtitle", "closeLabel", "showClose"], outputs: ["close"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: UserAvatarComponent, selector: "val-user-avatar", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: QrCodeComponent, selector: "val-qr-code", inputs: ["props"], outputs: ["actionComplete", "imageLoad", "imageError"] }, { kind: "component", type: ShareButtonsComponent, selector: "val-share-buttons", inputs: ["props"], outputs: ["shareComplete"] }] }); }
32737
+ }
32738
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ShareProfileModalComponent, decorators: [{
32739
+ type: Component,
32740
+ args: [{ selector: 'val-share-profile-modal', standalone: true, imports: [
32741
+ CommonModule,
32742
+ IonModal,
32743
+ IonSpinner,
32744
+ ModalShellComponent,
32745
+ DisplayComponent,
32746
+ UserAvatarComponent,
32747
+ QrCodeComponent,
32748
+ ShareButtonsComponent,
32749
+ ], template: `
32750
+ <ion-modal [isOpen]="isOpen" [style.--border-radius.px]="config().borderRadius" (didDismiss)="close()">
32751
+ <ng-template>
32752
+ <val-modal-shell [title]="''" [closeLabel]="config().closeLabel || ''" (close)="close()">
32753
+ <div class="share-profile">
32754
+ <val-user-avatar
32755
+ [props]="{ name: config().name, avatarUrl: config().avatarUrl, email: config().email, size: 'xlarge' }"
32756
+ />
32757
+ <val-display [props]="{ content: displayName(), size: 'small', color: 'dark' }" />
32758
+
32759
+ <div class="share-profile__qr">
32760
+ @if (qr(); as qrResult) {
32761
+ <val-qr-code
32762
+ [props]="{
32763
+ qr: qrResult,
32764
+ theme: config().qrTheme,
32765
+ displaySize: config().qrSize,
32766
+ alt: config().name,
32767
+ }"
32768
+ />
32769
+ } @else if (qrError()) {
32770
+ <p class="share-profile__qr-error">{{ config().url }}</p>
32771
+ } @else {
32772
+ <div class="share-profile__qr-loading" [style.height.px]="config().qrSize">
32773
+ <ion-spinner name="crescent"></ion-spinner>
32774
+ </div>
32775
+ }
32776
+ </div>
32777
+
32778
+ <p class="share-profile__caption">{{ caption() }}</p>
32779
+
32780
+ <val-share-buttons
32781
+ [props]="{
32782
+ shareData: { title: config().shareTitle || config().name, text: config().shareText, url: config().url },
32783
+ platforms: config().platforms,
32784
+ layout: 'horizontal',
32785
+ variant: 'icon-only',
32786
+ usePlatformColors: false,
32787
+ }"
32788
+ (shareComplete)="shared.emit($event)"
32789
+ />
32790
+ </div>
32791
+ </val-modal-shell>
32792
+ </ng-template>
32793
+ </ion-modal>
32794
+ `, styles: [".share-profile{display:flex;flex-direction:column;align-items:center;gap:1rem;padding:.5rem 0 1rem;text-align:center}.share-profile__name{margin:0;font-size:1.5rem;font-weight:700;line-height:1.2;color:var(--ion-text-color)}.share-profile__qr{display:flex;justify-content:center}.share-profile__qr-loading{display:flex;align-items:center;justify-content:center;min-width:120px}.share-profile__qr-error{margin:0;padding:1rem;max-width:28ch;word-break:break-all;font-size:.9rem;font-weight:600;color:var(--ion-color-medium-shade)}.share-profile__caption{margin:0;max-width:32ch;font-size:.95rem;line-height:1.45;color:var(--ion-color-medium-shade)}\n"] }]
32795
+ }], ctorParameters: () => [], propDecorators: { isOpen: [{
32796
+ type: Input
32797
+ }], props: [{
32798
+ type: Input
32799
+ }], dismissed: [{
32800
+ type: Output
32801
+ }], shared: [{
32802
+ type: Output
32803
+ }] } });
32804
+
32805
+ /**
32806
+ * Default values for FunModalMetadata.
32807
+ */
32808
+ const FUN_MODAL_DEFAULTS = {
32809
+ borderRadius: 28,
32810
+ imageRadius: 16,
32811
+ };
32812
+
32813
+ const IONIC_COLORS = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
32814
+ /**
32815
+ * `val-fun-modal` — modal moderno tipo promo/onboarding: imagen o ilustración
32816
+ * arriba, título, cuerpo y botones de acción, con redondeo personalizable.
32817
+ * Sigue la Regla #5 (header canónico vía `val-modal-shell`).
32818
+ *
32819
+ * El padre controla `[isOpen]` y reacciona a `(dismissed)` / `(action)`.
32820
+ *
32821
+ * @example
32822
+ * ```html
32823
+ * <val-fun-modal
32824
+ * [isOpen]="isOpen()"
32825
+ * [props]="{
32826
+ * image: '/promo.png',
32827
+ * title: '¿Cómo se conecta Lucas con los Salmos?',
32828
+ * subtitle: 'Pulsa la referencia cruzada para descubrirlo.',
32829
+ * actions: { position: 'center', columned: false, buttons: [
32830
+ * { text: 'Probar ahora', color: 'primary', shape: 'round', type: 'button', state: 'ENABLED', token: 'try' }
32831
+ * ] }
32832
+ * }"
32833
+ * (action)="onAction($event)"
32834
+ * (dismissed)="isOpen.set(false)"
32835
+ * />
32836
+ * ```
32837
+ */
32838
+ class FunModalComponent {
32839
+ constructor() {
32840
+ this._isOpen = false;
32841
+ /** Configuración del modal. */
32842
+ this.props = {};
32843
+ /** Emite cuando el user cierra el modal (botón Cerrar o backdrop). */
32844
+ this.dismissed = new EventEmitter();
32845
+ /** Emite con el token del botón de acción presionado. */
32846
+ this.action = new EventEmitter();
32847
+ this.config = computed(() => ({
32848
+ ...FUN_MODAL_DEFAULTS,
32849
+ ...this.props,
32850
+ }));
32851
+ }
32852
+ /** Controla la visibilidad del modal. */
32853
+ set isOpen(value) {
32854
+ this._isOpen = value;
32855
+ }
32856
+ get isOpen() {
32857
+ return this._isOpen;
32858
+ }
32859
+ getBackground() {
32860
+ const color = this.config().backgroundColor;
32861
+ if (!color)
32862
+ return null;
32863
+ return IONIC_COLORS.includes(color) ? `var(--ion-color-${color})` : color;
32864
+ }
32865
+ close() {
32866
+ this._isOpen = false;
32867
+ this.dismissed.emit();
32868
+ }
32869
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FunModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32870
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FunModalComponent, isStandalone: true, selector: "val-fun-modal", inputs: { isOpen: "isOpen", props: "props" }, outputs: { dismissed: "dismissed", action: "action" }, ngImport: i0, template: `
32871
+ <ion-modal [isOpen]="isOpen" [style.--border-radius.px]="config().borderRadius" (didDismiss)="close()">
32872
+ <ng-template>
32873
+ <val-modal-shell [title]="''" [closeLabel]="config().closeLabel || ''" (close)="close()">
32874
+ <div class="fun-modal" [style.background]="getBackground()">
32875
+ @if (config().image) {
32876
+ <div class="fun-modal__media" [style.border-radius.px]="config().imageRadius">
32877
+ <img [src]="config().image" [alt]="config().imageAlt || config().title" />
32878
+ </div>
32879
+ } @else if (config().emoji) {
32880
+ <div class="fun-modal__emoji">{{ config().emoji }}</div>
32881
+ }
32882
+
32883
+ <val-display [props]="{ content: config().title, size: 'small', color: 'dark' }" />
32884
+ @if (config().subtitle) {
32885
+ <val-title [props]="{ content: config().subtitle, size: 'large', color: '', bold: false }" />
32886
+ }
32887
+
32888
+ @if (config().actions; as actions) {
32889
+ <div class="fun-modal__actions">
32890
+ <val-button-group [props]="actions" (onClick)="action.emit($event)"></val-button-group>
32891
+ </div>
32892
+ }
32893
+ </div>
32894
+ </val-modal-shell>
32895
+ </ng-template>
32896
+ </ion-modal>
32897
+ `, isInline: true, styles: [".fun-modal{display:flex;flex-direction:column;align-items:center;gap:1.25rem;padding:.5rem 0;text-align:center}.fun-modal__media{width:100%;overflow:hidden;aspect-ratio:16/10;background:var(--ion-color-light, #f4f5f8)}.fun-modal__media img{width:100%;height:100%;object-fit:cover;display:block}.fun-modal__emoji{font-size:3.5rem;line-height:1}.fun-modal__actions{width:100%;margin-top:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ModalShellComponent, selector: "val-modal-shell", inputs: ["title", "subtitle", "closeLabel", "showClose"], outputs: ["close"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }] }); }
32898
+ }
32899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FunModalComponent, decorators: [{
32900
+ type: Component,
32901
+ args: [{ selector: 'val-fun-modal', standalone: true, imports: [CommonModule, IonModal, ModalShellComponent, DisplayComponent, TitleComponent, ButtonGroupComponent], template: `
32902
+ <ion-modal [isOpen]="isOpen" [style.--border-radius.px]="config().borderRadius" (didDismiss)="close()">
32903
+ <ng-template>
32904
+ <val-modal-shell [title]="''" [closeLabel]="config().closeLabel || ''" (close)="close()">
32905
+ <div class="fun-modal" [style.background]="getBackground()">
32906
+ @if (config().image) {
32907
+ <div class="fun-modal__media" [style.border-radius.px]="config().imageRadius">
32908
+ <img [src]="config().image" [alt]="config().imageAlt || config().title" />
32909
+ </div>
32910
+ } @else if (config().emoji) {
32911
+ <div class="fun-modal__emoji">{{ config().emoji }}</div>
32912
+ }
32913
+
32914
+ <val-display [props]="{ content: config().title, size: 'small', color: 'dark' }" />
32915
+ @if (config().subtitle) {
32916
+ <val-title [props]="{ content: config().subtitle, size: 'large', color: '', bold: false }" />
32917
+ }
32918
+
32919
+ @if (config().actions; as actions) {
32920
+ <div class="fun-modal__actions">
32921
+ <val-button-group [props]="actions" (onClick)="action.emit($event)"></val-button-group>
32922
+ </div>
32923
+ }
32924
+ </div>
32925
+ </val-modal-shell>
32926
+ </ng-template>
32927
+ </ion-modal>
32928
+ `, styles: [".fun-modal{display:flex;flex-direction:column;align-items:center;gap:1.25rem;padding:.5rem 0;text-align:center}.fun-modal__media{width:100%;overflow:hidden;aspect-ratio:16/10;background:var(--ion-color-light, #f4f5f8)}.fun-modal__media img{width:100%;height:100%;object-fit:cover;display:block}.fun-modal__emoji{font-size:3.5rem;line-height:1}.fun-modal__actions{width:100%;margin-top:.25rem}\n"] }]
32929
+ }], propDecorators: { isOpen: [{
32930
+ type: Input
32931
+ }], props: [{
32932
+ type: Input
32933
+ }], dismissed: [{
32934
+ type: Output
32935
+ }], action: [{
32936
+ type: Output
32937
+ }] } });
32938
+
32586
32939
  /**
32587
32940
  * `val-cookie-banner` — bottom/top fixed banner asking the user to choose
32588
32941
  * a cookie consent option. Presentational only: emits events on each
@@ -47261,6 +47614,185 @@ function news() {
47261
47614
  */
47262
47615
  // Transformer
47263
47616
 
47617
+ /**
47618
+ * Token de inyección para la configuración de la plataforma de contenido.
47619
+ */
47620
+ const VALTECH_CONTENT_CONFIG = new InjectionToken('ValtechContentConfig');
47621
+ /**
47622
+ * Provee la plataforma de contenido (`ContentService`) a la aplicación Angular.
47623
+ *
47624
+ * Wire en el `main.ts` de la app consumer. El origen es **híbrido** (ADR-020):
47625
+ * el backend siempre está disponible vía `apiUrl`; las `staticSources` son
47626
+ * opcionales — factories lazy generadas build-time por `scripts/build-content.ts`
47627
+ * (mismo patrón que `provideLegalContent`). Cada locale queda code-split por el
47628
+ * `import()` dinámico.
47629
+ *
47630
+ * @param config - Configuración de contenido (`apiUrl`, `appId`, `staticSources?`).
47631
+ * @returns EnvironmentProviders para usar en `bootstrapApplication`.
47632
+ *
47633
+ * @example
47634
+ * ```typescript
47635
+ * // main.ts — solo backend
47636
+ * provideValtechContent({
47637
+ * apiUrl: environment.apiUrl,
47638
+ * appId: 'showcase',
47639
+ * });
47640
+ *
47641
+ * // main.ts — híbrido (estático curado + backend)
47642
+ * provideValtechContent({
47643
+ * apiUrl: environment.apiUrl,
47644
+ * appId: 'web',
47645
+ * staticSources: {
47646
+ * es: () => import('./app/generated/content-store.es').then(m => m.CONTENT_STORE_ES),
47647
+ * en: () => import('./app/generated/content-store.en').then(m => m.CONTENT_STORE_EN),
47648
+ * },
47649
+ * });
47650
+ * ```
47651
+ */
47652
+ function provideValtechContent(config) {
47653
+ return makeEnvironmentProviders([{ provide: VALTECH_CONTENT_CONFIG, useValue: config }]);
47654
+ }
47655
+
47656
+ /**
47657
+ * Servicio de la plataforma de contenido (ADR-020 §2.5).
47658
+ *
47659
+ * Une dos orígenes (**híbrido**):
47660
+ * - **Estático** — `staticSources` lazy por locale, generadas build-time.
47661
+ * - **Backend** — DynamoDB + API (`/v2/content*`), publicación sin redeploy.
47662
+ *
47663
+ * Reglas de merge:
47664
+ * - `list()` une ambos orígenes por `type`. Colisión de `slug` → **estático
47665
+ * gana** (contenido curado). Ordena por `publishedAt` desc (sin fecha al final).
47666
+ * - `load()` resuelve estático primero, con **fallback** al backend.
47667
+ *
47668
+ * Render: `toArticle(doc)` convierte `doc.body` (Markdown) a `ArticleMetadata`
47669
+ * vía el `markdown-article-parser` existente — la page hace `<val-article [props]="...">`.
47670
+ *
47671
+ * Requiere `provideValtechContent({ apiUrl, appId, staticSources? })` en `main.ts`.
47672
+ * Sin provider, el servicio queda inerte (`isConfigured() === false`).
47673
+ */
47674
+ class ContentService {
47675
+ constructor() {
47676
+ this.config = inject(VALTECH_CONTENT_CONFIG, { optional: true });
47677
+ this.http = inject(HttpClient);
47678
+ this.parser = inject(MarkdownArticleParserService);
47679
+ /** `true` si `provideValtechContent()` fue llamado en el bootstrap. */
47680
+ this.isConfigured = signal(!!this.config);
47681
+ /** Cache de las promesas de cada factory estática, keyed por locale. */
47682
+ this.staticCache = new Map();
47683
+ /** Comparador: más reciente primero; sin `publishedAt` al final. */
47684
+ this.byPublishedDesc = (a, b) => {
47685
+ const ta = a.publishedAt ? Date.parse(a.publishedAt) : -Infinity;
47686
+ const tb = b.publishedAt ? Date.parse(b.publishedAt) : -Infinity;
47687
+ return tb - ta;
47688
+ };
47689
+ if (!this.config && isDevMode()) {
47690
+ console.warn('[valtech-components] ContentService: provideValtechContent() no está en main.ts. ' +
47691
+ 'El listado y la carga de contenido no funcionarán.');
47692
+ }
47693
+ }
47694
+ /**
47695
+ * Lista los documentos publicados de un `type`, uniendo estático + backend.
47696
+ * Colisión de `slug` → estático gana. Ordenados por `publishedAt` desc.
47697
+ *
47698
+ * @param type - Tipo de contenido (`'blog'`, `'news'`, …).
47699
+ * @param options - `{ locale }` (default `'es'`).
47700
+ */
47701
+ list(type, options = {}) {
47702
+ const locale = (options.locale ?? 'es').toLowerCase();
47703
+ const static$ = from(this.loadStatic(locale)).pipe(map(docs => docs.filter(d => d.type === type && d.status === 'published')));
47704
+ const backend$ = this.listBackend(type, locale).pipe(catchError$1(() => of([])));
47705
+ return forkJoin({ staticDocs: static$, backendDocs: backend$ }).pipe(map(({ staticDocs, backendDocs }) => this.merge(staticDocs, backendDocs)));
47706
+ }
47707
+ /**
47708
+ * Carga un documento por `slug`: estático primero, fallback al backend.
47709
+ *
47710
+ * @param type - Tipo de contenido.
47711
+ * @param slug - Slug del documento.
47712
+ * @param options - `{ locale }` (default `'es'`).
47713
+ */
47714
+ load(type, slug, options = {}) {
47715
+ const locale = (options.locale ?? 'es').toLowerCase();
47716
+ return from(this.loadStatic(locale)).pipe(map(docs => docs.find(d => d.type === type && d.slug === slug && d.status === 'published')), switchMap$1(staticDoc => staticDoc
47717
+ ? of(staticDoc)
47718
+ : this.loadBackend(type, slug, locale).pipe(catchError$1(() => throwError(() => new Error(`Contenido no encontrado: ${type}/${locale}/${slug}`))))));
47719
+ }
47720
+ /**
47721
+ * Convierte el `body` (Markdown) de un documento en `ArticleMetadata` para
47722
+ * renderizar con `<val-article [props]="...">`. Usa el parser existente.
47723
+ *
47724
+ * @param doc - Documento de contenido a renderizar.
47725
+ * @param config - Override parcial de la `ArticleMetadata` resultante.
47726
+ */
47727
+ toArticle(doc, config) {
47728
+ return this.parser.parse(doc.body, config);
47729
+ }
47730
+ /** Limpia la cache de fuentes estáticas. Llamar al cambiar de locale en runtime. */
47731
+ invalidate() {
47732
+ this.staticCache.clear();
47733
+ }
47734
+ // ===========================================================================
47735
+ // Internos
47736
+ // ===========================================================================
47737
+ /** Une estático + backend: estático gana por slug; orden por publishedAt desc. */
47738
+ merge(staticDocs, backendDocs) {
47739
+ const bySlug = new Map();
47740
+ for (const doc of backendDocs)
47741
+ bySlug.set(doc.slug, doc);
47742
+ // Estático gana — sobrescribe cualquier colisión del backend.
47743
+ for (const doc of staticDocs)
47744
+ bySlug.set(doc.slug, doc);
47745
+ return [...bySlug.values()].sort(this.byPublishedDesc);
47746
+ }
47747
+ /** Carga (y cachea) los documentos estáticos de un locale, si hay factory. */
47748
+ loadStatic(locale) {
47749
+ const factory = this.config?.staticSources?.[locale];
47750
+ if (!factory)
47751
+ return Promise.resolve([]);
47752
+ const cached = this.staticCache.get(locale);
47753
+ if (cached)
47754
+ return cached;
47755
+ const promise = factory().catch(() => []);
47756
+ this.staticCache.set(locale, promise);
47757
+ return promise;
47758
+ }
47759
+ /** GET `{apiUrl}/v2/content?type=&locale=` — solo publicados. */
47760
+ listBackend(type, locale) {
47761
+ if (!this.config?.apiUrl)
47762
+ return of([]);
47763
+ const params = new URLSearchParams({ type, locale });
47764
+ if (this.config.appId)
47765
+ params.set('appId', this.config.appId);
47766
+ return this.http
47767
+ .get(`${this.config.apiUrl}/v2/content?${params}`)
47768
+ .pipe(map(res => res?.items ?? []));
47769
+ }
47770
+ /** GET `{apiUrl}/v2/content/{type}/{locale}/{slug}` — detalle publicado. */
47771
+ loadBackend(type, slug, locale) {
47772
+ if (!this.config?.apiUrl) {
47773
+ return throwError(() => new Error('ContentService no está configurado.'));
47774
+ }
47775
+ const path = `${this.config.apiUrl}/v2/content/${type}/${locale}/${encodeURIComponent(slug)}`;
47776
+ return this.http
47777
+ .get(path)
47778
+ .pipe(map(res => res?.item ?? res));
47779
+ }
47780
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
47781
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentService, providedIn: 'root' }); }
47782
+ }
47783
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentService, decorators: [{
47784
+ type: Injectable,
47785
+ args: [{ providedIn: 'root' }]
47786
+ }], ctorParameters: () => [] });
47787
+
47788
+ /**
47789
+ * Content Platform — `ContentService` + `provideValtechContent` (ADR-020).
47790
+ *
47791
+ * Modelo canónico unificado (`ContentDocument`, flat + Markdown) con origen
47792
+ * híbrido (estático build-time + backend DynamoDB/API). Render vía el
47793
+ * `markdown-article-parser` existente.
47794
+ */
47795
+
47264
47796
  /**
47265
47797
  * Token de inyección para la configuración de Donation/Support.
47266
47798
  */
@@ -50912,5 +51444,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
50912
51444
  * Generated bundle index. Do not edit.
50913
51445
  */
50914
51446
 
50915
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, AttachmentUploaderComponent, AuthBackgroundComponent, 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, 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, ContentLoaderComponent, ContentReactionComponent, 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, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, 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, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MenuComponent, MessagingService, MetaService, 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, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SHAPE_KEYS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_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, 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_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, 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, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPresets, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
51447
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, AttachmentUploaderComponent, AuthBackgroundComponent, 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, 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, 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, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, 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, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MenuComponent, MessagingService, MetaService, 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, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_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, 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, 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, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
50916
51448
  //# sourceMappingURL=valtech-components.mjs.map