UNPKG

ng2-multi-modal

Version:
1 lines 85.8 kB
{"version":3,"file":"ng2-multi-modal.mjs","sources":["../../../projects/ng2-multi-modal/src/lib/components/icon/loading.icon.ts","../../../projects/ng2-multi-modal/src/lib/components/icon/close.icon.ts","../../../projects/ng2-multi-modal/src/lib/components/icon/maximize.icon.ts","../../../projects/ng2-multi-modal/src/lib/components/icon/minimize.icon.ts","../../../projects/ng2-multi-modal/src/lib/components/icon/maximized.icon.ts","../../../projects/ng2-multi-modal/src/lib/directive/string-template-outlet.directive.ts","../../../projects/ng2-multi-modal/src/lib/ng2-multi-modal.component.ts","../../../projects/ng2-multi-modal/src/lib/ng2-multi-modal.component.html","../../../projects/ng2-multi-modal/src/lib/components/dock/dock.component.ts","../../../projects/ng2-multi-modal/src/lib/ng2-multi-modal.service.ts","../../../projects/ng2-multi-modal/src/public-api.ts","../../../projects/ng2-multi-modal/src/ng2-multi-modal.ts"],"sourcesContent":["import {Component} from '@angular/core';\r\n\r\n@Component({\r\n selector: 'loading-icon',\r\n template: `\r\n <svg class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"50\" height=\"50\">\r\n <path d=\"M512.056 908.647c-84.516 0-166.416-27.084-235.266-78.637-84.15-63.028-138.741-155.109-153.675-259.2-14.934-104.119 11.559-207.816 74.588-291.994 130.162-173.812 377.438-209.25 551.194-79.172 72.844 54.562 124.819 133.228 146.391 221.484 3.684 15.103-5.569 30.319-20.644 34.003-15.075 3.572-30.319-5.541-34.003-20.644-18.45-75.628-63-143.044-125.466-189.816-148.866-111.516-360.844-81.112-472.444 67.866-54.028 72.141-76.725 161.016-63.9 250.256 12.797 89.241 59.597 168.131 131.737 222.131 149.006 111.656 360.956 81.197 472.5-67.781 29.194-39.009 49.219-82.716 59.456-129.938 3.319-15.188 18.366-24.834 33.441-21.544 15.188 3.291 24.834 18.281 21.544 33.441-12.009 55.181-35.353 106.2-69.413 151.762-63.028 84.15-155.109 138.769-259.256 153.675-18.984 2.756-37.941 4.106-56.784 4.106z\"\r\n fill=\"#272636\"></path>\r\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 0 0\"\r\n to=\"360 0 0\" dur=\"1s\" repeatCount=\"indefinite\"></animateTransform>\r\n </svg>\r\n `,\r\n styles: [],\r\n standalone: true\r\n})\r\nexport class LoadingIcon {\r\n constructor() {\r\n }\r\n}\r\n","import {Component} from '@angular/core';\r\n\r\n@Component({\r\n selector: 'close-icon',\r\n template: `\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"10\"\r\n height=\"10\"\r\n viewBox=\"0 0 10 10\"\r\n >\r\n <path\r\n class=\"color-path\"\r\n fill-rule=\"evenodd\"\r\n d=\"M5.707 5l3.647-3.646a.5.5 0 0 0-.708-.708L5 4.293 1.354.646a.5.5 0 0 0-.708.708L4.293 5 .646 8.646a.5.5 0 0 0 .708.708L5 5.707l3.646 3.647a.5.5 0 0 0 .708-.708L5.707 5z\"\r\n />\r\n </svg>\r\n `,\r\n styles: [],\r\n standalone: true\r\n})\r\nexport class CloseIcon {\r\n constructor() {\r\n }\r\n}\r\n","import { Component } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'maximize-icon',\r\n template: `\r\n <svg\r\n width=\"10\"\r\n height=\"10\"\r\n viewBox=\"0 0 10 10\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <polygon\r\n class=\"apple-theme color-path\"\r\n points=\"5,0 0,0 0,5\"\r\n />\r\n <polygon\r\n class=\"apple-theme color-path\"\r\n points=\"10,10 10,5 5,10\"\r\n />\r\n <rect\r\n class=\"win-theme color-rect\"\r\n x=\"0\"\r\n y=\"0\"\r\n width=\"10\"\r\n height=\"10\"\r\n stroke=\"#444\"\r\n stroke-width=\"1\"\r\n fill=\"none\"\r\n />\r\n <rect\r\n class=\"win-theme color-rect\"\r\n x=\"1\"\r\n y=\"1\"\r\n width=\"8\"\r\n height=\"1\"\r\n stroke=\"#444\"\r\n stroke-width=\"1\"\r\n />\r\n </svg>\r\n `,\r\n styles: [],\r\n standalone: true\r\n})\r\nexport class MaximizeIcon {\r\n constructor() {}\r\n}\r\n","import {Component} from '@angular/core';\r\n\r\n@Component({\r\n selector: 'minimize-icon',\r\n template: `\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"10\"\r\n height=\"10\"\r\n viewBox=\"0 0 10 10\"\r\n >\r\n <path\r\n class=\"color-path\"\r\n fill-rule=\"evenodd\"\r\n d=\"M0 5h10v1H0z\"\r\n />\r\n </svg>\r\n `,\r\n styles: [],\r\n standalone: true\r\n})\r\nexport class MinimizeIcon {\r\n constructor() {}\r\n}\r\n","import { Component } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'maximized-icon',\r\n template: `\r\n <svg width=\"100\"\r\n height=\"100\"\r\n viewBox=\"-2 -2 14 14\"\r\n xmlns=\"http://www.w3.org/2000/svg\">\r\n <polygon\r\n class=\"apple-theme color-path\"\r\n points=\"-2,4.6 4.6,4.6 4.6,-2\"\r\n ></polygon>\r\n <polygon\r\n class=\"apple-theme color-path\"\r\n points=\"5.4,5.4 12,5.4 5.4,12\"\r\n ></polygon>\r\n <!-- Two rectangles, one is under the other, one in the top right corner, one in the bottom left corner, and the one in the bottom left corner -->\r\n <rect\r\n class=\"win-theme color-path\"\r\n x=\"2\"\r\n y=\"-1\"\r\n width=\"9\"\r\n height=\"9\"\r\n stroke=\"#444\"\r\n stroke-width=\"1\"\r\n fill=\"none\"\r\n ></rect>\r\n <rect\r\n class=\"win-theme color-path\"\r\n x=\"-1\"\r\n y=\"2\"\r\n width=\"9\"\r\n height=\"9\"\r\n stroke=\"#444\"\r\n stroke-width=\"1\"\r\n ></rect>\r\n </svg>\r\n `,\r\n styles: [],\r\n standalone: true\r\n})\r\nexport class MaximizeDIcon {\r\n constructor() {}\r\n}\r\n","import {\r\n Directive,\r\n EmbeddedViewRef,\r\n TemplateRef,\r\n ViewContainerRef,\r\n input,\r\n effect,\r\n untracked\r\n} from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[stringTemplateOutlet]',\r\n exportAs: 'stringTemplateOutlet',\r\n standalone: true\r\n})\r\nexport class StringTemplateOutletDirective<_T = unknown> {\r\n private embeddedViewRef: EmbeddedViewRef<any> | null = null;\r\n private context = new StringTemplateOutletContext();\r\n\r\n // Using Angular 19's input() function instead of @Input decorator\r\n readonly stringTemplateOutletContext = input<any | null>(null);\r\n readonly stringTemplateOutlet = input<any | TemplateRef<any>>(null);\r\n\r\n static ngTemplateContextGuard<T>(\r\n _dir: StringTemplateOutletDirective<T>,\r\n _ctx: any\r\n ): _ctx is StringTemplateOutletContext {\r\n return true;\r\n }\r\n\r\n constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<any>) {\r\n // Effect that reacts to changes in inputs\r\n effect(() => {\r\n // Read the current values of inputs\r\n const outlet = this.stringTemplateOutlet();\r\n const _ = this.stringTemplateOutletContext();\r\n\r\n // Update the implicit context when outlet changes\r\n if (outlet !== null) {\r\n this.context.$implicit = outlet;\r\n }\r\n\r\n // Determine if we should recreate the view\r\n untracked(() => {\r\n const isNewOutletTemplate = outlet instanceof TemplateRef;\r\n\r\n // Check if the embedded view exists and if the template type changed\r\n const shouldRecreate =\r\n !this.embeddedViewRef ||\r\n (this.embeddedViewRef && isNewOutletTemplate);\r\n\r\n if (shouldRecreate) {\r\n this.recreateView();\r\n } else if (this.embeddedViewRef) {\r\n this.updateContext();\r\n }\r\n });\r\n });\r\n }\r\n\r\n private recreateView(): void {\r\n this.viewContainer.clear();\r\n const isTemplateRef = this.stringTemplateOutlet() instanceof TemplateRef;\r\n const templateRef = (isTemplateRef ? this.stringTemplateOutlet() : this.templateRef) as any;\r\n this.embeddedViewRef = this.viewContainer.createEmbeddedView(\r\n templateRef,\r\n isTemplateRef ? this.stringTemplateOutletContext() : this.context\r\n );\r\n }\r\n\r\n private updateContext(): void {\r\n if (!this.embeddedViewRef) return;\r\n\r\n const isTemplateRef = this.stringTemplateOutlet() instanceof TemplateRef;\r\n const newCtx = isTemplateRef ? this.stringTemplateOutletContext() : this.context;\r\n const oldCtx = this.embeddedViewRef.context as any;\r\n\r\n if (newCtx) {\r\n for (const propName of Object.keys(newCtx)) {\r\n oldCtx[propName] = newCtx[propName];\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport class StringTemplateOutletContext {\r\n public $implicit: any;\r\n}\r\n","import {\r\n AfterViewInit,\r\n Component,\r\n computed,\r\n ElementRef,\r\n HostListener,\r\n input,\r\n model,\r\n OnDestroy,\r\n output,\r\n signal,\r\n TemplateRef,\r\n ViewChild\r\n} from '@angular/core';\r\nimport { Ng2MultiModalService } from \"./ng2-multi-modal.service\";\r\nimport { CommonModule } from \"@angular/common\";\r\nimport { LoadingIcon } from \"./components/icon/loading.icon\";\r\nimport { CloseIcon } from './components/icon/close.icon';\r\nimport { MaximizeIcon } from \"./components/icon/maximize.icon\";\r\nimport { MinimizeIcon } from './components/icon/minimize.icon';\r\nimport { MaximizeDIcon } from \"./components/icon/maximized.icon\";\r\nimport { StringTemplateOutletDirective } from \"./directive/string-template-outlet.directive\";\r\n\r\ninterface ModalSize {\r\n offsetY: number;\r\n offsetX: number;\r\n align: 'leftTop' | 'rightTop' | 'leftBottom' | 'rightBottom';\r\n width: number;\r\n height: number;\r\n}\r\n\r\n@Component({\r\n selector: 'ng2-multi-modal',\r\n templateUrl: 'ng2-multi-modal.component.html',\r\n imports: [CommonModule, CloseIcon, LoadingIcon, MaximizeIcon, MinimizeIcon, MaximizeDIcon, StringTemplateOutletDirective],\r\n standalone: true,\r\n})\r\nexport class Ng2MultiModalComponent implements AfterViewInit, OnDestroy {\r\n readonly modalId = signal('window' + Math.floor(Math.random() * 1000000));\r\n readonly titleHeight = signal(0);\r\n readonly position = signal<{ [key: string]: string }>({});\r\n readonly dragging = signal(false);\r\n readonly windowMouseEnterFlag = signal(false);\r\n readonly windowMouseDownFlag = signal(false);\r\n readonly windowMouseLeaveFlag = signal(true);\r\n readonly clickedX = signal(0);\r\n readonly clickedY = signal(0);\r\n readonly mouseEventSignal = signal<MouseEvent | null>(null);\r\n readonly mouseEnteredSignal = signal<MouseEvent | null>(null);\r\n readonly borderWidth = signal(4);\r\n readonly cursorStyle = signal('default');\r\n readonly display = signal('none');\r\n readonly border = signal<{\r\n isLeft?: boolean;\r\n isRight?: boolean;\r\n isTop?: boolean;\r\n isBottom?: boolean;\r\n }>({\r\n isLeft: false,\r\n isRight: false,\r\n isTop: false,\r\n isBottom: false\r\n });\r\n readonly propertyBeforeMaximize = signal<ModalSize | null>(null);\r\n // Input signals\r\n readonly title = input<string | TemplateRef<any>>('Modal Name');\r\n readonly icon = input<string | TemplateRef<any> | null>(null);\r\n readonly align = input<'leftTop' | 'rightTop' | 'leftBottom' | 'rightBottom'>('leftTop');\r\n readonly bodyStyle = input<{ [key: string]: any }>({});\r\n readonly closeOnNavigation = input(false);\r\n readonly closable = input(true);\r\n readonly content = input<TemplateRef<any>>();\r\n readonly minHeight = input(100);\r\n readonly minWidth = input(175);\r\n readonly maximizable = input(true);\r\n readonly minimizable = input(true);\r\n readonly resizable = input(true);\r\n readonly outOfBounds = input(false);\r\n readonly loadingTip = input<string | TemplateRef<any>>(this.getLocaleText('loading'));\r\n // Model signals\r\n readonly height = model(300);\r\n readonly width = model(300);\r\n readonly zIndex = model(0);\r\n readonly offsetY = model(200);\r\n readonly offsetX = model(200);\r\n readonly loading = model(true);\r\n readonly theme = model<'light' | 'dark'>('light');\r\n readonly draggable = model(true);\r\n readonly contentScrollable = model(false);\r\n readonly minimized = model(false);\r\n readonly maximized = model(false);\r\n // Output events\r\n readonly onReady = output<Ng2MultiModalComponent>();\r\n readonly onClose = output<string>();\r\n readonly onResize = output<ModalSize>();\r\n readonly onMaximize = output<ModalSize>();\r\n readonly onMaximizeRestore = output<ModalSize>();\r\n readonly onMinimize = output<ModalSize>();\r\n readonly onMinimizeRestore = output<ModalSize>();\r\n readonly onSelected = output<string>();\r\n readonly onMove = output<ModalSize>();\r\n\r\n constructor(private modalService: Ng2MultiModalService) { }\r\n\r\n get language() {\r\n return this.modalService?.language() || 'en';\r\n }\r\n\r\n readonly windowSizeSignal = computed(() => ({\r\n offsetX: this.offsetX(),\r\n offsetY: this.offsetY(),\r\n align: this.align(),\r\n width: this.width(),\r\n height: this.height()\r\n }));\r\n\r\n readonly leftSignal = computed(() =>\r\n (this.align() === 'leftTop' || this.align() === 'leftBottom') ?\r\n this.offsetX() : window.innerWidth - this.width() - this.offsetX()\r\n );\r\n\r\n readonly rightSignal = computed(() =>\r\n (this.align() === 'rightTop' || this.align() === 'rightBottom') ?\r\n window.innerWidth - this.offsetX() : this.width() + this.offsetX()\r\n );\r\n\r\n readonly topSignal = computed(() =>\r\n (this.align() === 'leftTop' || this.align() === 'rightTop') ?\r\n this.offsetY() : window.innerHeight - this.height() - this.offsetY()\r\n );\r\n\r\n readonly bottomSignal = computed(() =>\r\n (this.align() === 'leftBottom' || this.align() === 'rightBottom') ?\r\n window.innerHeight - this.offsetY() : this.height() + this.offsetY()\r\n );\r\n\r\n readonly selectedSignal = computed(() => this.modalService.selectedWindow() === this.modalId());\r\n\r\n // Create a signal for the element\r\n readonly titleBarElement = signal<ElementRef | null>(null);\r\n\r\n // Update the setter\r\n @ViewChild('titleBar', { static: false }) set titleBar(titleBar: ElementRef) {\r\n this.titleBarElement.set(titleBar);\r\n if (titleBar) {\r\n this.titleHeight.set(titleBar.nativeElement.offsetHeight);\r\n }\r\n }\r\n\r\n getLocaleText(text: 'loading' | 'close' | 'maximize' | 'minimize' | 'windowMode') {\r\n const dictionary = {\r\n 'es': {\r\n loading: 'Loading...',\r\n close: 'Close Window',\r\n maximize: 'Maximize',\r\n minimize: 'Minimize',\r\n windowMode: 'Window Mode',\r\n },\r\n 'en': {\r\n loading: 'Loading...',\r\n close: 'Close Window',\r\n maximize: 'Maximize',\r\n minimize: 'Minimize',\r\n windowMode: 'Window Mode',\r\n }\r\n }\r\n return dictionary[this.language][text];\r\n }\r\n\r\n updateOffsetX(offsetX: number) {\r\n this.offsetX.set(offsetX);\r\n if (['leftTop', 'leftBottom'].includes(this.align())) {\r\n this.position.update((oldValue: any) => {\r\n return {\r\n ...oldValue,\r\n left: offsetX + 'px',\r\n right: null\r\n }\r\n })\r\n } else {\r\n this.position.update((oldValue: any) => {\r\n return {\r\n ...oldValue,\r\n left: null,\r\n right: offsetX + 'px'\r\n }\r\n })\r\n }\r\n }\r\n\r\n updateOffsetY(offsetY: number) {\r\n this.offsetY.set(offsetY);\r\n if (['leftTop', 'rightTop'].includes(this.align())) {\r\n this.position.update((oldValue: any) => {\r\n return {\r\n ...oldValue,\r\n top: offsetY + 'px',\r\n bottom: null\r\n }\r\n })\r\n } else {\r\n this.position.update((oldValue: any) => {\r\n return {\r\n ...oldValue,\r\n top: null,\r\n bottom: offsetY + 'px'\r\n }\r\n })\r\n }\r\n }\r\n\r\n private preventTextSelection(prevent: boolean): void {\r\n if (prevent) {\r\n // Create a temporary overlay div that covers the entire viewport\r\n // This catches all mouse events during resize/drag without affecting actual content\r\n if (!document.getElementById('ng2-modal-overlay')) {\r\n const overlay = document.createElement('div');\r\n overlay.id = 'ng2-modal-overlay';\r\n overlay.style.position = 'fixed';\r\n overlay.style.top = '0';\r\n overlay.style.left = '0';\r\n overlay.style.width = '100%';\r\n overlay.style.height = '100%';\r\n overlay.style.zIndex = '999999';\r\n overlay.style.pointerEvents = 'none'; // Allow events to pass through\r\n document.body.appendChild(overlay);\r\n }\r\n\r\n // Better to use a class to avoid direct style manipulation\r\n document.body.classList.add('ng2-modal-no-select');\r\n\r\n // Add style if it doesn't exist\r\n if (!document.getElementById('ng2-modal-style')) {\r\n const style = document.createElement('style');\r\n style.id = 'ng2-modal-style';\r\n style.innerHTML = `\r\n .ng2-modal-no-select {\r\n cursor: inherit !important;\r\n }\r\n .ng2-modal-no-select ::selection {\r\n background: transparent !important;\r\n }\r\n .ng2-modal-no-select ::-moz-selection {\r\n background: transparent !important;\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n }\r\n } else {\r\n // Remove all elements we added\r\n document.body.classList.remove('ng2-modal-no-select');\r\n const overlay = document.getElementById('ng2-modal-overlay');\r\n if (overlay) {\r\n overlay.remove();\r\n }\r\n }\r\n }\r\n\r\n @HostListener('document:mouseleave')\r\n documentMouseLeave() {\r\n // Ensure text selection is re-enabled when the mouse leaves the document\r\n this.preventTextSelection(false);\r\n this.dragging.set(false);\r\n this.windowMouseDownFlag.set(false);\r\n }\r\n\r\n @HostListener('document:mousemove', ['$event'])\r\n onMouseMove(event: MouseEvent) {\r\n if (!this.draggable() || this.maximized()) {\r\n return;\r\n }\r\n this.mouseEventSignal.set(event);\r\n // Only prevent text selection during actual dragging or resizing\r\n if (this.dragging() || (this.windowMouseDownFlag() && this.resizable() &&\r\n Object.values(this.border()).some(value => value === true))) {\r\n this.preventTextSelection(true);\r\n }\r\n if (this.dragging()) {\r\n // Replace when(this.align) with switch or if/else\r\n let newOffsetX = 0;\r\n if (this.align() === 'leftTop' || this.align() === 'leftBottom') {\r\n if (!this.outOfBounds) {\r\n let offsetX = Math.max(event.clientX - this.clickedX(), 0);\r\n if (offsetX + this.width() > window.innerWidth) {\r\n offsetX = window.innerWidth - this.width();\r\n }\r\n newOffsetX = offsetX;\r\n } else {\r\n newOffsetX = event.clientX - this.clickedX();\r\n }\r\n } else if (this.align() === 'rightTop' || this.align() === 'rightBottom') {\r\n if (!this.outOfBounds) {\r\n let offsetX = Math.max(window.innerWidth - event.clientX + this.clickedX() - this.width(), 0);\r\n if (offsetX + this.width() > window.innerWidth) {\r\n offsetX = window.innerWidth - this.width();\r\n }\r\n newOffsetX = offsetX;\r\n } else {\r\n newOffsetX = window.innerWidth - event.clientX + this.clickedX() - this.width();\r\n }\r\n }\r\n this.updateOffsetX(newOffsetX);\r\n\r\n // Handle Y positioning\r\n let newOffsetY = 0;\r\n if (this.align() === 'leftTop' || this.align() === 'rightTop') {\r\n if (!this.outOfBounds) {\r\n let offsetY = Math.max(event.clientY - this.clickedY(), 0);\r\n if (offsetY + this.height() > window.innerHeight) {\r\n offsetY = window.innerHeight - this.height();\r\n }\r\n newOffsetY = offsetY;\r\n } else {\r\n newOffsetY = event.clientY - this.clickedY();\r\n }\r\n } else if (this.align() === 'leftBottom' || this.align() === 'rightBottom') {\r\n if (!this.outOfBounds) {\r\n let offsetY = Math.max(window.innerHeight - event.clientY + this.clickedY() - this.height(), 0);\r\n if (offsetY + this.height() > window.innerHeight) {\r\n offsetY = window.innerHeight - this.height();\r\n }\r\n newOffsetY = offsetY;\r\n } else {\r\n newOffsetY = window.innerHeight - event.clientY + this.clickedY() - this.height();\r\n }\r\n }\r\n this.updateOffsetY(newOffsetY);\r\n }\r\n\r\n if (this.windowMouseDownFlag() && this.resizable()) {\r\n this.resizeWindow(event);\r\n } else {\r\n this.onMove.emit({ ...this as any });\r\n }\r\n\r\n let x = event.clientX;\r\n let y = event.clientY;\r\n\r\n let leftBorderX = Math.abs(this.leftSignal() - x) <= this.borderWidth();\r\n let rightBorderX = Math.abs(this.leftSignal() + this.width() - x) <= this.borderWidth();\r\n let rightLeftBorderY = (y > this.topSignal()) && (y < (this.topSignal() + this.height()));\r\n\r\n\r\n let topBorderY = Math.abs(this.topSignal() - y) <= this.borderWidth();\r\n let bottomBorderY = Math.abs(this.topSignal() + this.height() - y) <= this.borderWidth();\r\n let topBottomBorderX = x > this.leftSignal() && x < this.leftSignal() + this.width();\r\n\r\n if (this.resizable()) {\r\n if (leftBorderX && bottomBorderY) {\r\n this.cursorStyle.set('sw-resize');\r\n this.border.set({\r\n isLeft: true,\r\n isBottom: true,\r\n })\r\n this.contentScrollable.set(true);\r\n } else if (rightBorderX && bottomBorderY) {\r\n this.cursorStyle.set('se-resize');\r\n this.border.set({\r\n isRight: true,\r\n isBottom: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (leftBorderX && topBorderY) {\r\n this.cursorStyle.set('nw-resize');\r\n this.border.set({\r\n isLeft: true,\r\n isTop: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (rightBorderX && topBorderY) {\r\n this.cursorStyle.set('ne-resize');\r\n this.border.set({\r\n isRight: true,\r\n isTop: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (leftBorderX && rightLeftBorderY) {\r\n this.cursorStyle.set('w-resize');\r\n this.border.set({\r\n isLeft: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (rightBorderX && rightLeftBorderY) {\r\n this.cursorStyle.set('e-resize');\r\n this.border.set({\r\n isRight: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (topBorderY && topBottomBorderX) {\r\n this.cursorStyle.set('n-resize');\r\n this.border.set({\r\n isTop: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else if (bottomBorderY && topBottomBorderX) {\r\n this.cursorStyle.set('s-resize');\r\n this.border.set({\r\n isBottom: true,\r\n });\r\n this.contentScrollable.set(true);\r\n } else {\r\n this.border.set({});\r\n this.cursorStyle.set('auto');\r\n this.contentScrollable.set(false);\r\n }\r\n }\r\n }\r\n\r\n resizeWindow(event: MouseEvent) {\r\n if (!this.draggable()) {\r\n return;\r\n }\r\n if (this.dragging()) {\r\n return;\r\n }\r\n if (!this.border().isLeft && !this.border().isRight && !this.border().isTop && !this.border().isBottom) {\r\n return;\r\n }\r\n if (this.border().isLeft) {\r\n if (this.align().toLocaleLowerCase().includes('left')) {\r\n let r = this.rightSignal();\r\n this.updateOffsetX(event.clientX);\r\n this.width.set(r - this.leftSignal());\r\n } else {\r\n this.width.set(this.rightSignal() - event.clientX);\r\n }\r\n }\r\n if (this.border().isRight) {\r\n if (this.align().toLocaleLowerCase().includes('left')) {\r\n this.width.update(prev => prev + event.clientX - this.rightSignal());\r\n } else {\r\n this.width.update(prev => prev + event.clientX - this.rightSignal());;\r\n this.updateOffsetX(Math.max(window.innerWidth - event.clientX, 0));\r\n }\r\n }\r\n if (this.border().isTop) {\r\n if (this.align().toLocaleLowerCase().includes('top')) {\r\n let b = this.bottomSignal();\r\n this.updateOffsetY(Math.max(event.clientY, 0));\r\n this.height.set(b - this.topSignal());\r\n } else {\r\n this.height.set(this.bottomSignal() - event.clientY);\r\n }\r\n }\r\n if (this.border().isBottom) {\r\n if (this.align().toLocaleLowerCase().includes('top')) {\r\n this.height.update(prev => prev + event.clientY - this.bottomSignal());\r\n } else {\r\n this.height.update(prev => prev + event.clientY - this.bottomSignal());\r\n this.updateOffsetY(Math.max(window.innerHeight - event.clientY, 0));\r\n }\r\n }\r\n\r\n if (this.height() < this.minHeight()) {\r\n this.height.set(this.minHeight());\r\n }\r\n if (this.width() < this.minWidth()) {\r\n this.width.set(this.minWidth());\r\n }\r\n if (!this.outOfBounds() && this.height() + this.offsetY() > window.innerHeight) {\r\n this.updateOffsetY(Math.max(window.innerHeight - this.height(), 0));\r\n }\r\n if (!this.outOfBounds && this.width() + this.offsetX() > window.innerWidth) {\r\n this.updateOffsetX(Math.max(window.innerWidth - this.width(), 0));\r\n }\r\n if (this.offsetY() < 0) {\r\n this.updateOffsetY(0);\r\n }\r\n this.onResize.emit(this.windowSizeSignal());\r\n }\r\n\r\n titleBarMouseDown(event: MouseEvent) {\r\n if (event.button === 2) {\r\n return;\r\n }\r\n // Prevent default action to avoid text selection\r\n event.preventDefault();\r\n\r\n // Enable text selection prevention\r\n this.preventTextSelection(true);\r\n\r\n this.dragging.set(true);\r\n this.clickedX.set(event.clientX - this.leftSignal());\r\n this.clickedY.set(event.clientY - this.topSignal());\r\n }\r\n\r\n @HostListener('document:mouseup', ['$event'])\r\n titleBarMouseUp(event: MouseEvent) {\r\n // We should always re-enable text selection on mouse up\r\n this.preventTextSelection(false);\r\n this.dragging.set(false);\r\n this.windowMouseDownFlag.set(false);\r\n }\r\n\r\n // Add a key event listener to ensure we clean up if Escape is pressed\r\n @HostListener('document:keydown.escape', ['$event'])\r\n handleEscapeKey(event: KeyboardEvent) {\r\n this.preventTextSelection(false);\r\n }\r\n\r\n windowMouseEnter(event: MouseEvent) {\r\n if (!this.draggable()) {\r\n return;\r\n }\r\n this.mouseEnteredSignal.set(event);\r\n this.windowMouseEnterFlag.set(true);\r\n this.windowMouseLeaveFlag.set(false);\r\n }\r\n\r\n windowMouseDown(event: MouseEvent) {\r\n this.modalService.selectedWindow.set(this.modalId());\r\n if (!this.draggable() || event.button === 2) {\r\n return;\r\n }\r\n\r\n // Only prevent selection when clicking on a border for resizing\r\n const onBorder = Object.values(this.border()).some(value => value === true);\r\n if (onBorder && this.resizable()) {\r\n event.preventDefault();\r\n this.preventTextSelection(true);\r\n }\r\n\r\n this.windowMouseDownFlag.set(true);\r\n this.onSelected.emit(this.modalId());\r\n if (this.windowMouseDownFlag() && this.windowMouseEnterFlag()) {\r\n const idx = this.modalService.maxZIndex++;\r\n this.zIndex.set(idx);\r\n }\r\n }\r\n\r\n windowMouseLeave(event: MouseEvent) {\r\n if (!this.draggable()) {\r\n return;\r\n }\r\n this.windowMouseLeaveFlag.set(true);\r\n this.windowMouseEnterFlag.set(false);\r\n }\r\n\r\n close() {\r\n if (this.closable()) {\r\n this.height.set(0);\r\n window.onresize = null;\r\n this.toggleBodyScrollable(true);\r\n this.display.set('none');\r\n this.onClose.emit(this.modalId());\r\n }\r\n }\r\n\r\n minimize() {\r\n window.onresize = null;\r\n if (this.minimized()) {\r\n this.minimized.set(false);\r\n this.display.set('block');\r\n // this.modalService.dockComponentRef!.instance.docks =\r\n // this.modalService.dockComponentRef!.instance.docks.filter(win => win != this);\r\n this.modalService.dockComponentRef!.instance.docks.update(prev => prev.filter(win => win !== this));\r\n this.onMinimizeRestore.emit(this.windowSizeSignal());\r\n } else {\r\n this.toggleBodyScrollable(true);\r\n\r\n this.minimized.set(true);\r\n setTimeout(() => {\r\n this.display.set('none');\r\n }, 200);\r\n this.modalService.addMinimizeItem(this);\r\n this.onMinimize.emit(this.windowSizeSignal());\r\n }\r\n this.onResize.emit(this.windowSizeSignal());\r\n }\r\n\r\n maximize(): Promise<boolean> {\r\n return new Promise<boolean>(resolve => {\r\n const isCurrentlyMaximized = this.maximized();\r\n const hasStoredProperties = !!this.propertyBeforeMaximize();\r\n\r\n if (isCurrentlyMaximized && hasStoredProperties) {\r\n // Restore from maximized state\r\n this.toggleBodyScrollable(true);\r\n window.onresize = null;\r\n this.maximized.set(false);\r\n\r\n const { width, height, offsetX, offsetY } = this.propertyBeforeMaximize()!;\r\n this.width.set(width);\r\n this.height.set(height);\r\n this.updateOffsetX(offsetX);\r\n this.updateOffsetY(offsetY);\r\n this.draggable.set(true);\r\n\r\n this.onResize.emit(this.windowSizeSignal());\r\n this.onMaximizeRestore.emit(this.windowSizeSignal());\r\n resolve(true);\r\n } else {\r\n // Save current state before maximizing\r\n this.propertyBeforeMaximize.set({\r\n width: this.width(),\r\n height: this.height(),\r\n offsetX: this.offsetX(),\r\n offsetY: this.offsetY(),\r\n align: this.align()\r\n });\r\n\r\n // Maximize the window\r\n this.toggleBodyScrollable(false);\r\n this.maximized.set(true);\r\n this.draggable.set(false);\r\n\r\n // Set dimensions and position\r\n this.updateOffsetX(0);\r\n this.updateOffsetY(0);\r\n this.height.set(window.innerHeight);\r\n this.width.set(window.innerWidth);\r\n\r\n // Handle window resize when maximized\r\n window.onresize = () => {\r\n this.width.set(window.innerWidth);\r\n this.height.set(window.innerHeight);\r\n this.updateOffsetX(0);\r\n this.updateOffsetY(0);\r\n };\r\n\r\n this.onResize.emit(this.windowSizeSignal());\r\n this.onMaximize.emit(this.windowSizeSignal());\r\n resolve(true);\r\n }\r\n });\r\n }\r\n //if html window resized, judge if window is out of screen, if so, move it to the screen\r\n @HostListener('window: resize', ['$event'])\r\n resizeListener(event: Event) {\r\n if (this.offsetY() + this.height() > window.innerHeight) {\r\n this.updateOffsetY(Math.max(window.innerHeight - this.height(), 0));\r\n }\r\n if (this.offsetX() + this.width() > window.innerWidth) {\r\n this.updateOffsetX(Math.max(window.innerWidth - this.width(), 0));\r\n }\r\n this.onResize.emit(this.windowSizeSignal());\r\n }\r\n\r\n toggleBodyScrollable(scrollable = true) {\r\n setTimeout(() => {\r\n if (scrollable) {\r\n document.body.style.overflow = 'auto';\r\n } else {\r\n document.body.style.overflow = 'hidden';\r\n }\r\n }, 200);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n // Clean up any remaining text selection prevention\r\n this.preventTextSelection(false);\r\n\r\n // Remove any window resize handlers\r\n window.onresize = null;\r\n }\r\n\r\n async ngAfterViewInit(): Promise<void> {\r\n if (this.maximized()) {\r\n this.display.set('none');\r\n this.maximized.set(false);\r\n await this.maximize();\r\n }\r\n this.display.set('block');\r\n this.loading.set(false)\r\n this.onReady.emit(this);\r\n this.updateOffsetX(this.offsetX());\r\n this.updateOffsetY(this.offsetY());\r\n }\r\n}\r\n","<div\r\n [ngClass]=\"[\r\n 'ng-modal',\r\n 'ng-modal-theme' + (this.theme() === 'dark' ? '-dark' : '')\r\n ]\"\r\n [hidden]=\"loading()\"\r\n [ngStyle]=\"position()\"\r\n [style.width.px]=\"width()\"\r\n [style.height.px]=\"height()\"\r\n [style.cursor]=\"cursorStyle()\"\r\n [style.z-index]=\"zIndex()\"\r\n [style.display]=\"display()\"\r\n></div>\r\n<div\r\n [class]=\"'ng-modal ng-modal-theme' + (this.theme() === 'dark' ? '-dark' : '')\"\r\n [hidden]=\"loading()\"\r\n [ngClass]=\"{\r\n selected: selectedSignal(),\r\n minimized: minimized(),\r\n maximized: maximized()\r\n }\"\r\n [ngStyle]=\"position()\"\r\n [style.width.px]=\"width()\"\r\n [style.height.px]=\"height()\"\r\n [style.cursor]=\"cursorStyle()\"\r\n [style.z-index]=\"zIndex()\"\r\n [style.display]=\"display()\"\r\n (mouseenter)=\"windowMouseEnter($event)\"\r\n (mousedown)=\"windowMouseDown($event)\"\r\n (mouseleave)=\"windowMouseLeave($event)\"\r\n>\r\n <div\r\n #titleBar\r\n class=\"win-title-bar\"\r\n *ngIf=\"!!title()\"\r\n (dblclick)=\"maximize()\"\r\n [ngClass]=\"{ 'no-drag': !draggable() }\"\r\n (mousedown)=\"titleBarMouseDown($event)\"\r\n >\r\n <div class=\"title-name\" [title]=\"title()\">\r\n <ng-container *stringTemplateOutlet=\"icon()\">\r\n @if (icon()) {\r\n <img class=\"icon\" draggable=\"false\" [src]=\"icon()\" alt=\"icon\" />\r\n }\r\n </ng-container>\r\n <ng-container *stringTemplateOutlet=\"title()\">{{ title() }}</ng-container>\r\n </div>\r\n <div class=\"win-icons\">\r\n <close-icon\r\n class=\"win-icon\"\r\n [title]=\"getLocaleText('close')\"\r\n (click)=\"close()\"\r\n />\r\n <minimize-icon\r\n class=\"win-icon\"\r\n [title]=\"getLocaleText('minimize')\"\r\n (click)=\"minimize()\"\r\n />\r\n <maximize-icon\r\n class=\"win-icon\"\r\n [title]=\"getLocaleText('maximize')\"\r\n *ngIf=\"!maximized()\"\r\n (click)=\"maximize()\"\r\n />\r\n <maximized-icon\r\n class=\"win-icon\"\r\n [title]=\"getLocaleText('windowMode')\"\r\n *ngIf=\"maximized()\"\r\n (click)=\"maximize()\"\r\n />\r\n </div>\r\n </div>\r\n <div\r\n class=\"body\"\r\n [ngClass]=\"contentScrollable() ? 'no-scroll' : ''\"\r\n [ngStyle]=\"bodyStyle()\"\r\n >\r\n <ng-container *stringTemplateOutlet=\"content\">{{ content() }}</ng-container>\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n\r\n<ng-container *stringTemplateOutlet=\"loadingTip()\">\r\n <div\r\n [class]=\"'window-loading' + (this.theme() === 'dark' ? '-dark' : '')\"\r\n [ngStyle]=\"position()\"\r\n *ngIf=\"loading()\"\r\n >\r\n <div>\r\n <loading-icon />\r\n </div>\r\n <ng-container *stringTemplateOutlet=\"loadingTip()\">{{\r\n loadingTip()\r\n }}</ng-container>\r\n </div>\r\n</ng-container>\r\n","import { Component, computed, signal } from '@angular/core';\r\nimport { Ng2MultiModalComponent } from \"../../ng2-multi-modal.component\";\r\nimport { Ng2MultiModalService } from \"../../ng2-multi-modal.service\";\r\nimport { animate, style, transition, trigger } from \"@angular/animations\";\r\nimport { CommonModule } from \"@angular/common\";\r\nimport { CloseIcon } from \"../icon/close.icon\";\r\nimport { StringTemplateOutletDirective } from \"../../directive/string-template-outlet.directive\";\r\n\r\n@Component({\r\n selector: 'dock',\r\n imports: [CommonModule, CloseIcon, StringTemplateOutletDirective],\r\n template: `\r\n <div [ngClass]=\"['ng-modal-dock', 'ng-modal-theme' + themeSuffix()]\">\r\n @for (dock of docks(); track dock) {\r\n <ng-container>\r\n <div class=\"ng-modal-dock-item\"\r\n [@dockAnimation]\r\n (click)=\"restore(dock)\"\r\n [title]=\"dock.title()\">\r\n <ng-container *stringTemplateOutlet=\"dock.icon()\">\r\n @if (dock.icon()) {\r\n <img class=\"icon\" draggable=\"false\" [src]=\"dock.icon()\" alt=\"icon\"/>\r\n }\r\n </ng-container>\r\n <ng-container *stringTemplateOutlet=\"dock.title()\">{{ dock.title() }}</ng-container>\r\n <close-icon (click)=\"$event.stopPropagation(); close(dock)\"/>\r\n </div>\r\n </ng-container>\r\n }\r\n </div>\r\n `,\r\n animations: [\r\n trigger('dockAnimation', [\r\n transition(':enter', [\r\n style({\r\n opacity: 0,\r\n transform: 'translateY(10px) scale(0.9)',\r\n filter: 'blur(2px)'\r\n }),\r\n animate('350ms cubic-bezier(0.05, 0.7, 0.1, 1.0)',\r\n style({\r\n opacity: 1,\r\n transform: 'translateY(0) scale(1)',\r\n filter: 'blur(0)'\r\n })\r\n )\r\n ]),\r\n transition(':leave', [\r\n style({\r\n opacity: 1,\r\n transform: 'translateY(0) scale(1)',\r\n filter: 'blur(0)'\r\n }),\r\n animate('280ms cubic-bezier(0.3, 0.0, 0.8, 0.15)',\r\n style({\r\n opacity: 0,\r\n transform: 'translateY(10px) scale(0.9)',\r\n filter: 'blur(2px)'\r\n })\r\n )\r\n ])\r\n ])\r\n ],\r\n standalone: true\r\n})\r\nexport class DockComponent {\r\n constructor(private windowService: Ng2MultiModalService) { }\r\n\r\n readonly docks = signal<Ng2MultiModalComponent[]>([]);\r\n\r\n readonly themeSuffix = computed(() =>\r\n (this.windowService.dockTheme() === 'dark' ? '-dark' : '')\r\n );\r\n\r\n restore(win: Ng2MultiModalComponent) {\r\n this.docks.update(prev => prev.filter(dock => dock !== win));\r\n win.minimize();\r\n this.windowService.selectedWindow.set(win.modalId());\r\n const zIdx = this.windowService.maxZIndex++;\r\n win.zIndex.set(zIdx);\r\n }\r\n\r\n close(win: Ng2MultiModalComponent) {\r\n this.docks.update(prev => prev.filter(dock => dock !== win));\r\n win.close();\r\n }\r\n}\r\n","import {\r\n ApplicationRef,\r\n ComponentRef,\r\n createComponent,\r\n EnvironmentInjector,\r\n Injectable,\r\n Injector,\r\n InputSignal,\r\n ModelSignal,\r\n signal,\r\n TemplateRef,\r\n WritableSignal,\r\n} from '@angular/core';\r\nimport { NavigationStart, Router } from '@angular/router';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\nimport { Ng2MultiModalComponent } from \"./ng2-multi-modal.component\";\r\nimport { DockComponent } from \"./components/dock/dock.component\";\r\n\r\nexport interface ModalConfig {\r\n content: TemplateRef<any>;\r\n title?: InputSignal<string | TemplateRef<any>>;\r\n icon?: InputSignal<string | TemplateRef<any> | null>;\r\n align?: InputSignal<\"leftTop\" | \"rightTop\" | \"leftBottom\" | \"rightBottom\">;\r\n bodyStyle?: InputSignal<{\r\n [key: string]: any;\r\n }>;\r\n closeOnNavigation?: InputSignal<boolean>;\r\n closable?: InputSignal<boolean>;\r\n minHeight?: InputSignal<number>;\r\n minWidth?: InputSignal<number>;\r\n maximizable?: InputSignal<boolean>;\r\n minimizable?: InputSignal<boolean>;\r\n resizable?: InputSignal<boolean>;\r\n outOfBounds?: InputSignal<boolean>;\r\n loadingTip?: InputSignal<string | TemplateRef<any>>;\r\n height?: ModelSignal<number>;\r\n width?: ModelSignal<number>;\r\n zIndex?: ModelSignal<number>;\r\n offsetY?: ModelSignal<number>;\r\n offsetX?: ModelSignal<number>;\r\n loading?: ModelSignal<boolean>;\r\n theme?: ModelSignal<\"light\" | \"dark\">;\r\n draggable?: ModelSignal<boolean>;\r\n contentScrollable?: ModelSignal<boolean>;\r\n minimized?: ModelSignal<boolean>;\r\n maximized?: ModelSignal<boolean>;\r\n}\r\n@Injectable({ providedIn: 'root' })\r\nexport class Ng2MultiModalService {\r\n private unsubscribe$ = new Subject<void>();\r\n\r\n constructor(\r\n private _appRef: ApplicationRef,\r\n private _injector: Injector,\r\n private _environmentInjector: EnvironmentInjector,\r\n private router: Router\r\n ) {\r\n router.events.pipe(takeUntil(this.unsubscribe$)).subscribe((evt) => {\r\n if (evt instanceof NavigationStart) {\r\n this.instances.forEach(item => {\r\n if (item.instance.closeOnNavigation()) {\r\n item.instance.close();\r\n }\r\n });\r\n }\r\n });\r\n }\r\n\r\n readonly dockTheme = signal<'light' | 'dark'>('light');\r\n readonly language = signal<'es' | 'en'>('en');\r\n\r\n maxZIndex: number = 0;\r\n instances: ComponentRef<Ng2MultiModalComponent>[] = [];\r\n selectedWindow: WritableSignal<string | null> = signal(null);\r\n dockComponentRef: ComponentRef<DockComponent> | null = null;\r\n\r\n destroy(modalId: string) {\r\n const componentRef = this.instances.find(item => item.instance.modalId() === modalId);\r\n if (componentRef) {\r\n this.detachView(componentRef);\r\n componentRef.destroy();\r\n this.instances = this.instances.filter(item => item.instance.modalId() !== modalId);\r\n this.selectedWindow.set(null)\r\n }\r\n if (this.instances.length === 0) {\r\n this.destroyDock();\r\n this.destroyWrapper();\r\n }\r\n }\r\n\r\n addMinimizeItem(windowComponent: Ng2MultiModalComponent) {\r\n this.dockComponentRef!.instance.docks.update(prev => [...prev, windowComponent]);\r\n }\r\n\r\n createDock() {\r\n if (!this.dockComponentRef) {\r\n this.dockComponentRef = createComponent(DockComponent, {\r\n environmentInjector: this._environmentInjector,\r\n elementInjector: this._injector\r\n });\r\n this._appRef.attachView(this.dockComponentRef.hostView);\r\n document.body.prepend(this.dockComponentRef.location.nativeElement);\r\n }\r\n }\r\n\r\n destroyDock() {\r\n if (this.dockComponentRef) {\r\n this._appRef.detachView(this.dockComponentRef.hostView);\r\n this.dockComponentRef.destroy();\r\n this.dockComponentRef = null;\r\n }\r\n }\r\n\r\n createWrapper() {\r\n if (!document.querySelector('#ng-modal-wrapper')) {\r\n const wrapper = document.createElement('div');\r\n wrapper.id = 'ng-modal-wrapper';\r\n document.body.prepend(wrapper);\r\n }\r\n }\r\n\r\n destroyWrapper() {\r\n const wrapper = document.querySelector('#ng-modal-wrapper');\r\n if (wrapper) {\r\n document.body.removeChild(wrapper);\r\n }\r\n }\r\n\r\n create(options: ModalConfig): Promise<Ng2MultiModalComponent> {\r\n this.createDock();\r\n this.createWrapper();\r\n return new Promise(resolve => {\r\n const componentRef = createComponent(Ng2MultiModalComponent, {\r\n environmentInjector: this._environmentInjector,\r\n elementInjector: this._injector\r\n });\r\n\r\n // Position adjustment for viewport bounds\r\n if (options.offsetX && options.width && options.offsetX() + options.width() > window.innerWidth) {\r\n options.offsetX.set(window.innerWidth - options.width() - 10);\r\n }\r\n if (options.offsetY && options.height && options.offsetY() + options.height() > window.innerHeight) {\r\n options.offsetY.set(window.innerHeight - options.height() - 30);\r\n }\r\n\r\n // Apply options to component\r\n for (const [key, value] of Object.entries(options) as [keyof ModalConfig, any][]) {\r\n if (key in componentRef.instance) {\r\n (componentRef.instance as any)[key] = value;\r\n }\r\n }\r\n\r\n // Always increment maxZIndex to ensure this window is on top\r\n this.maxZIndex += 1;\r\n componentRef.instance.zIndex.set(this.maxZIndex);\r\n\r\n this._appRef.attachView(componentRef.hostView);\r\n this._appendToPage(componentRef.location.nativeElement, document.querySelector('#ng-modal-wrapper') as HTMLElement);\r\n\r\n // Add to instances array\r\n this.instances = [...this.instances, componentRef];\r\n\r\n // Set as selected window AFTER adding it to instances\r\n this.selectedWindow.set(componentRef.instance.modalId());\r\n componentRef.changeDetectorRef.detectChanges();\r\n\r\n componentRef.instance.onClose.subscribe((modalId: string) => {\r\n this.dockComponentRef!.instance.docks.update(prev =>\r\n prev.filter(win => win !== componentRef.instance)\r\n );\r\n this.destroy(modalId);\r\n if (this.selectedWindow() === modalId) {\r\n this.selectedWindow.set(null);\r\n }\r\n });\r\n\r\n resolve(componentRef.instance);\r\n });\r\n }\r\n\r\n detachView(componentRef: ComponentRef<any>) {\r\n this._appRef.detachView(componentRef.hostView);\r\n }\r\n\r\n private _appendToPage(innerElement: HTMLElement, outerElement?: HTMLElement) {\r\n if (outerElement) {\r\n outerElement.appendChild(innerElement);\r\n return;\r\n }\r\n document.body.appendChild(innerElement);\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ng2-multi-modal\r\n */\r\n\r\nexport * from './lib/ng2-multi-modal.service';\r\nexport * from './lib/ng2-multi-modal.component';\r\nexport * from './lib/components/icon/close.icon';\r\nexport * from './lib/components/icon/maximize.icon';\r\nexport * from './lib/components/icon/minimize.icon';\r\nexport * from './lib/components/icon/loading.icon';\r\nexport * from './lib/components/icon/maximized.icon';\r\nexport * from './lib/components/dock/dock.component';\r\nexport * from './lib/directive/string-template-outlet.directive';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.Ng2MultiModalService"],"mappings":";;;;;;;;;;MAea,WAAW,CAAA;AACpB,IAAA,WAAA,GAAA;;uGADS,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAXV,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA;;;;;;;AAOT,IAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAIQ,WAAW,EAAA,UAAA,EAAA,CAAA;kBAbvB,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EACd,QAAA,EAAA,CAAA;;;;;;;AAOT,IAAA,CAAA,EAAA,UAAA,EAEW,IAAI,EAAA;;;MCQP,SAAS,CAAA;AAClB,IAAA,WAAA,GAAA;;uGADS,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,EAjBR,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA;;;;;;;;;;;;;AAaT,IAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAIQ,SAAS,EAAA,UAAA,EAAA,CAAA;kBAnBrB,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,EACZ,QAAA,EAAA,CAAA;;;;;;;;;;;;;AAaT,IAAA,CAAA,EAAA,UAAA,EAEW,IAAI,EAAA;;;MCuBP,YAAY,CAAA;AACvB,IAAA,WAAA,GAAA;uGADW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,EAtCb,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAIU,YAAY,EAAA,UAAA,EAAA,CAAA;kBAxCxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,eAAe,EACf,QAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,EAAA,CAAA,EAAA,UAAA,EAEW,IAAI,EAAA;;;MCnBL,YAAY,CAAA;AACvB,IAAA,WAAA,GAAA;uGADW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,EAjBb,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA;;;;;;;;;;;;;AAaT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAIU,YAAY,EAAA,UAAA,EAAA,CAAA;kBAnBxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,eAAe,EACf,QAAA,EAAA,CAAA;;;;;;;;;;;;;AAaT,EAAA,CAAA,EAAA,UAAA,EAEW,IAAI,EAAA;;;MCuBL,aAAa,CAAA;AACxB,IAAA,WAAA,GAAA;uGADW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,EAtCd,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAIU,aAAa,EAAA,UAAA,EAAA,CAAA;kBAxCzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,EAChB,QAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,EAAA,CAAA,EAAA,UAAA,EAEW,IAAI,EAAA;;;MCzBL,6BAA6B,CAAA;AAepB,IAAA,aAAA;AAAyC,IAAA,WAAA;IAdrD,eAAe,GAAgC,IAAI;AACnD,IAAA,OAAO,GAAG,IAAI,2BAA2B,EAAE;;AAG1C,IAAA,2BAA2B,GAAG,KAAK,CAAa,IAAI,CAAC;AACrD,IAAA,oBAAoB,GAAG,KAAK,CAAyB,IAAI,CAAC;AAEnE,IAAA,OAAO,sBAAsB,CAC3B,IAAsC,EACtC,IAAS,EAAA;AAET,QAAA,OAAO,IAAI;;IAGb,WAAoB,CAAA,aAA+B,EAAU,WAA6B,EAAA;QAAtE,IAAa,CAAA,aAAA,GAAb,aAAa;QAA4B,IAAW,CAAA,WAAA,GAAX,WAAW;;QAEtE,MAAM,CAAC,MAAK;;AAEV,YAAA,MAAM,MAAM,GAAG,IAAI,CA