valtech-components 2.0.681 → 2.0.682
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.
- package/esm2022/lib/components/molecules/image-crop/image-crop.component.mjs +174 -0
- package/esm2022/lib/components/molecules/image-crop/index.mjs +2 -0
- package/esm2022/lib/components/organisms/avatar-upload/avatar-upload.component.mjs +345 -0
- package/esm2022/lib/components/organisms/avatar-upload/types.mjs +15 -0
- package/esm2022/lib/components/templates/docs-page/docs-page.component.mjs +35 -4
- package/esm2022/lib/components/templates/docs-page/types.mjs +1 -1
- package/esm2022/lib/services/auth/auth.service.mjs +11 -2
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/services/image/image.service.mjs +244 -0
- package/esm2022/lib/services/image/index.mjs +3 -0
- package/esm2022/lib/services/image/types.mjs +13 -0
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +7 -1
- package/fesm2022/valtech-components.mjs +815 -7
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/image-crop/image-crop.component.d.ts +59 -0
- package/lib/components/molecules/image-crop/index.d.ts +1 -0
- package/lib/components/organisms/avatar-upload/avatar-upload.component.d.ts +82 -0
- package/lib/components/organisms/avatar-upload/types.d.ts +62 -0
- package/lib/components/templates/docs-page/docs-page.component.d.ts +3 -0
- package/lib/components/templates/docs-page/types.d.ts +39 -0
- package/lib/services/auth/auth.service.d.ts +6 -1
- package/lib/services/auth/types.d.ts +18 -0
- package/lib/services/image/image.service.d.ts +76 -0
- package/lib/services/image/index.d.ts +2 -0
- package/lib/services/image/types.d.ts +74 -0
- package/lib/version.d.ts +1 -1
- package/package.json +2 -1
- package/public-api.d.ts +4 -0
- package/src/lib/services/firebase/firebase-messaging-sw.js +134 -0
|
@@ -5,7 +5,7 @@ import { IonAvatar, IonCard, IonIcon, IonButton, IonSpinner, IonText, IonModal,
|
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
6
6
|
import { CommonModule, NgStyle, NgFor, isPlatformBrowser, NgClass } from '@angular/common';
|
|
7
7
|
import { addIcons } from 'ionicons';
|
|
8
|
-
import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, settings, settingsOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notifications, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, home, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, logoGoogle, createOutline, trashOutline, playOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, removeOutline, 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, shuffleOutline, logoWhatsapp, paperPlaneOutline, mailOutline, trophyOutline, ticketOutline, giftOutline, personOutline, ellipsisVertical, closeCircle, alertCircle, logoApple, logoMicrosoft, linkOutline, unlinkOutline, chevronBackOutline, sendOutline, chatbubbleEllipsesOutline, swapVerticalOutline, chevronUpOutline, documentOutline, searchOutline, cartOutline, chatbubble, compass, compassOutline, gridOutline, listOutline, folderOutline, documents, documentsOutline, statsChart, statsChartOutline, bugOutline, bulbOutline, closeCircleOutline, menuOutline } from 'ionicons/icons';
|
|
8
|
+
import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, settings, settingsOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notifications, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, home, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, logoGoogle, createOutline, trashOutline, playOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, removeOutline, 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, shuffleOutline, logoWhatsapp, paperPlaneOutline, mailOutline, trophyOutline, ticketOutline, giftOutline, personOutline, ellipsisVertical, closeCircle, alertCircle, logoApple, logoMicrosoft, linkOutline, unlinkOutline, chevronBackOutline, sendOutline, chatbubbleEllipsesOutline, swapVerticalOutline, chevronUpOutline, documentOutline, searchOutline, cartOutline, chatbubble, compass, compassOutline, gridOutline, listOutline, folderOutline, documents, documentsOutline, statsChart, statsChartOutline, cameraOutline, bugOutline, bulbOutline, closeCircleOutline, menuOutline } from 'ionicons/icons';
|
|
9
9
|
import * as i1$1 from '@angular/router';
|
|
10
10
|
import { Router, NavigationEnd, RouterLink, RouterOutlet, RouterModule } from '@angular/router';
|
|
11
11
|
import { Browser } from '@capacitor/browser';
|
|
@@ -39,6 +39,7 @@ import * as i1$7 from '@angular/fire/storage';
|
|
|
39
39
|
import { provideStorage, getStorage, connectStorageEmulator, ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, listAll } from '@angular/fire/storage';
|
|
40
40
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
41
41
|
import { filter, map as map$1, catchError as catchError$1, tap, switchMap as switchMap$1, finalize, take, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
42
|
+
import { ImageCropperComponent } from 'ngx-image-cropper';
|
|
42
43
|
import * as i1$8 from '@angular/common/http';
|
|
43
44
|
import { provideHttpClient, withInterceptors, HttpClient } from '@angular/common/http';
|
|
44
45
|
import { Capacitor } from '@capacitor/core';
|
|
@@ -49,7 +50,7 @@ import 'prismjs/components/prism-json';
|
|
|
49
50
|
* Current version of valtech-components.
|
|
50
51
|
* This is automatically updated during the publish process.
|
|
51
52
|
*/
|
|
52
|
-
const VERSION = '2.0.
|
|
53
|
+
const VERSION = '2.0.682';
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* Servicio para gestionar presets de componentes.
|
|
@@ -21196,6 +21197,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
21196
21197
|
type: Input
|
|
21197
21198
|
}] } });
|
|
21198
21199
|
|
|
21200
|
+
/**
|
|
21201
|
+
* ImageCropComponent
|
|
21202
|
+
*
|
|
21203
|
+
* A modal-ready component for cropping images with a specified aspect ratio.
|
|
21204
|
+
* Uses ngx-image-cropper internally and provides a simple interface.
|
|
21205
|
+
*
|
|
21206
|
+
* @example Inside an ion-modal
|
|
21207
|
+
* ```html
|
|
21208
|
+
* <ion-modal [isOpen]="showCropModal">
|
|
21209
|
+
* <ng-template>
|
|
21210
|
+
* <val-image-crop
|
|
21211
|
+
* [image]="selectedFile"
|
|
21212
|
+
* [aspectRatio]="1"
|
|
21213
|
+
* [roundCropper]="true"
|
|
21214
|
+
* (cropComplete)="onCropComplete($event)"
|
|
21215
|
+
* (cancel)="showCropModal = false"
|
|
21216
|
+
* />
|
|
21217
|
+
* </ng-template>
|
|
21218
|
+
* </ion-modal>
|
|
21219
|
+
* ```
|
|
21220
|
+
*/
|
|
21221
|
+
class ImageCropComponent {
|
|
21222
|
+
constructor() {
|
|
21223
|
+
this.i18n = inject(I18nService);
|
|
21224
|
+
/** Image file to crop */
|
|
21225
|
+
this.image = input.required();
|
|
21226
|
+
/** Aspect ratio (1 for square, 16/9 for widescreen, etc.) */
|
|
21227
|
+
this.aspectRatio = input(1);
|
|
21228
|
+
/** Use round cropper (for avatars) */
|
|
21229
|
+
this.roundCropper = input(true);
|
|
21230
|
+
/** Resize output to specific width (0 = no resize) */
|
|
21231
|
+
this.resizeToWidth = input(0);
|
|
21232
|
+
/** i18n namespace for labels */
|
|
21233
|
+
this.i18nNamespace = input('ImageCrop');
|
|
21234
|
+
/** Emitted when crop is confirmed with the cropped blob */
|
|
21235
|
+
this.cropComplete = new EventEmitter();
|
|
21236
|
+
/** Emitted when user cancels the crop */
|
|
21237
|
+
this.cancel = new EventEmitter();
|
|
21238
|
+
/** Emitted when image fails to load */
|
|
21239
|
+
this.loadFailed = new EventEmitter();
|
|
21240
|
+
/** Internal signal for cropped blob */
|
|
21241
|
+
this.croppedBlob = signal(null);
|
|
21242
|
+
/** Computed text for cancel button */
|
|
21243
|
+
this.cancelText = computed(() => {
|
|
21244
|
+
this.i18n.lang(); // Track language changes
|
|
21245
|
+
return this.i18n.t('cancel', 'Common') || 'Cancelar';
|
|
21246
|
+
});
|
|
21247
|
+
/** Computed text for confirm button */
|
|
21248
|
+
this.confirmText = computed(() => {
|
|
21249
|
+
this.i18n.lang();
|
|
21250
|
+
return this.i18n.t('confirm', 'Common') || 'Confirmar';
|
|
21251
|
+
});
|
|
21252
|
+
/** Computed text for title */
|
|
21253
|
+
this.titleText = computed(() => {
|
|
21254
|
+
this.i18n.lang();
|
|
21255
|
+
return this.i18n.t('cropImage', this.i18nNamespace()) || 'Recortar imagen';
|
|
21256
|
+
});
|
|
21257
|
+
}
|
|
21258
|
+
/** Handle crop event from ngx-image-cropper */
|
|
21259
|
+
onImageCropped(event) {
|
|
21260
|
+
if (event.blob) {
|
|
21261
|
+
this.croppedBlob.set(event.blob);
|
|
21262
|
+
}
|
|
21263
|
+
}
|
|
21264
|
+
/** Confirm and emit the cropped blob */
|
|
21265
|
+
confirmCrop() {
|
|
21266
|
+
const blob = this.croppedBlob();
|
|
21267
|
+
if (blob) {
|
|
21268
|
+
this.cropComplete.emit(blob);
|
|
21269
|
+
}
|
|
21270
|
+
}
|
|
21271
|
+
/** Handle load failure */
|
|
21272
|
+
onLoadFailed() {
|
|
21273
|
+
this.loadFailed.emit();
|
|
21274
|
+
}
|
|
21275
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageCropComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
21276
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: ImageCropComponent, isStandalone: true, selector: "val-image-crop", inputs: { image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: true, transformFunction: null }, aspectRatio: { classPropertyName: "aspectRatio", publicName: "aspectRatio", isSignal: true, isRequired: false, transformFunction: null }, roundCropper: { classPropertyName: "roundCropper", publicName: "roundCropper", isSignal: true, isRequired: false, transformFunction: null }, resizeToWidth: { classPropertyName: "resizeToWidth", publicName: "resizeToWidth", isSignal: true, isRequired: false, transformFunction: null }, i18nNamespace: { classPropertyName: "i18nNamespace", publicName: "i18nNamespace", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cropComplete: "cropComplete", cancel: "cancel", loadFailed: "loadFailed" }, ngImport: i0, template: `
|
|
21277
|
+
<ion-header>
|
|
21278
|
+
<ion-toolbar>
|
|
21279
|
+
<ion-buttons slot="start">
|
|
21280
|
+
<ion-button (click)="cancel.emit()" color="medium">
|
|
21281
|
+
{{ cancelText() }}
|
|
21282
|
+
</ion-button>
|
|
21283
|
+
</ion-buttons>
|
|
21284
|
+
<ion-title>{{ titleText() }}</ion-title>
|
|
21285
|
+
<ion-buttons slot="end">
|
|
21286
|
+
<ion-button
|
|
21287
|
+
(click)="confirmCrop()"
|
|
21288
|
+
color="primary"
|
|
21289
|
+
[strong]="true"
|
|
21290
|
+
[disabled]="!croppedBlob()"
|
|
21291
|
+
>
|
|
21292
|
+
{{ confirmText() }}
|
|
21293
|
+
</ion-button>
|
|
21294
|
+
</ion-buttons>
|
|
21295
|
+
</ion-toolbar>
|
|
21296
|
+
</ion-header>
|
|
21297
|
+
|
|
21298
|
+
<ion-content class="image-crop-content">
|
|
21299
|
+
<image-cropper
|
|
21300
|
+
[imageFile]="image()"
|
|
21301
|
+
[aspectRatio]="aspectRatio()"
|
|
21302
|
+
[maintainAspectRatio]="true"
|
|
21303
|
+
[roundCropper]="roundCropper()"
|
|
21304
|
+
[resizeToWidth]="resizeToWidth()"
|
|
21305
|
+
format="jpeg"
|
|
21306
|
+
outputType="blob"
|
|
21307
|
+
(imageCropped)="onImageCropped($event)"
|
|
21308
|
+
(loadImageFailed)="onLoadFailed()"
|
|
21309
|
+
/>
|
|
21310
|
+
</ion-content>
|
|
21311
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.image-crop-content{--background: var(--ion-color-dark)}.image-crop-content::part(scroll){display:flex;flex-direction:column}image-cropper{--cropper-outline-color: rgba(255, 255, 255, .3);--cropper-background-color: var(--ion-color-dark);flex:1;height:100%;max-height:calc(100vh - 56px)}::ng-deep .ngx-ic-component{height:100%!important}::ng-deep .ngx-ic-source-image{max-height:100%!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { 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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }] }); }
|
|
21312
|
+
}
|
|
21313
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageCropComponent, decorators: [{
|
|
21314
|
+
type: Component,
|
|
21315
|
+
args: [{ selector: 'val-image-crop', standalone: true, imports: [
|
|
21316
|
+
CommonModule,
|
|
21317
|
+
IonHeader,
|
|
21318
|
+
IonToolbar,
|
|
21319
|
+
IonTitle,
|
|
21320
|
+
IonButtons,
|
|
21321
|
+
IonButton,
|
|
21322
|
+
IonContent,
|
|
21323
|
+
ImageCropperComponent,
|
|
21324
|
+
], template: `
|
|
21325
|
+
<ion-header>
|
|
21326
|
+
<ion-toolbar>
|
|
21327
|
+
<ion-buttons slot="start">
|
|
21328
|
+
<ion-button (click)="cancel.emit()" color="medium">
|
|
21329
|
+
{{ cancelText() }}
|
|
21330
|
+
</ion-button>
|
|
21331
|
+
</ion-buttons>
|
|
21332
|
+
<ion-title>{{ titleText() }}</ion-title>
|
|
21333
|
+
<ion-buttons slot="end">
|
|
21334
|
+
<ion-button
|
|
21335
|
+
(click)="confirmCrop()"
|
|
21336
|
+
color="primary"
|
|
21337
|
+
[strong]="true"
|
|
21338
|
+
[disabled]="!croppedBlob()"
|
|
21339
|
+
>
|
|
21340
|
+
{{ confirmText() }}
|
|
21341
|
+
</ion-button>
|
|
21342
|
+
</ion-buttons>
|
|
21343
|
+
</ion-toolbar>
|
|
21344
|
+
</ion-header>
|
|
21345
|
+
|
|
21346
|
+
<ion-content class="image-crop-content">
|
|
21347
|
+
<image-cropper
|
|
21348
|
+
[imageFile]="image()"
|
|
21349
|
+
[aspectRatio]="aspectRatio()"
|
|
21350
|
+
[maintainAspectRatio]="true"
|
|
21351
|
+
[roundCropper]="roundCropper()"
|
|
21352
|
+
[resizeToWidth]="resizeToWidth()"
|
|
21353
|
+
format="jpeg"
|
|
21354
|
+
outputType="blob"
|
|
21355
|
+
(imageCropped)="onImageCropped($event)"
|
|
21356
|
+
(loadImageFailed)="onLoadFailed()"
|
|
21357
|
+
/>
|
|
21358
|
+
</ion-content>
|
|
21359
|
+
`, styles: [":host{display:flex;flex-direction:column;height:100%}.image-crop-content{--background: var(--ion-color-dark)}.image-crop-content::part(scroll){display:flex;flex-direction:column}image-cropper{--cropper-outline-color: rgba(255, 255, 255, .3);--cropper-background-color: var(--ion-color-dark);flex:1;height:100%;max-height:calc(100vh - 56px)}::ng-deep .ngx-ic-component{height:100%!important}::ng-deep .ngx-ic-source-image{max-height:100%!important}\n"] }]
|
|
21360
|
+
}], propDecorators: { cropComplete: [{
|
|
21361
|
+
type: Output
|
|
21362
|
+
}], cancel: [{
|
|
21363
|
+
type: Output
|
|
21364
|
+
}], loadFailed: [{
|
|
21365
|
+
type: Output
|
|
21366
|
+
}] } });
|
|
21367
|
+
|
|
21199
21368
|
/**
|
|
21200
21369
|
* Configuración de espaciado predefinida
|
|
21201
21370
|
*/
|
|
@@ -30585,6 +30754,15 @@ class AuthService {
|
|
|
30585
30754
|
.put(`${this.baseUrl}/profile`, request)
|
|
30586
30755
|
.pipe(catchError$1(error => this.handleAuthError(error)));
|
|
30587
30756
|
}
|
|
30757
|
+
/**
|
|
30758
|
+
* Actualiza el avatar del usuario en el backend.
|
|
30759
|
+
* Nota: El estado local del avatar se maneja a través de getProfile().
|
|
30760
|
+
*/
|
|
30761
|
+
updateAvatar(request) {
|
|
30762
|
+
return this.http
|
|
30763
|
+
.put(`${this.baseUrl}/profile/avatar`, request)
|
|
30764
|
+
.pipe(catchError$1(error => this.handleAuthError(error)));
|
|
30765
|
+
}
|
|
30588
30766
|
// =============================================
|
|
30589
30767
|
// RECUPERACIÓN DE CONTRASEÑA
|
|
30590
30768
|
// =============================================
|
|
@@ -30707,7 +30885,7 @@ class AuthService {
|
|
|
30707
30885
|
*/
|
|
30708
30886
|
updateHandle(handle) {
|
|
30709
30887
|
return this.http
|
|
30710
|
-
.put(`${this.baseUrl}/handle`, { handle })
|
|
30888
|
+
.put(`${this.baseUrl}/profile/handle`, { handle })
|
|
30711
30889
|
.pipe(catchError$1(error => this.handleAuthError(error)));
|
|
30712
30890
|
}
|
|
30713
30891
|
/**
|
|
@@ -33501,6 +33679,607 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
33501
33679
|
type: Output
|
|
33502
33680
|
}] } });
|
|
33503
33681
|
|
|
33682
|
+
/**
|
|
33683
|
+
* Default values for image processing
|
|
33684
|
+
*/
|
|
33685
|
+
const IMAGE_DEFAULTS = {
|
|
33686
|
+
maxWidth: 800,
|
|
33687
|
+
maxHeight: 800,
|
|
33688
|
+
quality: 0.8,
|
|
33689
|
+
mimeType: 'image/jpeg',
|
|
33690
|
+
maxSize: 10 * 1024 * 1024, // 10MB
|
|
33691
|
+
allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
|
|
33692
|
+
thumbnailSize: 150,
|
|
33693
|
+
};
|
|
33694
|
+
|
|
33695
|
+
/**
|
|
33696
|
+
* ImageService
|
|
33697
|
+
*
|
|
33698
|
+
* Service for image processing including compression, thumbnails, cropping and validation.
|
|
33699
|
+
* Uses HTML Canvas for all operations - no external dependencies.
|
|
33700
|
+
*
|
|
33701
|
+
* @example
|
|
33702
|
+
* ```typescript
|
|
33703
|
+
* const imageService = inject(ImageService);
|
|
33704
|
+
*
|
|
33705
|
+
* // Compress an image
|
|
33706
|
+
* const compressed = await imageService.compress(file, { maxWidth: 800, quality: 0.8 });
|
|
33707
|
+
*
|
|
33708
|
+
* // Generate thumbnail
|
|
33709
|
+
* const thumb = await imageService.thumbnail(file, 150);
|
|
33710
|
+
*
|
|
33711
|
+
* // Validate before processing
|
|
33712
|
+
* const validation = imageService.validate(file, { maxSize: 5 * 1024 * 1024 });
|
|
33713
|
+
* if (!validation.valid) {
|
|
33714
|
+
* console.error(validation.message);
|
|
33715
|
+
* }
|
|
33716
|
+
* ```
|
|
33717
|
+
*/
|
|
33718
|
+
class ImageService {
|
|
33719
|
+
/**
|
|
33720
|
+
* Compress an image maintaining aspect ratio
|
|
33721
|
+
* @param file - File or Blob to compress
|
|
33722
|
+
* @param options - Compression options
|
|
33723
|
+
* @returns Promise with processed image data
|
|
33724
|
+
*/
|
|
33725
|
+
async compress(file, options) {
|
|
33726
|
+
const opts = {
|
|
33727
|
+
maxWidth: options?.maxWidth ?? IMAGE_DEFAULTS.maxWidth,
|
|
33728
|
+
maxHeight: options?.maxHeight ?? IMAGE_DEFAULTS.maxHeight,
|
|
33729
|
+
quality: options?.quality ?? IMAGE_DEFAULTS.quality,
|
|
33730
|
+
mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
|
|
33731
|
+
};
|
|
33732
|
+
const img = await this.loadImage(file);
|
|
33733
|
+
const { width, height } = this.calculateDimensions(img.width, img.height, opts.maxWidth, opts.maxHeight);
|
|
33734
|
+
const canvas = document.createElement('canvas');
|
|
33735
|
+
canvas.width = width;
|
|
33736
|
+
canvas.height = height;
|
|
33737
|
+
const ctx = canvas.getContext('2d');
|
|
33738
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
33739
|
+
const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
|
|
33740
|
+
const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
|
|
33741
|
+
return {
|
|
33742
|
+
blob,
|
|
33743
|
+
dataUrl,
|
|
33744
|
+
width,
|
|
33745
|
+
height,
|
|
33746
|
+
size: blob.size,
|
|
33747
|
+
};
|
|
33748
|
+
}
|
|
33749
|
+
/**
|
|
33750
|
+
* Generate a square thumbnail from an image
|
|
33751
|
+
* @param file - File or Blob to process
|
|
33752
|
+
* @param size - Thumbnail size in pixels (default: 150)
|
|
33753
|
+
* @returns Promise with processed thumbnail
|
|
33754
|
+
*/
|
|
33755
|
+
async thumbnail(file, size) {
|
|
33756
|
+
const thumbSize = size ?? IMAGE_DEFAULTS.thumbnailSize;
|
|
33757
|
+
const img = await this.loadImage(file);
|
|
33758
|
+
// Calculate square crop from center
|
|
33759
|
+
const minDim = Math.min(img.width, img.height);
|
|
33760
|
+
const cropX = (img.width - minDim) / 2;
|
|
33761
|
+
const cropY = (img.height - minDim) / 2;
|
|
33762
|
+
const canvas = document.createElement('canvas');
|
|
33763
|
+
canvas.width = thumbSize;
|
|
33764
|
+
canvas.height = thumbSize;
|
|
33765
|
+
const ctx = canvas.getContext('2d');
|
|
33766
|
+
ctx.drawImage(img, cropX, cropY, minDim, minDim, 0, 0, thumbSize, thumbSize);
|
|
33767
|
+
const blob = await this.canvasToBlob(canvas, IMAGE_DEFAULTS.mimeType, 0.7 // Lower quality for thumbnails
|
|
33768
|
+
);
|
|
33769
|
+
const dataUrl = canvas.toDataURL(IMAGE_DEFAULTS.mimeType, 0.7);
|
|
33770
|
+
return {
|
|
33771
|
+
blob,
|
|
33772
|
+
dataUrl,
|
|
33773
|
+
width: thumbSize,
|
|
33774
|
+
height: thumbSize,
|
|
33775
|
+
size: blob.size,
|
|
33776
|
+
};
|
|
33777
|
+
}
|
|
33778
|
+
/**
|
|
33779
|
+
* Crop an image with specific coordinates
|
|
33780
|
+
* @param file - File or Blob to crop
|
|
33781
|
+
* @param cropData - Crop coordinates and dimensions
|
|
33782
|
+
* @param options - Optional compression options for output
|
|
33783
|
+
* @returns Promise with cropped image
|
|
33784
|
+
*/
|
|
33785
|
+
async crop(file, cropData, options) {
|
|
33786
|
+
const img = await this.loadImage(file);
|
|
33787
|
+
const opts = {
|
|
33788
|
+
quality: options?.quality ?? IMAGE_DEFAULTS.quality,
|
|
33789
|
+
mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
|
|
33790
|
+
};
|
|
33791
|
+
const canvas = document.createElement('canvas');
|
|
33792
|
+
canvas.width = cropData.width;
|
|
33793
|
+
canvas.height = cropData.height;
|
|
33794
|
+
const ctx = canvas.getContext('2d');
|
|
33795
|
+
ctx.drawImage(img, cropData.x, cropData.y, cropData.width, cropData.height, 0, 0, cropData.width, cropData.height);
|
|
33796
|
+
// Apply max dimensions if specified
|
|
33797
|
+
if (options?.maxWidth || options?.maxHeight) {
|
|
33798
|
+
return this.compress(await this.canvasToBlob(canvas, opts.mimeType, 1), options);
|
|
33799
|
+
}
|
|
33800
|
+
const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
|
|
33801
|
+
const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
|
|
33802
|
+
return {
|
|
33803
|
+
blob,
|
|
33804
|
+
dataUrl,
|
|
33805
|
+
width: cropData.width,
|
|
33806
|
+
height: cropData.height,
|
|
33807
|
+
size: blob.size,
|
|
33808
|
+
};
|
|
33809
|
+
}
|
|
33810
|
+
/**
|
|
33811
|
+
* Validate an image file before processing
|
|
33812
|
+
* @param file - File to validate
|
|
33813
|
+
* @param options - Validation options
|
|
33814
|
+
* @returns Validation result with error details if invalid
|
|
33815
|
+
*/
|
|
33816
|
+
validate(file, options) {
|
|
33817
|
+
const opts = {
|
|
33818
|
+
maxSize: options?.maxSize ?? IMAGE_DEFAULTS.maxSize,
|
|
33819
|
+
allowedTypes: options?.allowedTypes ?? IMAGE_DEFAULTS.allowedTypes,
|
|
33820
|
+
};
|
|
33821
|
+
// Check file type
|
|
33822
|
+
if (!opts.allowedTypes.includes(file.type)) {
|
|
33823
|
+
return {
|
|
33824
|
+
valid: false,
|
|
33825
|
+
error: 'invalidType',
|
|
33826
|
+
message: `Formato no válido. Usa: ${opts.allowedTypes.map(t => t.split('/')[1].toUpperCase()).join(', ')}`,
|
|
33827
|
+
};
|
|
33828
|
+
}
|
|
33829
|
+
// Check file size
|
|
33830
|
+
if (file.size > opts.maxSize) {
|
|
33831
|
+
const maxMB = Math.round(opts.maxSize / (1024 * 1024));
|
|
33832
|
+
return {
|
|
33833
|
+
valid: false,
|
|
33834
|
+
error: 'fileTooLarge',
|
|
33835
|
+
message: `La imagen es muy grande. Máximo ${maxMB}MB`,
|
|
33836
|
+
};
|
|
33837
|
+
}
|
|
33838
|
+
return { valid: true };
|
|
33839
|
+
}
|
|
33840
|
+
/**
|
|
33841
|
+
* Validate image dimensions (async - requires loading image)
|
|
33842
|
+
* @param file - File to validate
|
|
33843
|
+
* @param options - Validation options with minWidth/minHeight
|
|
33844
|
+
* @returns Promise with validation result
|
|
33845
|
+
*/
|
|
33846
|
+
async validateDimensions(file, options) {
|
|
33847
|
+
const img = await this.loadImage(file);
|
|
33848
|
+
if (options.minWidth && img.width < options.minWidth) {
|
|
33849
|
+
return {
|
|
33850
|
+
valid: false,
|
|
33851
|
+
error: 'imageTooSmall',
|
|
33852
|
+
message: `La imagen debe tener al menos ${options.minWidth}px de ancho`,
|
|
33853
|
+
};
|
|
33854
|
+
}
|
|
33855
|
+
if (options.minHeight && img.height < options.minHeight) {
|
|
33856
|
+
return {
|
|
33857
|
+
valid: false,
|
|
33858
|
+
error: 'imageTooSmall',
|
|
33859
|
+
message: `La imagen debe tener al menos ${options.minHeight}px de alto`,
|
|
33860
|
+
};
|
|
33861
|
+
}
|
|
33862
|
+
return { valid: true };
|
|
33863
|
+
}
|
|
33864
|
+
/**
|
|
33865
|
+
* Convert a Blob/File to a data URL
|
|
33866
|
+
*/
|
|
33867
|
+
async toDataUrl(file) {
|
|
33868
|
+
return new Promise((resolve, reject) => {
|
|
33869
|
+
const reader = new FileReader();
|
|
33870
|
+
reader.onload = () => resolve(reader.result);
|
|
33871
|
+
reader.onerror = reject;
|
|
33872
|
+
reader.readAsDataURL(file);
|
|
33873
|
+
});
|
|
33874
|
+
}
|
|
33875
|
+
/**
|
|
33876
|
+
* Convert a data URL to a Blob
|
|
33877
|
+
*/
|
|
33878
|
+
dataUrlToBlob(dataUrl) {
|
|
33879
|
+
const arr = dataUrl.split(',');
|
|
33880
|
+
const mime = arr[0].match(/:(.*?);/)[1];
|
|
33881
|
+
const bstr = atob(arr[1]);
|
|
33882
|
+
let n = bstr.length;
|
|
33883
|
+
const u8arr = new Uint8Array(n);
|
|
33884
|
+
while (n--) {
|
|
33885
|
+
u8arr[n] = bstr.charCodeAt(n);
|
|
33886
|
+
}
|
|
33887
|
+
return new Blob([u8arr], { type: mime });
|
|
33888
|
+
}
|
|
33889
|
+
// ============== Private Helpers ==============
|
|
33890
|
+
loadImage(file) {
|
|
33891
|
+
return new Promise((resolve, reject) => {
|
|
33892
|
+
const img = new Image();
|
|
33893
|
+
img.onload = () => {
|
|
33894
|
+
URL.revokeObjectURL(img.src);
|
|
33895
|
+
resolve(img);
|
|
33896
|
+
};
|
|
33897
|
+
img.onerror = reject;
|
|
33898
|
+
img.src = URL.createObjectURL(file);
|
|
33899
|
+
});
|
|
33900
|
+
}
|
|
33901
|
+
calculateDimensions(originalWidth, originalHeight, maxWidth, maxHeight) {
|
|
33902
|
+
let width = originalWidth;
|
|
33903
|
+
let height = originalHeight;
|
|
33904
|
+
// Scale down if necessary, maintaining aspect ratio
|
|
33905
|
+
if (width > maxWidth) {
|
|
33906
|
+
height = (height * maxWidth) / width;
|
|
33907
|
+
width = maxWidth;
|
|
33908
|
+
}
|
|
33909
|
+
if (height > maxHeight) {
|
|
33910
|
+
width = (width * maxHeight) / height;
|
|
33911
|
+
height = maxHeight;
|
|
33912
|
+
}
|
|
33913
|
+
return {
|
|
33914
|
+
width: Math.round(width),
|
|
33915
|
+
height: Math.round(height),
|
|
33916
|
+
};
|
|
33917
|
+
}
|
|
33918
|
+
canvasToBlob(canvas, mimeType, quality) {
|
|
33919
|
+
return new Promise((resolve, reject) => {
|
|
33920
|
+
canvas.toBlob((blob) => {
|
|
33921
|
+
if (blob)
|
|
33922
|
+
resolve(blob);
|
|
33923
|
+
else
|
|
33924
|
+
reject(new Error('Failed to create blob from canvas'));
|
|
33925
|
+
}, mimeType, quality);
|
|
33926
|
+
});
|
|
33927
|
+
}
|
|
33928
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
33929
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, providedIn: 'root' }); }
|
|
33930
|
+
}
|
|
33931
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, decorators: [{
|
|
33932
|
+
type: Injectable,
|
|
33933
|
+
args: [{ providedIn: 'root' }]
|
|
33934
|
+
}] });
|
|
33935
|
+
|
|
33936
|
+
/**
|
|
33937
|
+
* Default values
|
|
33938
|
+
*/
|
|
33939
|
+
const AVATAR_UPLOAD_DEFAULTS = {
|
|
33940
|
+
size: 100,
|
|
33941
|
+
editable: true,
|
|
33942
|
+
storagePath: 'avatars',
|
|
33943
|
+
i18nNamespace: 'AvatarUpload',
|
|
33944
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
33945
|
+
compressQuality: 0.8,
|
|
33946
|
+
maxWidth: 800,
|
|
33947
|
+
thumbnailSize: 150,
|
|
33948
|
+
backgroundColor: '#6366f1', // Indigo
|
|
33949
|
+
};
|
|
33950
|
+
|
|
33951
|
+
addIcons({ cameraOutline });
|
|
33952
|
+
/**
|
|
33953
|
+
* AvatarUploadComponent
|
|
33954
|
+
*
|
|
33955
|
+
* A complete avatar upload solution with:
|
|
33956
|
+
* - Image selection from device
|
|
33957
|
+
* - Crop modal with round preview
|
|
33958
|
+
* - Automatic compression and thumbnail generation
|
|
33959
|
+
* - Upload to Firebase Storage
|
|
33960
|
+
* - Backend sync via AuthService
|
|
33961
|
+
*
|
|
33962
|
+
* @example Basic usage
|
|
33963
|
+
* ```html
|
|
33964
|
+
* <val-avatar-upload
|
|
33965
|
+
* [props]="{
|
|
33966
|
+
* currentUrl: user()?.avatarUrl,
|
|
33967
|
+
* initials: 'JD',
|
|
33968
|
+
* size: 120
|
|
33969
|
+
* }"
|
|
33970
|
+
* (uploaded)="onAvatarUploaded($event)"
|
|
33971
|
+
* (error)="onError($event)"
|
|
33972
|
+
* />
|
|
33973
|
+
* ```
|
|
33974
|
+
*/
|
|
33975
|
+
class AvatarUploadComponent {
|
|
33976
|
+
constructor() {
|
|
33977
|
+
this.imageService = inject(ImageService);
|
|
33978
|
+
this.storageService = inject(StorageService);
|
|
33979
|
+
this.authService = inject(AuthService);
|
|
33980
|
+
this.i18n = inject(I18nService);
|
|
33981
|
+
/** Component configuration */
|
|
33982
|
+
this.props = input({});
|
|
33983
|
+
/** Emitted after successful upload and backend sync */
|
|
33984
|
+
this.uploaded = new EventEmitter();
|
|
33985
|
+
/** Emitted on any error during the process */
|
|
33986
|
+
this.error = new EventEmitter();
|
|
33987
|
+
/** Emitted when upload starts */
|
|
33988
|
+
this.uploadStart = new EventEmitter();
|
|
33989
|
+
// Internal state
|
|
33990
|
+
this.loading = signal(false);
|
|
33991
|
+
this.showCropModal = signal(false);
|
|
33992
|
+
this.selectedFile = signal(null);
|
|
33993
|
+
this.previewUrl = signal(null);
|
|
33994
|
+
this.imageLoadError = signal(false);
|
|
33995
|
+
/** Merged config with defaults */
|
|
33996
|
+
this.config = computed(() => ({
|
|
33997
|
+
...AVATAR_UPLOAD_DEFAULTS,
|
|
33998
|
+
...this.props(),
|
|
33999
|
+
}));
|
|
34000
|
+
/** URL to display (preview takes priority over current) */
|
|
34001
|
+
this.displayUrl = computed(() => {
|
|
34002
|
+
if (this.imageLoadError())
|
|
34003
|
+
return null;
|
|
34004
|
+
return this.previewUrl() || this.config().currentUrl || null;
|
|
34005
|
+
});
|
|
34006
|
+
/** Aria label for edit button */
|
|
34007
|
+
this.editButtonLabel = computed(() => {
|
|
34008
|
+
this.i18n.lang();
|
|
34009
|
+
return this.i18n.t('changePhoto', this.config().i18nNamespace) || 'Cambiar foto';
|
|
34010
|
+
});
|
|
34011
|
+
}
|
|
34012
|
+
/** Open file picker dialog */
|
|
34013
|
+
openFilePicker() {
|
|
34014
|
+
this.fileInput.nativeElement.click();
|
|
34015
|
+
}
|
|
34016
|
+
/** Handle file selection */
|
|
34017
|
+
onFileSelected(event) {
|
|
34018
|
+
const input = event.target;
|
|
34019
|
+
const file = input.files?.[0];
|
|
34020
|
+
if (!file)
|
|
34021
|
+
return;
|
|
34022
|
+
// Reset input for same file selection
|
|
34023
|
+
input.value = '';
|
|
34024
|
+
// Validate file
|
|
34025
|
+
const validation = this.imageService.validate(file, {
|
|
34026
|
+
maxSize: this.config().maxFileSize,
|
|
34027
|
+
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
|
34028
|
+
});
|
|
34029
|
+
if (!validation.valid) {
|
|
34030
|
+
this.emitError(validation.error, validation.message);
|
|
34031
|
+
return;
|
|
34032
|
+
}
|
|
34033
|
+
// Open crop modal
|
|
34034
|
+
this.selectedFile.set(file);
|
|
34035
|
+
this.showCropModal.set(true);
|
|
34036
|
+
}
|
|
34037
|
+
/** Handle crop completion */
|
|
34038
|
+
async onCropComplete(croppedBlob) {
|
|
34039
|
+
this.showCropModal.set(false);
|
|
34040
|
+
this.selectedFile.set(null);
|
|
34041
|
+
await this.processAndUpload(croppedBlob);
|
|
34042
|
+
}
|
|
34043
|
+
/** Handle crop cancel */
|
|
34044
|
+
onCropCancel() {
|
|
34045
|
+
this.showCropModal.set(false);
|
|
34046
|
+
this.selectedFile.set(null);
|
|
34047
|
+
}
|
|
34048
|
+
/** Handle crop load failure */
|
|
34049
|
+
onCropLoadFailed() {
|
|
34050
|
+
this.showCropModal.set(false);
|
|
34051
|
+
this.selectedFile.set(null);
|
|
34052
|
+
this.emitError('invalidType', this.i18n.t('loadFailed', this.config().i18nNamespace) || 'No se pudo cargar la imagen');
|
|
34053
|
+
}
|
|
34054
|
+
/** Handle image load error */
|
|
34055
|
+
onImageError() {
|
|
34056
|
+
this.imageLoadError.set(true);
|
|
34057
|
+
}
|
|
34058
|
+
/** Process cropped image and upload */
|
|
34059
|
+
async processAndUpload(croppedBlob) {
|
|
34060
|
+
this.loading.set(true);
|
|
34061
|
+
this.uploadStart.emit();
|
|
34062
|
+
try {
|
|
34063
|
+
const config = this.config();
|
|
34064
|
+
// 1. Compress image
|
|
34065
|
+
const compressed = await this.imageService.compress(croppedBlob, {
|
|
34066
|
+
maxWidth: config.maxWidth,
|
|
34067
|
+
maxHeight: config.maxWidth,
|
|
34068
|
+
quality: config.compressQuality,
|
|
34069
|
+
});
|
|
34070
|
+
// 2. Generate thumbnail
|
|
34071
|
+
const thumbnail = await this.imageService.thumbnail(compressed.blob, config.thumbnailSize);
|
|
34072
|
+
// 3. Set preview immediately
|
|
34073
|
+
this.previewUrl.set(compressed.dataUrl);
|
|
34074
|
+
this.imageLoadError.set(false);
|
|
34075
|
+
// 4. Get user ID for storage path
|
|
34076
|
+
const userId = this.authService.user()?.userId;
|
|
34077
|
+
if (!userId) {
|
|
34078
|
+
throw new Error('User not authenticated');
|
|
34079
|
+
}
|
|
34080
|
+
// 5. Upload to Firebase Storage
|
|
34081
|
+
const timestamp = Date.now();
|
|
34082
|
+
const avatarPath = `${config.storagePath}/${userId}/avatar_${timestamp}.jpg`;
|
|
34083
|
+
const thumbPath = `${config.storagePath}/${userId}/thumb_${timestamp}.jpg`;
|
|
34084
|
+
const [avatarResult, thumbResult] = await Promise.all([
|
|
34085
|
+
this.storageService.uploadAndGetUrl(avatarPath, compressed.blob),
|
|
34086
|
+
this.storageService.uploadAndGetUrl(thumbPath, thumbnail.blob),
|
|
34087
|
+
]);
|
|
34088
|
+
// 6. Update backend
|
|
34089
|
+
await firstValueFrom(this.authService.updateAvatar({
|
|
34090
|
+
avatarUrl: avatarResult.downloadUrl,
|
|
34091
|
+
avatarThumbnail: thumbResult.downloadUrl,
|
|
34092
|
+
}));
|
|
34093
|
+
// 7. Emit success
|
|
34094
|
+
const result = {
|
|
34095
|
+
avatarUrl: avatarResult.downloadUrl,
|
|
34096
|
+
thumbnailUrl: thumbResult.downloadUrl,
|
|
34097
|
+
};
|
|
34098
|
+
this.uploaded.emit(result);
|
|
34099
|
+
}
|
|
34100
|
+
catch (err) {
|
|
34101
|
+
// Revert preview on error
|
|
34102
|
+
this.previewUrl.set(null);
|
|
34103
|
+
const message = err instanceof Error
|
|
34104
|
+
? err.message
|
|
34105
|
+
: this.i18n.t('uploadError', this.config().i18nNamespace) || 'Error al subir la imagen';
|
|
34106
|
+
this.emitError('uploadFailed', message, err);
|
|
34107
|
+
}
|
|
34108
|
+
finally {
|
|
34109
|
+
this.loading.set(false);
|
|
34110
|
+
}
|
|
34111
|
+
}
|
|
34112
|
+
/** Emit error event */
|
|
34113
|
+
emitError(type, message, originalError) {
|
|
34114
|
+
this.error.emit({ type, message, originalError });
|
|
34115
|
+
}
|
|
34116
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
34117
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AvatarUploadComponent, isStandalone: true, selector: "val-avatar-upload", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { uploaded: "uploaded", error: "error", uploadStart: "uploadStart" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
|
|
34118
|
+
<div
|
|
34119
|
+
class="avatar-upload"
|
|
34120
|
+
[style.--avatar-size.px]="config().size"
|
|
34121
|
+
[class.avatar-upload--loading]="loading()"
|
|
34122
|
+
>
|
|
34123
|
+
<div class="avatar-container">
|
|
34124
|
+
<!-- Avatar Image or Initials -->
|
|
34125
|
+
@if (displayUrl()) {
|
|
34126
|
+
<img
|
|
34127
|
+
class="avatar-image"
|
|
34128
|
+
[src]="displayUrl()"
|
|
34129
|
+
alt="Avatar"
|
|
34130
|
+
(error)="onImageError()"
|
|
34131
|
+
/>
|
|
34132
|
+
} @else {
|
|
34133
|
+
<div
|
|
34134
|
+
class="avatar-initials"
|
|
34135
|
+
[style.background-color]="config().backgroundColor"
|
|
34136
|
+
>
|
|
34137
|
+
{{ config().initials || '?' }}
|
|
34138
|
+
</div>
|
|
34139
|
+
}
|
|
34140
|
+
|
|
34141
|
+
<!-- Edit Button -->
|
|
34142
|
+
@if (config().editable && !loading()) {
|
|
34143
|
+
<button
|
|
34144
|
+
class="edit-button"
|
|
34145
|
+
type="button"
|
|
34146
|
+
(click)="openFilePicker()"
|
|
34147
|
+
[attr.aria-label]="editButtonLabel()"
|
|
34148
|
+
>
|
|
34149
|
+
<ion-icon name="camera-outline"></ion-icon>
|
|
34150
|
+
</button>
|
|
34151
|
+
}
|
|
34152
|
+
|
|
34153
|
+
<!-- Loading Overlay -->
|
|
34154
|
+
@if (loading()) {
|
|
34155
|
+
<div class="loading-overlay">
|
|
34156
|
+
<ion-spinner name="crescent"></ion-spinner>
|
|
34157
|
+
</div>
|
|
34158
|
+
}
|
|
34159
|
+
</div>
|
|
34160
|
+
|
|
34161
|
+
<!-- Hidden File Input -->
|
|
34162
|
+
<input
|
|
34163
|
+
#fileInput
|
|
34164
|
+
type="file"
|
|
34165
|
+
accept="image/jpeg,image/png,image/webp"
|
|
34166
|
+
(change)="onFileSelected($event)"
|
|
34167
|
+
hidden
|
|
34168
|
+
/>
|
|
34169
|
+
|
|
34170
|
+
<!-- Crop Modal -->
|
|
34171
|
+
<ion-modal
|
|
34172
|
+
[isOpen]="showCropModal()"
|
|
34173
|
+
(didDismiss)="onCropCancel()"
|
|
34174
|
+
[breakpoints]="[0, 1]"
|
|
34175
|
+
[initialBreakpoint]="1"
|
|
34176
|
+
>
|
|
34177
|
+
<ng-template>
|
|
34178
|
+
@if (selectedFile()) {
|
|
34179
|
+
<val-image-crop
|
|
34180
|
+
[image]="selectedFile()!"
|
|
34181
|
+
[aspectRatio]="1"
|
|
34182
|
+
[roundCropper]="true"
|
|
34183
|
+
[i18nNamespace]="config().i18nNamespace"
|
|
34184
|
+
(cropComplete)="onCropComplete($event)"
|
|
34185
|
+
(cancel)="onCropCancel()"
|
|
34186
|
+
(loadFailed)="onCropLoadFailed()"
|
|
34187
|
+
/>
|
|
34188
|
+
}
|
|
34189
|
+
</ng-template>
|
|
34190
|
+
</ion-modal>
|
|
34191
|
+
</div>
|
|
34192
|
+
`, isInline: true, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\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"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ImageCropComponent, selector: "val-image-crop", inputs: ["image", "aspectRatio", "roundCropper", "resizeToWidth", "i18nNamespace"], outputs: ["cropComplete", "cancel", "loadFailed"] }] }); }
|
|
34193
|
+
}
|
|
34194
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarUploadComponent, decorators: [{
|
|
34195
|
+
type: Component,
|
|
34196
|
+
args: [{ selector: 'val-avatar-upload', standalone: true, imports: [CommonModule, IonIcon, IonSpinner, IonModal, ImageCropComponent], template: `
|
|
34197
|
+
<div
|
|
34198
|
+
class="avatar-upload"
|
|
34199
|
+
[style.--avatar-size.px]="config().size"
|
|
34200
|
+
[class.avatar-upload--loading]="loading()"
|
|
34201
|
+
>
|
|
34202
|
+
<div class="avatar-container">
|
|
34203
|
+
<!-- Avatar Image or Initials -->
|
|
34204
|
+
@if (displayUrl()) {
|
|
34205
|
+
<img
|
|
34206
|
+
class="avatar-image"
|
|
34207
|
+
[src]="displayUrl()"
|
|
34208
|
+
alt="Avatar"
|
|
34209
|
+
(error)="onImageError()"
|
|
34210
|
+
/>
|
|
34211
|
+
} @else {
|
|
34212
|
+
<div
|
|
34213
|
+
class="avatar-initials"
|
|
34214
|
+
[style.background-color]="config().backgroundColor"
|
|
34215
|
+
>
|
|
34216
|
+
{{ config().initials || '?' }}
|
|
34217
|
+
</div>
|
|
34218
|
+
}
|
|
34219
|
+
|
|
34220
|
+
<!-- Edit Button -->
|
|
34221
|
+
@if (config().editable && !loading()) {
|
|
34222
|
+
<button
|
|
34223
|
+
class="edit-button"
|
|
34224
|
+
type="button"
|
|
34225
|
+
(click)="openFilePicker()"
|
|
34226
|
+
[attr.aria-label]="editButtonLabel()"
|
|
34227
|
+
>
|
|
34228
|
+
<ion-icon name="camera-outline"></ion-icon>
|
|
34229
|
+
</button>
|
|
34230
|
+
}
|
|
34231
|
+
|
|
34232
|
+
<!-- Loading Overlay -->
|
|
34233
|
+
@if (loading()) {
|
|
34234
|
+
<div class="loading-overlay">
|
|
34235
|
+
<ion-spinner name="crescent"></ion-spinner>
|
|
34236
|
+
</div>
|
|
34237
|
+
}
|
|
34238
|
+
</div>
|
|
34239
|
+
|
|
34240
|
+
<!-- Hidden File Input -->
|
|
34241
|
+
<input
|
|
34242
|
+
#fileInput
|
|
34243
|
+
type="file"
|
|
34244
|
+
accept="image/jpeg,image/png,image/webp"
|
|
34245
|
+
(change)="onFileSelected($event)"
|
|
34246
|
+
hidden
|
|
34247
|
+
/>
|
|
34248
|
+
|
|
34249
|
+
<!-- Crop Modal -->
|
|
34250
|
+
<ion-modal
|
|
34251
|
+
[isOpen]="showCropModal()"
|
|
34252
|
+
(didDismiss)="onCropCancel()"
|
|
34253
|
+
[breakpoints]="[0, 1]"
|
|
34254
|
+
[initialBreakpoint]="1"
|
|
34255
|
+
>
|
|
34256
|
+
<ng-template>
|
|
34257
|
+
@if (selectedFile()) {
|
|
34258
|
+
<val-image-crop
|
|
34259
|
+
[image]="selectedFile()!"
|
|
34260
|
+
[aspectRatio]="1"
|
|
34261
|
+
[roundCropper]="true"
|
|
34262
|
+
[i18nNamespace]="config().i18nNamespace"
|
|
34263
|
+
(cropComplete)="onCropComplete($event)"
|
|
34264
|
+
(cancel)="onCropCancel()"
|
|
34265
|
+
(loadFailed)="onCropLoadFailed()"
|
|
34266
|
+
/>
|
|
34267
|
+
}
|
|
34268
|
+
</ng-template>
|
|
34269
|
+
</ion-modal>
|
|
34270
|
+
</div>
|
|
34271
|
+
`, styles: [".avatar-upload{--avatar-size: 100px;--edit-button-size: 32px;--edit-button-offset: 4px;display:inline-block}.avatar-container{position:relative;width:var(--avatar-size);height:var(--avatar-size);border-radius:50%;overflow:visible}.avatar-image{width:100%;height:100%;border-radius:50%;object-fit:cover;background-color:var(--ion-color-light)}.avatar-initials{width:100%;height:100%;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(var(--avatar-size) * .4);font-weight:600;color:#fff;text-transform:uppercase;-webkit-user-select:none;user-select:none}.edit-button{position:absolute;bottom:var(--edit-button-offset);right:var(--edit-button-offset);width:var(--edit-button-size);height:var(--edit-button-size);border-radius:50%;border:2px solid white;background:var(--ion-color-primary);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:transform .2s ease,background-color .2s ease;box-shadow:0 2px 8px #00000026}.edit-button ion-icon{font-size:calc(var(--edit-button-size) * .5)}.edit-button:hover{transform:scale(1.1);background:var(--ion-color-primary-shade)}.edit-button:active{transform:scale(.95)}.edit-button:focus-visible{outline:2px solid var(--ion-color-primary);outline-offset:2px}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;background:#00000080;display:flex;align-items:center;justify-content:center}.loading-overlay ion-spinner{--color: white;width:calc(var(--avatar-size) * .4);height:calc(var(--avatar-size) * .4)}.avatar-upload--loading .edit-button{display:none}.avatar-upload--loading .avatar-image,.avatar-upload--loading .avatar-initials{filter:brightness(.7)}@container (max-width: 60px){.edit-button{--edit-button-size: 24px;--edit-button-offset: 0}}\n"] }]
|
|
34272
|
+
}], propDecorators: { fileInput: [{
|
|
34273
|
+
type: ViewChild,
|
|
34274
|
+
args: ['fileInput']
|
|
34275
|
+
}], uploaded: [{
|
|
34276
|
+
type: Output
|
|
34277
|
+
}], error: [{
|
|
34278
|
+
type: Output
|
|
34279
|
+
}], uploadStart: [{
|
|
34280
|
+
type: Output
|
|
34281
|
+
}] } });
|
|
34282
|
+
|
|
33504
34283
|
class LayoutComponent {
|
|
33505
34284
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
33506
34285
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: LayoutComponent, isStandalone: true, selector: "val-layout", ngImport: i0, template: `
|
|
@@ -40446,6 +41225,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
40446
41225
|
class DocsPageComponent {
|
|
40447
41226
|
constructor() {
|
|
40448
41227
|
this.elementRef = inject(ElementRef);
|
|
41228
|
+
this.router = inject(Router);
|
|
40449
41229
|
// Use signal internally so computed properties react to changes
|
|
40450
41230
|
this._props = signal({ title: '' });
|
|
40451
41231
|
this.tocItems = signal([]);
|
|
@@ -40491,6 +41271,22 @@ class DocsPageComponent {
|
|
|
40491
41271
|
homeRoute: props.breadcrumb.homeRoute ?? ['/'],
|
|
40492
41272
|
};
|
|
40493
41273
|
});
|
|
41274
|
+
this.feedbackProps = computed(() => {
|
|
41275
|
+
const props = this._props();
|
|
41276
|
+
const feedback = props.feedback;
|
|
41277
|
+
// Derive entityId from route if not provided
|
|
41278
|
+
const entityId = feedback?.entityId || this.router.url.replace(/^\//, '').replace(/\//g, '-') || 'unknown';
|
|
41279
|
+
return {
|
|
41280
|
+
entityRef: {
|
|
41281
|
+
entityType: feedback?.entityType || 'docs-page',
|
|
41282
|
+
entityId: entityId,
|
|
41283
|
+
},
|
|
41284
|
+
question: feedback?.question,
|
|
41285
|
+
showComment: feedback?.showComment ?? true,
|
|
41286
|
+
allowAnonymous: feedback?.allowAnonymous ?? true,
|
|
41287
|
+
showThankYou: true,
|
|
41288
|
+
};
|
|
41289
|
+
});
|
|
40494
41290
|
}
|
|
40495
41291
|
set props(value) {
|
|
40496
41292
|
this._props.set(value);
|
|
@@ -40562,6 +41358,12 @@ class DocsPageComponent {
|
|
|
40562
41358
|
<ng-content></ng-content>
|
|
40563
41359
|
</div>
|
|
40564
41360
|
|
|
41361
|
+
@if (props.feedback?.enabled) {
|
|
41362
|
+
<div class="docs-page__feedback">
|
|
41363
|
+
<val-content-reaction [props]="feedbackProps()"></val-content-reaction>
|
|
41364
|
+
</div>
|
|
41365
|
+
}
|
|
41366
|
+
|
|
40565
41367
|
@if (showNavLinks()) {
|
|
40566
41368
|
<val-docs-nav-links [props]="navLinksProps()"></val-docs-nav-links>
|
|
40567
41369
|
}
|
|
@@ -40573,11 +41375,11 @@ class DocsPageComponent {
|
|
|
40573
41375
|
</aside>
|
|
40574
41376
|
}
|
|
40575
41377
|
</div>
|
|
40576
|
-
`, isInline: true, styles: [".docs-page{display:grid;grid-template-columns:1fr;gap:2rem;max-width:1400px;margin:0 auto;padding:2rem 1.5rem}@media (min-width: 1200px){.docs-page{grid-template-columns:1fr 220px;padding:2rem}}.docs-page__content{min-width:0;max-width:900px}val-docs-breadcrumb{display:block;margin-bottom:1rem}.docs-page__header{margin-bottom:2rem}.docs-page__title-row{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.docs-page__title{margin:0;font-size:2rem;font-weight:700;color:var(--ion-text-color, #1a1a1a);line-height:1.2}@media (min-width: 768px){.docs-page__title{font-size:2.5rem}}.docs-page__badge{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;text-transform:uppercase;letter-spacing:.03em;border-radius:4px;background:#0000000a;color:#888}.docs-page__badge--success{background:#0000000a;color:#888}.docs-page__badge--warning{background:var(--ion-color-warning-tint, #fff3e0);color:var(--ion-color-warning-shade, #e65100)}.docs-page__badge--danger{background:var(--ion-color-danger-tint, #ffebee);color:var(--ion-color-danger-shade, #c62828)}.docs-page__lead{margin:1rem 0 0;font-size:1.125rem;line-height:1.7;color:var(--ion-color-medium, #666)}.docs-page__sections>*:last-child{margin-bottom:0}.docs-page__toc{display:none}@media (min-width: 1200px){.docs-page__toc{display:block;position:sticky;top:2rem;height:fit-content;max-height:calc(100vh - 4rem);overflow-y:auto}}.docs-page__sections h2{font-size:1.5rem;font-weight:600;margin:0 0 1rem;color:var(--ion-text-color, #1a1a1a);scroll-margin-top:2rem}.docs-page__sections h3{font-size:1.125rem;font-weight:600;margin:1.5rem 0 1rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections h4{font-size:1rem;font-weight:600;margin:1.25rem 0 .75rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections p{line-height:1.7;color:var(--ion-text-color, #1a1a1a);margin:0 0 1rem}.docs-page__sections ul,.docs-page__sections ol{padding-left:1.5rem;margin:0 0 1rem}.docs-page__sections li{margin-bottom:.5rem;line-height:1.6;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections a{color:var(--ion-color-primary, #3880ff);text-decoration:none}.docs-page__sections a:hover{text-decoration:underline}.docs-page__sections code:not([class*=language-]){background:#0000000f;padding:.125rem .375rem;border-radius:4px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:.875em}.docs-page__sections pre:not([class*=language-]){background:#0000000a;padding:1rem;border-radius:8px;overflow-x:auto;margin:0 0 1rem}.docs-page__sections pre:not([class*=language-]) code{background:none;padding:0}.docs-page__sections table{width:100%;border-collapse:collapse;margin:0 0 1rem;font-size:.875rem}.docs-page__sections th,.docs-page__sections td{padding:.75rem;text-align:left;border-bottom:1px solid rgba(0,0,0,.1)}.docs-page__sections th{font-weight:600;background:#00000005}.docs-page__sections blockquote{margin:0 0 1rem;padding:1rem 1.5rem;border-left:4px solid var(--ion-color-primary, #3880ff);background:#00000005;border-radius:0 8px 8px 0}.docs-page__sections blockquote p:last-child{margin-bottom:0}.docs-page__sections img{max-width:100%;height:auto;border-radius:8px}.docs-page__sections hr{border:none;border-top:1px solid rgba(0,0,0,.1);margin:2rem 0}.docs-page__sections strong{font-weight:600}.docs-page__sections section{margin-bottom:2rem}:host-context(.dark) .docs-page__badge,:host-context([color-scheme=\"dark\"]) .docs-page__badge{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--success,:host-context([color-scheme=\"dark\"]) .docs-page__badge--success{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--warning,:host-context([color-scheme=\"dark\"]) .docs-page__badge--warning{background:#e6510033;color:#ffb74d}:host-context(.dark) .docs-page__badge--danger,:host-context([color-scheme=\"dark\"]) .docs-page__badge--danger{background:#c6282833;color:#e57373}:host-context(.dark) .docs-page__sections code:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections code:not([class*=language-]){background:#ffffff1a}:host-context(.dark) .docs-page__sections pre:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections pre:not([class*=language-]){background:#ffffff0f}:host-context(.dark) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections th{background:#ffffff0a}:host-context(.dark) .docs-page__sections th,:host-context(.dark) .docs-page__sections td,:host-context([color-scheme=\"dark\"]) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections td{border-color:#ffffff1a}:host-context(.dark) .docs-page__sections blockquote,:host-context([color-scheme=\"dark\"]) .docs-page__sections blockquote{background:#ffffff0a}:host-context(.dark) .docs-page__sections hr,:host-context([color-scheme=\"dark\"]) .docs-page__sections hr{border-color:#ffffff1a}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DocsBreadcrumbComponent, selector: "val-docs-breadcrumb", inputs: ["props"], outputs: ["navigate"] }, { kind: "component", type: DocsNavLinksComponent, selector: "val-docs-nav-links", inputs: ["props"], outputs: ["navigate"] }, { kind: "component", type: DocsTocComponent, selector: "val-docs-toc", inputs: ["props"], outputs: ["sectionChange"] }] }); }
|
|
41378
|
+
`, isInline: true, styles: [".docs-page{display:grid;grid-template-columns:1fr;gap:2rem;max-width:1400px;margin:0 auto;padding:2rem 1.5rem}@media (min-width: 1200px){.docs-page{grid-template-columns:1fr 220px;padding:2rem}}.docs-page__content{min-width:0;max-width:900px}val-docs-breadcrumb{display:block;margin-bottom:1rem}.docs-page__header{margin-bottom:2rem}.docs-page__title-row{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.docs-page__title{margin:0;font-size:2rem;font-weight:700;color:var(--ion-text-color, #1a1a1a);line-height:1.2}@media (min-width: 768px){.docs-page__title{font-size:2.5rem}}.docs-page__badge{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;text-transform:uppercase;letter-spacing:.03em;border-radius:4px;background:#0000000a;color:#888}.docs-page__badge--success{background:#0000000a;color:#888}.docs-page__badge--warning{background:var(--ion-color-warning-tint, #fff3e0);color:var(--ion-color-warning-shade, #e65100)}.docs-page__badge--danger{background:var(--ion-color-danger-tint, #ffebee);color:var(--ion-color-danger-shade, #c62828)}.docs-page__lead{margin:1rem 0 0;font-size:1.125rem;line-height:1.7;color:var(--ion-color-medium, #666)}.docs-page__sections>*:last-child{margin-bottom:0}.docs-page__feedback{margin-top:3rem;padding-top:2rem;border-top:1px solid rgba(0,0,0,.08);display:flex;justify-content:center}.docs-page__toc{display:none}@media (min-width: 1200px){.docs-page__toc{display:block;position:sticky;top:2rem;height:fit-content;max-height:calc(100vh - 4rem);overflow-y:auto}}.docs-page__sections h2{font-size:1.5rem;font-weight:600;margin:0 0 1rem;color:var(--ion-text-color, #1a1a1a);scroll-margin-top:2rem}.docs-page__sections h3{font-size:1.125rem;font-weight:600;margin:1.5rem 0 1rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections h4{font-size:1rem;font-weight:600;margin:1.25rem 0 .75rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections p{line-height:1.7;color:var(--ion-text-color, #1a1a1a);margin:0 0 1rem}.docs-page__sections ul,.docs-page__sections ol{padding-left:1.5rem;margin:0 0 1rem}.docs-page__sections li{margin-bottom:.5rem;line-height:1.6;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections a{color:var(--ion-color-primary, #3880ff);text-decoration:none}.docs-page__sections a:hover{text-decoration:underline}.docs-page__sections code:not([class*=language-]){background:#0000000f;padding:.125rem .375rem;border-radius:4px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:.875em}.docs-page__sections pre:not([class*=language-]){background:#0000000a;padding:1rem;border-radius:8px;overflow-x:auto;margin:0 0 1rem}.docs-page__sections pre:not([class*=language-]) code{background:none;padding:0}.docs-page__sections table{width:100%;border-collapse:collapse;margin:0 0 1rem;font-size:.875rem}.docs-page__sections th,.docs-page__sections td{padding:.75rem;text-align:left;border-bottom:1px solid rgba(0,0,0,.1)}.docs-page__sections th{font-weight:600;background:#00000005}.docs-page__sections blockquote{margin:0 0 1rem;padding:1rem 1.5rem;border-left:4px solid var(--ion-color-primary, #3880ff);background:#00000005;border-radius:0 8px 8px 0}.docs-page__sections blockquote p:last-child{margin-bottom:0}.docs-page__sections img{max-width:100%;height:auto;border-radius:8px}.docs-page__sections hr{border:none;border-top:1px solid rgba(0,0,0,.1);margin:2rem 0}.docs-page__sections strong{font-weight:600}.docs-page__sections section{margin-bottom:2rem}:host-context(.dark) .docs-page__badge,:host-context([color-scheme=\"dark\"]) .docs-page__badge{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--success,:host-context([color-scheme=\"dark\"]) .docs-page__badge--success{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--warning,:host-context([color-scheme=\"dark\"]) .docs-page__badge--warning{background:#e6510033;color:#ffb74d}:host-context(.dark) .docs-page__badge--danger,:host-context([color-scheme=\"dark\"]) .docs-page__badge--danger{background:#c6282833;color:#e57373}:host-context(.dark) .docs-page__sections code:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections code:not([class*=language-]){background:#ffffff1a}:host-context(.dark) .docs-page__sections pre:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections pre:not([class*=language-]){background:#ffffff0f}:host-context(.dark) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections th{background:#ffffff0a}:host-context(.dark) .docs-page__sections th,:host-context(.dark) .docs-page__sections td,:host-context([color-scheme=\"dark\"]) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections td{border-color:#ffffff1a}:host-context(.dark) .docs-page__sections blockquote,:host-context([color-scheme=\"dark\"]) .docs-page__sections blockquote{background:#ffffff0a}:host-context(.dark) .docs-page__sections hr,:host-context([color-scheme=\"dark\"]) .docs-page__sections hr{border-color:#ffffff1a}:host-context(.dark) .docs-page__feedback,:host-context([color-scheme=\"dark\"]) .docs-page__feedback{border-color:#ffffff1a}@media (max-width: 768px){.docs-page__feedback{margin-top:2rem;padding-top:1.5rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DocsBreadcrumbComponent, selector: "val-docs-breadcrumb", inputs: ["props"], outputs: ["navigate"] }, { kind: "component", type: DocsNavLinksComponent, selector: "val-docs-nav-links", inputs: ["props"], outputs: ["navigate"] }, { kind: "component", type: DocsTocComponent, selector: "val-docs-toc", inputs: ["props"], outputs: ["sectionChange"] }, { kind: "component", type: ContentReactionComponent, selector: "val-content-reaction", inputs: ["props"], outputs: ["reactionSubmit", "reactionChange"] }] }); }
|
|
40577
41379
|
}
|
|
40578
41380
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DocsPageComponent, decorators: [{
|
|
40579
41381
|
type: Component,
|
|
40580
|
-
args: [{ selector: 'val-docs-page', standalone: true, imports: [CommonModule, DocsBreadcrumbComponent, DocsNavLinksComponent, DocsTocComponent], template: `
|
|
41382
|
+
args: [{ selector: 'val-docs-page', standalone: true, imports: [CommonModule, DocsBreadcrumbComponent, DocsNavLinksComponent, DocsTocComponent, ContentReactionComponent], template: `
|
|
40581
41383
|
<div class="docs-page" [class]="props.cssClass">
|
|
40582
41384
|
<div class="docs-page__content" #content>
|
|
40583
41385
|
@if (breadcrumbProps()) {
|
|
@@ -40606,6 +41408,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
40606
41408
|
<ng-content></ng-content>
|
|
40607
41409
|
</div>
|
|
40608
41410
|
|
|
41411
|
+
@if (props.feedback?.enabled) {
|
|
41412
|
+
<div class="docs-page__feedback">
|
|
41413
|
+
<val-content-reaction [props]="feedbackProps()"></val-content-reaction>
|
|
41414
|
+
</div>
|
|
41415
|
+
}
|
|
41416
|
+
|
|
40609
41417
|
@if (showNavLinks()) {
|
|
40610
41418
|
<val-docs-nav-links [props]="navLinksProps()"></val-docs-nav-links>
|
|
40611
41419
|
}
|
|
@@ -40617,7 +41425,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
40617
41425
|
</aside>
|
|
40618
41426
|
}
|
|
40619
41427
|
</div>
|
|
40620
|
-
`, styles: [".docs-page{display:grid;grid-template-columns:1fr;gap:2rem;max-width:1400px;margin:0 auto;padding:2rem 1.5rem}@media (min-width: 1200px){.docs-page{grid-template-columns:1fr 220px;padding:2rem}}.docs-page__content{min-width:0;max-width:900px}val-docs-breadcrumb{display:block;margin-bottom:1rem}.docs-page__header{margin-bottom:2rem}.docs-page__title-row{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.docs-page__title{margin:0;font-size:2rem;font-weight:700;color:var(--ion-text-color, #1a1a1a);line-height:1.2}@media (min-width: 768px){.docs-page__title{font-size:2.5rem}}.docs-page__badge{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;text-transform:uppercase;letter-spacing:.03em;border-radius:4px;background:#0000000a;color:#888}.docs-page__badge--success{background:#0000000a;color:#888}.docs-page__badge--warning{background:var(--ion-color-warning-tint, #fff3e0);color:var(--ion-color-warning-shade, #e65100)}.docs-page__badge--danger{background:var(--ion-color-danger-tint, #ffebee);color:var(--ion-color-danger-shade, #c62828)}.docs-page__lead{margin:1rem 0 0;font-size:1.125rem;line-height:1.7;color:var(--ion-color-medium, #666)}.docs-page__sections>*:last-child{margin-bottom:0}.docs-page__toc{display:none}@media (min-width: 1200px){.docs-page__toc{display:block;position:sticky;top:2rem;height:fit-content;max-height:calc(100vh - 4rem);overflow-y:auto}}.docs-page__sections h2{font-size:1.5rem;font-weight:600;margin:0 0 1rem;color:var(--ion-text-color, #1a1a1a);scroll-margin-top:2rem}.docs-page__sections h3{font-size:1.125rem;font-weight:600;margin:1.5rem 0 1rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections h4{font-size:1rem;font-weight:600;margin:1.25rem 0 .75rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections p{line-height:1.7;color:var(--ion-text-color, #1a1a1a);margin:0 0 1rem}.docs-page__sections ul,.docs-page__sections ol{padding-left:1.5rem;margin:0 0 1rem}.docs-page__sections li{margin-bottom:.5rem;line-height:1.6;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections a{color:var(--ion-color-primary, #3880ff);text-decoration:none}.docs-page__sections a:hover{text-decoration:underline}.docs-page__sections code:not([class*=language-]){background:#0000000f;padding:.125rem .375rem;border-radius:4px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:.875em}.docs-page__sections pre:not([class*=language-]){background:#0000000a;padding:1rem;border-radius:8px;overflow-x:auto;margin:0 0 1rem}.docs-page__sections pre:not([class*=language-]) code{background:none;padding:0}.docs-page__sections table{width:100%;border-collapse:collapse;margin:0 0 1rem;font-size:.875rem}.docs-page__sections th,.docs-page__sections td{padding:.75rem;text-align:left;border-bottom:1px solid rgba(0,0,0,.1)}.docs-page__sections th{font-weight:600;background:#00000005}.docs-page__sections blockquote{margin:0 0 1rem;padding:1rem 1.5rem;border-left:4px solid var(--ion-color-primary, #3880ff);background:#00000005;border-radius:0 8px 8px 0}.docs-page__sections blockquote p:last-child{margin-bottom:0}.docs-page__sections img{max-width:100%;height:auto;border-radius:8px}.docs-page__sections hr{border:none;border-top:1px solid rgba(0,0,0,.1);margin:2rem 0}.docs-page__sections strong{font-weight:600}.docs-page__sections section{margin-bottom:2rem}:host-context(.dark) .docs-page__badge,:host-context([color-scheme=\"dark\"]) .docs-page__badge{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--success,:host-context([color-scheme=\"dark\"]) .docs-page__badge--success{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--warning,:host-context([color-scheme=\"dark\"]) .docs-page__badge--warning{background:#e6510033;color:#ffb74d}:host-context(.dark) .docs-page__badge--danger,:host-context([color-scheme=\"dark\"]) .docs-page__badge--danger{background:#c6282833;color:#e57373}:host-context(.dark) .docs-page__sections code:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections code:not([class*=language-]){background:#ffffff1a}:host-context(.dark) .docs-page__sections pre:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections pre:not([class*=language-]){background:#ffffff0f}:host-context(.dark) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections th{background:#ffffff0a}:host-context(.dark) .docs-page__sections th,:host-context(.dark) .docs-page__sections td,:host-context([color-scheme=\"dark\"]) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections td{border-color:#ffffff1a}:host-context(.dark) .docs-page__sections blockquote,:host-context([color-scheme=\"dark\"]) .docs-page__sections blockquote{background:#ffffff0a}:host-context(.dark) .docs-page__sections hr,:host-context([color-scheme=\"dark\"]) .docs-page__sections hr{border-color:#ffffff1a}\n"] }]
|
|
41428
|
+
`, styles: [".docs-page{display:grid;grid-template-columns:1fr;gap:2rem;max-width:1400px;margin:0 auto;padding:2rem 1.5rem}@media (min-width: 1200px){.docs-page{grid-template-columns:1fr 220px;padding:2rem}}.docs-page__content{min-width:0;max-width:900px}val-docs-breadcrumb{display:block;margin-bottom:1rem}.docs-page__header{margin-bottom:2rem}.docs-page__title-row{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.docs-page__title{margin:0;font-size:2rem;font-weight:700;color:var(--ion-text-color, #1a1a1a);line-height:1.2}@media (min-width: 768px){.docs-page__title{font-size:2.5rem}}.docs-page__badge{display:inline-flex;align-items:center;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;text-transform:uppercase;letter-spacing:.03em;border-radius:4px;background:#0000000a;color:#888}.docs-page__badge--success{background:#0000000a;color:#888}.docs-page__badge--warning{background:var(--ion-color-warning-tint, #fff3e0);color:var(--ion-color-warning-shade, #e65100)}.docs-page__badge--danger{background:var(--ion-color-danger-tint, #ffebee);color:var(--ion-color-danger-shade, #c62828)}.docs-page__lead{margin:1rem 0 0;font-size:1.125rem;line-height:1.7;color:var(--ion-color-medium, #666)}.docs-page__sections>*:last-child{margin-bottom:0}.docs-page__feedback{margin-top:3rem;padding-top:2rem;border-top:1px solid rgba(0,0,0,.08);display:flex;justify-content:center}.docs-page__toc{display:none}@media (min-width: 1200px){.docs-page__toc{display:block;position:sticky;top:2rem;height:fit-content;max-height:calc(100vh - 4rem);overflow-y:auto}}.docs-page__sections h2{font-size:1.5rem;font-weight:600;margin:0 0 1rem;color:var(--ion-text-color, #1a1a1a);scroll-margin-top:2rem}.docs-page__sections h3{font-size:1.125rem;font-weight:600;margin:1.5rem 0 1rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections h4{font-size:1rem;font-weight:600;margin:1.25rem 0 .75rem;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections p{line-height:1.7;color:var(--ion-text-color, #1a1a1a);margin:0 0 1rem}.docs-page__sections ul,.docs-page__sections ol{padding-left:1.5rem;margin:0 0 1rem}.docs-page__sections li{margin-bottom:.5rem;line-height:1.6;color:var(--ion-text-color, #1a1a1a)}.docs-page__sections a{color:var(--ion-color-primary, #3880ff);text-decoration:none}.docs-page__sections a:hover{text-decoration:underline}.docs-page__sections code:not([class*=language-]){background:#0000000f;padding:.125rem .375rem;border-radius:4px;font-family:SF Mono,Fira Code,Consolas,monospace;font-size:.875em}.docs-page__sections pre:not([class*=language-]){background:#0000000a;padding:1rem;border-radius:8px;overflow-x:auto;margin:0 0 1rem}.docs-page__sections pre:not([class*=language-]) code{background:none;padding:0}.docs-page__sections table{width:100%;border-collapse:collapse;margin:0 0 1rem;font-size:.875rem}.docs-page__sections th,.docs-page__sections td{padding:.75rem;text-align:left;border-bottom:1px solid rgba(0,0,0,.1)}.docs-page__sections th{font-weight:600;background:#00000005}.docs-page__sections blockquote{margin:0 0 1rem;padding:1rem 1.5rem;border-left:4px solid var(--ion-color-primary, #3880ff);background:#00000005;border-radius:0 8px 8px 0}.docs-page__sections blockquote p:last-child{margin-bottom:0}.docs-page__sections img{max-width:100%;height:auto;border-radius:8px}.docs-page__sections hr{border:none;border-top:1px solid rgba(0,0,0,.1);margin:2rem 0}.docs-page__sections strong{font-weight:600}.docs-page__sections section{margin-bottom:2rem}:host-context(.dark) .docs-page__badge,:host-context([color-scheme=\"dark\"]) .docs-page__badge{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--success,:host-context([color-scheme=\"dark\"]) .docs-page__badge--success{background:#ffffff0f;color:#999}:host-context(.dark) .docs-page__badge--warning,:host-context([color-scheme=\"dark\"]) .docs-page__badge--warning{background:#e6510033;color:#ffb74d}:host-context(.dark) .docs-page__badge--danger,:host-context([color-scheme=\"dark\"]) .docs-page__badge--danger{background:#c6282833;color:#e57373}:host-context(.dark) .docs-page__sections code:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections code:not([class*=language-]){background:#ffffff1a}:host-context(.dark) .docs-page__sections pre:not([class*=language-]),:host-context([color-scheme=\"dark\"]) .docs-page__sections pre:not([class*=language-]){background:#ffffff0f}:host-context(.dark) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections th{background:#ffffff0a}:host-context(.dark) .docs-page__sections th,:host-context(.dark) .docs-page__sections td,:host-context([color-scheme=\"dark\"]) .docs-page__sections th,:host-context([color-scheme=\"dark\"]) .docs-page__sections td{border-color:#ffffff1a}:host-context(.dark) .docs-page__sections blockquote,:host-context([color-scheme=\"dark\"]) .docs-page__sections blockquote{background:#ffffff0a}:host-context(.dark) .docs-page__sections hr,:host-context([color-scheme=\"dark\"]) .docs-page__sections hr{border-color:#ffffff1a}:host-context(.dark) .docs-page__feedback,:host-context([color-scheme=\"dark\"]) .docs-page__feedback{border-color:#ffffff1a}@media (max-width: 768px){.docs-page__feedback{margin-top:2rem;padding-top:1.5rem}}\n"] }]
|
|
40621
41429
|
}], propDecorators: { props: [{
|
|
40622
41430
|
type: Input
|
|
40623
41431
|
}] } });
|
|
@@ -41109,5 +41917,5 @@ function buildFooterLinks(links, t) {
|
|
|
41109
41917
|
* Generated bundle index. Do not edit.
|
|
41110
41918
|
*/
|
|
41111
41919
|
|
|
41112
|
-
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContentLoaderComponent, ContentReactionComponent, CountdownComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LEGEND_LABELS, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAYMENT_STATUS_COLORS, DEFAULT_PAYMENT_STATUS_LABELS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_STATUS_COLORS, DEFAULT_STATUS_LABELS, DEFAULT_WINNER_LABELS, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlowCardComponent, GridSkeletonComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTION, MaintenancePageComponent, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, PaginationService, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RaffleStatusCardComponent, RangeInputComponent, RatingComponent, RecapCardComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UpdateBannerComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_DEFAULT_CONTENT, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_SOCIAL_LINKS, VERSION, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createTitleProps, extractPathParams, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, permissionGuard, permissionGuardFromRoute, provideValtechAds, provideValtechAppConfig, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechPresets, provideValtechSkeleton, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard };
|
|
41920
|
+
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContentLoaderComponent, ContentReactionComponent, CountdownComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LEGEND_LABELS, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAYMENT_STATUS_COLORS, DEFAULT_PAYMENT_STATUS_LABELS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_STATUS_COLORS, DEFAULT_STATUS_LABELS, DEFAULT_WINNER_LABELS, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlowCardComponent, GridSkeletonComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTION, MaintenancePageComponent, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NoContentComponent, NotesBoxComponent, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, PaginationService, ParticipantCardComponent, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RaffleStatusCardComponent, RangeInputComponent, RatingComponent, RecapCardComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TicketGridComponent, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UpdateBannerComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_DEFAULT_CONTENT, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_SOCIAL_LINKS, VERSION, WinnerDisplayComponent, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createTitleProps, extractPathParams, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, permissionGuard, permissionGuardFromRoute, provideValtechAds, provideValtechAppConfig, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechPresets, provideValtechSkeleton, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard };
|
|
41113
41921
|
//# sourceMappingURL=valtech-components.mjs.map
|