valtech-components 2.0.1024 → 2.0.1026

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/esm2022/lib/components/molecules/ticket-card/ticket-card.component.mjs +183 -0
  2. package/esm2022/lib/components/molecules/ticket-card/ticket-card.i18n.mjs +23 -0
  3. package/esm2022/lib/components/molecules/ticket-card/types.mjs +2 -0
  4. package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +23 -27
  5. package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +7 -7
  6. package/esm2022/lib/components/organisms/qr-scanner/qr-scanner.component.mjs +310 -0
  7. package/esm2022/lib/components/organisms/qr-scanner/qr-scanner.i18n.mjs +28 -0
  8. package/esm2022/lib/components/organisms/qr-scanner/types.mjs +2 -0
  9. package/esm2022/lib/version.mjs +2 -2
  10. package/esm2022/public-api.mjs +6 -1
  11. package/fesm2022/valtech-components.mjs +559 -35
  12. package/fesm2022/valtech-components.mjs.map +1 -1
  13. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +1 -1
  14. package/lib/components/molecules/ticket-card/ticket-card.component.d.ts +42 -0
  15. package/lib/components/molecules/ticket-card/ticket-card.i18n.d.ts +22 -0
  16. package/lib/components/molecules/ticket-card/types.d.ts +45 -0
  17. package/lib/components/organisms/article/article.component.d.ts +4 -4
  18. package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
  19. package/lib/components/organisms/qr-scanner/qr-scanner.component.d.ts +51 -0
  20. package/lib/components/organisms/qr-scanner/qr-scanner.i18n.d.ts +27 -0
  21. package/lib/components/organisms/qr-scanner/types.d.ts +31 -0
  22. package/lib/version.d.ts +1 -1
  23. package/package.json +3 -1
  24. package/public-api.d.ts +4 -0
@@ -25,7 +25,7 @@ import { getApps, getApp, initializeApp as initializeApp$1 } from 'firebase/app'
25
25
  import * as i2$1 from '@ionic/angular/standalone';
26
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, IonInput, IonSelect, IonSelectOption, IonPopover, IonList, IonItem, IonRadioGroup, IonRadio, IonRange, IonSearchbar, IonSegment, IonSegmentButton, IonToggle, IonRippleEffect, IonAccordion, IonAccordionGroup, IonTabBar, IonTabButton, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonChip, IonNote, IonDatetimeButton, 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
- 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, laptopOutline, swapHorizontalOutline, notificationsOffOutline, alarmOutline, chatboxEllipsesOutline, checkmarkDoneOutline, cogOutline, shareSocialOutline, helpCircleOutline, menuOutline } from 'ionicons/icons';
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, laptopOutline, swapHorizontalOutline, notificationsOffOutline, alarmOutline, chatboxEllipsesOutline, checkmarkDoneOutline, cogOutline, shareSocialOutline, helpCircleOutline, menuOutline, stopCircleOutline, videocamOffOutline } from 'ionicons/icons';
29
29
  import { Browser } from '@capacitor/browser';
30
30
  import * as i1$6 from '@angular/platform-browser';
31
31
  import { DomSanitizer, Meta, Title } from '@angular/platform-browser';
@@ -49,12 +49,13 @@ import Compressor from 'compressorjs';
49
49
  import { Capacitor } from '@capacitor/core';
50
50
  import 'prismjs/components/prism-scss';
51
51
  import 'prismjs/components/prism-json';
52
+ import { BrowserMultiFormatReader } from '@zxing/browser';
52
53
 
53
54
  /**
54
55
  * Current version of valtech-components.
55
56
  * This is automatically updated during the publish process.
56
57
  */
57
- const VERSION = '2.0.1024';
58
+ const VERSION = '2.0.1026';
58
59
 
59
60
  // Control de estado de refresco (singleton a nivel de módulo)
60
61
  let isRefreshing = false;
@@ -49641,11 +49642,11 @@ const ORGANIZATION_VIEW_I18N = {
49641
49642
  importOpen: 'Importar',
49642
49643
  apiKeysOpen: 'Gestionar',
49643
49644
  apiKeysSectionTitle: 'Integraciones (API Keys)',
49644
- apiKeysSectionHint: 'También puedes operar tu organización vía API: crea una Client API Key org-scopeada para integraciones máquina-a-máquina (por ejemplo, dar de alta miembros en masa desde tu propio sistema).',
49645
+ apiKeysSectionHint: 'Conecta tus sistemas externos a esta organización vía API Key.',
49645
49646
  apiKeysMoreInfo: 'Más información',
49646
49647
  apiKeysInfoTitle: 'Integraciones por API',
49647
- apiKeysInfoSubtitle: 'Opera tu organización máquina-a-máquina',
49648
- apiKeysInfoContent: 'Una API Key te permite operar tu organización desde tus propios sistemas, sin entrar a la app: dar de alta usuarios, asignar roles, leer datos y automatizar flujos.\n\nCada key es org-scopeada y lleva solo los permisos que le asignes — concede el mínimo necesario. Puedes revocarla en cualquier momento.\n\nEl secreto se muestra una sola vez al crearla: guárdalo en un lugar seguro. Si lo pierdes, genera una nueva key y revoca la anterior.',
49648
+ apiKeysInfoSubtitle: '¿Qué puedes hacer con una API Key?',
49649
+ apiKeysInfoContent: 'Una API Key te permite automatizar operaciones en tu organización desde tus propios sistemas, sin abrir la app. Es ideal para integraciones máquina-a-máquina: sincronizar usuarios desde tu ERP, asignar roles en masa o consultar datos desde tus reportes internos.\n\nCon una key puedes dar de alta y gestionar miembros, asignar roles y permisos, leer datos de la organización y conectar flujos de trabajo existentes.\n\nCada key lleva solo los permisos que le asignes — concede el mínimo necesario y revócala en cualquier momento desde la sección Integraciones.\n\nImportante: el secreto se muestra una sola vez al crear la key. Guárdalo en un lugar seguro (gestor de secretos, variable de entorno). Si lo pierdes, genera una nueva key y revoca la anterior.',
49649
49650
  apiKeysInfoClose: 'Cerrar',
49650
49651
  orgsMoreInfo: 'Aprender más sobre organizaciones',
49651
49652
  orgsInfoTitle: '¿Qué son las organizaciones?',
@@ -49724,11 +49725,11 @@ const ORGANIZATION_VIEW_I18N = {
49724
49725
  importOpen: 'Import',
49725
49726
  apiKeysOpen: 'Manage',
49726
49727
  apiKeysSectionTitle: 'Integrations (API Keys)',
49727
- apiKeysSectionHint: 'You can also operate your organization via API: create an org-scoped Client API Key for machine-to-machine integrations (for example, bulk-provisioning members from your own system).',
49728
+ apiKeysSectionHint: 'Connect your external systems to this organization via API Key.',
49728
49729
  apiKeysMoreInfo: 'More information',
49729
49730
  apiKeysInfoTitle: 'API integrations',
49730
- apiKeysInfoSubtitle: 'Operate your organization machine-to-machine',
49731
- apiKeysInfoContent: 'An API Key lets you operate your organization from your own systems, without opening the app: provision users, assign roles, read data, and automate flows.\n\nEach key is org-scoped and carries only the permissions you assign — grant the minimum needed. You can revoke it at any time.\n\nThe secret is shown only once at creation: store it somewhere safe. If you lose it, create a new key and revoke the old one.',
49731
+ apiKeysInfoSubtitle: 'What can you do with an API Key?',
49732
+ apiKeysInfoContent: 'An API Key lets you automate operations in your organization from your own systems, without opening the app. It is ideal for machine-to-machine integrations: sync users from your ERP, bulk-assign roles, or query data for your internal reports.\n\nWith a key you can provision and manage members, assign roles and permissions, read organization data, and connect existing workflows.\n\nEach key carries only the permissions you assign — grant the minimum needed and revoke it at any time from the Integrations section.\n\nImportant: the secret is shown only once when the key is created. Store it somewhere safe (secret manager, environment variable). If you lose it, create a new key and revoke the old one.',
49732
49733
  apiKeysInfoClose: 'Close',
49733
49734
  orgsMoreInfo: 'Learn more about organizations',
49734
49735
  orgsInfoTitle: 'What are organizations?',
@@ -50381,29 +50382,27 @@ class OrganizationViewComponent {
50381
50382
 
50382
50383
  <div class="section-body">
50383
50384
  @if (loading()) {
50384
- <val-skeleton-layout [props]="{ preset: 'detail', rows: 4 }" />
50385
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 4 }" />
50385
50386
  } @else if (orgErrorState()) {
50386
50387
  <val-empty-state [props]="orgErrorState()!" />
50387
50388
  } @else {
50388
50389
  @if (org(); as o) {
50389
50390
  <div class="org-info-card">
50390
- <div class="org-info-field org-info-field--full">
50391
+ <div class="org-info-field">
50391
50392
  <span class="org-info-label">{{ tt('infoName') }}</span>
50392
50393
  <span class="org-info-value">{{ o.name }}</span>
50393
50394
  </div>
50394
- <div class="org-info-field org-info-field--full">
50395
+ <div class="org-info-field">
50395
50396
  <span class="org-info-label">{{ tt('infoDescription') }}</span>
50396
50397
  <span class="org-info-value org-info-value--muted">{{ o.description || '—' }}</span>
50397
50398
  </div>
50398
- <div class="org-info-row">
50399
- <div class="org-info-field">
50400
- <span class="org-info-label">{{ tt('infoPlan') }}</span>
50401
- <span class="plan-badge plan-badge--{{ o.plan }}">{{ planLabel() }}</span>
50402
- </div>
50403
- <div class="org-info-field">
50404
- <span class="org-info-label">{{ tt('infoType') }}</span>
50405
- <span class="org-info-value">{{ o.type }}</span>
50406
- </div>
50399
+ <div class="org-info-field">
50400
+ <span class="org-info-label">{{ tt('infoPlan') }}</span>
50401
+ <span class="plan-badge plan-badge--{{ o.plan }}">{{ planLabel() }}</span>
50402
+ </div>
50403
+ <div class="org-info-field">
50404
+ <span class="org-info-label">{{ tt('infoType') }}</span>
50405
+ <span class="org-info-value">{{ o.type }}</span>
50407
50406
  </div>
50408
50407
  </div>
50409
50408
  }
@@ -50629,7 +50628,7 @@ class OrganizationViewComponent {
50629
50628
  </section>
50630
50629
  }
50631
50630
  </div>
50632
- `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }] }); }
50631
+ `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field:last-child{border-bottom:none}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }, { kind: "directive", type: HasPermissionDirective, selector: "[valHasPermission]", inputs: ["valHasPermission"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: MemberCardComponent, selector: "val-member-card", inputs: ["props"], outputs: ["onAction"] }] }); }
50633
50632
  }
50634
50633
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrganizationViewComponent, decorators: [{
50635
50634
  type: Component,
@@ -50683,29 +50682,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
50683
50682
 
50684
50683
  <div class="section-body">
50685
50684
  @if (loading()) {
50686
- <val-skeleton-layout [props]="{ preset: 'detail', rows: 4 }" />
50685
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 4 }" />
50687
50686
  } @else if (orgErrorState()) {
50688
50687
  <val-empty-state [props]="orgErrorState()!" />
50689
50688
  } @else {
50690
50689
  @if (org(); as o) {
50691
50690
  <div class="org-info-card">
50692
- <div class="org-info-field org-info-field--full">
50691
+ <div class="org-info-field">
50693
50692
  <span class="org-info-label">{{ tt('infoName') }}</span>
50694
50693
  <span class="org-info-value">{{ o.name }}</span>
50695
50694
  </div>
50696
- <div class="org-info-field org-info-field--full">
50695
+ <div class="org-info-field">
50697
50696
  <span class="org-info-label">{{ tt('infoDescription') }}</span>
50698
50697
  <span class="org-info-value org-info-value--muted">{{ o.description || '—' }}</span>
50699
50698
  </div>
50700
- <div class="org-info-row">
50701
- <div class="org-info-field">
50702
- <span class="org-info-label">{{ tt('infoPlan') }}</span>
50703
- <span class="plan-badge plan-badge--{{ o.plan }}">{{ planLabel() }}</span>
50704
- </div>
50705
- <div class="org-info-field">
50706
- <span class="org-info-label">{{ tt('infoType') }}</span>
50707
- <span class="org-info-value">{{ o.type }}</span>
50708
- </div>
50699
+ <div class="org-info-field">
50700
+ <span class="org-info-label">{{ tt('infoPlan') }}</span>
50701
+ <span class="plan-badge plan-badge--{{ o.plan }}">{{ planLabel() }}</span>
50702
+ </div>
50703
+ <div class="org-info-field">
50704
+ <span class="org-info-label">{{ tt('infoType') }}</span>
50705
+ <span class="org-info-value">{{ o.type }}</span>
50709
50706
  </div>
50710
50707
  </div>
50711
50708
  }
@@ -50931,7 +50928,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
50931
50928
  </section>
50932
50929
  }
50933
50930
  </div>
50934
- `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field--full{width:100%}.org-info-field:last-child{border-bottom:none}.org-info-row{display:flex}.org-info-row .org-info-field{flex:1}.org-info-row .org-info-field:first-child{border-right:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"] }]
50931
+ `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.org-more-info-link{background:none;border:none;padding:4px 0;margin-top:4px;font-size:13px;font-weight:600;color:var(--ion-color-primary, #7026df);cursor:pointer;text-align:left}.page-header{margin-bottom:16px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-header-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.section-body{display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.row-actions--gap{display:flex;gap:8px}.invite-cta{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap}.invite-cta__text{display:flex;flex-direction:column;gap:4px;flex:1}.org-info-card{border-radius:14px;background:var(--ion-color-light, #f4f5f8);overflow:hidden}:host-context(body.dark) .org-info-card,:host-context(html.ion-palette-dark) .org-info-card,:host-context([data-theme=\"dark\"]) .org-info-card{background:#ffffff0d}.org-info-field{padding:12px 16px;display:flex;flex-direction:column;gap:4px;border-bottom:1px solid var(--val-border-color, rgba(0, 0, 0, .06))}.org-info-field:last-child{border-bottom:none}.org-info-label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--ion-color-medium)}.org-info-value{font-size:.95rem;font-weight:500;color:var(--ion-color-dark)}.org-info-value--muted{color:var(--ion-color-medium);font-weight:400}.plan-badge{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:20px;width:fit-content}.plan-badge--free{background:var(--ion-color-light-shade, #d7d8da);color:var(--ion-color-dark)}.plan-badge--pro{background:var(--ion-color-primary);color:#fff}.plan-badge--enterprise{background:#f5c542;color:#222}.members-list{display:flex;flex-direction:column;gap:8px}.members-show-more{background:none;border:none;color:var(--ion-color-primary);font-size:14px;font-weight:500;cursor:pointer;padding:8px 0}.rbac-debug{opacity:.7}.rbac-debug__body{display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:.78rem}.rbac-debug__row{display:flex;gap:8px;align-items:flex-start}.rbac-debug__label{color:var(--ion-color-medium);min-width:72px;flex-shrink:0}.rbac-debug__value{color:var(--ion-color-dark);word-break:break-all}.rbac-debug__value--perms{color:var(--ion-color-medium)}\n"] }]
50935
50932
  }], ctorParameters: () => [], propDecorators: { config: [{
50936
50933
  type: Input
50937
50934
  }] } });
@@ -65334,6 +65331,533 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
65334
65331
  type: Output
65335
65332
  }] } });
65336
65333
 
65334
+ /**
65335
+ * Defaults i18n (es/en) del `val-ticket-card`. Auto-registrados en el
65336
+ * constructor del componente (namespace `TicketCard`) — el consumer NUNCA tiene
65337
+ * que registrarlos. Override pasando los labels por props o registrando el
65338
+ * namespace antes de montar el componente.
65339
+ */
65340
+ const TICKET_CARD_I18N = {
65341
+ es: {
65342
+ folio: 'Folio',
65343
+ statusSold: 'Vendida',
65344
+ statusCheckedIn: 'Canjeada',
65345
+ download: 'Descargar',
65346
+ share: 'Compartir',
65347
+ },
65348
+ en: {
65349
+ folio: 'Folio',
65350
+ statusSold: 'Sold',
65351
+ statusCheckedIn: 'Checked in',
65352
+ download: 'Download',
65353
+ share: 'Share',
65354
+ },
65355
+ };
65356
+
65357
+ /**
65358
+ * val-ticket-card
65359
+ *
65360
+ * Tarjeta presentacional de una entrada de bingo: muestra el QR escaneable
65361
+ * (generado del `qrToken` opaco firmado vía `QrGeneratorService`), el folio, el
65362
+ * nombre del comprador (si hay) y un badge de estado (vendida / canjeada).
65363
+ *
65364
+ * Es la pieza que el vendedor le entrega al comprador tras la venta y que la
65365
+ * taquilla escanea para canjear. Object-first (`input()` signal), i18n
65366
+ * auto-registrado (namespace `TicketCard`). Estados negativos/neutros en gris
65367
+ * muted (convención del factory — sin rojo de alarma).
65368
+ *
65369
+ * @example
65370
+ * ```html
65371
+ * <val-ticket-card [props]="{ qrToken: ticket.qrToken, folio: ticket.folio,
65372
+ * buyerName: ticket.compradorNombre, status: 'sold', showShare: true }" />
65373
+ * ```
65374
+ */
65375
+ class TicketCardComponent {
65376
+ constructor() {
65377
+ /** Props object-first del componente. */
65378
+ this.props = input.required();
65379
+ this.qrService = inject(QrGeneratorService);
65380
+ this.i18n = inject(I18nService);
65381
+ /** QR generado (null mientras carga o si falló). */
65382
+ this.qr = signal(null);
65383
+ /** Falló la generación del QR → fallback al token corto. */
65384
+ this.failed = signal(false);
65385
+ this.status = computed(() => this.props().status ?? 'neutral');
65386
+ this.tokenShort = computed(() => {
65387
+ const tk = this.props().qrToken ?? '';
65388
+ return tk.length > 16 ? `${tk.slice(0, 16)}…` : tk;
65389
+ });
65390
+ this.folioText = computed(() => {
65391
+ this.i18n.lang();
65392
+ const folio = this.props().folio;
65393
+ if (folio === undefined || folio === null || folio === '')
65394
+ return '';
65395
+ const label = this.props().folioLabel ?? this.t('folio');
65396
+ return `${label} #${folio}`;
65397
+ });
65398
+ this.statusLabel = computed(() => {
65399
+ this.i18n.lang();
65400
+ const status = this.status();
65401
+ if (status === 'sold') {
65402
+ return this.props().statusSoldLabel ?? this.t('statusSold');
65403
+ }
65404
+ if (status === 'checkedIn') {
65405
+ return this.props().statusCheckedInLabel ?? this.t('statusCheckedIn');
65406
+ }
65407
+ return '';
65408
+ });
65409
+ if (!this.i18n.hasNamespace('TicketCard')) {
65410
+ this.i18n.registerContent('TicketCard', TICKET_CARD_I18N);
65411
+ }
65412
+ // Regenera el QR cuando cambia el token o el tamaño.
65413
+ effect(() => {
65414
+ const token = this.props().qrToken;
65415
+ const size = this.props().qrSize ?? 200;
65416
+ if (!token) {
65417
+ this.qr.set(null);
65418
+ this.failed.set(false);
65419
+ return;
65420
+ }
65421
+ void this.generate(token, size);
65422
+ }, { allowSignalWrites: true });
65423
+ }
65424
+ async generate(data, size) {
65425
+ this.failed.set(false);
65426
+ try {
65427
+ const result = await this.qrService.generate({
65428
+ data,
65429
+ width: size,
65430
+ height: size,
65431
+ margin: 1,
65432
+ dotsStyle: 'square',
65433
+ dotsColor: '#000000',
65434
+ backgroundColor: '#ffffff',
65435
+ errorCorrectionLevel: 'M',
65436
+ format: 'png',
65437
+ });
65438
+ this.qr.set(result);
65439
+ }
65440
+ catch {
65441
+ // Sin toast/throw — el fallback muestra el token corto. El consumer
65442
+ // sigue pudiendo canjear tipeando/escaneando si hace falta.
65443
+ this.qr.set(null);
65444
+ this.failed.set(true);
65445
+ }
65446
+ }
65447
+ t(key) {
65448
+ return this.i18n.t(key, 'TicketCard');
65449
+ }
65450
+ qrProps(q) {
65451
+ const p = this.props();
65452
+ return {
65453
+ qr: q,
65454
+ displaySize: p.qrSize ?? 200,
65455
+ showDownload: p.showDownload ?? false,
65456
+ showShare: p.showShare ?? false,
65457
+ showBorder: false,
65458
+ alt: this.folioText() || 'QR',
65459
+ downloadLabel: this.t('download'),
65460
+ shareLabel: this.t('share'),
65461
+ shareTitle: p.title || this.folioText() || 'QR',
65462
+ };
65463
+ }
65464
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TicketCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
65465
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: TicketCardComponent, isStandalone: true, selector: "val-ticket-card", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
65466
+ <div class="ticket-card">
65467
+ @if (props().title) {
65468
+ <div class="ticket-card__title">{{ props().title }}</div>
65469
+ }
65470
+
65471
+ <div class="ticket-card__qr">
65472
+ @if (qr(); as q) {
65473
+ <val-qr-code [props]="qrProps(q)" />
65474
+ } @else if (failed()) {
65475
+ <div class="ticket-card__qr-fallback">{{ tokenShort() }}</div>
65476
+ } @else {
65477
+ <div class="ticket-card__qr-loading">
65478
+ <ion-spinner name="crescent" />
65479
+ </div>
65480
+ }
65481
+ </div>
65482
+
65483
+ <div class="ticket-card__meta">
65484
+ @if (folioText(); as f) {
65485
+ <div class="ticket-card__folio">{{ f }}</div>
65486
+ }
65487
+ @if (props().buyerName) {
65488
+ <div class="ticket-card__buyer">{{ props().buyerName }}</div>
65489
+ }
65490
+ @if (statusLabel(); as s) {
65491
+ <span class="ticket-card__badge" [attr.data-status]="status()">{{ s }}</span>
65492
+ }
65493
+ </div>
65494
+ </div>
65495
+ `, isInline: true, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: QrCodeComponent, selector: "val-qr-code", inputs: ["props"], outputs: ["actionComplete", "imageLoad", "imageError"] }] }); }
65496
+ }
65497
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TicketCardComponent, decorators: [{
65498
+ type: Component,
65499
+ args: [{ selector: 'val-ticket-card', standalone: true, imports: [CommonModule, IonSpinner, QrCodeComponent], template: `
65500
+ <div class="ticket-card">
65501
+ @if (props().title) {
65502
+ <div class="ticket-card__title">{{ props().title }}</div>
65503
+ }
65504
+
65505
+ <div class="ticket-card__qr">
65506
+ @if (qr(); as q) {
65507
+ <val-qr-code [props]="qrProps(q)" />
65508
+ } @else if (failed()) {
65509
+ <div class="ticket-card__qr-fallback">{{ tokenShort() }}</div>
65510
+ } @else {
65511
+ <div class="ticket-card__qr-loading">
65512
+ <ion-spinner name="crescent" />
65513
+ </div>
65514
+ }
65515
+ </div>
65516
+
65517
+ <div class="ticket-card__meta">
65518
+ @if (folioText(); as f) {
65519
+ <div class="ticket-card__folio">{{ f }}</div>
65520
+ }
65521
+ @if (props().buyerName) {
65522
+ <div class="ticket-card__buyer">{{ props().buyerName }}</div>
65523
+ }
65524
+ @if (statusLabel(); as s) {
65525
+ <span class="ticket-card__badge" [attr.data-status]="status()">{{ s }}</span>
65526
+ }
65527
+ </div>
65528
+ </div>
65529
+ `, styles: ["@charset \"UTF-8\";:host{display:block}.ticket-card{display:flex;flex-direction:column;align-items:center;gap:12px;padding:20px;border:1px solid var(--ion-color-light-shade, #e0e0e0);border-radius:16px;background:var(--ion-card-background, #ffffff);max-width:320px;margin:0 auto}.ticket-card__title{font-size:1rem;font-weight:700;color:var(--ion-color-dark);text-align:center}.ticket-card__qr{display:flex;align-items:center;justify-content:center;min-height:200px}.ticket-card__qr-loading{display:flex;align-items:center;justify-content:center;width:200px;height:200px}.ticket-card__qr-fallback{font-family:monospace;font-size:.75rem;color:var(--ion-color-medium);word-break:break-all;text-align:center;padding:16px}.ticket-card__meta{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}.ticket-card__folio{font-size:1rem;font-weight:700;color:var(--ion-color-dark)}.ticket-card__buyer{font-size:.875rem;color:var(--ion-color-medium)}.ticket-card__badge{margin-top:4px;font-size:.75rem;font-weight:600;padding:3px 12px;border-radius:999px;background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff);white-space:nowrap}.ticket-card__badge[data-status=sold]{background:var(--ion-color-success, #2dd36f);color:var(--ion-color-success-contrast, #fff)}.ticket-card__badge[data-status=checkedIn]{background:var(--ion-color-medium);color:var(--ion-color-medium-contrast, #fff)}\n"] }]
65530
+ }], ctorParameters: () => [] });
65531
+
65532
+ /**
65533
+ * Defaults i18n (es/en) del `val-qr-scanner`. Auto-registrados en el
65534
+ * constructor (namespace `QrScanner`) — el consumer NUNCA tiene que
65535
+ * registrarlos. Override por props (start/stop) o registrando el namespace.
65536
+ */
65537
+ const QR_SCANNER_I18N = {
65538
+ es: {
65539
+ start: 'Iniciar cámara',
65540
+ stop: 'Detener',
65541
+ starting: 'Iniciando cámara…',
65542
+ hint: 'Apunta la cámara al código QR de la entrada.',
65543
+ cameraLabel: 'Cámara',
65544
+ denied: 'No se pudo acceder a la cámara. Revisa los permisos del navegador e inténtalo de nuevo.',
65545
+ noCamera: 'No se encontró ninguna cámara en este dispositivo.',
65546
+ error: 'Ocurrió un problema con la cámara. Inténtalo de nuevo.',
65547
+ },
65548
+ en: {
65549
+ start: 'Start camera',
65550
+ stop: 'Stop',
65551
+ starting: 'Starting camera…',
65552
+ hint: 'Point the camera at the ticket QR code.',
65553
+ cameraLabel: 'Camera',
65554
+ denied: 'Could not access the camera. Check your browser permissions and try again.',
65555
+ noCamera: 'No camera was found on this device.',
65556
+ error: 'Something went wrong with the camera. Please try again.',
65557
+ },
65558
+ };
65559
+
65560
+ addIcons({
65561
+ cameraOutline,
65562
+ stopCircleOutline,
65563
+ videocamOffOutline,
65564
+ warningOutline,
65565
+ });
65566
+ /**
65567
+ * val-qr-scanner
65568
+ *
65569
+ * Organism: scanner de códigos QR por cámara (`@zxing/browser` +
65570
+ * `@zxing/library`). Emite el texto decodificado por `(scanned)`.
65571
+ *
65572
+ * Maneja: permiso de cámara denegado (`denied`), ausencia de cámara
65573
+ * (`no-camera`), selector cuando hay varias cámaras, y botón start/stop. Hace
65574
+ * cleanup del stream en `ngOnDestroy`. i18n auto-registrado (namespace
65575
+ * `QrScanner`).
65576
+ *
65577
+ * Object-first (`@Input() props`) + un único `@Output() scanned`.
65578
+ *
65579
+ * @example
65580
+ * ```html
65581
+ * <val-qr-scanner [props]="{ continuous: true }" (scanned)="onScan($event)" />
65582
+ * ```
65583
+ */
65584
+ class QrScannerComponent {
65585
+ constructor() {
65586
+ this.props = {};
65587
+ /** Emite el texto decodificado del QR. */
65588
+ this.scanned = new EventEmitter();
65589
+ this.i18n = inject(I18nService);
65590
+ this.state = signal('idle');
65591
+ this.devices = signal([]);
65592
+ this.activeDeviceId = signal(undefined);
65593
+ this.reader = null;
65594
+ this.controls = null;
65595
+ // Anti-rebote: ignora la misma lectura repetida dentro de `dedupeMs`.
65596
+ this.lastValue = '';
65597
+ this.lastAt = 0;
65598
+ this.viewReady = false;
65599
+ if (!this.i18n.hasNamespace('QrScanner')) {
65600
+ this.i18n.registerContent('QrScanner', QR_SCANNER_I18N);
65601
+ }
65602
+ }
65603
+ ngAfterViewInit() {
65604
+ this.viewReady = true;
65605
+ if (this.props.autoStart) {
65606
+ void this.start();
65607
+ }
65608
+ }
65609
+ ngOnDestroy() {
65610
+ this.teardown();
65611
+ }
65612
+ t(key) {
65613
+ return this.i18n.t(key, 'QrScanner');
65614
+ }
65615
+ stateMessage() {
65616
+ switch (this.state()) {
65617
+ case 'denied':
65618
+ return this.t('denied');
65619
+ case 'no-camera':
65620
+ return this.t('noCamera');
65621
+ default:
65622
+ return this.t('error');
65623
+ }
65624
+ }
65625
+ deviceLabel(d) {
65626
+ return d.label || `${this.t('cameraLabel')} ${this.devices().indexOf(d) + 1}`;
65627
+ }
65628
+ async start(deviceId) {
65629
+ if (!this.viewReady)
65630
+ return;
65631
+ this.teardown();
65632
+ this.state.set('starting');
65633
+ try {
65634
+ this.reader = new BrowserMultiFormatReader();
65635
+ // Enumerar cámaras. Algunos navegadores solo dan labels tras conceder
65636
+ // permiso, así que esto puede devolver labels vacíos la 1ª vez.
65637
+ let cams = [];
65638
+ try {
65639
+ cams = await BrowserMultiFormatReader.listVideoInputDevices();
65640
+ }
65641
+ catch {
65642
+ cams = [];
65643
+ }
65644
+ this.devices.set(cams);
65645
+ // Preferir la trasera (environment) si el label lo sugiere.
65646
+ const target = deviceId ||
65647
+ this.activeDeviceId() ||
65648
+ cams.find(c => /back|rear|environment|trasera/i.test(c.label))?.deviceId ||
65649
+ cams[0]?.deviceId;
65650
+ this.activeDeviceId.set(target);
65651
+ this.controls = await this.reader.decodeFromVideoDevice(target, this.videoRef.nativeElement, result => {
65652
+ if (result) {
65653
+ this.handleResult(result.getText());
65654
+ }
65655
+ });
65656
+ this.state.set('scanning');
65657
+ }
65658
+ catch (err) {
65659
+ this.handleStartError(err);
65660
+ }
65661
+ }
65662
+ stop() {
65663
+ this.teardown();
65664
+ this.state.set('idle');
65665
+ }
65666
+ async onSelectDevice(deviceId) {
65667
+ if (deviceId && deviceId !== this.activeDeviceId()) {
65668
+ await this.start(deviceId);
65669
+ }
65670
+ }
65671
+ handleResult(text) {
65672
+ const now = Date.now();
65673
+ const dedupe = this.props.dedupeMs ?? 1500;
65674
+ if (text === this.lastValue && now - this.lastAt < dedupe) {
65675
+ return;
65676
+ }
65677
+ this.lastValue = text;
65678
+ this.lastAt = now;
65679
+ this.scanned.emit(text);
65680
+ // Modo no continuo: detener tras el primer match (la página reanuda si
65681
+ // quiere). `continuous` default true → seguir escaneando.
65682
+ if (this.props.continuous === false) {
65683
+ this.stop();
65684
+ }
65685
+ }
65686
+ handleStartError(err) {
65687
+ const name = err?.name ?? '';
65688
+ if (name === 'NotAllowedError' || name === 'SecurityError') {
65689
+ this.state.set('denied');
65690
+ }
65691
+ else if (name === 'NotFoundError' || name === 'OverconstrainedError') {
65692
+ this.state.set('no-camera');
65693
+ }
65694
+ else {
65695
+ this.state.set('error');
65696
+ }
65697
+ this.teardown(false);
65698
+ }
65699
+ /** Detiene el decode + libera el stream de la cámara. */
65700
+ teardown(resetState = true) {
65701
+ try {
65702
+ this.controls?.stop();
65703
+ }
65704
+ catch {
65705
+ // ignore
65706
+ }
65707
+ this.controls = null;
65708
+ const video = this.videoRef?.nativeElement;
65709
+ const stream = video?.srcObject;
65710
+ if (stream) {
65711
+ stream.getTracks().forEach(track => track.stop());
65712
+ video.srcObject = null;
65713
+ }
65714
+ this.reader = null;
65715
+ if (resetState) {
65716
+ this.lastValue = '';
65717
+ this.lastAt = 0;
65718
+ }
65719
+ }
65720
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: QrScannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
65721
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: QrScannerComponent, isStandalone: true, selector: "val-qr-scanner", inputs: { props: "props" }, outputs: { scanned: "scanned" }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true }], ngImport: i0, template: `
65722
+ <div class="qr-scanner">
65723
+ <div class="qr-scanner__viewport" [class.is-active]="state() === 'scanning'">
65724
+ <video #video class="qr-scanner__video" muted playsinline></video>
65725
+
65726
+ @if (state() === 'idle') {
65727
+ <div class="qr-scanner__overlay">
65728
+ <ion-icon name="camera-outline" class="qr-scanner__overlay-icon" />
65729
+ </div>
65730
+ }
65731
+
65732
+ @if (state() === 'starting') {
65733
+ <div class="qr-scanner__overlay">
65734
+ <ion-spinner name="crescent" />
65735
+ <p>{{ t('starting') }}</p>
65736
+ </div>
65737
+ }
65738
+
65739
+ @if (state() === 'scanning') {
65740
+ <div class="qr-scanner__frame"></div>
65741
+ }
65742
+ </div>
65743
+
65744
+ @if (state() === 'denied' || state() === 'no-camera' || state() === 'error') {
65745
+ <div class="qr-scanner__message">
65746
+ <ion-icon [name]="state() === 'no-camera' ? 'videocam-off-outline' : 'warning-outline'" />
65747
+ <span>{{ stateMessage() }}</span>
65748
+ </div>
65749
+ }
65750
+
65751
+ @if (state() === 'scanning' || state() === 'starting') {
65752
+ <p class="qr-scanner__hint">{{ t('hint') }}</p>
65753
+ }
65754
+
65755
+ @if (devices().length > 1 && state() === 'scanning') {
65756
+ <ion-select
65757
+ class="qr-scanner__select"
65758
+ [label]="t('cameraLabel')"
65759
+ labelPlacement="stacked"
65760
+ interface="popover"
65761
+ [value]="activeDeviceId()"
65762
+ (ionChange)="onSelectDevice($any($event).detail.value)"
65763
+ >
65764
+ @for (d of devices(); track d.deviceId) {
65765
+ <ion-select-option [value]="d.deviceId">{{ deviceLabel(d) }}</ion-select-option>
65766
+ }
65767
+ </ion-select>
65768
+ }
65769
+
65770
+ <div class="qr-scanner__actions">
65771
+ @if (state() === 'scanning' || state() === 'starting') {
65772
+ <ion-button fill="outline" color="dark" (click)="stop()">
65773
+ <ion-icon name="stop-circle-outline" slot="start" />
65774
+ {{ props.stopLabel || t('stop') }}
65775
+ </ion-button>
65776
+ } @else {
65777
+ <ion-button color="dark" (click)="start()">
65778
+ <ion-icon name="camera-outline" slot="start" />
65779
+ {{ props.startLabel || t('start') }}
65780
+ </ion-button>
65781
+ }
65782
+ </div>
65783
+ </div>
65784
+ `, isInline: true, styles: ["@charset \"UTF-8\";:host{display:block}.qr-scanner{display:flex;flex-direction:column;align-items:stretch;gap:12px;max-width:420px;margin:0 auto}.qr-scanner__viewport{position:relative;width:100%;aspect-ratio:1/1;border-radius:16px;overflow:hidden;background:var(--ion-color-dark, #1c1c1e);display:flex;align-items:center;justify-content:center}.qr-scanner__video{width:100%;height:100%;object-fit:cover;display:block}.qr-scanner__overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--ion-color-light, #f4f5f8)}.qr-scanner__overlay p{margin:0;font-size:.875rem}.qr-scanner__overlay-icon{font-size:3rem;opacity:.6}.qr-scanner__frame{position:absolute;inset:18%;border:3px solid var(--ion-color-primary, #ff00b2);border-radius:12px;box-shadow:0 0 0 9999px #00000040;pointer-events:none}.qr-scanner__message{display:flex;align-items:center;gap:8px;padding:12px 14px;border-radius:12px;background:var(--ion-color-light, #f4f5f8);color:var(--ion-color-medium, #6b6675);font-size:.875rem}.qr-scanner__message ion-icon{font-size:1.25rem;flex-shrink:0}.qr-scanner__hint{margin:0;text-align:center;font-size:.8125rem;color:var(--ion-color-medium, #6b6675)}.qr-scanner__select{--padding-start: 0}.qr-scanner__actions{display:flex;justify-content:center}.qr-scanner__actions ion-button{--border-radius: 999px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }] }); }
65785
+ }
65786
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: QrScannerComponent, decorators: [{
65787
+ type: Component,
65788
+ args: [{ selector: 'val-qr-scanner', standalone: true, imports: [CommonModule, IonButton, IonIcon, IonSpinner, IonSelect, IonSelectOption], template: `
65789
+ <div class="qr-scanner">
65790
+ <div class="qr-scanner__viewport" [class.is-active]="state() === 'scanning'">
65791
+ <video #video class="qr-scanner__video" muted playsinline></video>
65792
+
65793
+ @if (state() === 'idle') {
65794
+ <div class="qr-scanner__overlay">
65795
+ <ion-icon name="camera-outline" class="qr-scanner__overlay-icon" />
65796
+ </div>
65797
+ }
65798
+
65799
+ @if (state() === 'starting') {
65800
+ <div class="qr-scanner__overlay">
65801
+ <ion-spinner name="crescent" />
65802
+ <p>{{ t('starting') }}</p>
65803
+ </div>
65804
+ }
65805
+
65806
+ @if (state() === 'scanning') {
65807
+ <div class="qr-scanner__frame"></div>
65808
+ }
65809
+ </div>
65810
+
65811
+ @if (state() === 'denied' || state() === 'no-camera' || state() === 'error') {
65812
+ <div class="qr-scanner__message">
65813
+ <ion-icon [name]="state() === 'no-camera' ? 'videocam-off-outline' : 'warning-outline'" />
65814
+ <span>{{ stateMessage() }}</span>
65815
+ </div>
65816
+ }
65817
+
65818
+ @if (state() === 'scanning' || state() === 'starting') {
65819
+ <p class="qr-scanner__hint">{{ t('hint') }}</p>
65820
+ }
65821
+
65822
+ @if (devices().length > 1 && state() === 'scanning') {
65823
+ <ion-select
65824
+ class="qr-scanner__select"
65825
+ [label]="t('cameraLabel')"
65826
+ labelPlacement="stacked"
65827
+ interface="popover"
65828
+ [value]="activeDeviceId()"
65829
+ (ionChange)="onSelectDevice($any($event).detail.value)"
65830
+ >
65831
+ @for (d of devices(); track d.deviceId) {
65832
+ <ion-select-option [value]="d.deviceId">{{ deviceLabel(d) }}</ion-select-option>
65833
+ }
65834
+ </ion-select>
65835
+ }
65836
+
65837
+ <div class="qr-scanner__actions">
65838
+ @if (state() === 'scanning' || state() === 'starting') {
65839
+ <ion-button fill="outline" color="dark" (click)="stop()">
65840
+ <ion-icon name="stop-circle-outline" slot="start" />
65841
+ {{ props.stopLabel || t('stop') }}
65842
+ </ion-button>
65843
+ } @else {
65844
+ <ion-button color="dark" (click)="start()">
65845
+ <ion-icon name="camera-outline" slot="start" />
65846
+ {{ props.startLabel || t('start') }}
65847
+ </ion-button>
65848
+ }
65849
+ </div>
65850
+ </div>
65851
+ `, styles: ["@charset \"UTF-8\";:host{display:block}.qr-scanner{display:flex;flex-direction:column;align-items:stretch;gap:12px;max-width:420px;margin:0 auto}.qr-scanner__viewport{position:relative;width:100%;aspect-ratio:1/1;border-radius:16px;overflow:hidden;background:var(--ion-color-dark, #1c1c1e);display:flex;align-items:center;justify-content:center}.qr-scanner__video{width:100%;height:100%;object-fit:cover;display:block}.qr-scanner__overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--ion-color-light, #f4f5f8)}.qr-scanner__overlay p{margin:0;font-size:.875rem}.qr-scanner__overlay-icon{font-size:3rem;opacity:.6}.qr-scanner__frame{position:absolute;inset:18%;border:3px solid var(--ion-color-primary, #ff00b2);border-radius:12px;box-shadow:0 0 0 9999px #00000040;pointer-events:none}.qr-scanner__message{display:flex;align-items:center;gap:8px;padding:12px 14px;border-radius:12px;background:var(--ion-color-light, #f4f5f8);color:var(--ion-color-medium, #6b6675);font-size:.875rem}.qr-scanner__message ion-icon{font-size:1.25rem;flex-shrink:0}.qr-scanner__hint{margin:0;text-align:center;font-size:.8125rem;color:var(--ion-color-medium, #6b6675)}.qr-scanner__select{--padding-start: 0}.qr-scanner__actions{display:flex;justify-content:center}.qr-scanner__actions ion-button{--border-radius: 999px}\n"] }]
65852
+ }], ctorParameters: () => [], propDecorators: { props: [{
65853
+ type: Input
65854
+ }], scanned: [{
65855
+ type: Output
65856
+ }], videoRef: [{
65857
+ type: ViewChild,
65858
+ args: ['video']
65859
+ }] } });
65860
+
65337
65861
  /*
65338
65862
  * Public API Surface of valtech-components
65339
65863
  */
@@ -65343,5 +65867,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
65343
65867
  * Generated bundle index. Do not edit.
65344
65868
  */
65345
65869
 
65346
- 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, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, 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, CreateOrgModalComponent, 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, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, 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, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, 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, PermissionCatalogService, PermissionSelectorComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, 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, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, 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, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, 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_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPermissionLabeler, 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, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
65870
+ 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, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, 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, CreateOrgModalComponent, 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, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmailInputComponent, EmptyStateComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HasPermissionDirective, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INFO_CARD_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoCardComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, 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, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, METRIC_CARD_DEFAULTS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MenuComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, 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, PermissionCatalogService, PermissionSelectorComponent, PermissionsViewComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, 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, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SettingsHubComponent, 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, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketCardComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, 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_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VERSION, ValtechErrorService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, collections, connectPageRefresh, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createPermissionLabeler, 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, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAuth, provideValtechAuthInterceptor, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, query, renderPatternSvgInner, replaceSpecialChars, resolveColor$1 as resolveColor, resolveInputDefaultValue, resolveWebBaseUrl, roleGuard, storagePaths, superAdminGuard, toArticle };
65347
65871
  //# sourceMappingURL=valtech-components.mjs.map