ngx-kit 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/angle-selector/README.md +34 -34
  2. package/box-shadow/README.md +33 -33
  3. package/color-picker/README.md +52 -52
  4. package/data-table/README.md +120 -120
  5. package/date-picker/README.md +74 -74
  6. package/dialog/README.md +92 -92
  7. package/drag-resize/README.md +55 -55
  8. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  9. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  10. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  11. package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -1
  12. package/fesm2022/ngx-kit-drawer-menu.mjs +2 -2
  13. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  15. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-gallery.mjs +2 -2
  17. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-grid-layout.mjs +108 -41
  19. package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-infinite-scroll.mjs +467 -0
  21. package/fesm2022/ngx-kit-infinite-scroll.mjs.map +1 -0
  22. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  23. package/fesm2022/ngx-kit-virtual-scroll.mjs +2 -2
  24. package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -1
  25. package/fesm2022/ngx-kit-webflow.mjs +38 -38
  26. package/fesm2022/ngx-kit-webflow.mjs.map +1 -1
  27. package/gallery/README.md +71 -71
  28. package/gradient-picker/README.md +41 -41
  29. package/grid-layout/README.md +64 -64
  30. package/image-editor/README.md +44 -44
  31. package/infinite-scroll/README.md +252 -0
  32. package/menu/README.md +85 -85
  33. package/message/README.md +70 -70
  34. package/notify/README.md +56 -56
  35. package/package.json +5 -1
  36. package/shared/README.md +117 -117
  37. package/time-picker/README.md +89 -89
  38. package/types/ngx-kit-grid-layout.d.ts +21 -20
  39. package/types/ngx-kit-infinite-scroll.d.ts +86 -0
  40. package/virtual-scroll/README.md +199 -199
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-kit-gallery.mjs","sources":["../../../projects/libs/gallery/contracts/image-viewer-types.ts","../../../projects/libs/gallery/utils/download-print.ts","../../../projects/libs/gallery/utils/zoom-math.ts","../../../projects/libs/gallery/components/image-viewer.component.ts","../../../projects/libs/gallery/components/image-viewer.component.html","../../../projects/libs/gallery/services/image-viewer.service.ts","../../../projects/libs/gallery/ngx-kit-gallery.ts"],"sourcesContent":["export interface NgxImageViewerItem {\n src: string;\n alt?: string;\n caption?: string;\n /** نام فایل هنگام دانلود؛ نبود یعنی از روی src حدس زده می‌شه */\n downloadFileName?: string;\n}\n\n/**\n * هر دکمه‌ی نوار ابزار جدا فعال/غیرفعال می‌شه — دقیقاً طبق خواسته: «این\n * دکمه‌های کانفیگی باشه که هر کدوم خواست فعال کنه».\n */\nexport interface NgxImageViewerToolbarConfig {\n prevNext?: boolean;\n counter?: boolean;\n zoomIn?: boolean;\n zoomOut?: boolean;\n resetZoom?: boolean;\n rotateLeft?: boolean;\n rotateRight?: boolean;\n download?: boolean;\n print?: boolean;\n fullscreen?: boolean;\n close?: boolean;\n}\n\nexport const NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR: Required<NgxImageViewerToolbarConfig> = {\n prevNext: true,\n counter: true,\n zoomIn: true,\n zoomOut: true,\n resetZoom: true,\n rotateLeft: true,\n rotateRight: true,\n download: true,\n print: true,\n fullscreen: true,\n close: false,\n};\n","/** دانلود تصویر با fetch→blob (نام‌گذاریِ درست فایل رو تضمین می‌کنه)؛ اگه CORS اجازه نداد، در تب جدید باز می‌شه */\nexport async function downloadImage(src: string, filename?: string): Promise<void> {\n try {\n const response = await fetch(src, { mode: 'cors' });\n if (!response.ok) throw new Error('fetch failed');\n const blob = await response.blob();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename || guessFileName(src);\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n } catch {\n window.open(src, '_blank', 'noopener,noreferrer');\n }\n}\n\nfunction guessFileName(src: string): string {\n try {\n const url = new URL(src, typeof window !== 'undefined' ? window.location.href : undefined);\n const last = url.pathname.split('/').pop();\n return last || 'image';\n } catch {\n return 'image';\n }\n}\n\n/** یه پنجره‌ی جدید فقط با همون تصویر باز می‌کنه و بعد از لود، print می‌زنه؛ با DOM API (نه innerHTML) پس در برابر src مخرب امنه */\nexport function printImage(src: string): void {\n const win = window.open('', '_blank', 'noopener,noreferrer,width=800,height=600');\n if (!win) return;\n\n win.document.title = 'Print';\n const style = win.document.createElement('style');\n style.textContent =\n 'body{margin:0;display:flex;align-items:center;justify-content:center;min-height:100vh;background:#fff;}img{max-width:100%;max-height:100vh;}';\n win.document.head.appendChild(style);\n\n const img = win.document.createElement('img');\n img.onload = () => {\n win.focus();\n win.print();\n };\n img.src = src;\n win.document.body.appendChild(img);\n}\n","export interface PanZoomState {\n zoom: number;\n panX: number;\n panY: number;\n}\n\n/**\n * با تغییر zoom، pan رو طوری تنظیم می‌کنه که نقطه‌ی زیر cursor/انگشت‌ها\n * (نسبت به مرکز کانتینر) سرجاش بمونه — یعنی zoom-to-cursor به‌جای\n * zoom-to-center (که تجربه‌ی خیلی بهتری داره، دقیقاً مثل هر ویوئر حرفه‌ای).\n *\n * ریاضیِ پشتش: با transform=\"translate(panX,panY) scale(zoom)\"، موقعیتِ\n * صفحه‌ایِ یه نقطه‌ی محلیِ p (نسبت به مرکز) برابره با\n * center + pan + p*zoom. اول p رو از روی وضعیت فعلی حساب می‌کنیم، بعد pan\n * جدید رو طوری می‌سازیم که با zoom تازه، همون p به همون مختصات صفحه برسه.\n */\nexport function zoomAroundPoint(\n current: PanZoomState,\n newZoom: number,\n cursorX: number,\n cursorY: number,\n containerWidth: number,\n containerHeight: number,\n): PanZoomState {\n const centerX = containerWidth / 2;\n const centerY = containerHeight / 2;\n const localX = (cursorX - centerX - current.panX) / current.zoom;\n const localY = (cursorY - centerY - current.panY) / current.zoom;\n return {\n zoom: newZoom,\n panX: cursorX - centerX - localX * newZoom,\n panY: cursorY - centerY - localY * newZoom,\n };\n}\n\nexport function distanceBetweenTouches(a: Touch, b: Touch): number {\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n}\n\nexport function midpointOfTouches(a: Touch, b: Touch): { x: number; y: number } {\n return { x: (a.clientX + b.clientX) / 2, y: (a.clientY + b.clientY) / 2 };\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n HostListener,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { startDragSession } from 'ngx-kit/shared';\nimport {\n NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR,\n NgxImageViewerItem,\n NgxImageViewerToolbarConfig,\n} from '../contracts/image-viewer-types';\nimport { downloadImage, printImage } from '../utils/download-print';\nimport {\n clamp,\n distanceBetweenTouches,\n midpointOfTouches,\n zoomAroundPoint,\n} from '../utils/zoom-math';\n\n/**\n * ویوئر حرفه‌ایِ تصویر: یه لیست تصویر می‌گیره، اولی رو نشون می‌ده، با\n * دکمه‌های چپ/راست (مثل کاروسل) بین‌شون می‌ره، و یه نوار ابزار کاملاً\n * قابل‌تنظیم (هر دکمه جدا فعال/غیرفعال می‌شه) داره: زوم این/اوت/ریست،\n * چرخش، دانلود، پرینت، تمام‌صفحه.\n *\n * تعامل‌ها:\n * - اسکرول موس روی تصویر = زوم (نسبت به همون نقطه‌ی زیر cursor، نه مرکز)\n * - دو انگشتی روی تاچ = پینچ زوم\n * - وقتی زوم‌شده، درگ با موس یا تک‌انگشتی = پن\n * - کیبورد: ← → برای قبلی/بعدی، +/- برای زوم، Esc برای closed\n *\n * چون wheel/touchmove باید preventDefault بشن (وگرنه صفحه اسکرول/زوم\n * می‌شه) و انگیولار این ایونت‌ها رو به‌صورت پیش‌فرض passive رجیستر می‌کنه\n * (که توش preventDefault اثر نداره)، این‌ها با addEventListener دستی و\n * {passive:false} وصل می‌شن، نه با بایندینگ تمپلیت.\n *\n * می‌تونه هم مستقیم توی صفحه جا بگیره، هم توسط مصرف‌کننده داخل\n * ngx-kit/dialog (یا هر overlay دیگه) قرار بگیره — خودش به هیچ‌کدوم وابسته\n * نیست، فقط با closed خروجی به بیرون خبر می‌ده که «ببندم».\n */\n@Component({\n selector: 'ngx-image-viewer',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './image-viewer.component.html',\n styleUrl: './image-viewer.component.scss',\n host: { class: 'ngx-image-viewer-host', tabindex: '0' },\n})\nexport class NgxImageViewerComponent {\n images = input.required<NgxImageViewerItem[]>();\n startIndex = input<number>(0);\n toolbar = input<NgxImageViewerToolbarConfig>({});\n minZoom = input<number>(1);\n maxZoom = input<number>(6);\n zoomStep = input<number>(0.4);\n\n indexChange = output<number>();\n closed = output<void>();\n\n protected readonly activeIndex = signal(0);\n protected readonly zoom = signal(1);\n protected readonly panX = signal(0);\n protected readonly panY = signal(0);\n protected readonly rotation = signal(0);\n\n protected readonly activeImage = computed<NgxImageViewerItem | undefined>(\n () => this.images()[this.activeIndex()],\n );\n\n protected readonly toolbarConfig = computed(() => ({\n ...NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR,\n ...this.toolbar(),\n }));\n\n protected readonly isZoomed = computed(() => this.zoom() > 1);\n\n protected readonly stageTransform = computed(\n () =>\n `translate(${this.panX()}px, ${this.panY()}px) scale(${this.zoom()}) rotate(${this.rotation()}deg)`,\n );\n\n private readonly stageEl = viewChild<ElementRef<HTMLElement>>('stage');\n private readonly hostElRef = inject(ElementRef<HTMLElement>);\n private readonly destroyRef = inject(DestroyRef);\n\n private pinchStartDistance = 0;\n private pinchStartZoom = 1;\n private stopPanDrag?: () => void;\n\n constructor() {\n this.activeIndex.set(this.startIndex());\n\n // wheel/touch با addEventListener دستی + passive:false وصل می‌شن (دلیلش\n // بالای کلاس توضیح داده شده)؛ effect به‌صورت خودکار وقتی stageEl از\n // undefined به یه ElementRef واقعی تغییر کنه (یعنی بعد از اولین رندر)\n // دوباره اجرا می‌شه، پس نیازی به ngAfterViewInit نیست.\n effect((onCleanup) => {\n const stage = this.stageEl()?.nativeElement;\n if (!stage) return;\n\n const onWheel = (ev: WheelEvent) => {\n ev.preventDefault();\n const rect = stage.getBoundingClientRect();\n this.applyZoomAt(\n this.zoom() + (ev.deltaY < 0 ? 1 : -1) * this.zoomStep(),\n ev.clientX - rect.left,\n ev.clientY - rect.top,\n rect.width,\n rect.height,\n );\n };\n\n const onTouchStart = (ev: TouchEvent) => {\n if (ev.touches.length === 2) {\n this.stopPanDrag?.();\n this.pinchStartDistance = distanceBetweenTouches(ev.touches[0], ev.touches[1]);\n this.pinchStartZoom = this.zoom();\n } else if (ev.touches.length === 1 && this.isZoomed()) {\n this.beginPanDrag(ev);\n }\n };\n\n const onTouchMove = (ev: TouchEvent) => {\n if (ev.touches.length === 2 && this.pinchStartDistance > 0) {\n ev.preventDefault();\n const dist = distanceBetweenTouches(ev.touches[0], ev.touches[1]);\n const newZoom = (dist / this.pinchStartDistance) * this.pinchStartZoom;\n const rect = stage.getBoundingClientRect();\n const mid = midpointOfTouches(ev.touches[0], ev.touches[1]);\n this.applyZoomAt(newZoom, mid.x - rect.left, mid.y - rect.top, rect.width, rect.height);\n }\n };\n\n const onTouchEnd = () => {\n this.pinchStartDistance = 0;\n };\n\n stage.addEventListener('wheel', onWheel, { passive: false });\n stage.addEventListener('touchstart', onTouchStart, { passive: false });\n stage.addEventListener('touchmove', onTouchMove, { passive: false });\n stage.addEventListener('touchend', onTouchEnd);\n stage.addEventListener('touchcancel', onTouchEnd);\n\n onCleanup(() => {\n stage.removeEventListener('wheel', onWheel);\n stage.removeEventListener('touchstart', onTouchStart);\n stage.removeEventListener('touchmove', onTouchMove);\n stage.removeEventListener('touchend', onTouchEnd);\n stage.removeEventListener('touchcancel', onTouchEnd);\n });\n });\n\n this.destroyRef.onDestroy(() => this.stopPanDrag?.());\n }\n\n @HostListener('keydown', ['$event'])\n protected onKeydown(ev: KeyboardEvent): void {\n if (ev.key === 'ArrowLeft') this.prev();\n else if (ev.key === 'ArrowRight') this.next();\n else if (ev.key === '+' || ev.key === '=') this.zoomIn();\n else if (ev.key === '-') this.zoomOut();\n else if (ev.key === 'Escape') this.closed.emit();\n else return;\n ev.preventDefault();\n }\n\n protected next(): void {\n const len = this.images().length;\n if (len) this.goTo((this.activeIndex() + 1) % len);\n }\n\n protected prev(): void {\n const len = this.images().length;\n if (len) this.goTo((this.activeIndex() - 1 + len) % len);\n }\n\n protected goTo(index: number): void {\n this.activeIndex.set(index);\n this.resetView();\n this.indexChange.emit(index);\n }\n\n protected zoomIn(): void {\n this.setZoomAtCenter(this.zoom() + this.zoomStep());\n }\n\n protected zoomOut(): void {\n this.setZoomAtCenter(this.zoom() - this.zoomStep());\n }\n\n protected resetView(): void {\n this.zoom.set(1);\n this.panX.set(0);\n this.panY.set(0);\n this.rotation.set(0);\n }\n\n protected rotateLeft(): void {\n this.rotation.update((r) => r - 90);\n }\n\n protected rotateRight(): void {\n this.rotation.update((r) => r + 90);\n }\n\n protected async download(): Promise<void> {\n const img = this.activeImage();\n if (img) await downloadImage(img.src, img.downloadFileName);\n }\n\n protected print(): void {\n const img = this.activeImage();\n if (img) printImage(img.src);\n }\n\n protected toggleFullscreen(): void {\n const el = this.hostElRef.nativeElement;\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else {\n el.requestFullscreen?.();\n }\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected onPanPointerDown(ev: MouseEvent): void {\n if (!this.isZoomed()) return;\n this.beginPanDrag(ev);\n }\n\n private beginPanDrag(ev: MouseEvent | TouchEvent): void {\n ev.preventDefault();\n const startPanX = this.panX();\n const startPanY = this.panY();\n const startX = this.clientXOf(ev);\n const startY = this.clientYOf(ev);\n this.stopPanDrag?.();\n this.stopPanDrag = startDragSession({\n onMove: (moveEv) => {\n this.panX.set(startPanX + (this.clientXOf(moveEv) - startX));\n this.panY.set(startPanY + (this.clientYOf(moveEv) - startY));\n },\n onEnd: () => {\n this.stopPanDrag = undefined;\n },\n });\n }\n\n private setZoomAtCenter(newZoom: number): void {\n const stage = this.stageEl()?.nativeElement;\n if (!stage) {\n this.zoom.set(clamp(newZoom, this.minZoom(), this.maxZoom()));\n return;\n }\n const rect = stage.getBoundingClientRect();\n this.applyZoomAt(newZoom, rect.width / 2, rect.height / 2, rect.width, rect.height);\n }\n\n private applyZoomAt(\n rawZoom: number,\n x: number,\n y: number,\n containerWidth: number,\n containerHeight: number,\n ): void {\n const newZoom = clamp(rawZoom, this.minZoom(), this.maxZoom());\n if (newZoom === this.zoom()) return;\n const result = zoomAroundPoint(\n { zoom: this.zoom(), panX: this.panX(), panY: this.panY() },\n newZoom,\n x,\n y,\n containerWidth,\n containerHeight,\n );\n this.zoom.set(result.zoom);\n this.panX.set(result.panX);\n this.panY.set(result.panY);\n }\n\n private clientXOf(ev: MouseEvent | TouchEvent): number {\n return 'touches' in ev\n ? (ev.touches[0]?.clientX ?? ev.changedTouches[0]?.clientX ?? 0)\n : ev.clientX;\n }\n\n private clientYOf(ev: MouseEvent | TouchEvent): number {\n return 'touches' in ev\n ? (ev.touches[0]?.clientY ?? ev.changedTouches[0]?.clientY ?? 0)\n : ev.clientY;\n }\n}\n","<div class=\"ngx-iv-stage\" #stage [class.zoomed]=\"isZoomed()\">\n @if (toolbarConfig().close) {\n <button type=\"button\" class=\"ngx-iv-close\" (click)=\"close()\" aria-label=\"Close\">✕</button>\n }\n\n @if (activeImage(); as img) {\n <img\n class=\"ngx-iv-image\"\n [class.grab]=\"isZoomed()\"\n [src]=\"img.src\"\n [alt]=\"img.alt || ''\"\n draggable=\"false\"\n [style.transform]=\"stageTransform()\"\n (mousedown)=\"onPanPointerDown($event)\" />\n }\n\n @if (toolbarConfig().prevNext && images().length > 1) {\n <button\n type=\"button\"\n class=\"ngx-iv-nav ngx-iv-nav--prev\"\n (click)=\"prev()\"\n aria-label=\"Previous\">\n ‹\n </button>\n <button type=\"button\" class=\"ngx-iv-nav ngx-iv-nav--next\" (click)=\"next()\" aria-label=\"Next\">\n ›\n </button>\n }\n\n @if (toolbarConfig().counter && images().length > 1) {\n <div class=\"ngx-iv-counter\">{{ activeIndex() + 1 }} / {{ images().length }}</div>\n }\n</div>\n\n@if (activeImage()?.caption) {\n <div class=\"ngx-iv-caption\">{{ activeImage()?.caption }}</div>\n}\n\n<div class=\"ngx-iv-toolbar\">\n @if (toolbarConfig().zoomOut) {\n <button type=\"button\" (click)=\"zoomOut()\" title=\"Zoom out\">-</button>\n }\n @if (toolbarConfig().zoomIn) {\n <button type=\"button\" (click)=\"zoomIn()\" title=\"Zoom in\">+</button>\n }\n @if (toolbarConfig().resetZoom) {\n <button type=\"button\" (click)=\"resetView()\" title=\"Reset zoom\">⤢</button>\n }\n @if (toolbarConfig().rotateLeft) {\n <button type=\"button\" (click)=\"rotateLeft()\" title=\"Rotate left\">⟲</button>\n }\n @if (toolbarConfig().rotateRight) {\n <button type=\"button\" (click)=\"rotateRight()\" title=\"Rotate right\">⟳</button>\n }\n @if (toolbarConfig().download) {\n <button type=\"button\" (click)=\"download()\" title=\"Download\">⭳</button>\n }\n @if (toolbarConfig().print) {\n <button type=\"button\" (click)=\"print()\" title=\"Print\">🖶</button>\n }\n @if (toolbarConfig().fullscreen) {\n <button type=\"button\" (click)=\"toggleFullscreen()\" title=\"Fullscreen\">⛶</button>\n }\n</div>\n","import {\n ApplicationRef,\n ComponentRef,\n createComponent,\n EmbeddedViewRef,\n EnvironmentInjector,\n Injectable,\n inject,\n} from '@angular/core';\nimport { NgxImageViewerComponent } from '../components/image-viewer.component';\nimport { NgxImageViewerItem, NgxImageViewerToolbarConfig } from '../contracts/image-viewer-types';\n\nexport interface NgxImageViewerOpenOptions {\n startIndex?: number;\n toolbar?: NgxImageViewerToolbarConfig;\n minZoom?: number;\n maxZoom?: number;\n zoomStep?: number;\n}\n\n/**\n * راه میان‌بر برای وقتی که کاربر می‌خواد ویوئر رو داخل یه دیالوگِ تمام‌صفحه\n * باز کنه، بدون این‌که خودش دستی wire کنه. اگه کسی می‌خواد داخل دیالوگِ\n * خودش (مثلاً ngx-kit/dialog) بذارتش، کافیه مستقیم از NgxImageViewerComponent\n * استفاده کنه — این سرویس صرفاً یه میان‌بَره، وابستگی اجباری نیست.\n *\n * دقیقاً همون الگوی امن‌شده‌ی NgxMessageService: با Map<id, ComponentRef> و\n * detachView قبل از destroy، تا اون نشتی حافظه‌ای که قبلاً توی message\n * service پیدا و رفع شد، اینجا از اول تکرار نشه.\n */\n@Injectable({ providedIn: 'root' })\nexport class NgxImageViewerService {\n private readonly appRef = inject(ApplicationRef);\n private readonly envInjector = inject(EnvironmentInjector);\n private nextId = 0;\n private readonly openInstances = new Map<number, ComponentRef<NgxImageViewerComponent>>();\n\n open(\n images: NgxImageViewerItem[],\n options: NgxImageViewerOpenOptions = {},\n ): { close: () => void } {\n const componentRef = createComponent(NgxImageViewerComponent, {\n environmentInjector: this.envInjector,\n });\n\n componentRef.setInput('images', images);\n if (options.startIndex != null) componentRef.setInput('startIndex', options.startIndex);\n componentRef.setInput('toolbar', { close: true, ...options.toolbar });\n if (options.minZoom != null) componentRef.setInput('minZoom', options.minZoom);\n if (options.maxZoom != null) componentRef.setInput('maxZoom', options.maxZoom);\n if (options.zoomStep != null) componentRef.setInput('zoomStep', options.zoomStep);\n\n this.appRef.attachView(componentRef.hostView);\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n\n const dialog = document.createElement('dialog');\n dialog.className = 'ngx-image-viewer-dialog';\n dialog.appendChild(domElem);\n document.body.appendChild(dialog);\n dialog.showModal();\n domElem.focus?.();\n\n const id = this.nextId++;\n this.openInstances.set(id, componentRef);\n\n const close = () => {\n const ref = this.openInstances.get(id);\n if (!ref) return;\n try {\n if (dialog.open) dialog.close();\n } catch {\n /* noop */\n }\n this.appRef.detachView(ref.hostView);\n ref.destroy();\n dialog.remove();\n this.openInstances.delete(id);\n };\n\n componentRef.instance.closed.subscribe(close);\n dialog.addEventListener('cancel', close, { once: true });\n\n return { close };\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AA0BO,MAAM,gCAAgC,GAA0C;AACrF,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,MAAM,EAAE,IAAI;AACZ,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,SAAS,EAAE,IAAI;AACf,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,WAAW,EAAE,IAAI;AACjB,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,KAAK,EAAE,KAAK;;;ACrCd;AACO,eAAe,aAAa,CAAC,GAAW,EAAE,QAAiB,EAAA;AAChE,IAAA,IAAI;AACF,QAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,EAAE;AAAE,YAAA,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC;AACjD,QAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;QAClC,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;QACrC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC;AACrC,QAAA,CAAC,CAAC,IAAI,GAAG,GAAG;QACZ,CAAC,CAAC,QAAQ,GAAG,QAAQ,IAAI,aAAa,CAAC,GAAG,CAAC;AAC3C,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,KAAK,EAAE;QACT,CAAC,CAAC,MAAM,EAAE;AACV,QAAA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;IAC1B;AAAE,IAAA,MAAM;QACN,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,qBAAqB,CAAC;IACnD;AACF;AAEA,SAAS,aAAa,CAAC,GAAW,EAAA;AAChC,IAAA,IAAI;QACF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,MAAM,KAAK,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC;AAC1F,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;QAC1C,OAAO,IAAI,IAAI,OAAO;IACxB;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,OAAO;IAChB;AACF;AAEA;AACM,SAAU,UAAU,CAAC,GAAW,EAAA;AACpC,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,0CAA0C,CAAC;AACjF,IAAA,IAAI,CAAC,GAAG;QAAE;AAEV,IAAA,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,OAAO;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AACjD,IAAA,KAAK,CAAC,WAAW;AACf,QAAA,8IAA8I;IAChJ,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IAEpC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AAC7C,IAAA,GAAG,CAAC,MAAM,GAAG,MAAK;QAChB,GAAG,CAAC,KAAK,EAAE;QACX,GAAG,CAAC,KAAK,EAAE;AACb,IAAA,CAAC;AACD,IAAA,GAAG,CAAC,GAAG,GAAG,GAAG;IACb,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;AACpC;;ACzCA;;;;;;;;;AASG;AACG,SAAU,eAAe,CAC7B,OAAqB,EACrB,OAAe,EACf,OAAe,EACf,OAAe,EACf,cAAsB,EACtB,eAAuB,EAAA;AAEvB,IAAA,MAAM,OAAO,GAAG,cAAc,GAAG,CAAC;AAClC,IAAA,MAAM,OAAO,GAAG,eAAe,GAAG,CAAC;AACnC,IAAA,MAAM,MAAM,GAAG,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;AAChE,IAAA,MAAM,MAAM,GAAG,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;IAChE,OAAO;AACL,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO;AAC1C,QAAA,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO;KAC3C;AACH;AAEM,SAAU,sBAAsB,CAAC,CAAQ,EAAE,CAAQ,EAAA;IACvD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;AACjE;AAEM,SAAU,iBAAiB,CAAC,CAAQ,EAAE,CAAQ,EAAA;AAClD,IAAA,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE;AAC3E;SAEgB,KAAK,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW,EAAA;AAC3D,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC5C;;ACjBA;;;;;;;;;;;;;;;;;;;;AAoBG;MASU,uBAAuB,CAAA;IAClC,MAAM,GAAG,KAAK,CAAC,QAAQ;+EAAwB;IAC/C,UAAU,GAAG,KAAK,CAAS,CAAC;mFAAC;IAC7B,OAAO,GAAG,KAAK,CAA8B,EAAE;gFAAC;IAChD,OAAO,GAAG,KAAK,CAAS,CAAC;gFAAC;IAC1B,OAAO,GAAG,KAAK,CAAS,CAAC;gFAAC;IAC1B,QAAQ,GAAG,KAAK,CAAS,GAAG;iFAAC;IAE7B,WAAW,GAAG,MAAM,EAAU;IAC9B,MAAM,GAAG,MAAM,EAAQ;IAEJ,WAAW,GAAG,MAAM,CAAC,CAAC;oFAAC;IACvB,IAAI,GAAG,MAAM,CAAC,CAAC;6EAAC;IAChB,IAAI,GAAG,MAAM,CAAC,CAAC;6EAAC;IAChB,IAAI,GAAG,MAAM,CAAC,CAAC;6EAAC;IAChB,QAAQ,GAAG,MAAM,CAAC,CAAC;iFAAC;AAEpB,IAAA,WAAW,GAAG,QAAQ,CACvC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;oFACxC;AAEkB,IAAA,aAAa,GAAG,QAAQ,CAAC,OAAO;AACjD,QAAA,GAAG,gCAAgC;QACnC,GAAG,IAAI,CAAC,OAAO,EAAE;KAClB,CAAC;sFAAC;IAEgB,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC;iFAAC;IAE1C,cAAc,GAAG,QAAQ,CAC1C,MACE,CAAA,UAAA,EAAa,IAAI,CAAC,IAAI,EAAE,CAAA,IAAA,EAAO,IAAI,CAAC,IAAI,EAAE,CAAA,UAAA,EAAa,IAAI,CAAC,IAAI,EAAE,CAAA,SAAA,EAAY,IAAI,CAAC,QAAQ,EAAE,CAAA,IAAA,CAAM;uFACtG;IAEgB,OAAO,GAAG,SAAS,CAA0B,OAAO;gFAAC;AACrD,IAAA,SAAS,GAAG,MAAM,EAAC,UAAuB,EAAC;AAC3C,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAExC,kBAAkB,GAAG,CAAC;IACtB,cAAc,GAAG,CAAC;AAClB,IAAA,WAAW;AAEnB,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;;;;;AAMvC,QAAA,MAAM,CAAC,CAAC,SAAS,KAAI;YACnB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa;AAC3C,YAAA,IAAI,CAAC,KAAK;gBAAE;AAEZ,YAAA,MAAM,OAAO,GAAG,CAAC,EAAc,KAAI;gBACjC,EAAE,CAAC,cAAc,EAAE;AACnB,gBAAA,MAAM,IAAI,GAAG,KAAK,CAAC,qBAAqB,EAAE;gBAC1C,IAAI,CAAC,WAAW,CACd,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,EACxD,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EACtB,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EACrB,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,CACZ;AACH,YAAA,CAAC;AAED,YAAA,MAAM,YAAY,GAAG,CAAC,EAAc,KAAI;gBACtC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3B,oBAAA,IAAI,CAAC,WAAW,IAAI;AACpB,oBAAA,IAAI,CAAC,kBAAkB,GAAG,sBAAsB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9E,oBAAA,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE;gBACnC;AAAO,qBAAA,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACrD,oBAAA,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;gBACvB;AACF,YAAA,CAAC;AAED,YAAA,MAAM,WAAW,GAAG,CAAC,EAAc,KAAI;AACrC,gBAAA,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,kBAAkB,GAAG,CAAC,EAAE;oBAC1D,EAAE,CAAC,cAAc,EAAE;AACnB,oBAAA,MAAM,IAAI,GAAG,sBAAsB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACjE,oBAAA,MAAM,OAAO,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,cAAc;AACtE,oBAAA,MAAM,IAAI,GAAG,KAAK,CAAC,qBAAqB,EAAE;AAC1C,oBAAA,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,oBAAA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;gBACzF;AACF,YAAA,CAAC;YAED,MAAM,UAAU,GAAG,MAAK;AACtB,gBAAA,IAAI,CAAC,kBAAkB,GAAG,CAAC;AAC7B,YAAA,CAAC;AAED,YAAA,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5D,YAAA,KAAK,CAAC,gBAAgB,CAAC,YAAY,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACtE,YAAA,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACpE,YAAA,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC;AAC9C,YAAA,KAAK,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,CAAC;YAEjD,SAAS,CAAC,MAAK;AACb,gBAAA,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;AAC3C,gBAAA,KAAK,CAAC,mBAAmB,CAAC,YAAY,EAAE,YAAY,CAAC;AACrD,gBAAA,KAAK,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;AACnD,gBAAA,KAAK,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC;AACjD,gBAAA,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE,UAAU,CAAC;AACtD,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,WAAW,IAAI,CAAC;IACvD;AAGU,IAAA,SAAS,CAAC,EAAiB,EAAA;AACnC,QAAA,IAAI,EAAE,CAAC,GAAG,KAAK,WAAW;YAAE,IAAI,CAAC,IAAI,EAAE;AAClC,aAAA,IAAI,EAAE,CAAC,GAAG,KAAK,YAAY;YAAE,IAAI,CAAC,IAAI,EAAE;aACxC,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG;YAAE,IAAI,CAAC,MAAM,EAAE;AACnD,aAAA,IAAI,EAAE,CAAC,GAAG,KAAK,GAAG;YAAE,IAAI,CAAC,OAAO,EAAE;AAClC,aAAA,IAAI,EAAE,CAAC,GAAG,KAAK,QAAQ;AAAE,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;;YAC3C;QACL,EAAE,CAAC,cAAc,EAAE;IACrB;IAEU,IAAI,GAAA;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM;AAChC,QAAA,IAAI,GAAG;AAAE,YAAA,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;IACpD;IAEU,IAAI,GAAA;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM;AAChC,QAAA,IAAI,GAAG;AAAE,YAAA,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;IAC1D;AAEU,IAAA,IAAI,CAAC,KAAa,EAAA;AAC1B,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,EAAE;AAChB,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;IAC9B;IAEU,MAAM,GAAA;AACd,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrD;IAEU,OAAO,GAAA;AACf,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrD;IAEU,SAAS,GAAA;AACjB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB;IAEU,UAAU,GAAA;AAClB,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACrC;IAEU,WAAW,GAAA;AACnB,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACrC;AAEU,IAAA,MAAM,QAAQ,GAAA;AACtB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE;AAC9B,QAAA,IAAI,GAAG;YAAE,MAAM,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,gBAAgB,CAAC;IAC7D;IAEU,KAAK,GAAA;AACb,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE;AAC9B,QAAA,IAAI,GAAG;AAAE,YAAA,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9B;IAEU,gBAAgB,GAAA;AACxB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa;AACvC,QAAA,IAAI,QAAQ,CAAC,iBAAiB,EAAE;YAC9B,QAAQ,CAAC,cAAc,EAAE;QAC3B;aAAO;AACL,YAAA,EAAE,CAAC,iBAAiB,IAAI;QAC1B;IACF;IAEU,KAAK,GAAA;AACb,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;AAEU,IAAA,gBAAgB,CAAC,EAAc,EAAA;AACvC,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAAE;AACtB,QAAA,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;IACvB;AAEQ,IAAA,YAAY,CAAC,EAA2B,EAAA;QAC9C,EAAE,CAAC,cAAc,EAAE;AACnB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE;AAC7B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;AACjC,QAAA,IAAI,CAAC,WAAW,IAAI;AACpB,QAAA,IAAI,CAAC,WAAW,GAAG,gBAAgB,CAAC;AAClC,YAAA,MAAM,EAAE,CAAC,MAAM,KAAI;AACjB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAC5D,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;YAC9D,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,WAAW,GAAG,SAAS;YAC9B,CAAC;AACF,SAAA,CAAC;IACJ;AAEQ,IAAA,eAAe,CAAC,OAAe,EAAA;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa;QAC3C,IAAI,CAAC,KAAK,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7D;QACF;AACA,QAAA,MAAM,IAAI,GAAG,KAAK,CAAC,qBAAqB,EAAE;QAC1C,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;IACrF;IAEQ,WAAW,CACjB,OAAe,EACf,CAAS,EACT,CAAS,EACT,cAAsB,EACtB,eAAuB,EAAA;AAEvB,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;AAC9D,QAAA,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE;YAAE;AAC7B,QAAA,MAAM,MAAM,GAAG,eAAe,CAC5B,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAC3D,OAAO,EACP,CAAC,EACD,CAAC,EACD,cAAc,EACd,eAAe,CAChB;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAC5B;AAEQ,IAAA,SAAS,CAAC,EAA2B,EAAA;QAC3C,OAAO,SAAS,IAAI;eACf,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC;AAC/D,cAAE,EAAE,CAAC,OAAO;IAChB;AAEQ,IAAA,SAAS,CAAC,EAA2B,EAAA;QAC3C,OAAO,SAAS,IAAI;eACf,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC;AAC/D,cAAE,EAAE,CAAC,OAAO;IAChB;uGArPW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,ooCCzDpC,6rEAgEA,EAAA,MAAA,EAAA,CAAA,6tDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDPa,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBARnC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAGzC,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAA,QAAA,EAAA,6rEAAA,EAAA,MAAA,EAAA,CAAA,6tDAAA,CAAA,EAAA;owBAmCO,OAAO,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA;sBA0EpE,YAAY;uBAAC,SAAS,EAAE,CAAC,QAAQ,CAAC;;;AEhJrC;;;;;;;;;AASG;MAEU,qBAAqB,CAAA;AACf,IAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;AAC/B,IAAA,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC;IAClD,MAAM,GAAG,CAAC;AACD,IAAA,aAAa,GAAG,IAAI,GAAG,EAAiD;AAEzF,IAAA,IAAI,CACF,MAA4B,EAC5B,OAAA,GAAqC,EAAE,EAAA;AAEvC,QAAA,MAAM,YAAY,GAAG,eAAe,CAAC,uBAAuB,EAAE;YAC5D,mBAAmB,EAAE,IAAI,CAAC,WAAW;AACtC,SAAA,CAAC;AAEF,QAAA,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;AACvC,QAAA,IAAI,OAAO,CAAC,UAAU,IAAI,IAAI;YAAE,YAAY,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC;AACvF,QAAA,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;AACrE,QAAA,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI;YAAE,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC;AAC9E,QAAA,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI;YAAE,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC;AAC9E,QAAA,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI;YAAE,YAAY,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC;QAEjF,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;QAC7C,MAAM,OAAO,GAAI,YAAY,CAAC,QAAqC,CAAC,SAAS,CAAC,CAAC,CAAgB;QAE/F,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,QAAA,MAAM,CAAC,SAAS,GAAG,yBAAyB;AAC5C,QAAA,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;AAC3B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QACjC,MAAM,CAAC,SAAS,EAAE;AAClB,QAAA,OAAO,CAAC,KAAK,IAAI;AAEjB,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE;QACxB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,YAAY,CAAC;QAExC,MAAM,KAAK,GAAG,MAAK;YACjB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;AACtC,YAAA,IAAI,CAAC,GAAG;gBAAE;AACV,YAAA,IAAI;gBACF,IAAI,MAAM,CAAC,IAAI;oBAAE,MAAM,CAAC,KAAK,EAAE;YACjC;AAAE,YAAA,MAAM;;YAER;YACA,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;YACpC,GAAG,CAAC,OAAO,EAAE;YACb,MAAM,CAAC,MAAM,EAAE;AACf,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC/B,QAAA,CAAC;QAED,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;AAC7C,QAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAExD,OAAO,EAAE,KAAK,EAAE;IAClB;uGApDW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAArB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,cADR,MAAM,EAAA,CAAA;;2FACnB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBADjC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC9BlC;;AAEG;;;;"}
1
+ {"version":3,"file":"ngx-kit-gallery.mjs","sources":["../../../projects/libs/gallery/contracts/image-viewer-types.ts","../../../projects/libs/gallery/utils/download-print.ts","../../../projects/libs/gallery/utils/zoom-math.ts","../../../projects/libs/gallery/components/image-viewer.component.ts","../../../projects/libs/gallery/components/image-viewer.component.html","../../../projects/libs/gallery/services/image-viewer.service.ts","../../../projects/libs/gallery/ngx-kit-gallery.ts"],"sourcesContent":["export interface NgxImageViewerItem {\n src: string;\n alt?: string;\n caption?: string;\n /** نام فایل هنگام دانلود؛ نبود یعنی از روی src حدس زده می‌شه */\n downloadFileName?: string;\n}\n\n/**\n * هر دکمه‌ی نوار ابزار جدا فعال/غیرفعال می‌شه — دقیقاً طبق خواسته: «این\n * دکمه‌های کانفیگی باشه که هر کدوم خواست فعال کنه».\n */\nexport interface NgxImageViewerToolbarConfig {\n prevNext?: boolean;\n counter?: boolean;\n zoomIn?: boolean;\n zoomOut?: boolean;\n resetZoom?: boolean;\n rotateLeft?: boolean;\n rotateRight?: boolean;\n download?: boolean;\n print?: boolean;\n fullscreen?: boolean;\n close?: boolean;\n}\n\nexport const NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR: Required<NgxImageViewerToolbarConfig> = {\n prevNext: true,\n counter: true,\n zoomIn: true,\n zoomOut: true,\n resetZoom: true,\n rotateLeft: true,\n rotateRight: true,\n download: true,\n print: true,\n fullscreen: true,\n close: false,\n};\n","/** دانلود تصویر با fetch→blob (نام‌گذاریِ درست فایل رو تضمین می‌کنه)؛ اگه CORS اجازه نداد، در تب جدید باز می‌شه */\nexport async function downloadImage(src: string, filename?: string): Promise<void> {\n try {\n const response = await fetch(src, { mode: 'cors' });\n if (!response.ok) throw new Error('fetch failed');\n const blob = await response.blob();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename || guessFileName(src);\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n } catch {\n window.open(src, '_blank', 'noopener,noreferrer');\n }\n}\n\nfunction guessFileName(src: string): string {\n try {\n const url = new URL(src, typeof window !== 'undefined' ? window.location.href : undefined);\n const last = url.pathname.split('/').pop();\n return last || 'image';\n } catch {\n return 'image';\n }\n}\n\n/** یه پنجره‌ی جدید فقط با همون تصویر باز می‌کنه و بعد از لود، print می‌زنه؛ با DOM API (نه innerHTML) پس در برابر src مخرب امنه */\nexport function printImage(src: string): void {\n const win = window.open('', '_blank', 'noopener,noreferrer,width=800,height=600');\n if (!win) return;\n\n win.document.title = 'Print';\n const style = win.document.createElement('style');\n style.textContent =\n 'body{margin:0;display:flex;align-items:center;justify-content:center;min-height:100vh;background:#fff;}img{max-width:100%;max-height:100vh;}';\n win.document.head.appendChild(style);\n\n const img = win.document.createElement('img');\n img.onload = () => {\n win.focus();\n win.print();\n };\n img.src = src;\n win.document.body.appendChild(img);\n}\n","export interface PanZoomState {\n zoom: number;\n panX: number;\n panY: number;\n}\n\n/**\n * با تغییر zoom، pan رو طوری تنظیم می‌کنه که نقطه‌ی زیر cursor/انگشت‌ها\n * (نسبت به مرکز کانتینر) سرجاش بمونه — یعنی zoom-to-cursor به‌جای\n * zoom-to-center (که تجربه‌ی خیلی بهتری داره، دقیقاً مثل هر ویوئر حرفه‌ای).\n *\n * ریاضیِ پشتش: با transform=\"translate(panX,panY) scale(zoom)\"، موقعیتِ\n * صفحه‌ایِ یه نقطه‌ی محلیِ p (نسبت به مرکز) برابره با\n * center + pan + p*zoom. اول p رو از روی وضعیت فعلی حساب می‌کنیم، بعد pan\n * جدید رو طوری می‌سازیم که با zoom تازه، همون p به همون مختصات صفحه برسه.\n */\nexport function zoomAroundPoint(\n current: PanZoomState,\n newZoom: number,\n cursorX: number,\n cursorY: number,\n containerWidth: number,\n containerHeight: number,\n): PanZoomState {\n const centerX = containerWidth / 2;\n const centerY = containerHeight / 2;\n const localX = (cursorX - centerX - current.panX) / current.zoom;\n const localY = (cursorY - centerY - current.panY) / current.zoom;\n return {\n zoom: newZoom,\n panX: cursorX - centerX - localX * newZoom,\n panY: cursorY - centerY - localY * newZoom,\n };\n}\n\nexport function distanceBetweenTouches(a: Touch, b: Touch): number {\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);\n}\n\nexport function midpointOfTouches(a: Touch, b: Touch): { x: number; y: number } {\n return { x: (a.clientX + b.clientX) / 2, y: (a.clientY + b.clientY) / 2 };\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n HostListener,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { startDragSession } from 'ngx-kit/shared';\nimport {\n NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR,\n NgxImageViewerItem,\n NgxImageViewerToolbarConfig,\n} from '../contracts/image-viewer-types';\nimport { downloadImage, printImage } from '../utils/download-print';\nimport {\n clamp,\n distanceBetweenTouches,\n midpointOfTouches,\n zoomAroundPoint,\n} from '../utils/zoom-math';\n\n/**\n * ویوئر حرفه‌ایِ تصویر: یه لیست تصویر می‌گیره، اولی رو نشون می‌ده، با\n * دکمه‌های چپ/راست (مثل کاروسل) بین‌شون می‌ره، و یه نوار ابزار کاملاً\n * قابل‌تنظیم (هر دکمه جدا فعال/غیرفعال می‌شه) داره: زوم این/اوت/ریست،\n * چرخش، دانلود، پرینت، تمام‌صفحه.\n *\n * تعامل‌ها:\n * - اسکرول موس روی تصویر = زوم (نسبت به همون نقطه‌ی زیر cursor، نه مرکز)\n * - دو انگشتی روی تاچ = پینچ زوم\n * - وقتی زوم‌شده، درگ با موس یا تک‌انگشتی = پن\n * - کیبورد: ← → برای قبلی/بعدی، +/- برای زوم، Esc برای closed\n *\n * چون wheel/touchmove باید preventDefault بشن (وگرنه صفحه اسکرول/زوم\n * می‌شه) و انگیولار این ایونت‌ها رو به‌صورت پیش‌فرض passive رجیستر می‌کنه\n * (که توش preventDefault اثر نداره)، این‌ها با addEventListener دستی و\n * {passive:false} وصل می‌شن، نه با بایندینگ تمپلیت.\n *\n * می‌تونه هم مستقیم توی صفحه جا بگیره، هم توسط مصرف‌کننده داخل\n * ngx-kit/dialog (یا هر overlay دیگه) قرار بگیره — خودش به هیچ‌کدوم وابسته\n * نیست، فقط با closed خروجی به بیرون خبر می‌ده که «ببندم».\n */\n@Component({\n selector: 'ngx-image-viewer',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './image-viewer.component.html',\n styleUrl: './image-viewer.component.scss',\n host: { class: 'ngx-image-viewer-host', tabindex: '0' },\n})\nexport class NgxImageViewerComponent {\n images = input.required<NgxImageViewerItem[]>();\n startIndex = input<number>(0);\n toolbar = input<NgxImageViewerToolbarConfig>({});\n minZoom = input<number>(1);\n maxZoom = input<number>(6);\n zoomStep = input<number>(0.4);\n\n indexChange = output<number>();\n closed = output<void>();\n\n protected readonly activeIndex = signal(0);\n protected readonly zoom = signal(1);\n protected readonly panX = signal(0);\n protected readonly panY = signal(0);\n protected readonly rotation = signal(0);\n\n protected readonly activeImage = computed<NgxImageViewerItem | undefined>(\n () => this.images()[this.activeIndex()],\n );\n\n protected readonly toolbarConfig = computed(() => ({\n ...NGX_IMAGE_VIEWER_DEFAULT_TOOLBAR,\n ...this.toolbar(),\n }));\n\n protected readonly isZoomed = computed(() => this.zoom() > 1);\n\n protected readonly stageTransform = computed(\n () =>\n `translate(${this.panX()}px, ${this.panY()}px) scale(${this.zoom()}) rotate(${this.rotation()}deg)`,\n );\n\n private readonly stageEl = viewChild<ElementRef<HTMLElement>>('stage');\n private readonly hostElRef = inject(ElementRef<HTMLElement>);\n private readonly destroyRef = inject(DestroyRef);\n\n private pinchStartDistance = 0;\n private pinchStartZoom = 1;\n private stopPanDrag?: () => void;\n\n constructor() {\n this.activeIndex.set(this.startIndex());\n\n // wheel/touch با addEventListener دستی + passive:false وصل می‌شن (دلیلش\n // بالای کلاس توضیح داده شده)؛ effect به‌صورت خودکار وقتی stageEl از\n // undefined به یه ElementRef واقعی تغییر کنه (یعنی بعد از اولین رندر)\n // دوباره اجرا می‌شه، پس نیازی به ngAfterViewInit نیست.\n effect((onCleanup) => {\n const stage = this.stageEl()?.nativeElement;\n if (!stage) return;\n\n const onWheel = (ev: WheelEvent) => {\n ev.preventDefault();\n const rect = stage.getBoundingClientRect();\n this.applyZoomAt(\n this.zoom() + (ev.deltaY < 0 ? 1 : -1) * this.zoomStep(),\n ev.clientX - rect.left,\n ev.clientY - rect.top,\n rect.width,\n rect.height,\n );\n };\n\n const onTouchStart = (ev: TouchEvent) => {\n if (ev.touches.length === 2) {\n this.stopPanDrag?.();\n this.pinchStartDistance = distanceBetweenTouches(ev.touches[0], ev.touches[1]);\n this.pinchStartZoom = this.zoom();\n } else if (ev.touches.length === 1 && this.isZoomed()) {\n this.beginPanDrag(ev);\n }\n };\n\n const onTouchMove = (ev: TouchEvent) => {\n if (ev.touches.length === 2 && this.pinchStartDistance > 0) {\n ev.preventDefault();\n const dist = distanceBetweenTouches(ev.touches[0], ev.touches[1]);\n const newZoom = (dist / this.pinchStartDistance) * this.pinchStartZoom;\n const rect = stage.getBoundingClientRect();\n const mid = midpointOfTouches(ev.touches[0], ev.touches[1]);\n this.applyZoomAt(newZoom, mid.x - rect.left, mid.y - rect.top, rect.width, rect.height);\n }\n };\n\n const onTouchEnd = () => {\n this.pinchStartDistance = 0;\n };\n\n stage.addEventListener('wheel', onWheel, { passive: false });\n stage.addEventListener('touchstart', onTouchStart, { passive: false });\n stage.addEventListener('touchmove', onTouchMove, { passive: false });\n stage.addEventListener('touchend', onTouchEnd);\n stage.addEventListener('touchcancel', onTouchEnd);\n\n onCleanup(() => {\n stage.removeEventListener('wheel', onWheel);\n stage.removeEventListener('touchstart', onTouchStart);\n stage.removeEventListener('touchmove', onTouchMove);\n stage.removeEventListener('touchend', onTouchEnd);\n stage.removeEventListener('touchcancel', onTouchEnd);\n });\n });\n\n this.destroyRef.onDestroy(() => this.stopPanDrag?.());\n }\n\n @HostListener('keydown', ['$event'])\n protected onKeydown(ev: KeyboardEvent): void {\n if (ev.key === 'ArrowLeft') this.prev();\n else if (ev.key === 'ArrowRight') this.next();\n else if (ev.key === '+' || ev.key === '=') this.zoomIn();\n else if (ev.key === '-') this.zoomOut();\n else if (ev.key === 'Escape') this.closed.emit();\n else return;\n ev.preventDefault();\n }\n\n protected next(): void {\n const len = this.images().length;\n if (len) this.goTo((this.activeIndex() + 1) % len);\n }\n\n protected prev(): void {\n const len = this.images().length;\n if (len) this.goTo((this.activeIndex() - 1 + len) % len);\n }\n\n protected goTo(index: number): void {\n this.activeIndex.set(index);\n this.resetView();\n this.indexChange.emit(index);\n }\n\n protected zoomIn(): void {\n this.setZoomAtCenter(this.zoom() + this.zoomStep());\n }\n\n protected zoomOut(): void {\n this.setZoomAtCenter(this.zoom() - this.zoomStep());\n }\n\n protected resetView(): void {\n this.zoom.set(1);\n this.panX.set(0);\n this.panY.set(0);\n this.rotation.set(0);\n }\n\n protected rotateLeft(): void {\n this.rotation.update((r) => r - 90);\n }\n\n protected rotateRight(): void {\n this.rotation.update((r) => r + 90);\n }\n\n protected async download(): Promise<void> {\n const img = this.activeImage();\n if (img) await downloadImage(img.src, img.downloadFileName);\n }\n\n protected print(): void {\n const img = this.activeImage();\n if (img) printImage(img.src);\n }\n\n protected toggleFullscreen(): void {\n const el = this.hostElRef.nativeElement;\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else {\n el.requestFullscreen?.();\n }\n }\n\n protected close(): void {\n this.closed.emit();\n }\n\n protected onPanPointerDown(ev: MouseEvent): void {\n if (!this.isZoomed()) return;\n this.beginPanDrag(ev);\n }\n\n private beginPanDrag(ev: MouseEvent | TouchEvent): void {\n ev.preventDefault();\n const startPanX = this.panX();\n const startPanY = this.panY();\n const startX = this.clientXOf(ev);\n const startY = this.clientYOf(ev);\n this.stopPanDrag?.();\n this.stopPanDrag = startDragSession({\n onMove: (moveEv) => {\n this.panX.set(startPanX + (this.clientXOf(moveEv) - startX));\n this.panY.set(startPanY + (this.clientYOf(moveEv) - startY));\n },\n onEnd: () => {\n this.stopPanDrag = undefined;\n },\n });\n }\n\n private setZoomAtCenter(newZoom: number): void {\n const stage = this.stageEl()?.nativeElement;\n if (!stage) {\n this.zoom.set(clamp(newZoom, this.minZoom(), this.maxZoom()));\n return;\n }\n const rect = stage.getBoundingClientRect();\n this.applyZoomAt(newZoom, rect.width / 2, rect.height / 2, rect.width, rect.height);\n }\n\n private applyZoomAt(\n rawZoom: number,\n x: number,\n y: number,\n containerWidth: number,\n containerHeight: number,\n ): void {\n const newZoom = clamp(rawZoom, this.minZoom(), this.maxZoom());\n if (newZoom === this.zoom()) return;\n const result = zoomAroundPoint(\n { zoom: this.zoom(), panX: this.panX(), panY: this.panY() },\n newZoom,\n x,\n y,\n containerWidth,\n containerHeight,\n );\n this.zoom.set(result.zoom);\n this.panX.set(result.panX);\n this.panY.set(result.panY);\n }\n\n private clientXOf(ev: MouseEvent | TouchEvent): number {\n return 'touches' in ev\n ? (ev.touches[0]?.clientX ?? ev.changedTouches[0]?.clientX ?? 0)\n : ev.clientX;\n }\n\n private clientYOf(ev: MouseEvent | TouchEvent): number {\n return 'touches' in ev\n ? (ev.touches[0]?.clientY ?? ev.changedTouches[0]?.clientY ?? 0)\n : ev.clientY;\n }\n}\n","<div class=\"ngx-iv-stage\" #stage [class.zoomed]=\"isZoomed()\">\r\n @if (toolbarConfig().close) {\r\n <button type=\"button\" class=\"ngx-iv-close\" (click)=\"close()\" aria-label=\"Close\">✕</button>\r\n }\r\n\r\n @if (activeImage(); as img) {\r\n <img\r\n class=\"ngx-iv-image\"\r\n [class.grab]=\"isZoomed()\"\r\n [src]=\"img.src\"\r\n [alt]=\"img.alt || ''\"\r\n draggable=\"false\"\r\n [style.transform]=\"stageTransform()\"\r\n (mousedown)=\"onPanPointerDown($event)\" />\r\n }\r\n\r\n @if (toolbarConfig().prevNext && images().length > 1) {\r\n <button\r\n type=\"button\"\r\n class=\"ngx-iv-nav ngx-iv-nav--prev\"\r\n (click)=\"prev()\"\r\n aria-label=\"Previous\">\r\n ‹\r\n </button>\r\n <button type=\"button\" class=\"ngx-iv-nav ngx-iv-nav--next\" (click)=\"next()\" aria-label=\"Next\">\r\n ›\r\n </button>\r\n }\r\n\r\n @if (toolbarConfig().counter && images().length > 1) {\r\n <div class=\"ngx-iv-counter\">{{ activeIndex() + 1 }} / {{ images().length }}</div>\r\n }\r\n</div>\r\n\r\n@if (activeImage()?.caption) {\r\n <div class=\"ngx-iv-caption\">{{ activeImage()?.caption }}</div>\r\n}\r\n\r\n<div class=\"ngx-iv-toolbar\">\r\n @if (toolbarConfig().zoomOut) {\r\n <button type=\"button\" (click)=\"zoomOut()\" title=\"Zoom out\">-</button>\r\n }\r\n @if (toolbarConfig().zoomIn) {\r\n <button type=\"button\" (click)=\"zoomIn()\" title=\"Zoom in\">+</button>\r\n }\r\n @if (toolbarConfig().resetZoom) {\r\n <button type=\"button\" (click)=\"resetView()\" title=\"Reset zoom\">⤢</button>\r\n }\r\n @if (toolbarConfig().rotateLeft) {\r\n <button type=\"button\" (click)=\"rotateLeft()\" title=\"Rotate left\">⟲</button>\r\n }\r\n @if (toolbarConfig().rotateRight) {\r\n <button type=\"button\" (click)=\"rotateRight()\" title=\"Rotate right\">⟳</button>\r\n }\r\n @if (toolbarConfig().download) {\r\n <button type=\"button\" (click)=\"download()\" title=\"Download\">⭳</button>\r\n }\r\n @if (toolbarConfig().print) {\r\n <button type=\"button\" (click)=\"print()\" title=\"Print\">🖶</button>\r\n }\r\n @if (toolbarConfig().fullscreen) {\r\n <button type=\"button\" (click)=\"toggleFullscreen()\" title=\"Fullscreen\">⛶</button>\r\n }\r\n</div>\r\n","import {\n ApplicationRef,\n ComponentRef,\n createComponent,\n EmbeddedViewRef,\n EnvironmentInjector,\n Injectable,\n inject,\n} from '@angular/core';\nimport { NgxImageViewerComponent } from '../components/image-viewer.component';\nimport { NgxImageViewerItem, NgxImageViewerToolbarConfig } from '../contracts/image-viewer-types';\n\nexport interface NgxImageViewerOpenOptions {\n startIndex?: number;\n toolbar?: NgxImageViewerToolbarConfig;\n minZoom?: number;\n maxZoom?: number;\n zoomStep?: number;\n}\n\n/**\n * راه میان‌بر برای وقتی که کاربر می‌خواد ویوئر رو داخل یه دیالوگِ تمام‌صفحه\n * باز کنه، بدون این‌که خودش دستی wire کنه. اگه کسی می‌خواد داخل دیالوگِ\n * خودش (مثلاً ngx-kit/dialog) بذارتش، کافیه مستقیم از NgxImageViewerComponent\n * استفاده کنه — این سرویس صرفاً یه میان‌بَره، وابستگی اجباری نیست.\n *\n * دقیقاً همون الگوی امن‌شده‌ی NgxMessageService: با Map<id, ComponentRef> و\n * detachView قبل از destroy، تا اون نشتی حافظه‌ای که قبلاً توی message\n * service پیدا و رفع شد، اینجا از اول تکرار نشه.\n */\n@Injectable({ providedIn: 'root' })\nexport class NgxImageViewerService {\n private readonly appRef = inject(ApplicationRef);\n private readonly envInjector = inject(EnvironmentInjector);\n private nextId = 0;\n private readonly openInstances = new Map<number, ComponentRef<NgxImageViewerComponent>>();\n\n open(\n images: NgxImageViewerItem[],\n options: NgxImageViewerOpenOptions = {},\n ): { close: () => void } {\n const componentRef = createComponent(NgxImageViewerComponent, {\n environmentInjector: this.envInjector,\n });\n\n componentRef.setInput('images', images);\n if (options.startIndex != null) componentRef.setInput('startIndex', options.startIndex);\n componentRef.setInput('toolbar', { close: true, ...options.toolbar });\n if (options.minZoom != null) componentRef.setInput('minZoom', options.minZoom);\n if (options.maxZoom != null) componentRef.setInput('maxZoom', options.maxZoom);\n if (options.zoomStep != null) componentRef.setInput('zoomStep', options.zoomStep);\n\n this.appRef.attachView(componentRef.hostView);\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n\n const dialog = document.createElement('dialog');\n dialog.className = 'ngx-image-viewer-dialog';\n dialog.appendChild(domElem);\n document.body.appendChild(dialog);\n dialog.showModal();\n domElem.focus?.();\n\n const id = this.nextId++;\n this.openInstances.set(id, componentRef);\n\n const close = () => {\n const ref = this.openInstances.get(id);\n if (!ref) return;\n try {\n if (dialog.open) dialog.close();\n } catch {\n /* noop */\n }\n this.appRef.detachView(ref.hostView);\n ref.destroy();\n dialog.remove();\n this.openInstances.delete(id);\n };\n\n componentRef.instance.closed.subscribe(close);\n dialog.addEventListener('cancel', close, { once: true });\n\n return { close };\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -139,6 +139,17 @@ function moveItem(items, id, x, y, opts, depth = 0) {
139
139
  let guard = 0;
140
140
  while (guard++ < arr.length + 24) {
141
141
  const mover = arr.find((i) => i.id === id);
142
+ const staticBlocker = arr.find((i) => i.id !== id && isStatic(i) && collides(mover.config, i.config));
143
+ if (staticBlocker) {
144
+ if (opts.compact === 'horizontal') {
145
+ mover.config.x = staticBlocker.config.x + staticBlocker.config.w;
146
+ }
147
+ else {
148
+ mover.config.y = staticBlocker.config.y + staticBlocker.config.h;
149
+ }
150
+ clampToCols(mover.config, opts.cols);
151
+ continue; // the new position may collide with something else — re-check from the top.
152
+ }
142
153
  const blockers = arr
143
154
  .filter((i) => i.id !== id && !isStatic(i) && collides(mover.config, i.config))
144
155
  .sort(compareFn);
@@ -164,6 +175,8 @@ function compareForCompaction(mode) {
164
175
  * caller (service) decides when to offer this vs. falling back to `moveItem`.
165
176
  */
166
177
  function trySwap(items, id, previous, next) {
178
+ if (items.some((i) => i.id !== id && isStatic(i) && collides(i.config, next)))
179
+ return null;
167
180
  const collisions = items.filter((i) => i.id !== id && !isStatic(i) && collides(i.config, next));
168
181
  if (collisions.length !== 1)
169
182
  return null;
@@ -212,6 +225,38 @@ function compact(items, mode) {
212
225
  function maxOccupiedRow(items) {
213
226
  return items.reduce((max, i) => Math.max(max, i.config.y + i.config.h), 0);
214
227
  }
228
+ /**
229
+ * Finds a cell for `config` that doesn't collide with any existing item.
230
+ * Tries the requested (x, y) first; if that's already occupied, scans
231
+ * forward in reading order (row by row, top to bottom, left to right — the
232
+ * caller is responsible for any RTL flipping when it turns this back into
233
+ * pixels) for the first gap large enough to fit it.
234
+ *
235
+ * This is what a newly-registered item (or one whose config changes to a
236
+ * position that's no longer free) should go through instead of silently
237
+ * overlapping whatever's already there: unlike a drag/resize, registering an
238
+ * item isn't a deliberate "make room for me" gesture, so relocating the new
239
+ * item to open space reads far better than shoving already-placed items
240
+ * around to accommodate it.
241
+ */
242
+ function findFreeSpot(items, config, cols, excludeId) {
243
+ const others = excludeId ? items.filter((i) => i.id !== excludeId) : items;
244
+ const fits = (x, y) => !others.some((i) => collides(i.config, { ...config, x, y }));
245
+ const startX = Math.max(0, Math.min(config.x, cols - config.w));
246
+ const startY = Math.max(0, config.y);
247
+ if (fits(startX, startY))
248
+ return { x: startX, y: startY };
249
+ // The row just past the current bottom is always fully empty, so this loop
250
+ // is guaranteed to find a fit no later than `maxY`.
251
+ const maxY = maxOccupiedRow(others) + 1;
252
+ for (let y = 0; y <= maxY; y++) {
253
+ for (let x = 0; x <= cols - config.w; x++) {
254
+ if (fits(x, y))
255
+ return { x, y };
256
+ }
257
+ }
258
+ return { x: startX, y: maxY + 1 };
259
+ }
215
260
 
216
261
  function computeMetrics(containerWidth, options) {
217
262
  const cols = Math.max(1, Math.floor(options.cols));
@@ -269,6 +314,30 @@ function itemsEqual(a, b) {
269
314
  return (!!itemB && itemA.element === itemB.element && gridItemConfigsEqual(itemA.config, itemB.config));
270
315
  });
271
316
  }
317
+ /** Value equality for two options objects — see `setOptions` for why this matters. */
318
+ function optionsEqual(a, b) {
319
+ const bg1 = a.gridBackgroundConfig ?? {};
320
+ const bg2 = b.gridBackgroundConfig ?? {};
321
+ return (a.cols === b.cols &&
322
+ a.rowHeight === b.rowHeight &&
323
+ a.gap === b.gap &&
324
+ a.padding === b.padding &&
325
+ a.flow === b.flow &&
326
+ a.compact === b.compact &&
327
+ a.allowOverlap === b.allowOverlap &&
328
+ a.pushItems === b.pushItems &&
329
+ a.swap === b.swap &&
330
+ a.dragThreshold === b.dragThreshold &&
331
+ a.animate === b.animate &&
332
+ a.rtl === b.rtl &&
333
+ (a.maxRows ?? null) === (b.maxRows ?? null) &&
334
+ bg1.show === bg2.show &&
335
+ bg1.borderColor === bg2.borderColor &&
336
+ bg1.gapColor === bg2.gapColor &&
337
+ bg1.rowColor === bg2.rowColor &&
338
+ bg1.columnColor === bg2.columnColor &&
339
+ bg1.borderWidth === bg2.borderWidth);
340
+ }
272
341
  class GridLayoutService {
273
342
  options = signal(new GridLayoutOptions(), /* @ts-ignore */
274
343
  ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
@@ -286,8 +355,10 @@ class GridLayoutService {
286
355
  ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
287
356
  columns = computed(() => Math.max(1, Math.floor(this.options().cols)), /* @ts-ignore */
288
357
  ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
289
- /** Resolves `rtl: 'auto'` against the attached element's *actual* computed direction. */
290
- rtl = computed(() => this.resolveRtl(), /* @ts-ignore */
358
+ rtl = computed(() => {
359
+ this.rtlTick();
360
+ return this.resolveRtl();
361
+ }, /* @ts-ignore */
291
362
  ...(ngDevMode ? [{ debugName: "rtl" }] : /* istanbul ignore next */ []));
292
363
  rtlTick = signal(0, /* @ts-ignore */
293
364
  ...(ngDevMode ? [{ debugName: "rtlTick" }] : /* istanbul ignore next */ []));
@@ -313,7 +384,10 @@ class GridLayoutService {
313
384
  this.layoutListener = onLayout;
314
385
  }
315
386
  setOptions(value) {
316
- this.options.update((o) => Object.assign(new GridLayoutOptions(), o, value));
387
+ const next = Object.assign(new GridLayoutOptions(), this.options(), value);
388
+ if (optionsEqual(this.options(), next))
389
+ return;
390
+ this.options.set(next);
317
391
  }
318
392
  setEditMode(value) {
319
393
  this.editMode.set(value);
@@ -323,18 +397,14 @@ class GridLayoutService {
323
397
  this.settle();
324
398
  this.emit();
325
399
  }
326
- /**
327
- * Registers a new item, or refreshes the DOM element reference of one that's
328
- * already tracked. Adding an item can shift the whole layout (compaction /
329
- * push), so that path settles. Merely re-supplying the same element on an
330
- * already-known id has no geometric effect, so it is a deliberate no-op —
331
- * skipping it is what keeps a per-item `effect()` that calls this on every
332
- * change-detection pass from re-triggering `settle()` indefinitely.
333
- */
334
400
  registerItem(item) {
335
401
  const existing = this.items().find((x) => x.id === item.id);
336
402
  if (!existing) {
337
- this.items.update((xs) => [...xs, { ...item, config: normalizeGridItem(item.config) }]);
403
+ const normalized = normalizeGridItem(item.config);
404
+ const placed = this.options().allowOverlap
405
+ ? normalized
406
+ : { ...normalized, ...findFreeSpot(this.items(), normalized, this.columns()) };
407
+ this.items.update((xs) => [...xs, { ...item, config: placed }]);
338
408
  this.settle();
339
409
  return;
340
410
  }
@@ -342,20 +412,17 @@ class GridLayoutService {
342
412
  return;
343
413
  this.items.update((xs) => xs.map((x) => (x.id === item.id ? { ...x, element: item.element } : x)));
344
414
  }
345
- /**
346
- * Updates an item's config. Only writes the signal and re-settles the layout
347
- * when the *value* actually changed. Without this guard, any caller that
348
- * supplies a structurally-equal but referentially-new config object (e.g. a
349
- * template bound to a `computed()` layout) would cause an unconditional
350
- * `items.set()` on every run — which produces new output objects, which
351
- * feed back into that same new config reference, forever.
352
- */
353
415
  updateItemConfig(id, config) {
354
- const normalized = normalizeGridItem(config);
355
416
  const existing = this.items().find((x) => x.id === id);
356
- if (!existing || gridItemConfigsEqual(existing.config, normalized))
417
+ if (!existing)
418
+ return;
419
+ const normalized = normalizeGridItem(config);
420
+ const placed = this.options().allowOverlap
421
+ ? normalized
422
+ : { ...normalized, ...findFreeSpot(this.items(), normalized, this.columns(), id) };
423
+ if (gridItemConfigsEqual(existing.config, placed))
357
424
  return;
358
- this.items.update((xs) => xs.map((x) => (x.id === id ? { ...x, config: normalized } : x)));
425
+ this.items.update((xs) => xs.map((x) => (x.id === id ? { ...x, config: placed } : x)));
359
426
  this.settle();
360
427
  }
361
428
  unregisterItem(id) {
@@ -714,26 +781,26 @@ class NgxGridLayoutComponent {
714
781
  : '1');
715
782
  }
716
783
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxGridLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
717
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NgxGridLayoutComponent, isStandalone: true, selector: "ngx-grid-layout", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layoutChange: "layoutChange" }, host: { properties: { "class.ngx-grid-layout--dragging": "service.isInteracting()", "class.ngx-grid-layout--view": "!editMode()", "style.height.px": "service.height()", "attr.dir": "dirOverride() ?? null" } }, ngImport: i0, template: `
718
- <div class="ngx-grid-layout__surface">
719
- <div class="ngx-grid-layout__placeholder"></div>
720
- <ng-content />
721
- </div>
722
- `, isInline: true, styles: [":host{display:block;position:relative;contain:layout style;min-height:1px}.ngx-grid-layout__surface{position:relative;width:100%;height:100%;min-height:inherit}.ngx-grid-layout__placeholder{display:none;position:absolute;box-sizing:border-box;pointer-events:none;z-index:0;border:2px dashed currentColor;border-radius:inherit;opacity:.45}.ngx-grid-layout__surface:before{content:\"\";position:absolute;inset:0;pointer-events:none;opacity:var(--grid-bg-opacity);border:var(--grid-border-width) solid var(--grid-border-color);box-sizing:border-box;transition:opacity .15s ease;background-image:repeating-linear-gradient(var(--grid-border-color) 0 var(--grid-border-width),var(--grid-row-color) var(--grid-border-width) calc(var(--grid-row) - var(--grid-border-width)),var(--grid-border-color) calc(var(--grid-row) - var(--grid-border-width)) calc(var(--grid-row)),var(--grid-gap-color) calc(var(--grid-row)) calc(var(--grid-row) + var(--grid-gap))),repeating-linear-gradient(90deg,var(--grid-border-color) 0 var(--grid-border-width),var(--grid-col-color) var(--grid-border-width) calc(100% - (var(--grid-border-width) + var(--grid-gap))),var(--grid-border-color) calc(100% - (var(--grid-border-width) + var(--grid-gap))) calc(100% - var(--grid-gap)),var(--grid-gap-color) calc(100% - var(--grid-gap)) 100%);background-size:calc((100% + var(--grid-gap)) / var(--grid-cols)) calc(var(--grid-row) + var(--grid-gap));background-position:0 0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
784
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NgxGridLayoutComponent, isStandalone: true, selector: "ngx-grid-layout", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layoutChange: "layoutChange" }, host: { properties: { "class.ngx-grid-layout--dragging": "service.isInteracting()", "class.ngx-grid-layout--view": "!editMode()", "style.height.px": "service.height()", "attr.dir": "dirOverride() ?? null" } }, ngImport: i0, template: `
785
+ <div class="ngx-grid-layout__surface" [class.edit-mode]="editMode()">
786
+ <div class="ngx-grid-layout__placeholder"></div>
787
+ <ng-content />
788
+ </div>
789
+ `, isInline: true, styles: [":host{display:block;position:relative;contain:layout style;min-height:1px}.ngx-grid-layout__surface{position:relative;width:100%;height:100%;min-height:inherit}.ngx-grid-layout__placeholder{display:none;position:absolute;box-sizing:border-box;pointer-events:none;z-index:0;border:2px dashed currentColor;border-radius:inherit;opacity:.45}.ngx-grid-layout__surface.edit-mode:before{content:\"\";position:absolute;inset:0;pointer-events:none;opacity:var(--grid-bg-opacity);border:var(--grid-border-width) solid var(--grid-border-color);box-sizing:border-box;transition:opacity .15s ease;background-image:repeating-linear-gradient(var(--grid-border-color) 0 var(--grid-border-width),var(--grid-row-color) var(--grid-border-width) calc(var(--grid-row) - var(--grid-border-width)),var(--grid-border-color) calc(var(--grid-row) - var(--grid-border-width)) calc(var(--grid-row)),var(--grid-gap-color) calc(var(--grid-row)) calc(var(--grid-row) + var(--grid-gap))),repeating-linear-gradient(90deg,var(--grid-border-color) 0 var(--grid-border-width),var(--grid-col-color) var(--grid-border-width) calc(100% - (var(--grid-border-width) + var(--grid-gap))),var(--grid-border-color) calc(100% - (var(--grid-border-width) + var(--grid-gap))) calc(100% - var(--grid-gap)),var(--grid-gap-color) calc(100% - var(--grid-gap)) 100%);background-size:calc((100% + var(--grid-gap)) / var(--grid-cols)) calc(var(--grid-row) + var(--grid-gap));background-position:0 0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
723
790
  }
724
791
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxGridLayoutComponent, decorators: [{
725
792
  type: Component,
726
- args: [{ selector: 'ngx-grid-layout', standalone: true, template: `
727
- <div class="ngx-grid-layout__surface">
728
- <div class="ngx-grid-layout__placeholder"></div>
729
- <ng-content />
730
- </div>
793
+ args: [{ selector: 'ngx-grid-layout', standalone: true, template: `
794
+ <div class="ngx-grid-layout__surface" [class.edit-mode]="editMode()">
795
+ <div class="ngx-grid-layout__placeholder"></div>
796
+ <ng-content />
797
+ </div>
731
798
  `, host: {
732
799
  '[class.ngx-grid-layout--dragging]': 'service.isInteracting()',
733
800
  '[class.ngx-grid-layout--view]': '!editMode()',
734
801
  '[style.height.px]': 'service.height()',
735
802
  '[attr.dir]': 'dirOverride() ?? null',
736
- }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative;contain:layout style;min-height:1px}.ngx-grid-layout__surface{position:relative;width:100%;height:100%;min-height:inherit}.ngx-grid-layout__placeholder{display:none;position:absolute;box-sizing:border-box;pointer-events:none;z-index:0;border:2px dashed currentColor;border-radius:inherit;opacity:.45}.ngx-grid-layout__surface:before{content:\"\";position:absolute;inset:0;pointer-events:none;opacity:var(--grid-bg-opacity);border:var(--grid-border-width) solid var(--grid-border-color);box-sizing:border-box;transition:opacity .15s ease;background-image:repeating-linear-gradient(var(--grid-border-color) 0 var(--grid-border-width),var(--grid-row-color) var(--grid-border-width) calc(var(--grid-row) - var(--grid-border-width)),var(--grid-border-color) calc(var(--grid-row) - var(--grid-border-width)) calc(var(--grid-row)),var(--grid-gap-color) calc(var(--grid-row)) calc(var(--grid-row) + var(--grid-gap))),repeating-linear-gradient(90deg,var(--grid-border-color) 0 var(--grid-border-width),var(--grid-col-color) var(--grid-border-width) calc(100% - (var(--grid-border-width) + var(--grid-gap))),var(--grid-border-color) calc(100% - (var(--grid-border-width) + var(--grid-gap))) calc(100% - var(--grid-gap)),var(--grid-gap-color) calc(100% - var(--grid-gap)) 100%);background-size:calc((100% + var(--grid-gap)) / var(--grid-cols)) calc(var(--grid-row) + var(--grid-gap));background-position:0 0}\n"] }]
803
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative;contain:layout style;min-height:1px}.ngx-grid-layout__surface{position:relative;width:100%;height:100%;min-height:inherit}.ngx-grid-layout__placeholder{display:none;position:absolute;box-sizing:border-box;pointer-events:none;z-index:0;border:2px dashed currentColor;border-radius:inherit;opacity:.45}.ngx-grid-layout__surface.edit-mode:before{content:\"\";position:absolute;inset:0;pointer-events:none;opacity:var(--grid-bg-opacity);border:var(--grid-border-width) solid var(--grid-border-color);box-sizing:border-box;transition:opacity .15s ease;background-image:repeating-linear-gradient(var(--grid-border-color) 0 var(--grid-border-width),var(--grid-row-color) var(--grid-border-width) calc(var(--grid-row) - var(--grid-border-width)),var(--grid-border-color) calc(var(--grid-row) - var(--grid-border-width)) calc(var(--grid-row)),var(--grid-gap-color) calc(var(--grid-row)) calc(var(--grid-row) + var(--grid-gap))),repeating-linear-gradient(90deg,var(--grid-border-color) 0 var(--grid-border-width),var(--grid-col-color) var(--grid-border-width) calc(100% - (var(--grid-border-width) + var(--grid-gap))),var(--grid-border-color) calc(100% - (var(--grid-border-width) + var(--grid-gap))) calc(100% - var(--grid-gap)),var(--grid-gap-color) calc(100% - var(--grid-gap)) 100%);background-size:calc((100% + var(--grid-gap)) / var(--grid-cols)) calc(var(--grid-row) + var(--grid-gap));background-position:0 0}\n"] }]
737
804
  }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], layoutChange: [{ type: i0.Output, args: ["layoutChange"] }], dir: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } });
738
805
 
739
806
  class NgxGridItemComponent {
@@ -763,7 +830,7 @@ class NgxGridItemComponent {
763
830
  drag = inject(NgxDraggable);
764
831
  resize = inject(NgxResizable);
765
832
  resizable = computed(() => {
766
- return !this.resize.disabled;
833
+ return !this.resize.disabled && this.service.editMode();
767
834
  }, /* @ts-ignore */
768
835
  ...(ngDevMode ? [{ debugName: "resizable" }] : /* istanbul ignore next */ []));
769
836
  constructor() {
@@ -878,8 +945,8 @@ class NgxGridItemComponent {
878
945
  this.resize.maxHeight = config.maxH ? config.maxH * rowPx : Infinity;
879
946
  }
880
947
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxGridItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
881
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NgxGridItemComponent, isStandalone: true, selector: "ngx-grid-item", inputs: { itemId: { classPropertyName: "itemId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layoutChange: "layoutChange" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "style.position": "\"absolute\"", "style.display": "\"block\"", "style.boxSizing": "\"border-box\"", "style.transition": "transitionStyle()", "class.ngx-grid-item--dragging": "dragging()", "class.ngx-grid-item--resizing": "resizing()", "class.ngx-grid-item--static": "config().static", "class.with-resize-handler": "resizable()", "attr.tabindex": "interactive() ? 0 : null", "attr.aria-grabbed": "dragging()", "attr.data-grid-id": "itemId()" } }, hostDirectives: [{ directive: i1.NgxDraggable, inputs: ["dragHandle", "dragHandle", "lockAxis", "lockAxis"] }, { directive: i1.NgxResizable }], ngImport: i0, template: `
882
- <ng-content />
948
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: NgxGridItemComponent, isStandalone: true, selector: "ngx-grid-item", inputs: { itemId: { classPropertyName: "itemId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layoutChange: "layoutChange" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "style.position": "\"absolute\"", "style.display": "\"block\"", "style.boxSizing": "\"border-box\"", "style.transition": "transitionStyle()", "class.ngx-grid-item--dragging": "dragging()", "class.ngx-grid-item--resizing": "resizing()", "class.ngx-grid-item--static": "config().static", "class.with-resize-handler": "resizable()", "attr.tabindex": "interactive() ? 0 : null", "attr.aria-grabbed": "dragging()", "attr.data-grid-id": "itemId()" } }, hostDirectives: [{ directive: i1.NgxDraggable, inputs: ["dragHandle", "dragHandle", "lockAxis", "lockAxis"] }, { directive: i1.NgxResizable }], ngImport: i0, template: `
949
+ <ng-content />
883
950
  `, isInline: true, styles: [":host{display:block}:host.with-resize-handler:after{position:absolute;pointer-events:none;outline:1px #2196f3 solid;outline-offset:-5px;background:linear-gradient(#2196f3,#2196f3) 0 0/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 100% 0/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 0 100%/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 100% 100%/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 50% 0/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 50% 100%/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 0 50%/10px 10px no-repeat,linear-gradient(#2196f3,#2196f3) 100% 50%/10px 10px no-repeat;background-repeat:no-repeat;transition:none;inset:-2.5px;opacity:0;animation:showResizeHandle .3s forwards}:host:hover:after{opacity:1;content:\" \"}@keyframes showResizeHandle{0%{opacity:0}to{opacity:1}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
884
951
  }
885
952
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxGridItemComponent, decorators: [{
@@ -887,8 +954,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
887
954
  args: [{ selector: 'ngx-grid-item', standalone: true, hostDirectives: [
888
955
  { directive: NgxDraggable, inputs: ['dragHandle', 'lockAxis'], outputs: [] },
889
956
  NgxResizable,
890
- ], template: `
891
- <ng-content />
957
+ ], template: `
958
+ <ng-content />
892
959
  `, host: {
893
960
  '[style.position]': '"absolute"',
894
961
  '[style.display]': '"block"',
@@ -923,5 +990,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
923
990
  * Generated bundle index. Do not edit.
924
991
  */
925
992
 
926
- export { GridItemConfig, GridLayoutOptions, GridLayoutService, NgxGridItemComponent, NgxGridLayoutComponent, NgxGridLayoutModule, colToLeft, collides, compact, computeMetrics, getAllCollisions, getFirstCollision, gridItemConfigsEqual, leftToCol, maxOccupiedRow, moveItem, normalizeGridItem, placeItem, rowToTop, spanToHeightPx, spanToWidthPx, topToRow, trySwap };
993
+ export { GridItemConfig, GridLayoutOptions, GridLayoutService, NgxGridItemComponent, NgxGridLayoutComponent, NgxGridLayoutModule, colToLeft, collides, compact, computeMetrics, findFreeSpot, getAllCollisions, getFirstCollision, gridItemConfigsEqual, leftToCol, maxOccupiedRow, moveItem, normalizeGridItem, placeItem, rowToTop, spanToHeightPx, spanToWidthPx, topToRow, trySwap };
927
994
  //# sourceMappingURL=ngx-kit-grid-layout.mjs.map