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.
- package/angle-selector/README.md +34 -34
- package/box-shadow/README.md +33 -33
- package/color-picker/README.md +52 -52
- package/data-table/README.md +120 -120
- package/date-picker/README.md +74 -74
- package/dialog/README.md +92 -92
- package/drag-resize/README.md +55 -55
- package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
- package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -1
- package/fesm2022/ngx-kit-drawer-menu.mjs +2 -2
- package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
- package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
- package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
- package/fesm2022/ngx-kit-gallery.mjs +2 -2
- package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
- package/fesm2022/ngx-kit-grid-layout.mjs +108 -41
- package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -1
- package/fesm2022/ngx-kit-infinite-scroll.mjs +467 -0
- package/fesm2022/ngx-kit-infinite-scroll.mjs.map +1 -0
- package/fesm2022/ngx-kit-shared.mjs.map +1 -1
- package/fesm2022/ngx-kit-virtual-scroll.mjs +2 -2
- package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ngx-kit-webflow.mjs +38 -38
- package/fesm2022/ngx-kit-webflow.mjs.map +1 -1
- package/gallery/README.md +71 -71
- package/gradient-picker/README.md +41 -41
- package/grid-layout/README.md +64 -64
- package/image-editor/README.md +44 -44
- package/infinite-scroll/README.md +252 -0
- package/menu/README.md +85 -85
- package/message/README.md +70 -70
- package/notify/README.md +56 -56
- package/package.json +5 -1
- package/shared/README.md +117 -117
- package/time-picker/README.md +89 -89
- package/types/ngx-kit-grid-layout.d.ts +21 -20
- package/types/ngx-kit-infinite-scroll.d.ts +86 -0
- 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
|
-
|
|
290
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|