@shival99/z-ui 2.0.48 → 2.0.50

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, signal, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, viewChild, effect, model, EventEmitter, Injector, PLATFORM_ID, Injectable, ElementRef, Directive } from '@angular/core';
2
+ import { input, output, signal, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, viewChild, effect, EventEmitter, Injector, PLATFORM_ID, Injectable, DestroyRef, model, ElementRef, Directive } from '@angular/core';
3
3
  import * as i1$1 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import { TranslatePipe } from '@ngx-translate/core';
@@ -12,14 +12,14 @@ import { ZInputComponent } from '@shival99/z-ui/components/z-input';
12
12
  import { ZSkeletonComponent } from '@shival99/z-ui/components/z-skeleton';
13
13
  import { zMergeClasses, zTransform } from '@shival99/z-ui/utils';
14
14
  import { ZTooltipDirective } from '@shival99/z-ui/components/z-tooltip';
15
+ import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
16
+ import { ComponentPortal } from '@angular/cdk/portal';
15
17
  import { DOCUMENT, isPlatformBrowser } from '@angular/common';
18
+ import { ZOverlayZIndexService } from '@shival99/z-ui/services';
16
19
  import { DomSanitizer } from '@angular/platform-browser';
17
20
  import * as i1 from 'ng2-pdfjs-viewer';
18
21
  import { PdfJsViewerModule } from 'ng2-pdfjs-viewer';
19
22
  import { cva } from 'class-variance-authority';
20
- import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
21
- import { ComponentPortal } from '@angular/cdk/portal';
22
- import { ZOverlayZIndexService } from '@shival99/z-ui/services';
23
23
 
24
24
  const FILE_CATEGORY_STYLES = {
25
25
  image: {
@@ -1372,6 +1372,107 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
1372
1372
  }, template: "<div\n class=\"animate-in fade-in fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm duration-200\"\n (click)=\"onBackdropClick($event)\">\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute top-3 right-3 z-20 text-white hover:bg-white/20 lg:top-4 lg:right-4\"\n (click)=\"close()\">\n <i z-icon zType=\"lucideX\" zSize=\"24\"></i>\n </button>\n\n @if (hasPrev()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute left-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(-1)\">\n <i z-icon zType=\"lucideChevronLeft\" zSize=\"32\"></i>\n </button>\n }\n\n @if (hasNext()) {\n <button\n z-button\n zType=\"ghost\"\n zShape=\"circle\"\n class=\"absolute right-4 z-10 text-white hover:bg-white/20\"\n (click)=\"navigate(1)\">\n <i z-icon zType=\"lucideChevronRight\" zSize=\"32\"></i>\n </button>\n }\n\n <div class=\"flex h-full w-full flex-col items-center\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"dark:!border-border absolute top-3 right-14 left-3 z-10 flex min-w-0 items-center justify-between gap-2 rounded-[0.375rem] border !border-transparent bg-black/70 px-2.5 py-1.5 text-xs text-white shadow-lg backdrop-blur-sm lg:top-4 lg:right-auto lg:left-1/2 lg:max-w-[calc(100vw-10rem)] lg:-translate-x-1/2 lg:justify-start lg:bg-black/60 lg:px-4 lg:py-2 lg:text-sm dark:border\">\n <div class=\"flex min-w-0 items-baseline gap-1.5\">\n <span class=\"min-w-0 truncate font-medium lg:max-w-[12.5rem]\">{{ file().name }}</span>\n <span class=\"hidden shrink-0 text-white/70 lg:inline\">({{ formattedSize() }})</span>\n </div>\n\n @if (files().length > 1) {\n <span class=\"hidden shrink-0 text-white/70 md:inline\">{{ currentIndex() + 1 }} / {{ files().length }}</span>\n }\n\n <div class=\"ml-1 flex shrink-0 items-center gap-0.5\">\n @if (isImageFile()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_left' | translate\"\n (click)=\"rotateLeft()\">\n <i z-icon zType=\"lucideUndo\" zSize=\"14\"></i>\n </button>\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_rotate_right' | translate\"\n (click)=\"rotateRight()\">\n <i z-icon zType=\"lucideRedo\" zSize=\"14\"></i>\n </button>\n }\n\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_download' | translate\"\n (click)=\"download()\">\n <i z-icon zType=\"lucideDownload\" zSize=\"14\"></i>\n </button>\n\n @if (zShowRemove()) {\n <button\n z-button\n zType=\"ghost\"\n zSize=\"xs\"\n zShape=\"circle\"\n class=\"text-white hover:bg-white/20\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_gallery_delete' | translate\"\n (click)=\"remove()\">\n <i z-icon zType=\"lucideTrash2\" zSize=\"14\"></i>\n </button>\n }\n </div>\n </div>\n\n <div class=\"relative flex flex-1 items-center justify-center pt-16\">\n @if (isImageFile()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <img\n [src]=\"file().url || file().thumbnailUrl\"\n [alt]=\"file().name\"\n class=\"max-h-full max-w-full rounded-lg object-contain shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n [class.cursor-zoom-in]=\"!zoomed()\"\n [class.cursor-zoom-out]=\"zoomed()\"\n [style.transform]=\"imageTransform()\"\n (load)=\"onImageLoad()\"\n (error)=\"onMediaError()\"\n (click)=\"toggleZoom()\" />\n }\n </div>\n } @else if (isPdf() && pdfUrl()) {\n <div\n class=\"z-gallery-pdf-frame relative h-[75vh] w-[85vw] max-w-[96vw] overflow-hidden rounded-sm border shadow-xs\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-sm\" />\n <div\n class=\"text-muted-foreground absolute inset-0 z-10 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center p-8\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <div\n class=\"relative size-full bg-white transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\">\n @let pdfConfig = pdfViewerConfig();\n <ng2-pdfjs-viewer\n #pdfViewer\n class=\"block size-full\"\n [viewerFolder]=\"pdfConfig.viewerFolder!\"\n [viewerId]=\"pdfViewerId()\"\n [pdfSrc]=\"pdfUrl()!\"\n [downloadFileName]=\"file().name\"\n [locale]=\"pdfConfig.locale!\"\n [showSpinner]=\"pdfConfig.showSpinner!\"\n [useOnlyCssZoom]=\"pdfConfig.useOnlyCssZoom!\"\n [diagnosticLogs]=\"pdfConfig.diagnosticLogs!\"\n [showOpenFile]=\"pdfConfig.showOpenFile!\"\n [showAnnotations]=\"pdfConfig.showAnnotations!\"\n [showDownload]=\"pdfConfig.showDownload!\"\n [showViewBookmark]=\"pdfConfig.showViewBookmark!\"\n [showPrint]=\"pdfConfig.showPrint!\"\n [showFullScreen]=\"pdfConfig.showFullScreen!\"\n [showFind]=\"pdfConfig.showFind!\"\n [downloadOnLoad]=\"pdfConfig.downloadOnLoad!\"\n [printOnLoad]=\"pdfConfig.printOnLoad!\"\n [rotateCW]=\"pdfConfig.rotateCW!\"\n [rotateCCW]=\"pdfConfig.rotateCCW!\"\n [showLastPageOnLoad]=\"pdfConfig.showLastPageOnLoad!\"\n [showToolbarLeft]=\"pdfConfig.showToolbarLeft!\"\n [showToolbarMiddle]=\"pdfConfig.showToolbarMiddle!\"\n [showToolbarRight]=\"pdfConfig.showToolbarRight!\"\n [showSecondaryToolbarToggle]=\"pdfConfig.showSecondaryToolbarToggle!\"\n [showSidebar]=\"pdfConfig.showSidebar!\"\n [showSidebarLeft]=\"pdfConfig.showSidebarLeft!\"\n [showSidebarRight]=\"pdfConfig.showSidebarRight!\"\n [toolbarDensity]=\"pdfConfig.toolbarDensity!\"\n [sidebarWidth]=\"pdfConfig.sidebarWidth\"\n [toolbarPosition]=\"pdfConfig.toolbarPosition!\"\n [sidebarPosition]=\"pdfConfig.sidebarPosition!\"\n [responsiveBreakpoint]=\"pdfConfig.responsiveBreakpoint\"\n [zoom]=\"pdfConfig.zoom!\"\n [rotation]=\"pdfConfig.rotation!\"\n [cursor]=\"pdfConfig.cursor!\"\n [scroll]=\"pdfConfig.scroll!\"\n [spread]=\"pdfConfig.spread!\"\n [pageMode]=\"pdfConfig.pageMode!\"\n [page]=\"pdfConfig.page!\"\n [iframeBorder]=\"pdfConfig.iframeBorder!\"\n [theme]=\"pdfConfig.theme!\"\n [primaryColor]=\"pdfConfig.primaryColor\"\n [backgroundColor]=\"pdfConfig.backgroundColor\"\n [pageBorderColor]=\"pdfConfig.pageBorderColor\"\n [pageSpacing]=\"pdfConfig.pageSpacing\"\n [toolbarColor]=\"pdfConfig.toolbarColor\"\n [textColor]=\"pdfConfig.textColor\"\n [borderRadius]=\"pdfConfig.borderRadius\"\n [customCSS]=\"pdfConfig.customCSS\"\n [cspNonce]=\"pdfConfig.cspNonce\"\n [iframeTitle]=\"pdfConfig.iframeTitle || ('i18n_z_ui_gallery_pdf_preview' | translate)\"\n [urlValidation]=\"pdfConfig.urlValidation!\"\n [controlVisibility]=\"pdfConfig.controlVisibility!\"\n [groupVisibility]=\"pdfConfig.groupVisibility!\"\n [autoActions]=\"pdfConfig.autoActions!\"\n [viewerConfig]=\"pdfConfig.viewerConfig!\"\n [themeConfig]=\"pdfConfig.themeConfig!\"\n [layoutConfig]=\"pdfConfig.layoutConfig!\"\n (onDocumentLoad)=\"onPdfLoad()\"\n (onDocumentError)=\"onMediaError()\" />\n </div>\n }\n </div>\n } @else if (isVideo()) {\n <div class=\"relative flex h-[60vh] w-[70vw] items-center justify-center\">\n @if (isLoading()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (previewError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-8 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-16 items-center justify-center rounded-xl\">\n <i z-icon zType=\"lucideTriangleAlert\" zSize=\"28\" class=\"text-destructive\"></i>\n </div>\n <span class=\"text-foreground text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_preview_load_error' | translate }}\n </span>\n </div>\n } @else {\n <video\n [src]=\"file().url\"\n controls\n autoplay\n class=\"max-h-full max-w-full rounded-lg shadow-2xl transition-opacity duration-300\"\n [class.opacity-0]=\"isLoading()\"\n [class.opacity-100]=\"!isLoading()\"\n (loadeddata)=\"onVideoLoad()\"\n (error)=\"onMediaError()\">\n {{ 'i18n_z_ui_gallery_video_not_supported' | translate }}\n </video>\n }\n </div>\n } @else if (isWordFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-8 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isExcelFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (docHtmlContent()) {\n <div\n class=\"absolute inset-0 overflow-auto rounded-lg bg-white p-4 text-gray-950 shadow-2xl\"\n [innerHTML]=\"docHtmlContent()\"></div>\n }\n </div>\n } @else if (isTextFile()) {\n <div class=\"relative h-[75vh] w-[85vw]\">\n @if (isLoading() || isConverting()) {\n <z-skeleton class=\"absolute inset-0 rounded-lg\" />\n <div class=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm font-medium\">\n {{ 'i18n_z_ui_gallery_loading_preview' | translate }}\n </div>\n }\n @if (conversionError()) {\n <div class=\"bg-card flex size-full flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground rounded-md bg-red-100 px-3 py-1.5 text-xs dark:bg-red-900/30\">\n <span class=\"text-red-700 dark:text-red-300\">{{ conversionError() }}</span>\n </span>\n </div>\n } @else if (textContent()) {\n <div class=\"absolute inset-0 overflow-auto rounded-lg bg-gray-950 p-6 shadow-2xl\">\n <pre class=\"font-mono text-sm leading-relaxed whitespace-pre-wrap text-gray-100\">{{ textContent() }}</pre>\n </div>\n }\n </div>\n } @else {\n <div class=\"bg-card flex flex-col items-center justify-center rounded-lg p-12 shadow-2xl\">\n <div class=\"bg-muted mb-4 flex size-24 items-center justify-center rounded-xl\">\n <i z-icon [zType]=\"fileIcon()\" zSize=\"40\" class=\"text-muted-foreground\"></i>\n </div>\n <span class=\"text-foreground mb-2 text-lg font-medium\">{{ file().name }}</span>\n <span class=\"text-muted-foreground mb-4 text-sm\">{{ formattedSize() }}</span>\n <span class=\"text-muted-foreground rounded-md bg-amber-100 px-3 py-1.5 text-xs dark:bg-amber-900/30\">\n <i\n z-icon\n zType=\"lucideInfo\"\n zSize=\"14\"\n class=\"mr-1 inline-block align-middle text-amber-600 dark:text-amber-400\"></i>\n <span class=\"align-middle text-amber-700 dark:text-amber-300\">\n {{ 'i18n_z_ui_gallery_preview_not_supported' | translate }}\n </span>\n </span>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [".z-gallery-pdf-frame,.z-gallery-pdf-frame *{border-color:#606060!important;outline-color:#606060!important}.z-gallery-pdf-frame{border-width:1px!important;border-style:solid!important;background:#606060}.z-gallery-pdf-frame ng2-pdfjs-viewer,.z-gallery-pdf-frame ng2-pdfjs-viewer iframe{display:block;width:100%;height:100%;border:0!important;outline:0!important;box-shadow:none!important;background:#606060}\n"] }]
1373
1373
  }], ctorParameters: () => [], propDecorators: { file: [{ type: i0.Input, args: [{ isSignal: true, alias: "file", required: true }] }], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], zShowRemove: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowRemove", required: false }] }], zPdfViewerConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPdfViewerConfig", required: false }] }], zTrustedResourceOrigins: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTrustedResourceOrigins", required: false }] }], zOnClose: [{ type: i0.Output, args: ["zOnClose"] }], zOnDownload: [{ type: i0.Output, args: ["zOnDownload"] }], zOnNavigate: [{ type: i0.Output, args: ["zOnNavigate"] }], zOnRemove: [{ type: i0.Output, args: ["zOnRemove"] }], pdfViewer: [{ type: i0.ViewChild, args: ['pdfViewer', { isSignal: true }] }] } });
1374
1374
 
1375
+ class ZGalleryPreviewRef {
1376
+ _overlayRef;
1377
+ _closed = false;
1378
+ componentInstance = null;
1379
+ zAfterClose = new EventEmitter();
1380
+ constructor(_overlayRef) {
1381
+ this._overlayRef = _overlayRef;
1382
+ }
1383
+ close() {
1384
+ if (this._closed) {
1385
+ return;
1386
+ }
1387
+ this._closed = true;
1388
+ this.zAfterClose.emit();
1389
+ this.zAfterClose.complete();
1390
+ this._overlayRef?.dispose();
1391
+ }
1392
+ }
1393
+
1394
+ class ZGalleryPreviewService {
1395
+ _document = inject(DOCUMENT);
1396
+ _injector = inject(Injector);
1397
+ _overlay = inject(Overlay);
1398
+ _platformId = inject(PLATFORM_ID);
1399
+ _zIndexService = inject(ZOverlayZIndexService);
1400
+ open(fileOrOptions, options = {}) {
1401
+ const previewOptions = this._normalizeOptions(fileOrOptions, options);
1402
+ const overlayRef = this._createOverlay();
1403
+ const previewRef = new ZGalleryPreviewRef(overlayRef ?? null);
1404
+ if (!overlayRef) {
1405
+ return previewRef;
1406
+ }
1407
+ const componentRef = overlayRef.attach(new ComponentPortal(ZGalleryPreviewComponent, null, this._injector));
1408
+ previewRef.componentInstance = componentRef.instance;
1409
+ componentRef.setInput('file', previewOptions.file);
1410
+ componentRef.setInput('files', previewOptions.files);
1411
+ componentRef.setInput('zShowRemove', previewOptions.zShowRemove ?? false);
1412
+ componentRef.setInput('zPdfViewerConfig', previewOptions.zPdfViewerConfig ?? {});
1413
+ componentRef.setInput('zTrustedResourceOrigins', previewOptions.zTrustedResourceOrigins ?? []);
1414
+ componentRef.instance.zOnClose.subscribe(() => {
1415
+ previewOptions.zOnClose?.();
1416
+ previewRef.close();
1417
+ });
1418
+ componentRef.instance.zOnDownload.subscribe(file => this._handleDownload(file, previewOptions));
1419
+ componentRef.instance.zOnNavigate.subscribe(file => {
1420
+ componentRef.setInput('file', file);
1421
+ previewOptions.zOnNavigate?.(file);
1422
+ });
1423
+ componentRef.instance.zOnRemove.subscribe(file => previewOptions.zOnRemove?.(file));
1424
+ return previewRef;
1425
+ }
1426
+ _createOverlay() {
1427
+ if (!isPlatformBrowser(this._platformId)) {
1428
+ return undefined;
1429
+ }
1430
+ const overlayRef = this._overlay.create(new OverlayConfig({
1431
+ hasBackdrop: false,
1432
+ panelClass: 'z-gallery-preview-overlay-pane',
1433
+ positionStrategy: this._overlay.position().global(),
1434
+ scrollStrategy: this._overlay.scrollStrategies.block(),
1435
+ }));
1436
+ this._zIndexService.applyToOverlay(overlayRef);
1437
+ this._zIndexService.deferMoveToTop(overlayRef);
1438
+ return overlayRef;
1439
+ }
1440
+ _normalizeOptions(fileOrOptions, options) {
1441
+ const previewOptions = 'file' in fileOrOptions ? fileOrOptions : { ...options, file: fileOrOptions };
1442
+ const files = previewOptions.files?.length ? previewOptions.files : [previewOptions.file];
1443
+ const hasCurrentFile = files.some(file => file.id === previewOptions.file.id);
1444
+ return {
1445
+ ...previewOptions,
1446
+ files: hasCurrentFile ? files : [previewOptions.file, ...files],
1447
+ };
1448
+ }
1449
+ _handleDownload(file, options) {
1450
+ options.zOnDownload?.(file);
1451
+ if (options.zDownload === false) {
1452
+ return;
1453
+ }
1454
+ const downloadLink = file.downloadUrl || file.url;
1455
+ if (!downloadLink || !isPlatformBrowser(this._platformId)) {
1456
+ return;
1457
+ }
1458
+ const link = this._document.createElement('a');
1459
+ link.href = downloadLink;
1460
+ link.download = file.name;
1461
+ link.target = '_blank';
1462
+ this._document.body.appendChild(link);
1463
+ link.click();
1464
+ this._document.body.removeChild(link);
1465
+ }
1466
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1467
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, providedIn: 'root' });
1468
+ }
1469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, decorators: [{
1470
+ type: Injectable,
1471
+ args: [{
1472
+ providedIn: 'root',
1473
+ }]
1474
+ }] });
1475
+
1375
1476
  const zGalleryVariants = cva('z-gallery', {
1376
1477
  variants: {
1377
1478
  zSize: {
@@ -1437,6 +1538,9 @@ const zGalleryFileIconVariants = cva('flex items-center justify-center rounded-m
1437
1538
  });
1438
1539
 
1439
1540
  class ZGalleryComponent {
1541
+ _destroyRef = inject(DestroyRef);
1542
+ _previewService = inject(ZGalleryPreviewService);
1543
+ _previewRef = null;
1440
1544
  zFiles = input([], ...(ngDevMode ? [{ debugName: "zFiles" }] : []));
1441
1545
  zMode = model('grid', ...(ngDevMode ? [{ debugName: "zMode" }] : []));
1442
1546
  zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
@@ -1471,7 +1575,6 @@ class ZGalleryComponent {
1471
1575
  zSelectionChange = output();
1472
1576
  zOnAction = output();
1473
1577
  modeIndex = signal(0, ...(ngDevMode ? [{ debugName: "modeIndex" }] : []));
1474
- previewFile = signal(null, ...(ngDevMode ? [{ debugName: "previewFile" }] : []));
1475
1578
  searchInputQuery = signal('', ...(ngDevMode ? [{ debugName: "searchInputQuery" }] : []));
1476
1579
  searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1477
1580
  skeletonItems = computed(() => {
@@ -1579,6 +1682,7 @@ class ZGalleryComponent {
1579
1682
  }, ...(ngDevMode ? [{ debugName: "isIndeterminate" }] : []));
1580
1683
  selectedCount = computed(() => this.zSelectedFiles().length, ...(ngDevMode ? [{ debugName: "selectedCount" }] : []));
1581
1684
  ngAfterViewInit() {
1685
+ this._destroyRef.onDestroy(() => this.closePreview());
1582
1686
  this.zControl.emit({
1583
1687
  setMode: mode => {
1584
1688
  this.modeIndex.set(mode === 'list' ? 1 : 0);
@@ -1587,8 +1691,8 @@ class ZGalleryComponent {
1587
1691
  },
1588
1692
  getMode: () => this.currentMode(),
1589
1693
  getFiles: () => this.zFiles(),
1590
- openPreview: file => this.previewFile.set(file),
1591
- closePreview: () => this.previewFile.set(null),
1694
+ openPreview: file => this._openPreview(file),
1695
+ closePreview: () => this.closePreview(),
1592
1696
  selectAll: () => this.selectAll(),
1593
1697
  deselectAll: () => this.deselectAll(),
1594
1698
  toggleSelection: file => this.toggleSelection(file),
@@ -1615,17 +1719,14 @@ class ZGalleryComponent {
1615
1719
  }
1616
1720
  }
1617
1721
  onPreview(file) {
1618
- this.previewFile.set(file);
1619
- this.zOnPreview.emit(file);
1722
+ this._openPreview(file, true);
1620
1723
  }
1621
1724
  onRemove(file) {
1622
1725
  this.zOnRemove.emit(file);
1623
1726
  }
1624
1727
  closePreview() {
1625
- this.previewFile.set(null);
1626
- }
1627
- onNavigatePreview(file) {
1628
- this.previewFile.set(file);
1728
+ this._previewRef?.close();
1729
+ this._previewRef = null;
1629
1730
  }
1630
1731
  onRemoveFromPreview(file) {
1631
1732
  this.zOnRemove.emit(file);
@@ -1633,12 +1734,30 @@ class ZGalleryComponent {
1633
1734
  const currentIndex = allFiles.findIndex(f => f.id === file.id);
1634
1735
  if (allFiles.length <= 1) {
1635
1736
  this.closePreview();
1636
- }
1637
- if (currentIndex < allFiles.length - 1) {
1638
- this.previewFile.set(allFiles[currentIndex + 1]);
1639
1737
  return;
1640
1738
  }
1641
- this.previewFile.set(allFiles[currentIndex - 1]);
1739
+ const nextFile = currentIndex < allFiles.length - 1 ? allFiles[currentIndex + 1] : allFiles[currentIndex - 1];
1740
+ this._openPreview(nextFile);
1741
+ }
1742
+ _openPreview(file, emitPreview = false) {
1743
+ this.closePreview();
1744
+ if (emitPreview) {
1745
+ this.zOnPreview.emit(file);
1746
+ }
1747
+ const previewRef = this._previewService.open({
1748
+ file,
1749
+ files: this.filteredFiles(),
1750
+ zShowRemove: this.zShowRemove(),
1751
+ zPdfViewerConfig: this.zPdfViewerConfig(),
1752
+ zTrustedResourceOrigins: this.zTrustedResourceOrigins(),
1753
+ zDownload: false,
1754
+ zOnClose: () => {
1755
+ this._previewRef = null;
1756
+ },
1757
+ zOnDownload: previewFile => this.onDownload(previewFile),
1758
+ zOnRemove: previewFile => this.onRemoveFromPreview(previewFile),
1759
+ });
1760
+ this._previewRef = previewRef;
1642
1761
  }
1643
1762
  isFileSelected(file) {
1644
1763
  return this.selectedIds().has(file.id);
@@ -1867,22 +1986,8 @@ class ZGalleryComponent {
1867
1986
  zSize="sm"
1868
1987
  />
1869
1988
  }
1870
-
1871
- @if (previewFile()) {
1872
- <z-gallery-preview
1873
- [file]="previewFile()!"
1874
- [files]="filteredFiles()"
1875
- [zShowRemove]="zShowRemove()"
1876
- [zPdfViewerConfig]="zPdfViewerConfig()"
1877
- [zTrustedResourceOrigins]="zTrustedResourceOrigins()"
1878
- (zOnClose)="closePreview()"
1879
- (zOnDownload)="onDownload($event)"
1880
- (zOnNavigate)="onNavigatePreview($event)"
1881
- (zOnRemove)="onRemoveFromPreview($event)"
1882
- />
1883
- }
1884
1989
  </div>
1885
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ZGalleryItemComponent, selector: "z-gallery-item", inputs: ["file", "zMode", "zSize", "zShowDownload", "zShowPreview", "zShowRemove", "zSelectable", "zSelected"], outputs: ["zOnDownload", "zOnPreview", "zOnRemove", "zOnSelect"] }, { kind: "component", type: ZGalleryPreviewComponent, selector: "z-gallery-preview", inputs: ["file", "files", "zShowRemove", "zPdfViewerConfig", "zTrustedResourceOrigins"], outputs: ["zOnClose", "zOnDownload", "zOnNavigate", "zOnRemove"] }, { kind: "component", type: ZButtonGroupComponent, selector: "z-button-group", inputs: ["zClass", "zOrientation", "zActive"], outputs: ["zActiveChange"], exportAs: ["zButtonGroup"] }, { kind: "directive", type: ZButtonGroupItemDirective, selector: "[z-button-group-item]", exportAs: ["zButtonGroupItem"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1990
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ZGalleryItemComponent, selector: "z-gallery-item", inputs: ["file", "zMode", "zSize", "zShowDownload", "zShowPreview", "zShowRemove", "zSelectable", "zSelected"], outputs: ["zOnDownload", "zOnPreview", "zOnRemove", "zOnSelect"] }, { kind: "component", type: ZButtonGroupComponent, selector: "z-button-group", inputs: ["zClass", "zOrientation", "zActive"], outputs: ["zActiveChange"], exportAs: ["zButtonGroup"] }, { kind: "directive", type: ZButtonGroupItemDirective, selector: "[z-button-group-item]", exportAs: ["zButtonGroupItem"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1886
1991
  }
1887
1992
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryComponent, decorators: [{
1888
1993
  type: Component,
@@ -1892,7 +1997,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
1892
1997
  FormsModule,
1893
1998
  TranslatePipe,
1894
1999
  ZGalleryItemComponent,
1895
- ZGalleryPreviewComponent,
1896
2000
  ZButtonGroupComponent,
1897
2001
  ZButtonGroupItemDirective,
1898
2002
  ZButtonComponent,
@@ -2080,20 +2184,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
2080
2184
  zSize="sm"
2081
2185
  />
2082
2186
  }
2083
-
2084
- @if (previewFile()) {
2085
- <z-gallery-preview
2086
- [file]="previewFile()!"
2087
- [files]="filteredFiles()"
2088
- [zShowRemove]="zShowRemove()"
2089
- [zPdfViewerConfig]="zPdfViewerConfig()"
2090
- [zTrustedResourceOrigins]="zTrustedResourceOrigins()"
2091
- (zOnClose)="closePreview()"
2092
- (zOnDownload)="onDownload($event)"
2093
- (zOnNavigate)="onNavigatePreview($event)"
2094
- (zOnRemove)="onRemoveFromPreview($event)"
2095
- />
2096
- }
2097
2187
  </div>
2098
2188
  `,
2099
2189
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -2197,107 +2287,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
2197
2287
  }]
2198
2288
  }], propDecorators: { file: [{ type: i0.Input, args: [{ isSignal: true, alias: "file", required: true }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMode", required: false }] }] } });
2199
2289
 
2200
- class ZGalleryPreviewRef {
2201
- _overlayRef;
2202
- _closed = false;
2203
- componentInstance = null;
2204
- zAfterClose = new EventEmitter();
2205
- constructor(_overlayRef) {
2206
- this._overlayRef = _overlayRef;
2207
- }
2208
- close() {
2209
- if (this._closed) {
2210
- return;
2211
- }
2212
- this._closed = true;
2213
- this.zAfterClose.emit();
2214
- this.zAfterClose.complete();
2215
- this._overlayRef?.dispose();
2216
- }
2217
- }
2218
-
2219
- class ZGalleryPreviewService {
2220
- _document = inject(DOCUMENT);
2221
- _injector = inject(Injector);
2222
- _overlay = inject(Overlay);
2223
- _platformId = inject(PLATFORM_ID);
2224
- _zIndexService = inject(ZOverlayZIndexService);
2225
- open(fileOrOptions, options = {}) {
2226
- const previewOptions = this._normalizeOptions(fileOrOptions, options);
2227
- const overlayRef = this._createOverlay();
2228
- const previewRef = new ZGalleryPreviewRef(overlayRef ?? null);
2229
- if (!overlayRef) {
2230
- return previewRef;
2231
- }
2232
- const componentRef = overlayRef.attach(new ComponentPortal(ZGalleryPreviewComponent, null, this._injector));
2233
- previewRef.componentInstance = componentRef.instance;
2234
- componentRef.setInput('file', previewOptions.file);
2235
- componentRef.setInput('files', previewOptions.files);
2236
- componentRef.setInput('zShowRemove', previewOptions.zShowRemove ?? false);
2237
- componentRef.setInput('zPdfViewerConfig', previewOptions.zPdfViewerConfig ?? {});
2238
- componentRef.setInput('zTrustedResourceOrigins', previewOptions.zTrustedResourceOrigins ?? []);
2239
- componentRef.instance.zOnClose.subscribe(() => {
2240
- previewOptions.zOnClose?.();
2241
- previewRef.close();
2242
- });
2243
- componentRef.instance.zOnDownload.subscribe(file => this._handleDownload(file, previewOptions));
2244
- componentRef.instance.zOnNavigate.subscribe(file => {
2245
- componentRef.setInput('file', file);
2246
- previewOptions.zOnNavigate?.(file);
2247
- });
2248
- componentRef.instance.zOnRemove.subscribe(file => previewOptions.zOnRemove?.(file));
2249
- return previewRef;
2250
- }
2251
- _createOverlay() {
2252
- if (!isPlatformBrowser(this._platformId)) {
2253
- return undefined;
2254
- }
2255
- const overlayRef = this._overlay.create(new OverlayConfig({
2256
- hasBackdrop: false,
2257
- panelClass: 'z-gallery-preview-overlay-pane',
2258
- positionStrategy: this._overlay.position().global(),
2259
- scrollStrategy: this._overlay.scrollStrategies.block(),
2260
- }));
2261
- this._zIndexService.applyToOverlay(overlayRef);
2262
- this._zIndexService.deferMoveToTop(overlayRef);
2263
- return overlayRef;
2264
- }
2265
- _normalizeOptions(fileOrOptions, options) {
2266
- const previewOptions = 'file' in fileOrOptions ? fileOrOptions : { ...options, file: fileOrOptions };
2267
- const files = previewOptions.files?.length ? previewOptions.files : [previewOptions.file];
2268
- const hasCurrentFile = files.some(file => file.id === previewOptions.file.id);
2269
- return {
2270
- ...previewOptions,
2271
- files: hasCurrentFile ? files : [previewOptions.file, ...files],
2272
- };
2273
- }
2274
- _handleDownload(file, options) {
2275
- options.zOnDownload?.(file);
2276
- if (options.zDownload === false) {
2277
- return;
2278
- }
2279
- const downloadLink = file.downloadUrl || file.url;
2280
- if (!downloadLink || !isPlatformBrowser(this._platformId)) {
2281
- return;
2282
- }
2283
- const link = this._document.createElement('a');
2284
- link.href = downloadLink;
2285
- link.download = file.name;
2286
- link.target = '_blank';
2287
- this._document.body.appendChild(link);
2288
- link.click();
2289
- this._document.body.removeChild(link);
2290
- }
2291
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2292
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, providedIn: 'root' });
2293
- }
2294
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZGalleryPreviewService, decorators: [{
2295
- type: Injectable,
2296
- args: [{
2297
- providedIn: 'root',
2298
- }]
2299
- }] });
2300
-
2301
2290
  class ZGalleryPreviewItemDirective {
2302
2291
  zGalleryPreviewItem = input.required(...(ngDevMode ? [{ debugName: "zGalleryPreviewItem" }] : []));
2303
2292
  zGalleryPreviewFiles = input(null, ...(ngDevMode ? [{ debugName: "zGalleryPreviewFiles" }] : []));