valtech-components 2.0.963 → 2.0.965

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 (40) hide show
  1. package/esm2022/lib/components/molecules/content-card/content-card.component.mjs +86 -0
  2. package/esm2022/lib/components/molecules/content-card/types.mjs +11 -0
  3. package/esm2022/lib/components/molecules/info-card/info-card.component.mjs +126 -0
  4. package/esm2022/lib/components/molecules/info-card/types.mjs +11 -0
  5. package/esm2022/lib/components/molecules/metric-card/metric-card.component.mjs +146 -0
  6. package/esm2022/lib/components/molecules/metric-card/types.mjs +10 -0
  7. package/esm2022/lib/components/molecules/pill/pill.component.mjs +100 -105
  8. package/esm2022/lib/components/molecules/pill/types.mjs +1 -1
  9. package/esm2022/lib/components/organisms/article-strip/article-strip.component.mjs +127 -0
  10. package/esm2022/lib/components/organisms/article-strip/types.mjs +8 -0
  11. package/esm2022/lib/components/organisms/auth-cta/auth-cta.component.mjs +180 -0
  12. package/esm2022/lib/components/organisms/auth-cta/types.mjs +9 -0
  13. package/esm2022/lib/services/requests/request.service.mjs +11 -4
  14. package/esm2022/lib/shared/utils/validators.mjs +7 -3
  15. package/esm2022/lib/version.mjs +2 -2
  16. package/esm2022/public-api.mjs +12 -1
  17. package/fesm2022/valtech-components.mjs +817 -126
  18. package/fesm2022/valtech-components.mjs.map +1 -1
  19. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +1 -1
  20. package/lib/components/atoms/text/text.component.d.ts +1 -1
  21. package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +1 -1
  22. package/lib/components/molecules/article-card/article-card.component.d.ts +1 -1
  23. package/lib/components/molecules/content-card/content-card.component.d.ts +26 -0
  24. package/lib/components/molecules/content-card/types.d.ts +30 -0
  25. package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
  26. package/lib/components/molecules/info-card/info-card.component.d.ts +37 -0
  27. package/lib/components/molecules/info-card/types.d.ts +44 -0
  28. package/lib/components/molecules/metric-card/metric-card.component.d.ts +34 -0
  29. package/lib/components/molecules/metric-card/types.d.ts +46 -0
  30. package/lib/components/molecules/pill/pill.component.d.ts +10 -26
  31. package/lib/components/molecules/pill/types.d.ts +76 -35
  32. package/lib/components/organisms/article/article.component.d.ts +4 -4
  33. package/lib/components/organisms/article-strip/article-strip.component.d.ts +38 -0
  34. package/lib/components/organisms/article-strip/types.d.ts +29 -0
  35. package/lib/components/organisms/auth-cta/auth-cta.component.d.ts +44 -0
  36. package/lib/components/organisms/auth-cta/types.d.ts +42 -0
  37. package/lib/shared/utils/validators.d.ts +3 -2
  38. package/lib/version.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/public-api.d.ts +10 -0
@@ -23,7 +23,7 @@ import { IonicModule, ToastController, NavController } from '@ionic/angular';
23
23
  import { isSupported, getMessaging as getMessaging$1 } from 'firebase/messaging';
24
24
  import { getApps, getApp, initializeApp as initializeApp$1 } from 'firebase/app';
25
25
  import * as i2$1 from '@ionic/angular/standalone';
26
- import { AlertController, 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, IonMenuButton, IonFooter, IonListHeader, IonInfiniteScroll, IonInfiniteScrollContent, IonGrid, MenuController, IonMenu, IonMenuToggle, IonSplitPane } from '@ionic/angular/standalone';
26
+ import { AlertController, 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, IonRippleEffect, IonAccordion, IonAccordionGroup, IonTabBar, IonTabButton, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonChip, IonNote, ToastController as ToastController$1, IonCol, IonRow, IonRefresher, IonRefresherContent, IonMenuButton, IonFooter, IonListHeader, IonInfiniteScroll, IonInfiniteScrollContent, IonGrid, MenuController, IonMenu, IonMenuToggle, IonSplitPane } from '@ionic/angular/standalone';
27
27
  import { addIcons } from 'ionicons';
28
28
  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, peopleOutline, phonePortraitOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, removeOutline, optionsOutline, personOutline, shieldCheckmarkOutline, keyOutline, desktopOutline, logOutOutline, cloudDownloadOutline, cloudOutline, gitBranchOutline, layersOutline, serverOutline, warningOutline, bulbOutline, lockOpenOutline, diamondOutline, 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, chevronDownCircleOutline, closeCircle, alertCircle, logoApple, logoMicrosoft, linkOutline, unlinkOutline, cloudOfflineOutline, documentOutline, attachOutline, cameraOutline, closeCircleOutline, imageOutline, chevronBackOutline, sendOutline, chatbubbleEllipsesOutline, swapVerticalOutline, chevronUpOutline, searchOutline, cartOutline, chatbubble, compass, compassOutline, gridOutline, listOutline, folderOutline, documents, documentsOutline, statsChart, statsChartOutline, menuOutline } from 'ionicons/icons';
29
29
  import { Browser } from '@capacitor/browser';
@@ -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.963';
57
+ const VERSION = '2.0.965';
58
58
 
59
59
  // Control de estado de refresco (singleton a nivel de módulo)
60
60
  let isRefreshing = false;
@@ -16009,7 +16009,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
16009
16009
  * resolveColor('--my-custom-color'); // returns 'var(--my-custom-color)'
16010
16010
  * resolveColor('#ff0000'); // returns '#ff0000'
16011
16011
  */
16012
- function resolveColor(color) {
16012
+ function resolveColor$1(color) {
16013
16013
  // Si el color empieza con "--", se asume que es una variable CSS válida
16014
16014
  if (color.startsWith('--')) {
16015
16015
  return `var(${color})`;
@@ -16064,7 +16064,7 @@ class ExpandableTextComponent {
16064
16064
  this.expanded = !this.expanded;
16065
16065
  }
16066
16066
  color() {
16067
- return resolveColor(this.props.color || this.defaultColor);
16067
+ return resolveColor$1(this.props.color || this.defaultColor);
16068
16068
  }
16069
16069
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ExpandableTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16070
16070
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ExpandableTextComponent, isStandalone: true, selector: "val-expandable-text", inputs: { props: "props" }, ngImport: i0, template: `
@@ -16987,7 +16987,7 @@ class LayeredCardComponent {
16987
16987
  if (!background) {
16988
16988
  return '';
16989
16989
  }
16990
- return resolveColor(background);
16990
+ return resolveColor$1(background);
16991
16991
  }
16992
16992
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayeredCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16993
16993
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LayeredCardComponent, isStandalone: true, selector: "layered-card", inputs: { props: "props" }, ngImport: i0, template: `
@@ -19319,102 +19319,95 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19319
19319
  type: Input
19320
19320
  }] } });
19321
19321
 
19322
- /**
19323
- * val-pill
19324
- *
19325
- * Has two modes:
19326
- *
19327
- * 1. **Card mode** (legacy) — pass `content` (`ActionHeaderMetadata`). Renders a
19328
- * large fun-card with a title + action. Backwards compatible.
19329
- *
19330
- * 2. **Text-pill / badge mode** — pass `label`. Renders a compact rounded pill
19331
- * with configurable `color`, `weight`, `size`, optional `icon`, and an
19332
- * optional click action (`clickable` → emits `pillClick`).
19333
- *
19334
- * @example Text-pill (badge):
19335
- * <val-pill [props]="{ label: 'v1.2.0', color: 'dark', weight: 'bold' }" />
19336
- *
19337
- * @example Clickable text-pill:
19338
- * <val-pill
19339
- * [props]="{ label: 'Beta', color: 'primary', clickable: true }"
19340
- * (pillClick)="onClick($event)"
19341
- * />
19342
- *
19343
- * @example Card mode (legacy):
19344
- * <val-pill [props]="{ background: '#fff', bordered: true, content: {...} }" />
19345
- *
19346
- * @input preset: string - Name of preset to apply
19347
- * @input props: PillMetadata - Configuration for the pill
19348
- * @output pillClick: PillClickEvent - Emits when a clickable text-pill is activated
19349
- */
19322
+ const IONIC_COLORS$9 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
19350
19323
  class PillComponent {
19351
19324
  constructor() {
19352
- this.theme = inject(ThemeService);
19353
19325
  this.presets = inject(PresetService);
19354
- /**
19355
- * Pill configuration object. Values here override preset values.
19356
- */
19326
+ /** Pill configuration. Overrides preset values when both are set. */
19357
19327
  this.props = {};
19358
- /**
19359
- * Emits when a clickable text-pill is activated (click / Enter / Space).
19360
- */
19328
+ /** Emits when a clickable badge pill is activated. */
19361
19329
  this.pillClick = new EventEmitter();
19362
- /**
19363
- * Resolved props after merging preset + explicit props.
19364
- */
19330
+ /** Emits when a notification-pill action button is pressed. */
19331
+ this.pillAction = new EventEmitter();
19365
19332
  this.resolvedProps = {};
19366
19333
  }
19367
19334
  ngOnInit() {
19368
19335
  this.resolveProps();
19369
19336
  }
19370
19337
  ngOnChanges(changes) {
19371
- if (changes['preset'] || changes['props']) {
19338
+ if (changes['preset'] || changes['props'])
19372
19339
  this.resolveProps();
19373
- }
19374
19340
  }
19375
- /**
19376
- * Merge preset configuration with explicit props.
19377
- * Explicit props take precedence over preset values.
19378
- */
19379
19341
  resolveProps() {
19380
19342
  const presetProps = this.preset ? this.presets.get('pill', this.preset) : {};
19381
- this.resolvedProps = {
19382
- ...presetProps,
19383
- ...this.props,
19384
- };
19343
+ this.resolvedProps = { ...presetProps, ...this.props };
19344
+ }
19345
+ get isNotificationPill() {
19346
+ return !!this.resolvedProps.notification && !this.resolvedProps.label;
19385
19347
  }
19386
- /** Text-pill mode is active when a `label` is provided. */
19387
19348
  get isTextPill() {
19388
19349
  return !!this.resolvedProps.label;
19389
19350
  }
19390
- /** Color variant for the text-pill, with a sensible default. */
19391
19351
  get pillColor() {
19392
19352
  return this.resolvedProps.color || 'medium';
19393
19353
  }
19394
- /** Font weight for the text-pill, with a sensible default. */
19395
19354
  get pillWeight() {
19396
19355
  return this.resolvedProps.weight || 'medium';
19397
19356
  }
19398
- /** Size for the text-pill, with a sensible default. */
19399
19357
  get pillSize() {
19400
19358
  return this.resolvedProps.size || 'small';
19401
19359
  }
19402
- /** Handles activation of a clickable text-pill. */
19360
+ getIconColor() {
19361
+ const c = this.resolvedProps.notification?.iconColor || 'warning';
19362
+ return IONIC_COLORS$9.includes(c) ? `var(--ion-color-${c})` : c;
19363
+ }
19403
19364
  onPillClick(event) {
19404
- if (!this.resolvedProps.clickable) {
19365
+ if (!this.resolvedProps.clickable)
19405
19366
  return;
19406
- }
19407
- // For the Space key, prevent the page from scrolling.
19408
19367
  event?.preventDefault();
19409
- this.pillClick.emit({
19410
- token: this.resolvedProps.token,
19411
- label: this.resolvedProps.label,
19412
- });
19368
+ this.pillClick.emit({ token: this.resolvedProps.token, label: this.resolvedProps.label });
19369
+ }
19370
+ onActionClick(actionToken, event) {
19371
+ event.stopPropagation();
19372
+ this.pillAction.emit({ actionToken, pillToken: this.resolvedProps.token });
19413
19373
  }
19414
19374
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PillComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19415
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PillComponent, isStandalone: true, selector: "val-pill", inputs: { preset: "preset", props: "props" }, outputs: { pillClick: "pillClick" }, usesOnChanges: true, ngImport: i0, template: `
19416
- @if (isTextPill) {
19417
- <!-- Text-pill / badge mode -->
19375
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PillComponent, isStandalone: true, selector: "val-pill", inputs: { preset: "preset", props: "props" }, outputs: { pillClick: "pillClick", pillAction: "pillAction" }, usesOnChanges: true, ngImport: i0, template: `
19376
+ @if (isNotificationPill) {
19377
+ <!-- Notification mode -->
19378
+ <div class="notif-pill" [attr.aria-live]="'polite'">
19379
+ @if (resolvedProps.notification?.icon) {
19380
+ <div class="notif-pill__icon-wrap" [style.color]="getIconColor()">
19381
+ <ion-icon [name]="resolvedProps.notification!.icon!" />
19382
+ </div>
19383
+ }
19384
+
19385
+ <div class="notif-pill__content">
19386
+ @if (resolvedProps.notification?.time) {
19387
+ <span class="notif-pill__time">{{ resolvedProps.notification!.time }}</span>
19388
+ }
19389
+ <span class="notif-pill__title">{{ resolvedProps.notification!.title }}</span>
19390
+ @if (resolvedProps.notification?.body) {
19391
+ <span class="notif-pill__body">{{ resolvedProps.notification!.body }}</span>
19392
+ }
19393
+ </div>
19394
+
19395
+ @if (resolvedProps.notification?.actions?.length) {
19396
+ <div class="notif-pill__actions">
19397
+ @for (action of resolvedProps.notification!.actions!; track action.token) {
19398
+ <button
19399
+ class="notif-pill__action-btn"
19400
+ [attr.aria-label]="action.ariaLabel || action.token"
19401
+ (click)="onActionClick(action.token, $event)"
19402
+ >
19403
+ <ion-icon [name]="action.icon" />
19404
+ </button>
19405
+ }
19406
+ </div>
19407
+ }
19408
+ </div>
19409
+ } @else if (isTextPill) {
19410
+ <!-- Badge mode -->
19418
19411
  <span
19419
19412
  class="val-pill"
19420
19413
  [class.val-pill--clickable]="resolvedProps.clickable"
@@ -19427,7 +19420,7 @@ class PillComponent {
19427
19420
  [class.val-pill--w-bold]="pillWeight === 'bold'"
19428
19421
  [style.--val-pill-color]="'var(--ion-color-' + pillColor + ')'"
19429
19422
  [style.--val-pill-color-rgb]="'var(--ion-color-' + pillColor + '-rgb)'"
19430
- [style.--val-pill-contrast]="'var(--ion-color-' + pillColor + '-contrast)'"
19423
+ [style.--val-pill-color-contrast]="'var(--ion-color-' + pillColor + '-contrast)'"
19431
19424
  [attr.role]="resolvedProps.clickable ? 'button' : null"
19432
19425
  [attr.tabindex]="resolvedProps.clickable ? 0 : null"
19433
19426
  [attr.aria-label]="resolvedProps.clickable ? resolvedProps.ariaLabel || resolvedProps.label : null"
@@ -19440,29 +19433,47 @@ class PillComponent {
19440
19433
  }
19441
19434
  <span class="val-pill__label">{{ resolvedProps.label }}</span>
19442
19435
  </span>
19443
- } @else {
19444
- <!-- Card mode (legacy fun-card) -->
19445
- <div
19446
- [id]="resolvedProps.token"
19447
- class="fun-card"
19448
- [class.bordered]="resolvedProps.bordered"
19449
- [class.hoverable]="resolvedProps.hoverable"
19450
- [ngStyle]="{
19451
- background: theme.IsDark ? 'var(--ion-background-color)' : resolvedProps.background,
19452
- }"
19453
- >
19454
- @if (resolvedProps.content) {
19455
- <val-action-header style="width: 100%;" [props]="resolvedProps.content" />
19456
- }
19457
- </div>
19458
19436
  }
19459
- `, 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)}.fun-card{z-index:0;position:relative;margin-bottom:8px;cursor:pointer;background:var(--ion-card-background, var(--ion-item-background, var(--ion-background-color, #fff)));display:flex;border-radius:48px;align-items:start;padding:8px 8px 8px 24px;flex-direction:column;box-shadow:0 .25rem .75rem #12195412}.fun-card.hoverable{transition:transform .3s ease,box-shadow .3s ease}.fun-card.hoverable:hover{transform:scale(1.01);box-shadow:.1875rem .625rem .5rem #1219541a}.bordered{border:.0625rem solid var(--ion-color-medium)}.val-pill{display:inline-flex;align-items:center;gap:6px;border-radius:999px;white-space:nowrap;line-height:1;background:rgba(var(--val-pill-color-rgb),.12);color:var(--val-pill-color);border:.0625rem solid rgba(var(--val-pill-color-rgb),.22);transition:background .15s ease,transform .15s ease,box-shadow .15s ease}.val-pill__icon{font-size:1em;flex-shrink:0}.val-pill__label{display:inline-block}.val-pill--solid{background:var(--val-pill-color);color:var(--val-pill-contrast);border-color:var(--val-pill-color)}.val-pill--small{padding:5px 12px;font-size:.75rem}.val-pill--medium{padding:7px 14px;font-size:.875rem}.val-pill--large{padding:9px 18px;font-size:1rem}.val-pill--w-normal{font-weight:400}.val-pill--w-medium{font-weight:600}.val-pill--w-bold{font-weight:700}.val-pill--clickable{cursor:pointer;-webkit-tap-highlight-color:transparent}.val-pill--clickable:hover{background:rgba(var(--val-pill-color-rgb),.2);transform:translateY(-1px)}.val-pill--clickable:active{transform:translateY(0) scale(.98)}.val-pill--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--val-pill-color-rgb),.3)}.val-pill--clickable.val-pill--solid:hover{filter:brightness(1.08)}:host-context(body.dark) .val-pill:not(.val-pill--solid),:host-context(html.ion-palette-dark) .val-pill:not(.val-pill--solid),:host-context([data-theme=dark]) .val-pill:not(.val-pill--solid){background:rgba(var(--val-pill-color-rgb),.22);border-color:rgba(var(--val-pill-color-rgb),.32)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ActionHeaderComponent, selector: "val-action-header", inputs: ["props"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
19437
+ `, 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)}.val-pill{display:inline-flex;align-items:center;gap:6px;border-radius:999px;white-space:nowrap;line-height:1;background:rgba(var(--val-pill-color-rgb),.12);color:var(--val-pill-color);border:.0625rem solid rgba(var(--val-pill-color-rgb),.22);transition:background .15s ease,transform .15s ease,box-shadow .15s ease}.val-pill__icon{font-size:1em;flex-shrink:0}.val-pill__label{display:inline-block}.val-pill--solid{background:var(--val-pill-color);color:var(--val-pill-color-contrast);border-color:var(--val-pill-color)}.val-pill--small{padding:5px 12px;font-size:.75rem}.val-pill--medium{padding:7px 14px;font-size:.875rem}.val-pill--large{padding:9px 18px;font-size:1rem}.val-pill--w-normal{font-weight:400}.val-pill--w-medium{font-weight:600}.val-pill--w-bold{font-weight:700}.val-pill--clickable{cursor:pointer;-webkit-tap-highlight-color:transparent}.val-pill--clickable:hover{background:rgba(var(--val-pill-color-rgb),.2);transform:translateY(-1px)}.val-pill--clickable:active{transform:translateY(0) scale(.98)}.val-pill--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--val-pill-color-rgb),.3)}.val-pill--clickable.val-pill--solid:hover{filter:brightness(1.08)}:host-context(body.dark) .val-pill:not(.val-pill--solid),:host-context(html.ion-palette-dark) .val-pill:not(.val-pill--solid),:host-context([data-theme=dark]) .val-pill:not(.val-pill--solid){background:rgba(var(--val-pill-color-rgb),.22);border-color:rgba(var(--val-pill-color-rgb),.32)}.notif-pill{display:inline-flex;align-items:center;gap:12px;padding:10px 14px;border-radius:999px;background:var(--ion-color-dark);color:var(--ion-color-dark-contrast);max-width:100%;box-sizing:border-box;box-shadow:.1875rem .625rem .5rem #1219541a}.notif-pill__icon-wrap{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:32px;height:32px;border-radius:50%;background:#ffffff1a;font-size:1rem}.notif-pill__content{display:flex;align-items:baseline;gap:8px;flex:1;min-width:0;overflow:hidden}.notif-pill__time{font-size:.72rem;font-weight:600;opacity:.55;flex-shrink:0;letter-spacing:.02em}.notif-pill__title{font-size:.875rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.notif-pill__body{font-size:.75rem;opacity:.7;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:1}.notif-pill__actions{display:flex;align-items:center;gap:6px;flex-shrink:0;margin-left:4px}.notif-pill__action-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#ffffff1f;color:var(--ion-color-dark-contrast);cursor:pointer;font-size:.9rem;transition:background .15s ease,transform .1s ease;-webkit-tap-highlight-color:transparent}.notif-pill__action-btn:hover{background:#ffffff38}.notif-pill__action-btn:active{transform:scale(.9)}.notif-pill__action-btn:focus-visible{outline:none;box-shadow:0 0 0 2px #ffffff80}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
19460
19438
  }
19461
19439
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PillComponent, decorators: [{
19462
19440
  type: Component,
19463
- args: [{ selector: 'val-pill', standalone: true, imports: [CommonModule, ActionHeaderComponent, IonIcon], template: `
19464
- @if (isTextPill) {
19465
- <!-- Text-pill / badge mode -->
19441
+ args: [{ selector: 'val-pill', standalone: true, imports: [CommonModule, IonIcon, IonRippleEffect], template: `
19442
+ @if (isNotificationPill) {
19443
+ <!-- Notification mode -->
19444
+ <div class="notif-pill" [attr.aria-live]="'polite'">
19445
+ @if (resolvedProps.notification?.icon) {
19446
+ <div class="notif-pill__icon-wrap" [style.color]="getIconColor()">
19447
+ <ion-icon [name]="resolvedProps.notification!.icon!" />
19448
+ </div>
19449
+ }
19450
+
19451
+ <div class="notif-pill__content">
19452
+ @if (resolvedProps.notification?.time) {
19453
+ <span class="notif-pill__time">{{ resolvedProps.notification!.time }}</span>
19454
+ }
19455
+ <span class="notif-pill__title">{{ resolvedProps.notification!.title }}</span>
19456
+ @if (resolvedProps.notification?.body) {
19457
+ <span class="notif-pill__body">{{ resolvedProps.notification!.body }}</span>
19458
+ }
19459
+ </div>
19460
+
19461
+ @if (resolvedProps.notification?.actions?.length) {
19462
+ <div class="notif-pill__actions">
19463
+ @for (action of resolvedProps.notification!.actions!; track action.token) {
19464
+ <button
19465
+ class="notif-pill__action-btn"
19466
+ [attr.aria-label]="action.ariaLabel || action.token"
19467
+ (click)="onActionClick(action.token, $event)"
19468
+ >
19469
+ <ion-icon [name]="action.icon" />
19470
+ </button>
19471
+ }
19472
+ </div>
19473
+ }
19474
+ </div>
19475
+ } @else if (isTextPill) {
19476
+ <!-- Badge mode -->
19466
19477
  <span
19467
19478
  class="val-pill"
19468
19479
  [class.val-pill--clickable]="resolvedProps.clickable"
@@ -19475,7 +19486,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19475
19486
  [class.val-pill--w-bold]="pillWeight === 'bold'"
19476
19487
  [style.--val-pill-color]="'var(--ion-color-' + pillColor + ')'"
19477
19488
  [style.--val-pill-color-rgb]="'var(--ion-color-' + pillColor + '-rgb)'"
19478
- [style.--val-pill-contrast]="'var(--ion-color-' + pillColor + '-contrast)'"
19489
+ [style.--val-pill-color-contrast]="'var(--ion-color-' + pillColor + '-contrast)'"
19479
19490
  [attr.role]="resolvedProps.clickable ? 'button' : null"
19480
19491
  [attr.tabindex]="resolvedProps.clickable ? 0 : null"
19481
19492
  [attr.aria-label]="resolvedProps.clickable ? resolvedProps.ariaLabel || resolvedProps.label : null"
@@ -19488,29 +19499,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
19488
19499
  }
19489
19500
  <span class="val-pill__label">{{ resolvedProps.label }}</span>
19490
19501
  </span>
19491
- } @else {
19492
- <!-- Card mode (legacy fun-card) -->
19493
- <div
19494
- [id]="resolvedProps.token"
19495
- class="fun-card"
19496
- [class.bordered]="resolvedProps.bordered"
19497
- [class.hoverable]="resolvedProps.hoverable"
19498
- [ngStyle]="{
19499
- background: theme.IsDark ? 'var(--ion-background-color)' : resolvedProps.background,
19500
- }"
19501
- >
19502
- @if (resolvedProps.content) {
19503
- <val-action-header style="width: 100%;" [props]="resolvedProps.content" />
19504
- }
19505
- </div>
19506
19502
  }
19507
- `, 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)}.fun-card{z-index:0;position:relative;margin-bottom:8px;cursor:pointer;background:var(--ion-card-background, var(--ion-item-background, var(--ion-background-color, #fff)));display:flex;border-radius:48px;align-items:start;padding:8px 8px 8px 24px;flex-direction:column;box-shadow:0 .25rem .75rem #12195412}.fun-card.hoverable{transition:transform .3s ease,box-shadow .3s ease}.fun-card.hoverable:hover{transform:scale(1.01);box-shadow:.1875rem .625rem .5rem #1219541a}.bordered{border:.0625rem solid var(--ion-color-medium)}.val-pill{display:inline-flex;align-items:center;gap:6px;border-radius:999px;white-space:nowrap;line-height:1;background:rgba(var(--val-pill-color-rgb),.12);color:var(--val-pill-color);border:.0625rem solid rgba(var(--val-pill-color-rgb),.22);transition:background .15s ease,transform .15s ease,box-shadow .15s ease}.val-pill__icon{font-size:1em;flex-shrink:0}.val-pill__label{display:inline-block}.val-pill--solid{background:var(--val-pill-color);color:var(--val-pill-contrast);border-color:var(--val-pill-color)}.val-pill--small{padding:5px 12px;font-size:.75rem}.val-pill--medium{padding:7px 14px;font-size:.875rem}.val-pill--large{padding:9px 18px;font-size:1rem}.val-pill--w-normal{font-weight:400}.val-pill--w-medium{font-weight:600}.val-pill--w-bold{font-weight:700}.val-pill--clickable{cursor:pointer;-webkit-tap-highlight-color:transparent}.val-pill--clickable:hover{background:rgba(var(--val-pill-color-rgb),.2);transform:translateY(-1px)}.val-pill--clickable:active{transform:translateY(0) scale(.98)}.val-pill--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--val-pill-color-rgb),.3)}.val-pill--clickable.val-pill--solid:hover{filter:brightness(1.08)}:host-context(body.dark) .val-pill:not(.val-pill--solid),:host-context(html.ion-palette-dark) .val-pill:not(.val-pill--solid),:host-context([data-theme=dark]) .val-pill:not(.val-pill--solid){background:rgba(var(--val-pill-color-rgb),.22);border-color:rgba(var(--val-pill-color-rgb),.32)}\n"] }]
19503
+ `, 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)}.val-pill{display:inline-flex;align-items:center;gap:6px;border-radius:999px;white-space:nowrap;line-height:1;background:rgba(var(--val-pill-color-rgb),.12);color:var(--val-pill-color);border:.0625rem solid rgba(var(--val-pill-color-rgb),.22);transition:background .15s ease,transform .15s ease,box-shadow .15s ease}.val-pill__icon{font-size:1em;flex-shrink:0}.val-pill__label{display:inline-block}.val-pill--solid{background:var(--val-pill-color);color:var(--val-pill-color-contrast);border-color:var(--val-pill-color)}.val-pill--small{padding:5px 12px;font-size:.75rem}.val-pill--medium{padding:7px 14px;font-size:.875rem}.val-pill--large{padding:9px 18px;font-size:1rem}.val-pill--w-normal{font-weight:400}.val-pill--w-medium{font-weight:600}.val-pill--w-bold{font-weight:700}.val-pill--clickable{cursor:pointer;-webkit-tap-highlight-color:transparent}.val-pill--clickable:hover{background:rgba(var(--val-pill-color-rgb),.2);transform:translateY(-1px)}.val-pill--clickable:active{transform:translateY(0) scale(.98)}.val-pill--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--val-pill-color-rgb),.3)}.val-pill--clickable.val-pill--solid:hover{filter:brightness(1.08)}:host-context(body.dark) .val-pill:not(.val-pill--solid),:host-context(html.ion-palette-dark) .val-pill:not(.val-pill--solid),:host-context([data-theme=dark]) .val-pill:not(.val-pill--solid){background:rgba(var(--val-pill-color-rgb),.22);border-color:rgba(var(--val-pill-color-rgb),.32)}.notif-pill{display:inline-flex;align-items:center;gap:12px;padding:10px 14px;border-radius:999px;background:var(--ion-color-dark);color:var(--ion-color-dark-contrast);max-width:100%;box-sizing:border-box;box-shadow:.1875rem .625rem .5rem #1219541a}.notif-pill__icon-wrap{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:32px;height:32px;border-radius:50%;background:#ffffff1a;font-size:1rem}.notif-pill__content{display:flex;align-items:baseline;gap:8px;flex:1;min-width:0;overflow:hidden}.notif-pill__time{font-size:.72rem;font-weight:600;opacity:.55;flex-shrink:0;letter-spacing:.02em}.notif-pill__title{font-size:.875rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.notif-pill__body{font-size:.75rem;opacity:.7;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:1}.notif-pill__actions{display:flex;align-items:center;gap:6px;flex-shrink:0;margin-left:4px}.notif-pill__action-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#ffffff1f;color:var(--ion-color-dark-contrast);cursor:pointer;font-size:.9rem;transition:background .15s ease,transform .1s ease;-webkit-tap-highlight-color:transparent}.notif-pill__action-btn:hover{background:#ffffff38}.notif-pill__action-btn:active{transform:scale(.9)}.notif-pill__action-btn:focus-visible{outline:none;box-shadow:0 0 0 2px #ffffff80}\n"] }]
19508
19504
  }], propDecorators: { preset: [{
19509
19505
  type: Input
19510
19506
  }], props: [{
19511
19507
  type: Input
19512
19508
  }], pillClick: [{
19513
19509
  type: Output
19510
+ }], pillAction: [{
19511
+ type: Output
19514
19512
  }] } });
19515
19513
 
19516
19514
  class CommandDisplayComponent {
@@ -27046,7 +27044,7 @@ const ACTION_CARD_DEFAULTS = {
27046
27044
  };
27047
27045
 
27048
27046
  addIcons({ chevronForwardOutline });
27049
- const IONIC_COLORS$5 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27047
+ const IONIC_COLORS$8 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27050
27048
  /**
27051
27049
  * val-action-card
27052
27050
  *
@@ -27126,7 +27124,7 @@ class ActionCardComponent {
27126
27124
  resolveColor(color) {
27127
27125
  if (!color)
27128
27126
  return null;
27129
- if (IONIC_COLORS$5.includes(color)) {
27127
+ if (IONIC_COLORS$8.includes(color)) {
27130
27128
  return `var(--ion-color-${color})`;
27131
27129
  }
27132
27130
  return color;
@@ -27319,7 +27317,7 @@ const MEDIA_OBJECT_DEFAULTS = {
27319
27317
  circle: false,
27320
27318
  };
27321
27319
 
27322
- const IONIC_COLORS$4 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27320
+ const IONIC_COLORS$7 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27323
27321
  /**
27324
27322
  * val-media-object
27325
27323
  *
@@ -27359,7 +27357,7 @@ class MediaObjectComponent {
27359
27357
  const color = this.config().color;
27360
27358
  if (!color)
27361
27359
  return 'var(--ion-color-primary)';
27362
- return IONIC_COLORS$4.includes(color) ? `var(--ion-color-${color})` : color;
27360
+ return IONIC_COLORS$7.includes(color) ? `var(--ion-color-${color})` : color;
27363
27361
  }
27364
27362
  handleLinkClick(event) {
27365
27363
  const link = this.config().link;
@@ -27463,7 +27461,7 @@ const STATS_BAR_DEFAULTS = {
27463
27461
  stackOnMobile: true,
27464
27462
  };
27465
27463
 
27466
- const IONIC_COLORS$3 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27464
+ const IONIC_COLORS$6 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27467
27465
  /**
27468
27466
  * val-stats-bar
27469
27467
  *
@@ -27500,7 +27498,7 @@ class StatsBarComponent {
27500
27498
  const color = stat.color;
27501
27499
  if (!color)
27502
27500
  return null;
27503
- return IONIC_COLORS$3.includes(color) ? `var(--ion-color-${color})` : color;
27501
+ return IONIC_COLORS$6.includes(color) ? `var(--ion-color-${color})` : color;
27504
27502
  }
27505
27503
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StatsBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27506
27504
  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: `
@@ -27568,7 +27566,7 @@ const ARTICLE_CARD_DEFAULTS = {
27568
27566
  excerptLines: 3,
27569
27567
  };
27570
27568
 
27571
- const IONIC_COLORS$2 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27569
+ const IONIC_COLORS$5 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27572
27570
  /**
27573
27571
  * val-article-card
27574
27572
  *
@@ -27611,7 +27609,7 @@ class ArticleCardComponent {
27611
27609
  const color = this.config().topicColor;
27612
27610
  if (!color)
27613
27611
  return 'var(--ion-color-primary)';
27614
- return IONIC_COLORS$2.includes(color) ? `var(--ion-color-${color})` : color;
27612
+ return IONIC_COLORS$5.includes(color) ? `var(--ion-color-${color})` : color;
27615
27613
  }
27616
27614
  handleClick(event) {
27617
27615
  const cfg = this.config();
@@ -27726,7 +27724,7 @@ const CTA_CARD_DEFAULTS = {
27726
27724
  shadowed: false,
27727
27725
  };
27728
27726
 
27729
- const IONIC_COLORS$1 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27727
+ const IONIC_COLORS$4 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
27730
27728
  /**
27731
27729
  * val-cta-card
27732
27730
  *
@@ -27770,7 +27768,7 @@ class CtaCardComponent {
27770
27768
  resolveColor(color) {
27771
27769
  if (!color)
27772
27770
  return null;
27773
- return IONIC_COLORS$1.includes(color) ? `var(--ion-color-${color})` : color;
27771
+ return IONIC_COLORS$4.includes(color) ? `var(--ion-color-${color})` : color;
27774
27772
  }
27775
27773
  getBackground() {
27776
27774
  return this.resolveColor(this.config().backgroundColor) || 'var(--ion-color-light, #f4f5f8)';
@@ -30537,11 +30535,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
30537
30535
  }] } });
30538
30536
 
30539
30537
  const MIN_LENGTH = 8;
30538
+ // bcrypt silently truncates input at 72 bytes — cap here so FE/BE stay aligned.
30539
+ const MAX_LENGTH = 72;
30540
30540
  // Special chars: ASCII 33-47, 58-64, 91-96, 123-126
30541
30541
  const SPECIAL_CHAR_RE = /[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]/;
30542
30542
  /**
30543
- * Mirrors the backend `authPassword` validator (`pkg/validator.go`):
30544
- * min 8 chars, ≥1 uppercase, ≥1 lowercase, ≥1 digit, ≥1 special char.
30543
+ * Mirrors the backend `authPassword` validator (services/authv2/password.go):
30544
+ * min 8 chars, max 72 chars (bcrypt limit), ≥1 uppercase, ≥1 lowercase,
30545
+ * ≥1 digit, ≥1 special char.
30545
30546
  *
30546
30547
  * Returns `{ authPassword: true }` on failure so the form can surface the
30547
30548
  * inline error via `errorKeys: { authPassword: 'passwordStrength' }`.
@@ -30552,6 +30553,7 @@ function authPasswordValidator() {
30552
30553
  if (!value)
30553
30554
  return null; // `required` handles empty
30554
30555
  const valid = value.length >= MIN_LENGTH &&
30556
+ value.length <= MAX_LENGTH &&
30555
30557
  /[A-Z]/.test(value) &&
30556
30558
  /[a-z]/.test(value) &&
30557
30559
  /[0-9]/.test(value) &&
@@ -32913,7 +32915,7 @@ const FUN_MODAL_DEFAULTS = {
32913
32915
  imageRadius: 16,
32914
32916
  };
32915
32917
 
32916
- const IONIC_COLORS = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
32918
+ const IONIC_COLORS$3 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
32917
32919
  /**
32918
32920
  * `val-fun-modal` — modal moderno tipo promo/onboarding: imagen o ilustración
32919
32921
  * arriba, título, cuerpo y botones de acción, con redondeo personalizable.
@@ -32963,7 +32965,7 @@ class FunModalComponent {
32963
32965
  const color = this.config().backgroundColor;
32964
32966
  if (!color)
32965
32967
  return null;
32966
- return IONIC_COLORS.includes(color) ? `var(--ion-color-${color})` : color;
32968
+ return IONIC_COLORS$3.includes(color) ? `var(--ion-color-${color})` : color;
32967
32969
  }
32968
32970
  close() {
32969
32971
  this._isOpen = false;
@@ -34712,7 +34714,7 @@ class ItemListComponent {
34712
34714
  * Devuelve el color de borde de la lista.
34713
34715
  */
34714
34716
  color() {
34715
- return resolveColor(this.props.color || this.defaultColor);
34717
+ return resolveColor$1(this.props.color || this.defaultColor);
34716
34718
  }
34717
34719
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ItemListComponent, deps: [{ token: IconService }], target: i0.ɵɵFactoryTarget.Component }); }
34718
34720
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ItemListComponent, isStandalone: true, selector: "val-item-list", inputs: { props: "props" }, outputs: { onClick: "onClick", onActionClick: "onActionClick" }, ngImport: i0, template: `
@@ -42378,7 +42380,7 @@ class PageContentComponent {
42378
42380
  if (!bg) {
42379
42381
  return 'var(--ion-background-color)';
42380
42382
  }
42381
- return resolveColor(bg);
42383
+ return resolveColor$1(bg);
42382
42384
  }
42383
42385
  /**
42384
42386
  * Handles header action clicks.
@@ -42784,7 +42786,7 @@ class PageWrapperComponent {
42784
42786
  if (!bg) {
42785
42787
  return 'var(--ion-background-color)';
42786
42788
  }
42787
- return resolveColor(bg);
42789
+ return resolveColor$1(bg);
42788
42790
  });
42789
42791
  }
42790
42792
  /**
@@ -51608,17 +51610,23 @@ class RequestService {
51608
51610
  return this.http.get(`${this.baseUrl}/my${qs}`);
51609
51611
  }
51610
51612
  getRequest(id) {
51611
- return this.http.get(`${this.baseUrl}/${id}`);
51613
+ return this.http
51614
+ .get(`${this.baseUrl}/${id}`)
51615
+ .pipe(map$1(r => r.request));
51612
51616
  }
51613
51617
  updateRequest(id, payload) {
51614
- return this.http.put(`${this.baseUrl}/${id}`, payload);
51618
+ return this.http
51619
+ .put(`${this.baseUrl}/${id}`, payload)
51620
+ .pipe(map$1(r => r.request));
51615
51621
  }
51616
51622
  transition(id, payload) {
51617
51623
  return this.http.post(`${this.baseUrl}/${id}/transition`, payload);
51618
51624
  }
51619
51625
  // ── Comments ──
51620
51626
  addComment(requestId, payload) {
51621
- return this.http.post(`${this.baseUrl}/${requestId}/comments`, payload);
51627
+ return this.http
51628
+ .post(`${this.baseUrl}/${requestId}/comments`, payload)
51629
+ .pipe(map$1(r => r.comment));
51622
51630
  }
51623
51631
  listComments(requestId) {
51624
51632
  return this.http.get(`${this.baseUrl}/${requestId}/comments`);
@@ -51821,6 +51829,689 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51821
51829
  args: [{ providedIn: 'root' }]
51822
51830
  }] });
51823
51831
 
51832
+ /**
51833
+ * Default values for ArticleStripMetadata.
51834
+ */
51835
+ const ARTICLE_STRIP_DEFAULTS = {
51836
+ cardWidth: '280px',
51837
+ gap: '16px',
51838
+ };
51839
+
51840
+ /**
51841
+ * val-article-strip
51842
+ *
51843
+ * Horizontal scroll row of article cards with a section header and an optional
51844
+ * "see all" link/action. Reuses val-horizontal-scroll + val-article-card.
51845
+ *
51846
+ * @example
51847
+ * ```html
51848
+ * <val-article-strip
51849
+ * [props]="{
51850
+ * title: 'Latest Articles',
51851
+ * seeAllLabel: 'View all',
51852
+ * seeAllRoute: '/blog',
51853
+ * articles: [...]
51854
+ * }"
51855
+ * (onArticleClick)="openArticle($event)"
51856
+ * />
51857
+ * ```
51858
+ */
51859
+ class ArticleStripComponent {
51860
+ constructor() {
51861
+ this.navigation = inject(NavigationService);
51862
+ /** Component configuration */
51863
+ this.props = input({ articles: [] });
51864
+ /** Emitted when the "see all" link/button is clicked */
51865
+ this.onSeeAll = new EventEmitter();
51866
+ /** Re-emits the onClick event from each article card */
51867
+ this.onArticleClick = new EventEmitter();
51868
+ /** Merged configuration with defaults */
51869
+ this.config = computed(() => ({
51870
+ ...ARTICLE_STRIP_DEFAULTS,
51871
+ articles: [],
51872
+ ...this.props(),
51873
+ }));
51874
+ this.hasSeeAll = computed(() => !!(this.config().seeAllLabel &&
51875
+ (this.config().seeAllRoute || this.config().seeAllHref || this.config().seeAllToken)));
51876
+ }
51877
+ handleSeeAll(event) {
51878
+ const cfg = this.config();
51879
+ if (cfg.seeAllHref) {
51880
+ event.preventDefault();
51881
+ this.navigation.openInNewTab(cfg.seeAllHref);
51882
+ }
51883
+ this.onSeeAll.emit(cfg.seeAllToken);
51884
+ }
51885
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleStripComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
51886
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ArticleStripComponent, isStandalone: true, selector: "val-article-strip", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSeeAll: "onSeeAll", onArticleClick: "onArticleClick" }, ngImport: i0, template: `
51887
+ @if (config().title || hasSeeAll()) {
51888
+ <div class="article-strip__header">
51889
+ @if (config().title) {
51890
+ <h3 class="article-strip__title">{{ config().title }}</h3>
51891
+ }
51892
+
51893
+ @if (hasSeeAll()) {
51894
+ <a
51895
+ class="article-strip__see-all"
51896
+ [routerLink]="config().seeAllRoute ?? null"
51897
+ [attr.href]="config().seeAllHref ?? null"
51898
+ (click)="handleSeeAll($event)"
51899
+ >
51900
+ {{ config().seeAllLabel }}
51901
+ </a>
51902
+ }
51903
+ </div>
51904
+ }
51905
+
51906
+ <val-horizontal-scroll
51907
+ [items]="config().articles"
51908
+ [itemTemplate]="cardTpl"
51909
+ [props]="{ gap: config().gap }"
51910
+ ></val-horizontal-scroll>
51911
+
51912
+ <ng-template #cardTpl let-article>
51913
+ <div [style.width]="config().cardWidth" [style.flex-shrink]="0">
51914
+ <val-article-card [props]="article" (onClick)="onArticleClick.emit($event)"></val-article-card>
51915
+ </div>
51916
+ </ng-template>
51917
+ `, isInline: true, styles: [":host{display:block}.article-strip__header{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:0 0 .75rem}.article-strip__title{margin:0;font-size:1.1rem;font-weight:700;color:var(--ion-text-color);line-height:1.3}.article-strip__see-all{flex-shrink:0;font-size:.875rem;font-weight:600;color:var(--ion-color-primary);text-decoration:none;transition:opacity .15s ease;cursor:pointer}.article-strip__see-all:hover{opacity:.75;text-decoration:underline}:host-context(body.dark) .article-strip__title,:host-context(html.ion-palette-dark) .article-strip__title,:host-context([data-theme=dark]) .article-strip__title{color:var(--ion-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: HorizontalScrollComponent, selector: "val-horizontal-scroll", inputs: ["items", "itemTemplate", "props"] }, { kind: "component", type: ArticleCardComponent, selector: "val-article-card", inputs: ["props"], outputs: ["onClick"] }] }); }
51918
+ }
51919
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ArticleStripComponent, decorators: [{
51920
+ type: Component,
51921
+ args: [{ selector: 'val-article-strip', standalone: true, imports: [CommonModule, RouterLink, HorizontalScrollComponent, ArticleCardComponent], template: `
51922
+ @if (config().title || hasSeeAll()) {
51923
+ <div class="article-strip__header">
51924
+ @if (config().title) {
51925
+ <h3 class="article-strip__title">{{ config().title }}</h3>
51926
+ }
51927
+
51928
+ @if (hasSeeAll()) {
51929
+ <a
51930
+ class="article-strip__see-all"
51931
+ [routerLink]="config().seeAllRoute ?? null"
51932
+ [attr.href]="config().seeAllHref ?? null"
51933
+ (click)="handleSeeAll($event)"
51934
+ >
51935
+ {{ config().seeAllLabel }}
51936
+ </a>
51937
+ }
51938
+ </div>
51939
+ }
51940
+
51941
+ <val-horizontal-scroll
51942
+ [items]="config().articles"
51943
+ [itemTemplate]="cardTpl"
51944
+ [props]="{ gap: config().gap }"
51945
+ ></val-horizontal-scroll>
51946
+
51947
+ <ng-template #cardTpl let-article>
51948
+ <div [style.width]="config().cardWidth" [style.flex-shrink]="0">
51949
+ <val-article-card [props]="article" (onClick)="onArticleClick.emit($event)"></val-article-card>
51950
+ </div>
51951
+ </ng-template>
51952
+ `, styles: [":host{display:block}.article-strip__header{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:0 0 .75rem}.article-strip__title{margin:0;font-size:1.1rem;font-weight:700;color:var(--ion-text-color);line-height:1.3}.article-strip__see-all{flex-shrink:0;font-size:.875rem;font-weight:600;color:var(--ion-color-primary);text-decoration:none;transition:opacity .15s ease;cursor:pointer}.article-strip__see-all:hover{opacity:.75;text-decoration:underline}:host-context(body.dark) .article-strip__title,:host-context(html.ion-palette-dark) .article-strip__title,:host-context([data-theme=dark]) .article-strip__title{color:var(--ion-text-color)}\n"] }]
51953
+ }], propDecorators: { onSeeAll: [{
51954
+ type: Output
51955
+ }], onArticleClick: [{
51956
+ type: Output
51957
+ }] } });
51958
+
51959
+ /**
51960
+ * Default values for InfoCardMetadata.
51961
+ */
51962
+ const INFO_CARD_DEFAULTS = {
51963
+ iconColor: 'primary',
51964
+ bordered: true,
51965
+ shadowed: false,
51966
+ padding: '1.5rem',
51967
+ borderRadius: '16px',
51968
+ };
51969
+
51970
+ const IONIC_COLORS$2 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
51971
+ /**
51972
+ * val-info-card
51973
+ *
51974
+ * Card with icon + overtitle + title + subtitle on the left side, and a list
51975
+ * of key-value pairs (label: value) on the right side. Inspired by npm's
51976
+ * "Provenance" / metadata panel style.
51977
+ *
51978
+ * Two-column layout on desktop, stacked single-column on mobile.
51979
+ *
51980
+ * Presentational — pass already-resolved strings.
51981
+ *
51982
+ * @example
51983
+ * ```html
51984
+ * <val-info-card
51985
+ * [props]="{
51986
+ * icon: 'cube-outline',
51987
+ * title: 'valtech-components',
51988
+ * subtitle: 'v2.0.962',
51989
+ * keyValues: [
51990
+ * { label: 'License', value: 'MIT' },
51991
+ * { label: 'Downloads', value: '1.2M' }
51992
+ * ]
51993
+ * }"
51994
+ * />
51995
+ * ```
51996
+ */
51997
+ class InfoCardComponent {
51998
+ constructor() {
51999
+ /** Component configuration */
52000
+ this.props = input({});
52001
+ /** Merged configuration with defaults */
52002
+ this.config = computed(() => ({
52003
+ ...INFO_CARD_DEFAULTS,
52004
+ ...this.props(),
52005
+ }));
52006
+ }
52007
+ getIconColor() {
52008
+ const color = this.config().iconColor;
52009
+ if (!color)
52010
+ return `var(--ion-color-primary)`;
52011
+ return IONIC_COLORS$2.includes(color) ? `var(--ion-color-${color})` : color;
52012
+ }
52013
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InfoCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
52014
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: InfoCardComponent, isStandalone: true, selector: "val-info-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
52015
+ <div
52016
+ class="info-card"
52017
+ [class.info-card--bordered]="config().bordered"
52018
+ [class.info-card--shadowed]="config().shadowed"
52019
+ [style.padding]="config().padding"
52020
+ [style.border-radius]="config().borderRadius"
52021
+ >
52022
+ <div class="info-card__left">
52023
+ @if (config().icon) {
52024
+ <ion-icon class="info-card__icon" [name]="config().icon" [style.color]="getIconColor()"></ion-icon>
52025
+ }
52026
+
52027
+ @if (config().overtitle) {
52028
+ <span class="info-card__overtitle">{{ config().overtitle }}</span>
52029
+ }
52030
+
52031
+ <h3 class="info-card__title">{{ config().title }}</h3>
52032
+
52033
+ @if (config().subtitle) {
52034
+ <p class="info-card__subtitle">{{ config().subtitle }}</p>
52035
+ }
52036
+ </div>
52037
+
52038
+ @if (config().keyValues?.length) {
52039
+ <div class="info-card__right">
52040
+ @for (kv of config().keyValues; track $index) {
52041
+ <div class="info-card__kv">
52042
+ <span class="info-card__kv-label">{{ kv.label }}</span>
52043
+ <span class="info-card__kv-value">{{ kv.value }}</span>
52044
+ </div>
52045
+ }
52046
+ </div>
52047
+ }
52048
+ </div>
52049
+ `, isInline: true, styles: [":host{display:block}.info-card{display:flex;flex-direction:row;gap:2rem;background:var(--ion-card-background, var(--ion-background-color))}.info-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.info-card--shadowed{box-shadow:0 2px 8px #00000014}.info-card__left{display:flex;flex-direction:column;gap:.35rem;flex:1 1 0;min-width:0}.info-card__icon{font-size:2rem;margin-bottom:.25rem}.info-card__overtitle{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--ion-color-medium)}.info-card__title{margin:0;font-size:1.25rem;font-weight:700;color:var(--ion-text-color);line-height:1.3}.info-card__subtitle{margin:0;font-size:.875rem;color:var(--ion-color-medium-shade)}.info-card__right{display:flex;flex-direction:column;gap:.6rem;flex:0 0 auto;min-width:160px;max-width:260px}.info-card__kv{display:flex;flex-direction:column;gap:.1rem}.info-card__kv-label{font-size:.75rem;color:var(--ion-color-medium)}.info-card__kv-value{font-size:.9rem;font-weight:600;color:var(--ion-text-color);word-break:break-word}@media (max-width: 600px){.info-card{flex-direction:column;gap:1.25rem}.info-card__right{max-width:100%;flex-direction:row;flex-wrap:wrap;gap:.75rem 1.5rem}.info-card__kv{flex:0 0 auto}}:host-context(body.dark) .info-card--bordered,:host-context(html.ion-palette-dark) .info-card--bordered,:host-context([data-theme=dark]) .info-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .info-card--shadowed,:host-context(html.ion-palette-dark) .info-card--shadowed,:host-context([data-theme=dark]) .info-card--shadowed{box-shadow:0 2px 8px #0000004d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
52050
+ }
52051
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InfoCardComponent, decorators: [{
52052
+ type: Component,
52053
+ args: [{ selector: 'val-info-card', standalone: true, imports: [CommonModule, IonIcon], template: `
52054
+ <div
52055
+ class="info-card"
52056
+ [class.info-card--bordered]="config().bordered"
52057
+ [class.info-card--shadowed]="config().shadowed"
52058
+ [style.padding]="config().padding"
52059
+ [style.border-radius]="config().borderRadius"
52060
+ >
52061
+ <div class="info-card__left">
52062
+ @if (config().icon) {
52063
+ <ion-icon class="info-card__icon" [name]="config().icon" [style.color]="getIconColor()"></ion-icon>
52064
+ }
52065
+
52066
+ @if (config().overtitle) {
52067
+ <span class="info-card__overtitle">{{ config().overtitle }}</span>
52068
+ }
52069
+
52070
+ <h3 class="info-card__title">{{ config().title }}</h3>
52071
+
52072
+ @if (config().subtitle) {
52073
+ <p class="info-card__subtitle">{{ config().subtitle }}</p>
52074
+ }
52075
+ </div>
52076
+
52077
+ @if (config().keyValues?.length) {
52078
+ <div class="info-card__right">
52079
+ @for (kv of config().keyValues; track $index) {
52080
+ <div class="info-card__kv">
52081
+ <span class="info-card__kv-label">{{ kv.label }}</span>
52082
+ <span class="info-card__kv-value">{{ kv.value }}</span>
52083
+ </div>
52084
+ }
52085
+ </div>
52086
+ }
52087
+ </div>
52088
+ `, styles: [":host{display:block}.info-card{display:flex;flex-direction:row;gap:2rem;background:var(--ion-card-background, var(--ion-background-color))}.info-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.info-card--shadowed{box-shadow:0 2px 8px #00000014}.info-card__left{display:flex;flex-direction:column;gap:.35rem;flex:1 1 0;min-width:0}.info-card__icon{font-size:2rem;margin-bottom:.25rem}.info-card__overtitle{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--ion-color-medium)}.info-card__title{margin:0;font-size:1.25rem;font-weight:700;color:var(--ion-text-color);line-height:1.3}.info-card__subtitle{margin:0;font-size:.875rem;color:var(--ion-color-medium-shade)}.info-card__right{display:flex;flex-direction:column;gap:.6rem;flex:0 0 auto;min-width:160px;max-width:260px}.info-card__kv{display:flex;flex-direction:column;gap:.1rem}.info-card__kv-label{font-size:.75rem;color:var(--ion-color-medium)}.info-card__kv-value{font-size:.9rem;font-weight:600;color:var(--ion-text-color);word-break:break-word}@media (max-width: 600px){.info-card{flex-direction:column;gap:1.25rem}.info-card__right{max-width:100%;flex-direction:row;flex-wrap:wrap;gap:.75rem 1.5rem}.info-card__kv{flex:0 0 auto}}:host-context(body.dark) .info-card--bordered,:host-context(html.ion-palette-dark) .info-card--bordered,:host-context([data-theme=dark]) .info-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .info-card--shadowed,:host-context(html.ion-palette-dark) .info-card--shadowed,:host-context([data-theme=dark]) .info-card--shadowed{box-shadow:0 2px 8px #0000004d}\n"] }]
52089
+ }] });
52090
+
52091
+ /**
52092
+ * Default values for MetricCardMetadata.
52093
+ */
52094
+ const METRIC_CARD_DEFAULTS = {
52095
+ bordered: true,
52096
+ shadowed: false,
52097
+ padding: '1.25rem 1.5rem',
52098
+ borderRadius: '16px',
52099
+ };
52100
+
52101
+ /**
52102
+ * val-metric-card
52103
+ *
52104
+ * Card with title + optional info link + description + horizontal stats row
52105
+ * (val-stats-bar) + a discrete icon action button in the top-right corner.
52106
+ *
52107
+ * Presentational — pass already-resolved strings.
52108
+ *
52109
+ * @example
52110
+ * ```html
52111
+ * <val-metric-card
52112
+ * [props]="{
52113
+ * title: 'Email Activity',
52114
+ * description: 'Last 30 days',
52115
+ * stats: { stats: [{ label: 'Sent', value: 1240 }, { label: 'Opens', value: 680 }] },
52116
+ * action: { icon: 'refresh-outline', token: 'refresh' }
52117
+ * }"
52118
+ * (onAction)="handleAction($event)"
52119
+ * />
52120
+ * ```
52121
+ */
52122
+ class MetricCardComponent {
52123
+ constructor() {
52124
+ /** Component configuration */
52125
+ this.props = input({});
52126
+ /** Emitted with the token of the clicked action */
52127
+ this.onAction = new EventEmitter();
52128
+ /** Merged configuration with defaults */
52129
+ this.config = computed(() => ({
52130
+ ...METRIC_CARD_DEFAULTS,
52131
+ ...this.props(),
52132
+ }));
52133
+ }
52134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MetricCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
52135
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: MetricCardComponent, isStandalone: true, selector: "val-metric-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: `
52136
+ <div
52137
+ class="metric-card"
52138
+ [class.metric-card--bordered]="config().bordered"
52139
+ [class.metric-card--shadowed]="config().shadowed"
52140
+ [style.padding]="config().padding"
52141
+ [style.border-radius]="config().borderRadius"
52142
+ >
52143
+ <div class="metric-card__header">
52144
+ <div class="metric-card__header-left">
52145
+ <h3 class="metric-card__title">{{ config().title }}</h3>
52146
+
52147
+ @if (config().infoLabel) {
52148
+ <a
52149
+ class="metric-card__info-link"
52150
+ [routerLink]="config().infoRoute ?? null"
52151
+ [attr.href]="config().infoHref ?? null"
52152
+ [attr.target]="config().infoHref ? '_blank' : null"
52153
+ [attr.rel]="config().infoHref ? 'noopener noreferrer' : null"
52154
+ >
52155
+ {{ config().infoLabel }}
52156
+ </a>
52157
+ }
52158
+ </div>
52159
+
52160
+ @if (config().action; as action) {
52161
+ <ion-button
52162
+ class="metric-card__action"
52163
+ fill="clear"
52164
+ size="small"
52165
+ [disabled]="action.disabled ?? false"
52166
+ (click)="onAction.emit(action.token)"
52167
+ >
52168
+ <ion-icon [name]="action.icon" slot="icon-only"></ion-icon>
52169
+ </ion-button>
52170
+ }
52171
+ </div>
52172
+
52173
+ @if (config().description) {
52174
+ <p class="metric-card__description">{{ config().description }}</p>
52175
+ }
52176
+
52177
+ @if (config().stats; as stats) {
52178
+ <div class="metric-card__stats">
52179
+ <val-stats-bar [props]="stats"></val-stats-bar>
52180
+ </div>
52181
+ }
52182
+ </div>
52183
+ `, isInline: true, styles: [":host{display:block}.metric-card{background:var(--ion-card-background, var(--ion-background-color))}.metric-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.metric-card--shadowed{box-shadow:0 2px 8px #00000014}.metric-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.25rem}.metric-card__header-left{display:flex;flex-direction:column;gap:.2rem;flex:1 1 0;min-width:0}.metric-card__title{margin:0;font-size:1rem;font-weight:700;color:var(--ion-text-color);line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.metric-card__info-link{font-size:.8rem;font-weight:500;color:var(--ion-color-primary);text-decoration:none;transition:opacity .15s ease;width:fit-content}.metric-card__info-link:hover{opacity:.75;text-decoration:underline}.metric-card__action{flex-shrink:0;margin:-6px -8px 0 0}.metric-card__description{margin:0 0 .75rem;font-size:.875rem;color:var(--ion-color-medium-shade);line-height:1.5}.metric-card__stats{margin-top:.5rem}:host-context(body.dark) .metric-card--bordered,:host-context(html.ion-palette-dark) .metric-card--bordered,:host-context([data-theme=dark]) .metric-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .metric-card--shadowed,:host-context(html.ion-palette-dark) .metric-card--shadowed,:host-context([data-theme=dark]) .metric-card--shadowed{box-shadow:0 2px 8px #0000004d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: StatsBarComponent, selector: "val-stats-bar", inputs: ["props"] }] }); }
52184
+ }
52185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MetricCardComponent, decorators: [{
52186
+ type: Component,
52187
+ args: [{ selector: 'val-metric-card', standalone: true, imports: [CommonModule, RouterLink, IonButton, IonIcon, StatsBarComponent], template: `
52188
+ <div
52189
+ class="metric-card"
52190
+ [class.metric-card--bordered]="config().bordered"
52191
+ [class.metric-card--shadowed]="config().shadowed"
52192
+ [style.padding]="config().padding"
52193
+ [style.border-radius]="config().borderRadius"
52194
+ >
52195
+ <div class="metric-card__header">
52196
+ <div class="metric-card__header-left">
52197
+ <h3 class="metric-card__title">{{ config().title }}</h3>
52198
+
52199
+ @if (config().infoLabel) {
52200
+ <a
52201
+ class="metric-card__info-link"
52202
+ [routerLink]="config().infoRoute ?? null"
52203
+ [attr.href]="config().infoHref ?? null"
52204
+ [attr.target]="config().infoHref ? '_blank' : null"
52205
+ [attr.rel]="config().infoHref ? 'noopener noreferrer' : null"
52206
+ >
52207
+ {{ config().infoLabel }}
52208
+ </a>
52209
+ }
52210
+ </div>
52211
+
52212
+ @if (config().action; as action) {
52213
+ <ion-button
52214
+ class="metric-card__action"
52215
+ fill="clear"
52216
+ size="small"
52217
+ [disabled]="action.disabled ?? false"
52218
+ (click)="onAction.emit(action.token)"
52219
+ >
52220
+ <ion-icon [name]="action.icon" slot="icon-only"></ion-icon>
52221
+ </ion-button>
52222
+ }
52223
+ </div>
52224
+
52225
+ @if (config().description) {
52226
+ <p class="metric-card__description">{{ config().description }}</p>
52227
+ }
52228
+
52229
+ @if (config().stats; as stats) {
52230
+ <div class="metric-card__stats">
52231
+ <val-stats-bar [props]="stats"></val-stats-bar>
52232
+ </div>
52233
+ }
52234
+ </div>
52235
+ `, styles: [":host{display:block}.metric-card{background:var(--ion-card-background, var(--ion-background-color))}.metric-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.metric-card--shadowed{box-shadow:0 2px 8px #00000014}.metric-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.25rem}.metric-card__header-left{display:flex;flex-direction:column;gap:.2rem;flex:1 1 0;min-width:0}.metric-card__title{margin:0;font-size:1rem;font-weight:700;color:var(--ion-text-color);line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.metric-card__info-link{font-size:.8rem;font-weight:500;color:var(--ion-color-primary);text-decoration:none;transition:opacity .15s ease;width:fit-content}.metric-card__info-link:hover{opacity:.75;text-decoration:underline}.metric-card__action{flex-shrink:0;margin:-6px -8px 0 0}.metric-card__description{margin:0 0 .75rem;font-size:.875rem;color:var(--ion-color-medium-shade);line-height:1.5}.metric-card__stats{margin-top:.5rem}:host-context(body.dark) .metric-card--bordered,:host-context(html.ion-palette-dark) .metric-card--bordered,:host-context([data-theme=dark]) .metric-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .metric-card--shadowed,:host-context(html.ion-palette-dark) .metric-card--shadowed,:host-context([data-theme=dark]) .metric-card--shadowed{box-shadow:0 2px 8px #0000004d}\n"] }]
52236
+ }], propDecorators: { onAction: [{
52237
+ type: Output
52238
+ }] } });
52239
+
52240
+ /**
52241
+ * Default values for ContentCardMetadata.
52242
+ */
52243
+ const CONTENT_CARD_DEFAULTS = {
52244
+ padding: '1.5rem',
52245
+ borderRadius: '20px',
52246
+ bordered: false,
52247
+ shadowed: true,
52248
+ align: 'start',
52249
+ };
52250
+
52251
+ const IONIC_COLORS$1 = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
52252
+ function resolveColor(value) {
52253
+ if (!value)
52254
+ return undefined;
52255
+ return IONIC_COLORS$1.includes(value) ? `var(--ion-color-${value})` : value;
52256
+ }
52257
+ /**
52258
+ * val-content-card
52259
+ *
52260
+ * Generic container card with configurable padding, border radius, background
52261
+ * color and shadow. Accepts arbitrary content via ng-content. Use it to wrap
52262
+ * val-article, stats, or any other content that needs a card shell.
52263
+ *
52264
+ * @example
52265
+ * ```html
52266
+ * <val-content-card [props]="{ title: 'Summary', shadowed: true }">
52267
+ * <p>Any inner content here.</p>
52268
+ * </val-content-card>
52269
+ * ```
52270
+ */
52271
+ class ContentCardComponent {
52272
+ constructor() {
52273
+ /** Component configuration */
52274
+ this.props = input({});
52275
+ /** Merged configuration with defaults */
52276
+ this.config = computed(() => ({
52277
+ ...CONTENT_CARD_DEFAULTS,
52278
+ ...this.props(),
52279
+ }));
52280
+ this.resolvedBg = computed(() => resolveColor(this.config().backgroundColor));
52281
+ this.resolvedColor = computed(() => resolveColor(this.config().color));
52282
+ }
52283
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
52284
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ContentCardComponent, isStandalone: true, selector: "val-content-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
52285
+ <div
52286
+ class="content-card"
52287
+ [class.content-card--bordered]="config().bordered"
52288
+ [class.content-card--shadowed]="config().shadowed"
52289
+ [class.content-card--center]="config().align === 'center'"
52290
+ [style.padding]="config().padding"
52291
+ [style.border-radius]="config().borderRadius"
52292
+ [style.background-color]="resolvedBg()"
52293
+ [style.color]="resolvedColor()"
52294
+ >
52295
+ @if (config().title) {
52296
+ <h3 class="content-card__title">{{ config().title }}</h3>
52297
+ }
52298
+
52299
+ @if (config().description) {
52300
+ <p class="content-card__description">{{ config().description }}</p>
52301
+ }
52302
+
52303
+ <ng-content></ng-content>
52304
+ </div>
52305
+ `, isInline: true, styles: [":host{display:block}.content-card{background:var(--ion-card-background, var(--ion-background-color))}.content-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.content-card--shadowed{box-shadow:0 4px 16px #00000014}.content-card--center{text-align:center}.content-card__title{margin:0 0 .5rem;font-size:1.1rem;font-weight:700;color:inherit;line-height:1.3}.content-card__description{margin:0 0 1rem;font-size:.875rem;color:var(--ion-color-medium-shade);line-height:1.5}:host-context(body.dark) .content-card--bordered,:host-context(html.ion-palette-dark) .content-card--bordered,:host-context([data-theme=dark]) .content-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .content-card--shadowed,:host-context(html.ion-palette-dark) .content-card--shadowed,:host-context([data-theme=dark]) .content-card--shadowed{box-shadow:0 4px 16px #0000004d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
52306
+ }
52307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ContentCardComponent, decorators: [{
52308
+ type: Component,
52309
+ args: [{ selector: 'val-content-card', standalone: true, imports: [CommonModule], template: `
52310
+ <div
52311
+ class="content-card"
52312
+ [class.content-card--bordered]="config().bordered"
52313
+ [class.content-card--shadowed]="config().shadowed"
52314
+ [class.content-card--center]="config().align === 'center'"
52315
+ [style.padding]="config().padding"
52316
+ [style.border-radius]="config().borderRadius"
52317
+ [style.background-color]="resolvedBg()"
52318
+ [style.color]="resolvedColor()"
52319
+ >
52320
+ @if (config().title) {
52321
+ <h3 class="content-card__title">{{ config().title }}</h3>
52322
+ }
52323
+
52324
+ @if (config().description) {
52325
+ <p class="content-card__description">{{ config().description }}</p>
52326
+ }
52327
+
52328
+ <ng-content></ng-content>
52329
+ </div>
52330
+ `, styles: [":host{display:block}.content-card{background:var(--ion-card-background, var(--ion-background-color))}.content-card--bordered{border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .1))}.content-card--shadowed{box-shadow:0 4px 16px #00000014}.content-card--center{text-align:center}.content-card__title{margin:0 0 .5rem;font-size:1.1rem;font-weight:700;color:inherit;line-height:1.3}.content-card__description{margin:0 0 1rem;font-size:.875rem;color:var(--ion-color-medium-shade);line-height:1.5}:host-context(body.dark) .content-card--bordered,:host-context(html.ion-palette-dark) .content-card--bordered,:host-context([data-theme=dark]) .content-card--bordered{border-color:#ffffff1f}:host-context(body.dark) .content-card--shadowed,:host-context(html.ion-palette-dark) .content-card--shadowed,:host-context([data-theme=dark]) .content-card--shadowed{box-shadow:0 4px 16px #0000004d}\n"] }]
52331
+ }] });
52332
+
52333
+ /**
52334
+ * Default values for AuthCtaMetadata.
52335
+ */
52336
+ const AUTH_CTA_DEFAULTS = {
52337
+ align: 'center',
52338
+ borderRadius: '0',
52339
+ padding: '3rem 1.5rem',
52340
+ };
52341
+
52342
+ const IONIC_COLORS = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger', 'light', 'medium', 'dark'];
52343
+ const AUTH_CTA_I18N = {
52344
+ es: { login: 'Iniciar sesión', register: 'Registrarse' },
52345
+ en: { login: 'Log in', register: 'Sign up' },
52346
+ };
52347
+ /**
52348
+ * val-auth-cta
52349
+ *
52350
+ * Full-width CTA section inviting unauthenticated users to sign up or log in.
52351
+ * Desktop: text on the left, optional image on the right.
52352
+ * Mobile: stacked, image below text.
52353
+ *
52354
+ * Auto-registers its own i18n defaults (AuthCta namespace) so there are never
52355
+ * missing keys, even if the consumer does not register them.
52356
+ *
52357
+ * @example
52358
+ * ```html
52359
+ * <val-auth-cta
52360
+ * [props]="{
52361
+ * title: 'Join Valtech today',
52362
+ * subtitle: 'The platform built for teams that ship.',
52363
+ * loginRoute: '/login',
52364
+ * registerRoute: '/register'
52365
+ * }"
52366
+ * (onLogin)="openLogin()"
52367
+ * (onRegister)="openRegister()"
52368
+ * />
52369
+ * ```
52370
+ */
52371
+ class AuthCtaComponent {
52372
+ constructor() {
52373
+ this.i18n = inject(I18nService);
52374
+ /** Component configuration */
52375
+ this.props = input({});
52376
+ /** Emitted when the login button is clicked */
52377
+ this.onLogin = new EventEmitter();
52378
+ /** Emitted when the register button is clicked */
52379
+ this.onRegister = new EventEmitter();
52380
+ /** Merged configuration with defaults */
52381
+ this.config = computed(() => ({
52382
+ ...AUTH_CTA_DEFAULTS,
52383
+ ...this.props(),
52384
+ }));
52385
+ this.loginLabel = computed(() => this.config().loginLabel ?? this.i18n.t('AuthCta.login'));
52386
+ this.registerLabel = computed(() => this.config().registerLabel ?? this.i18n.t('AuthCta.register'));
52387
+ this.resolvedBg = computed(() => {
52388
+ const bg = this.config().backgroundColor;
52389
+ if (!bg)
52390
+ return undefined;
52391
+ return IONIC_COLORS.includes(bg) ? `var(--ion-color-${bg})` : bg;
52392
+ });
52393
+ if (!this.i18n.hasNamespace('AuthCta')) {
52394
+ this.i18n.registerContent('AuthCta', AUTH_CTA_I18N);
52395
+ }
52396
+ }
52397
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthCtaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
52398
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AuthCtaComponent, isStandalone: true, selector: "val-auth-cta", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onLogin: "onLogin", onRegister: "onRegister" }, ngImport: i0, template: `
52399
+ <div
52400
+ class="auth-cta"
52401
+ [class.auth-cta--center]="config().align === 'center'"
52402
+ [class.auth-cta--has-image]="!!config().image"
52403
+ [style.padding]="config().padding"
52404
+ [style.border-radius]="config().borderRadius"
52405
+ [style.background-color]="resolvedBg()"
52406
+ >
52407
+ <div class="auth-cta__text">
52408
+ @if (config().eyebrow) {
52409
+ <span class="auth-cta__eyebrow">{{ config().eyebrow }}</span>
52410
+ }
52411
+
52412
+ <h2 class="auth-cta__title">{{ config().title }}</h2>
52413
+
52414
+ @if (config().subtitle) {
52415
+ <p class="auth-cta__subtitle">{{ config().subtitle }}</p>
52416
+ }
52417
+
52418
+ <div class="auth-cta__actions">
52419
+ <ion-button
52420
+ class="auth-cta__btn-register"
52421
+ fill="solid"
52422
+ color="dark"
52423
+ shape="round"
52424
+ [routerLink]="config().registerRoute ?? null"
52425
+ [attr.href]="config().registerHref ?? null"
52426
+ (click)="onRegister.emit()"
52427
+ >
52428
+ {{ registerLabel() }}
52429
+ </ion-button>
52430
+
52431
+ <ion-button
52432
+ class="auth-cta__btn-login"
52433
+ fill="outline"
52434
+ color="dark"
52435
+ shape="round"
52436
+ [routerLink]="config().loginRoute ?? null"
52437
+ [attr.href]="config().loginHref ?? null"
52438
+ (click)="onLogin.emit()"
52439
+ >
52440
+ {{ loginLabel() }}
52441
+ </ion-button>
52442
+ </div>
52443
+ </div>
52444
+
52445
+ @if (config().image) {
52446
+ <div class="auth-cta__image-wrap">
52447
+ <img class="auth-cta__image" [src]="config().image" [alt]="config().imageAlt ?? ''" loading="lazy" />
52448
+ </div>
52449
+ }
52450
+ </div>
52451
+ `, isInline: true, styles: [":host{display:block}.auth-cta{display:flex;flex-direction:row;align-items:center;gap:3rem;background:var(--ion-background-color)}.auth-cta--center{text-align:center}.auth-cta--center .auth-cta__actions{justify-content:center}.auth-cta--has-image{text-align:start}.auth-cta--has-image .auth-cta__actions{justify-content:flex-start}.auth-cta__text{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:1rem}.auth-cta__eyebrow{font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--ion-color-primary)}.auth-cta__title{margin:0;font-size:2rem;font-weight:800;line-height:1.2;color:var(--ion-text-color)}.auth-cta__subtitle{margin:0;font-size:1.05rem;line-height:1.6;color:var(--ion-color-medium-shade)}.auth-cta__actions{display:flex;flex-wrap:wrap;gap:.75rem;align-items:center;margin-top:.5rem}.auth-cta__image-wrap{flex:0 0 auto;max-width:420px;width:40%}.auth-cta__image{display:block;width:100%;height:auto;border-radius:12px;object-fit:cover}@media (max-width: 768px){.auth-cta{flex-direction:column;gap:2rem;text-align:center}.auth-cta--has-image{text-align:center}.auth-cta--has-image .auth-cta__actions{justify-content:center}.auth-cta__image-wrap{max-width:100%;width:100%}.auth-cta__actions{justify-content:center}}:host-context(body.dark) .auth-cta__title,:host-context(html.ion-palette-dark) .auth-cta__title,:host-context([data-theme=dark]) .auth-cta__title{color:var(--ion-text-color)}:host-context(body.dark) .auth-cta__subtitle,:host-context(html.ion-palette-dark) .auth-cta__subtitle,:host-context([data-theme=dark]) .auth-cta__subtitle{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }] }); }
52452
+ }
52453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthCtaComponent, decorators: [{
52454
+ type: Component,
52455
+ args: [{ selector: 'val-auth-cta', standalone: true, imports: [CommonModule, RouterLink, IonButton], template: `
52456
+ <div
52457
+ class="auth-cta"
52458
+ [class.auth-cta--center]="config().align === 'center'"
52459
+ [class.auth-cta--has-image]="!!config().image"
52460
+ [style.padding]="config().padding"
52461
+ [style.border-radius]="config().borderRadius"
52462
+ [style.background-color]="resolvedBg()"
52463
+ >
52464
+ <div class="auth-cta__text">
52465
+ @if (config().eyebrow) {
52466
+ <span class="auth-cta__eyebrow">{{ config().eyebrow }}</span>
52467
+ }
52468
+
52469
+ <h2 class="auth-cta__title">{{ config().title }}</h2>
52470
+
52471
+ @if (config().subtitle) {
52472
+ <p class="auth-cta__subtitle">{{ config().subtitle }}</p>
52473
+ }
52474
+
52475
+ <div class="auth-cta__actions">
52476
+ <ion-button
52477
+ class="auth-cta__btn-register"
52478
+ fill="solid"
52479
+ color="dark"
52480
+ shape="round"
52481
+ [routerLink]="config().registerRoute ?? null"
52482
+ [attr.href]="config().registerHref ?? null"
52483
+ (click)="onRegister.emit()"
52484
+ >
52485
+ {{ registerLabel() }}
52486
+ </ion-button>
52487
+
52488
+ <ion-button
52489
+ class="auth-cta__btn-login"
52490
+ fill="outline"
52491
+ color="dark"
52492
+ shape="round"
52493
+ [routerLink]="config().loginRoute ?? null"
52494
+ [attr.href]="config().loginHref ?? null"
52495
+ (click)="onLogin.emit()"
52496
+ >
52497
+ {{ loginLabel() }}
52498
+ </ion-button>
52499
+ </div>
52500
+ </div>
52501
+
52502
+ @if (config().image) {
52503
+ <div class="auth-cta__image-wrap">
52504
+ <img class="auth-cta__image" [src]="config().image" [alt]="config().imageAlt ?? ''" loading="lazy" />
52505
+ </div>
52506
+ }
52507
+ </div>
52508
+ `, styles: [":host{display:block}.auth-cta{display:flex;flex-direction:row;align-items:center;gap:3rem;background:var(--ion-background-color)}.auth-cta--center{text-align:center}.auth-cta--center .auth-cta__actions{justify-content:center}.auth-cta--has-image{text-align:start}.auth-cta--has-image .auth-cta__actions{justify-content:flex-start}.auth-cta__text{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:1rem}.auth-cta__eyebrow{font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--ion-color-primary)}.auth-cta__title{margin:0;font-size:2rem;font-weight:800;line-height:1.2;color:var(--ion-text-color)}.auth-cta__subtitle{margin:0;font-size:1.05rem;line-height:1.6;color:var(--ion-color-medium-shade)}.auth-cta__actions{display:flex;flex-wrap:wrap;gap:.75rem;align-items:center;margin-top:.5rem}.auth-cta__image-wrap{flex:0 0 auto;max-width:420px;width:40%}.auth-cta__image{display:block;width:100%;height:auto;border-radius:12px;object-fit:cover}@media (max-width: 768px){.auth-cta{flex-direction:column;gap:2rem;text-align:center}.auth-cta--has-image{text-align:center}.auth-cta--has-image .auth-cta__actions{justify-content:center}.auth-cta__image-wrap{max-width:100%;width:100%}.auth-cta__actions{justify-content:center}}:host-context(body.dark) .auth-cta__title,:host-context(html.ion-palette-dark) .auth-cta__title,:host-context([data-theme=dark]) .auth-cta__title{color:var(--ion-text-color)}:host-context(body.dark) .auth-cta__subtitle,:host-context(html.ion-palette-dark) .auth-cta__subtitle,:host-context([data-theme=dark]) .auth-cta__subtitle{color:var(--ion-color-medium)}\n"] }]
52509
+ }], ctorParameters: () => [], propDecorators: { onLogin: [{
52510
+ type: Output
52511
+ }], onRegister: [{
52512
+ type: Output
52513
+ }] } });
52514
+
51824
52515
  /*
51825
52516
  * Public API Surface of valtech-components
51826
52517
  */
@@ -51830,5 +52521,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
51830
52521
  * Generated bundle index. Do not edit.
51831
52522
  */
51832
52523
 
51833
- 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, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, 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 };
52524
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CONTENT_CARD_DEFAULTS, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentCardComponent, ContentLoaderComponent, ContentReactionComponent, ContentService, ContentTransformer, CookieBannerComponent, CountdownComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DebugConsoleComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, ShareProfileModalComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, blogPost, buildFooterLinks, buildPath, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createRefreshableStream, createTitleProps, docs, errorLoggingInterceptor, extractPathParams, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, provideLegalContent, provideSplashScreen, provideValtechAds, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechPresets, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
51834
52525
  //# sourceMappingURL=valtech-components.mjs.map