@tekus/design-system 5.24.0 → 5.25.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/fesm2022/tekus-design-system-components-date-picker.mjs +50 -20
- package/fesm2022/tekus-design-system-components-date-picker.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-drawer.mjs +40 -24
- package/fesm2022/tekus-design-system-components-drawer.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-modal.mjs +37 -23
- package/fesm2022/tekus-design-system-components-modal.mjs.map +1 -1
- package/fesm2022/tekus-design-system-core-types.mjs +71 -2
- package/fesm2022/tekus-design-system-core-types.mjs.map +1 -1
- package/fesm2022/tekus-design-system-core.mjs +71 -2
- package/fesm2022/tekus-design-system-core.mjs.map +1 -1
- package/package.json +2 -2
- package/types/tekus-design-system-components-date-picker.d.ts +24 -6
- package/types/tekus-design-system-components-drawer.d.ts +12 -7
- package/types/tekus-design-system-components-modal.d.ts +12 -10
- package/types/tekus-design-system-core-types.d.ts +45 -1
- package/types/tekus-design-system-core.d.ts +45 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tekus-design-system-components-drawer.mjs","sources":["../../../projects/design-system/components/drawer/src/drawer.component.ts","../../../projects/design-system/components/drawer/src/drawer.component.html","../../../projects/design-system/components/drawer/src/services/drawer.service.ts","../../../projects/design-system/components/drawer/tekus-design-system-components-drawer.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, model, output, Type, ElementRef, ViewContainerRef, viewChild, ComponentRef, effect, untracked, OnDestroy, afterEveryRender, inject } from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DrawerModule } from 'primeng/drawer';\nimport { DrawerHeaderAction, DrawerSizeType } from './drawer.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n} from '@tekus/design-system/core/types';\n\n/**\n * @component DrawerComponent\n * @description\n * A programmatically controlled drawer overlay used for displaying dynamic content,\n * titles, and header actions. The drawer is opened through a service with a configuration object,\n * similar to tk-modal.\n *\n * This component supports:\n * - Required title with ellipsis for long text.\n * - Optional header action button + close button.\n * - Content as string or component.\n * - Position: always right.\n * - Sizes: small (500px), large (1024px).\n * - Closable and dismissible mask behavior.\n *\n * @usage\n * ### Open a drawer from TypeScript using the drawer service\n * ```ts\n * this.drawerService.open({\n * title: 'Drawer name',\n * content: 'Content text drawer example',\n * headerAction: {\n * label: 'Action',\n * severity: 'primary',\n * action: () => console.log('Action clicked'),\n * returnValue: true,\n * },\n * size: 'small',\n * }).subscribe((result) => {\n * console.log('Drawer closed with value:', result);\n * });\n * ```\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-drawer',\n imports: [DrawerModule, ButtonComponent],\n templateUrl: './drawer.component.html',\n styleUrl: './drawer.component.scss',\n})\nexport class DrawerComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The required title displayed at the top left of the drawer header */\n title = input.required<string>();\n\n /** The main content of the drawer. Can be a string or a Component Type. */\n content = input<string | Type<T> | null>(null);\n\n /** Optional header action button (displayed before close button) */\n headerAction = input<DrawerHeaderAction | null>(null);\n\n /** Drawer size: 'small' (500px), 'large' (1024px) */\n size = input<DrawerSizeType>('small');\n\n /** Whether the drawer can be closed by the user via close button */\n closable = input<boolean>(true);\n\n /** Whether clicking the mask closes the drawer */\n dismissible = input<boolean>(true);\n\n /** Optional data to be passed as inputs to the dynamic component. */\n data = input<Partial<T>>({});\n\n /** Optional interceptor called before the drawer closes. */\n interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n isContentString = computed(() => typeof this.content() === 'string');\n hasHeaderAction = computed(() => this.headerAction() != null);\n\n /** Computed: drawer width (responsive) and max-width based on `size`. Always right position. */\n drawerStyle = computed(() => {\n const sz = this.size();\n const maxWidth = sz === 'large' ? '1024px' : '500px';\n return {\n width: 'calc(100vw - 1rem)',\n maxWidth,\n };\n });\n\n /** Visibility flag. Use model for two-way binding when using drawer in template. */\n isOpened = model<boolean>(false);\n\n /** Whether the drawer content has a scrollbar */\n hasScroll = false;\n\n /** Emits when the drawer closes, passing the return value from header action or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n */\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n\n afterEveryRender(() => {\n this.checkScroll();\n });\n }\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) return;\n this.detachDynamicContent();\n this.componentRef = host.createComponent(type);\n this.syncDynamicInputs(this.data());\n }\n\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) return;\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the drawer content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-drawer-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n /** Opens the drawer */\n open(): void {\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /**\n * @summary Main entry point for closure requests.\n * @returns true if closure was executed.\n */\n tryClose(returnValue: unknown = null): boolean {\n if (this.canExecuteClosure()) {\n this.executeClosure(returnValue, arguments.length > 0);\n return true;\n } else {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n instance?.onBlockedClose?.();\n return false;\n }\n }\n\n private canExecuteClosure(): boolean {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canClose = instance?.canClose ? instance.canClose() : true;\n if (!canClose) return false;\n\n const configInterceptor = this.interceptor();\n if (configInterceptor && !configInterceptor()) return false;\n\n return true;\n }\n\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n }\n\n /** Handles external visibility changes (from p-drawer close button or mask) */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n const closed = this.tryClose();\n\n if (!closed) {\n this.isOpened.set(true);\n }\n }\n }\n\n /** Closes the drawer and emits onClose */\n handleClose(): void {\n if (this.isOpened()) {\n return;\n }\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n }\n\n /** Forcefully closes the drawer without checks */\n close(): void {\n this.tryClose();\n }\n\n /**\n * Handles header action button click.\n */\n handleHeaderAction(\n action: (() => void) | undefined,\n returnValue: unknown\n ): void {\n if (action) action();\n this.tryClose(returnValue);\n }\n\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-drawer\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissible]=\"dismissible()\"\n [closeOnEscape]=\"true\"\n position=\"right\"\n [style]=\"drawerStyle()\"\n [styleClass]=\"'tk-drawer'\"\n [class.tk-drawer--has-scroll]=\"hasScroll\"\n (onHide)=\"handleClose()\">\n <ng-template pTemplate=\"header\">\n <div class=\"tk-drawer__header\">\n <h2 class=\"tk-drawer__title\" [title]=\"title()\">{{ title() }}</h2>\n @if (hasHeaderAction()) {\n <div class=\"tk-drawer__actions\">\n <tk-button\n [label]=\"headerAction()!.label\"\n [severity]=\"headerAction()!.severity\"\n [variant]=\"headerAction()!.variant\"\n (clicked)=\"\n handleHeaderAction(\n headerAction()!.action,\n headerAction()!.returnValue\n )\n \" />\n </div>\n }\n </div>\n </ng-template>\n\n <section class=\"tk-drawer__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n</p-drawer>\n","import { Injectable, ApplicationRef, ComponentRef, createComponent, EmbeddedViewRef, inject } from '@angular/core';\nimport { DrawerComponent } from '../drawer.component';\nimport { Observable, Subject } from 'rxjs';\nimport { DrawerConfig } from '../drawer.types';\n\n@Injectable({ providedIn: 'root' })\nexport class DrawerService {\n private readonly appRef = inject(ApplicationRef);\n\n private drawerRef: ComponentRef<DrawerComponent<unknown>> | null = null;\n\n get _drawerRefForTesting(): ComponentRef<DrawerComponent<unknown>> | null {\n return this.drawerRef;\n }\n set _drawerRefForTesting(ref: ComponentRef<DrawerComponent<unknown>> | null) {\n this.drawerRef = ref;\n }\n\n open(config: DrawerConfig): Observable<unknown> {\n if (this.drawerRef) {\n this.drawerRef.instance.close();\n this.appRef.detachView(this.drawerRef.hostView);\n this.drawerRef.destroy();\n this.drawerRef = null;\n }\n\n const componentRef = createComponent(DrawerComponent, {\n environmentInjector: this.appRef.injector,\n });\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>)\n .rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content ?? null);\n componentRef.setInput('headerAction', config.headerAction ?? null);\n componentRef.setInput('size', config.size ?? 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('dismissible', config.dismissible ?? true);\n componentRef.setInput('data', config.data ?? {});\n componentRef.setInput('interceptor', config.interceptor ?? undefined);\n\n const close$ = new Subject<unknown>();\n\n componentRef.instance.closed.subscribe(value => {\n close$.next(value);\n close$.complete();\n\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n if (this.drawerRef === (componentRef as unknown)) {\n this.drawerRef = null;\n }\n });\n\n componentRef.instance.open();\n this.drawerRef = componentRef as unknown as ComponentRef<\n DrawerComponent<unknown>\n >;\n\n return close$.asObservable();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MAQU,eAAe,CAAA;AAwD1B,IAAA,WAAA,GAAA;AAvDiB,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QAE/B,IAAA,CAAA,WAAW,GAAG,SAAS,CAAC,aAAa,mFACpD,IAAI,EAAE,gBAAgB,EAAA,CACtB;;AAIF,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,2EAAU;;AAGhC,QAAA,IAAA,CAAA,OAAO,GAAG,KAAK,CAA0B,IAAI,8EAAC;;AAG9C,QAAA,IAAA,CAAA,YAAY,GAAG,KAAK,CAA4B,IAAI,mFAAC;;AAGrD,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAiB,OAAO,2EAAC;;AAGrC,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAU,IAAI,+EAAC;;AAG/B,QAAA,IAAA,CAAA,WAAW,GAAG,KAAK,CAAU,IAAI,kFAAC;;AAGlC,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAa,EAAE,2EAAC;;AAG5B,QAAA,IAAA,CAAA,WAAW,GAAG,KAAK,CAAiC,SAAS,kFAAC;AAE9D,QAAA,IAAA,CAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,QAAQ,sFAAC;AACpE,QAAA,IAAA,CAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,sFAAC;;AAG7D,QAAA,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AAC1B,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;AACtB,YAAA,MAAM,QAAQ,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,GAAG,OAAO;YACpD,OAAO;AACL,gBAAA,KAAK,EAAE,oBAAoB;gBAC3B,QAAQ;aACT;AACH,QAAA,CAAC,kFAAC;;AAGF,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC;;QAGhC,IAAA,CAAA,SAAS,GAAG,KAAK;;QAGR,IAAA,CAAA,MAAM,GAAG,MAAM,EAAW;QAC3B,IAAA,CAAA,cAAc,GAAG,KAAK;QACtB,IAAA,CAAA,kBAAkB,GAAY,IAAI;AAGxC;;AAEG;QACH,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC9B,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;YAE/B,SAAS,CAAC,MAAK;AACb,gBAAA,IAAI,MAAM,IAAI,IAAI,EAAE;oBAClB,IAAI,CAAC,oBAAoB,EAAE;gBAC7B;qBAAO,IAAI,CAAC,MAAM,EAAE;oBAClB,IAAI,CAAC,oBAAoB,EAAE;gBAC7B;AACF,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE;YAC/B,SAAS,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACtD,QAAA,CAAC,CAAC;QAEF,gBAAgB,CAAC,MAAK;YACpB,IAAI,CAAC,WAAW,EAAE;AACpB,QAAA,CAAC,CAAC;IACJ;IAEA,WAAW,GAAA;QACT,IAAI,CAAC,oBAAoB,EAAE;IAC7B;IAEQ,oBAAoB,GAAA;AAC1B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE;AAC3B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;QAE/B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI;YAAE;QAChD,IAAI,CAAC,oBAAoB,EAAE;QAC3B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;QAC9C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrC;AAEQ,IAAA,iBAAiB,CAAC,IAAgB,EAAA;QACxC,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE;AACxB,QAAA,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;YAC5C,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC;AACzC,QAAA,CAAC,CAAC;IACJ;IAEQ,oBAAoB,GAAA;AAC1B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;AAC3B,YAAA,IAAI,CAAC,YAAY,GAAG,SAAS;QAC/B;IACF;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,MAAM,SAAS,GACb,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,mBAAmB,CAAC;QAClE,IAAI,SAAS,EAAE;YACb,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY;QAClE;IACF;;IAGA,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,iBAAiB,EAAE;IAC1B;AAEA;;;AAGG;IACH,QAAQ,CAAC,cAAuB,IAAI,EAAA;AAClC,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC5B,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;AACtD,YAAA,OAAO,IAAI;QACb;aAAO;AACL,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,QAAkC;AACtE,YAAA,QAAQ,EAAE,cAAc,IAAI;AAC5B,YAAA,OAAO,KAAK;QACd;IACF;IAEQ,iBAAiB,GAAA;AACvB,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,QAAkC;AACtE,QAAA,MAAM,QAAQ,GAAG,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,IAAI;AAChE,QAAA,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,KAAK;AAE3B,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE;AAC5C,QAAA,IAAI,iBAAiB,IAAI,CAAC,iBAAiB,EAAE;AAAE,YAAA,OAAO,KAAK;AAE3D,QAAA,OAAO,IAAI;IACb;IAEQ,cAAc,CAAC,WAAoB,EAAE,cAAuB,EAAA;QAClE,IAAI,cAAc,EAAE;AAClB,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAC1B,YAAA,IAAI,CAAC,kBAAkB,GAAG,WAAW;QACvC;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAC1B;;AAGA,IAAA,eAAe,CAAC,OAAgB,EAAA;QAC9B,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE;YAE9B,IAAI,CAAC,MAAM,EAAE;AACX,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YACzB;QACF;IACF;;IAGA,WAAW,GAAA;AACT,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;AACA,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI;AACxE,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;QAC7B,IAAI,CAAC,iBAAiB,EAAE;IAC1B;;IAGA,KAAK,GAAA;QACH,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;AAEG;IACH,kBAAkB,CAChB,MAAgC,EAChC,WAAoB,EAAA;AAEpB,QAAA,IAAI,MAAM;AAAE,YAAA,MAAM,EAAE;AACpB,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC5B;IAEQ,iBAAiB,GAAA;AACvB,QAAA,IAAI,CAAC,cAAc,GAAG,KAAK;AAC3B,QAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI;IAChC;8GA1MW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAf,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,q2CAIlB,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECtD1B,wuCA0CA,EAAA,MAAA,EAAA,CAAA,+vCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDIY,YAAY,0hBAAE,eAAe,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,UAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;2FAI5B,eAAe,EAAA,UAAA,EAAA,CAAA;kBAP3B,SAAS;sCACS,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,WAAW,WACZ,CAAC,YAAY,EAAE,eAAe,CAAC,EAAA,QAAA,EAAA,wuCAAA,EAAA,MAAA,EAAA,CAAA,+vCAAA,CAAA,EAAA;AAOC,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,CAAA,aAAa,EAAA,EAAA,GAAE;AACtD,4BAAA,IAAI,EAAE,gBAAgB;AACvB,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,cAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;MEjDU,aAAa,CAAA;AAD1B,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;QAExC,IAAA,CAAA,SAAS,GAAkD,IAAI;AAwDxE,IAAA;AAtDC,IAAA,IAAI,oBAAoB,GAAA;QACtB,OAAO,IAAI,CAAC,SAAS;IACvB;IACA,IAAI,oBAAoB,CAAC,GAAkD,EAAA;AACzE,QAAA,IAAI,CAAC,SAAS,GAAG,GAAG;IACtB;AAEA,IAAA,IAAI,CAAC,MAAoB,EAAA;AACvB,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC/B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;AAC/C,YAAA,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;AACxB,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACvB;AAEA,QAAA,MAAM,YAAY,GAAG,eAAe,CAAC,eAAe,EAAE;AACpD,YAAA,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC1C,SAAA,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;AAE7C,QAAA,MAAM,OAAO,GAAI,YAAY,CAAC;aAC3B,SAAS,CAAC,CAAC,CAAgB;AAC9B,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;QAElC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;QAC5C,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;QACxD,YAAY,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;QAClE,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC;QACrD,YAAY,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC;QAC1D,YAAY,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC;QAChE,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QAChD,YAAY,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,IAAI,SAAS,CAAC;AAErE,QAAA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAW;QAErC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,IAAG;AAC7C,YAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YAClB,MAAM,CAAC,QAAQ,EAAE;YAEjB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;YAC7C,YAAY,CAAC,OAAO,EAAE;AACtB,YAAA,IAAI,IAAI,CAAC,SAAS,KAAM,YAAwB,EAAE;AAChD,gBAAA,IAAI,CAAC,SAAS,GAAG,IAAI;YACvB;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC5B,QAAA,IAAI,CAAC,SAAS,GAAG,YAEhB;AAED,QAAA,OAAO,MAAM,CAAC,YAAY,EAAE;IAC9B;8GA1DW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAb,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,aAAa,cADA,MAAM,EAAA,CAAA,CAAA;;2FACnB,aAAa,EAAA,UAAA,EAAA,CAAA;kBADzB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACLlC;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"tekus-design-system-components-drawer.mjs","sources":["../../../projects/design-system/components/drawer/src/drawer.component.ts","../../../projects/design-system/components/drawer/src/drawer.component.html","../../../projects/design-system/components/drawer/src/services/drawer.service.ts","../../../projects/design-system/components/drawer/tekus-design-system-components-drawer.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n model,\n output,\n Type,\n ElementRef,\n ViewContainerRef,\n viewChild,\n ComponentRef,\n effect,\n untracked,\n OnDestroy,\n afterEveryRender,\n inject,\n Injector,\n} from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DrawerModule } from 'primeng/drawer';\nimport { DrawerHeaderAction, DrawerSizeType } from './drawer.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n TkDialogRef,\n} from '@tekus/design-system/core/types';\n\n/**\n * @component DrawerComponent\n * @description\n * A programmatically controlled drawer overlay used for displaying dynamic content,\n * titles, and header actions. The drawer is opened through a service with a configuration object,\n * similar to tk-modal.\n *\n * This component supports:\n * - Required title with ellipsis for long text.\n * - Optional header action button + close button.\n * - Content as string or component.\n * - Position: always right.\n * - Sizes: small (500px), large (1024px).\n * - Closable and dismissible mask behavior.\n *\n * @usage\n * ### Open a drawer from TypeScript using the drawer service\n * ```ts\n * this.drawerService.open({\n * title: 'Drawer name',\n * content: 'Content text drawer example',\n * headerAction: {\n * label: 'Action',\n * severity: 'primary',\n * action: () => console.log('Action clicked'),\n * returnValue: true,\n * },\n * size: 'small',\n * }).subscribe((result) => {\n * console.log('Drawer closed with value:', result);\n * });\n * ```\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-drawer',\n imports: [DrawerModule, ButtonComponent],\n templateUrl: './drawer.component.html',\n styleUrl: './drawer.component.scss',\n})\nexport class DrawerComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n private readonly injector = inject(Injector);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The dialog ref associated with this drawer */\n dialogRef = input<TkDialogRef<DrawerComponent<T>, unknown> | null>(null);\n\n /** The required title displayed at the top left of the drawer header */\n title = input.required<string>();\n\n /** The main content of the drawer. Can be a string or a Component Type. */\n content = input<string | Type<T> | null>(null);\n\n /** Optional header action button (displayed before close button) */\n headerAction = input<DrawerHeaderAction | null>(null);\n\n /** Drawer size: 'small' (500px), 'large' (1024px) */\n size = input<DrawerSizeType>('small');\n\n /** Whether the drawer can be closed by the user via close button */\n closable = input<boolean>(true);\n\n /** Whether clicking the mask closes the drawer */\n dismissible = input<boolean>(true);\n\n /** Optional data to be passed as inputs to the dynamic component. */\n data = input<Partial<T>>({});\n\n /** Optional interceptor called before the drawer closes. */\n interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n isContentString = computed(() => typeof this.content() === 'string');\n hasHeaderAction = computed(() => this.headerAction() != null);\n\n /** Computed: drawer width (responsive) and max-width based on `size`. Always right position. */\n drawerStyle = computed(() => {\n const sz = this.size();\n const maxWidth = sz === 'large' ? '1024px' : '500px';\n return {\n width: 'calc(100vw - 1rem)',\n maxWidth,\n };\n });\n\n /** Visibility flag. Use model for two-way binding when using drawer in template. */\n isOpened = model<boolean>(false);\n\n /** Whether the drawer content has a scrollbar */\n hasScroll = false;\n\n /** Emits when the drawer closes, passing the return value from header action or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n */\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n this.dialogRef();\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n\n afterEveryRender(() => {\n this.checkScroll();\n });\n }\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) return;\n this.detachDynamicContent();\n\n const customInjector = Injector.create({\n providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],\n parent: this.injector,\n });\n\n this.componentRef = host.createComponent(type, {\n injector: customInjector,\n });\n this.syncDynamicInputs(this.data());\n }\n\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) return;\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the drawer content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-drawer-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n private wasOpened = false;\n \n /** Opens the drawer */\n open(): void {\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /** Marks the drawer as shown to enable closure emission guards */\n handleShow(): void {\n this.wasOpened = true;\n }\n\n /**\n * @summary Main entry point for closure requests.\n * @returns true if closure was executed.\n */\n tryClose(returnValue: unknown = null): boolean {\n if (this.canExecuteClosure()) {\n this.executeClosure(returnValue, arguments.length > 0);\n return true;\n } else {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n instance?.onBlockedClose?.();\n return false;\n }\n }\n\n private canExecuteClosure(): boolean {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canClose = instance?.canClose ? instance.canClose() : true;\n if (!canClose) return false;\n\n const configInterceptor = this.interceptor();\n if (configInterceptor && !configInterceptor()) return false;\n\n return true;\n }\n\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n this.handleClose();\n }\n\n /** Handles external visibility changes (from p-drawer close button or mask) */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n const closed = this.tryClose();\n\n if (!closed) {\n this.isOpened.set(true);\n }\n }\n }\n\n /** Closes the drawer and emits onClose */\n handleClose(): void {\n if (this.isOpened()) {\n return;\n }\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n }\n\n /** Forcefully closes the drawer without checks */\n close(): void {\n this.tryClose();\n }\n\n /**\n * Handles header action button click.\n */\n handleHeaderAction(\n action: (() => void) | undefined,\n returnValue: unknown\n ): void {\n if (action) action();\n this.tryClose(returnValue);\n }\n\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-drawer\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissible]=\"dismissible()\"\n [closeOnEscape]=\"true\"\n position=\"right\"\n [style]=\"drawerStyle()\"\n [styleClass]=\"'tk-drawer'\"\n [class.tk-drawer--has-scroll]=\"hasScroll\">\n @if (title() || hasHeaderAction()) {\n <ng-template pTemplate=\"header\">\n <div class=\"tk-drawer__header\">\n <h2 class=\"tk-drawer__title\" [title]=\"title()\">{{ title() }}</h2>\n @if (hasHeaderAction()) {\n <div class=\"tk-drawer__actions\">\n <tk-button\n [label]=\"headerAction()!.label\"\n [severity]=\"headerAction()!.severity\"\n [variant]=\"headerAction()!.variant\"\n (clicked)=\"\n handleHeaderAction(\n headerAction()!.action,\n headerAction()!.returnValue\n )\n \" />\n </div>\n }\n </div>\n </ng-template>\n }\n\n <section class=\"tk-drawer__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n</p-drawer>\n","import {\n Injectable,\n ApplicationRef,\n ComponentRef,\n createComponent,\n EmbeddedViewRef,\n inject,\n} from '@angular/core';\nimport { DrawerComponent } from '../drawer.component';\nimport { DrawerConfig } from '../drawer.types';\nimport { TkDialogRef } from '@tekus/design-system/core/types';\n\n@Injectable({ providedIn: 'root' })\nexport class DrawerService {\n private readonly appRef = inject(ApplicationRef);\n\n private dialogRef: TkDialogRef<DrawerComponent<unknown>> | null = null;\n\n get drawerRefForTesting(): ComponentRef<DrawerComponent<unknown>> | null {\n return (\n (this.dialogRef?.componentRef as ComponentRef<\n DrawerComponent<unknown>\n >) || null\n );\n }\n set drawerRefForTesting(ref: ComponentRef<DrawerComponent<unknown>> | null) {\n this.dialogRef = ref ? new TkDialogRef(ref) : null;\n }\n\n open<T = unknown, R = unknown>(\n config: DrawerConfig\n ): TkDialogRef<DrawerComponent<T>, R> {\n if (this.dialogRef) {\n // Clear the previous one without triggering a real \"null\" result\n this.dialogRef.emitClose();\n this.dialogRef.componentRef.destroy();\n this.dialogRef = null;\n }\n\n const componentRef = createComponent(DrawerComponent, {\n environmentInjector: this.appRef.injector,\n }) as ComponentRef<DrawerComponent<T>>;\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>)\n .rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content ?? null);\n componentRef.setInput('headerAction', config.headerAction ?? null);\n componentRef.setInput('size', config.size ?? 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('dismissible', config.dismissible ?? true);\n componentRef.setInput('data', config.data ?? {});\n componentRef.setInput('interceptor', config.interceptor ?? undefined);\n\n const dialogRef = new TkDialogRef<DrawerComponent<T>, R>(componentRef);\n componentRef.setInput('dialogRef', dialogRef);\n this.dialogRef = dialogRef as unknown as TkDialogRef<\n DrawerComponent<unknown>\n >;\n\n componentRef.instance.closed.subscribe((value: unknown) => {\n dialogRef.emitClose(value as R);\n\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n if (this.dialogRef === (dialogRef as unknown)) {\n this.dialogRef = null;\n }\n });\n\n componentRef.instance.open();\n\n return dialogRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, viewChild, ViewContainerRef, input, computed, model, output, effect, untracked, afterEveryRender, ChangeDetectionStrategy, Component,
|
|
2
|
+
import { inject, ElementRef, Injector, viewChild, ViewContainerRef, input, computed, model, output, effect, untracked, afterEveryRender, ChangeDetectionStrategy, Component, ApplicationRef, createComponent, Injectable } from '@angular/core';
|
|
3
3
|
import { ButtonComponent } from '@tekus/design-system/components/button';
|
|
4
4
|
import * as i1 from 'primeng/dialog';
|
|
5
5
|
import { DialogModule } from 'primeng/dialog';
|
|
6
|
+
import { TkDialogRef } from '@tekus/design-system/core/types';
|
|
6
7
|
import * as i2 from 'primeng/api';
|
|
7
|
-
import { outputToObservable } from '@angular/core/rxjs-interop';
|
|
8
|
-
import { Subject } from 'rxjs';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* @component ModalComponent
|
|
@@ -19,7 +18,10 @@ class ModalComponent {
|
|
|
19
18
|
* @summary Orchestrates the reactive dynamic lifecycle.
|
|
20
19
|
*/
|
|
21
20
|
this.elementRef = inject(ElementRef);
|
|
21
|
+
this.injector = inject(Injector);
|
|
22
22
|
this.contentHost = viewChild('contentHost', { ...(ngDevMode ? { debugName: "contentHost" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
23
|
+
/** The dialog ref associated with this modal */
|
|
24
|
+
this.dialogRef = input(null, ...(ngDevMode ? [{ debugName: "dialogRef" }] : /* istanbul ignore next */ []));
|
|
23
25
|
/** The title displayed at the top of the modal */
|
|
24
26
|
this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
25
27
|
/** The main content of the modal. Can be a string or a Component Type. */
|
|
@@ -69,9 +71,11 @@ class ModalComponent {
|
|
|
69
71
|
return '25rem';
|
|
70
72
|
}
|
|
71
73
|
}, ...(ngDevMode ? [{ debugName: "modalMaxWidth" }] : /* istanbul ignore next */ []));
|
|
74
|
+
this.wasOpened = false;
|
|
72
75
|
effect(() => {
|
|
73
76
|
const opened = this.isOpened();
|
|
74
77
|
const host = this.contentHost();
|
|
78
|
+
this.dialogRef(); // Track it to re-run if it's set later
|
|
75
79
|
untracked(() => {
|
|
76
80
|
if (opened && host) {
|
|
77
81
|
this.attachDynamicContent();
|
|
@@ -102,7 +106,13 @@ class ModalComponent {
|
|
|
102
106
|
if (!type || typeof type === 'string' || !host)
|
|
103
107
|
return;
|
|
104
108
|
this.detachDynamicContent();
|
|
105
|
-
|
|
109
|
+
const customInjector = Injector.create({
|
|
110
|
+
providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],
|
|
111
|
+
parent: this.injector,
|
|
112
|
+
});
|
|
113
|
+
this.componentRef = host.createComponent(type, {
|
|
114
|
+
injector: customInjector,
|
|
115
|
+
});
|
|
106
116
|
this.syncDynamicInputs(this.data());
|
|
107
117
|
}
|
|
108
118
|
/**
|
|
@@ -139,6 +149,7 @@ class ModalComponent {
|
|
|
139
149
|
* Opens the modal dialog.
|
|
140
150
|
*/
|
|
141
151
|
open() {
|
|
152
|
+
this.wasOpened = true;
|
|
142
153
|
this.isOpened.set(true);
|
|
143
154
|
this.resetClosureState();
|
|
144
155
|
}
|
|
@@ -195,9 +206,13 @@ class ModalComponent {
|
|
|
195
206
|
* Handles the close event from the underlying dialog component.
|
|
196
207
|
*/
|
|
197
208
|
handleClose() {
|
|
209
|
+
if (!this.wasOpened || this.isOpened()) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
198
212
|
const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;
|
|
199
213
|
this.closed.emit(valueToEmit);
|
|
200
214
|
this.resetClosureState();
|
|
215
|
+
this.wasOpened = false;
|
|
201
216
|
}
|
|
202
217
|
/**
|
|
203
218
|
* @summary Handles actions triggered by footer buttons.
|
|
@@ -222,14 +237,14 @@ class ModalComponent {
|
|
|
222
237
|
this.returnValueOnClose = null;
|
|
223
238
|
}
|
|
224
239
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
225
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: ModalComponent, isStandalone: true, selector: "tk-modal", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footerButtons: { classPropertyName: "footerButtons", publicName: "footerButtons", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, interceptor: { classPropertyName: "interceptor", publicName: "interceptor", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, isOpened: { classPropertyName: "isOpened", publicName: "isOpened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpened: "isOpenedChange", closed: "closed" }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n
|
|
240
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: ModalComponent, isStandalone: true, selector: "tk-modal", inputs: { dialogRef: { classPropertyName: "dialogRef", publicName: "dialogRef", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footerButtons: { classPropertyName: "footerButtons", publicName: "footerButtons", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, interceptor: { classPropertyName: "interceptor", publicName: "interceptor", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, isOpened: { classPropertyName: "isOpened", publicName: "isOpened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpened: "isOpenedChange", closed: "closed" }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n @if (hasFooter()) {\n <ng-template pTemplate=\"footer\">\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"btn.label\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n (clicked)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue)\" />\n }\n </section>\n </ng-template>\n }\n</p-dialog>\n", styles: [":host ::ng-deep .p-dialog{max-height:90vh;display:flex;flex-direction:column}:host ::ng-deep .p-dialog-content{overflow-y:auto}:host ::ng-deep .p-dialog-title{color:var(--tk-color-text-default, #212121)}:host ::ng-deep .p-dialog-close-button{color:var(--tk-surface-500, #8a8a8b)}:host ::ng-deep .p-dialog-close-button:hover{background:var(--tk-color-base-surface-100, #f0f0f0)!important;color:var(--tk-surface-500, #8a8a8b)}.tk-modal__content{padding-bottom:var(--tk-spacing-paddingY-l, 1.25rem);color:var(--tk-surface-1000, #000000)}.tk-modal__footer{display:flex;flex-direction:row;justify-content:end;align-items:center;gap:var(--tk-spacing-base-50, .5rem)}.tk-modal__footer--with-content{padding-right:var(--tk-spacing-paddingX-l, 1.25rem)}\n"], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "tooltipText"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
226
241
|
}
|
|
227
242
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: ModalComponent, decorators: [{
|
|
228
243
|
type: Component,
|
|
229
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-modal', imports: [DialogModule, ButtonComponent], template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n
|
|
244
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'tk-modal', imports: [DialogModule, ButtonComponent], template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n @if (hasFooter()) {\n <ng-template pTemplate=\"footer\">\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"btn.label\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n (clicked)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue)\" />\n }\n </section>\n </ng-template>\n }\n</p-dialog>\n", styles: [":host ::ng-deep .p-dialog{max-height:90vh;display:flex;flex-direction:column}:host ::ng-deep .p-dialog-content{overflow-y:auto}:host ::ng-deep .p-dialog-title{color:var(--tk-color-text-default, #212121)}:host ::ng-deep .p-dialog-close-button{color:var(--tk-surface-500, #8a8a8b)}:host ::ng-deep .p-dialog-close-button:hover{background:var(--tk-color-base-surface-100, #f0f0f0)!important;color:var(--tk-surface-500, #8a8a8b)}.tk-modal__content{padding-bottom:var(--tk-spacing-paddingY-l, 1.25rem);color:var(--tk-surface-1000, #000000)}.tk-modal__footer{display:flex;flex-direction:row;justify-content:end;align-items:center;gap:var(--tk-spacing-base-50, .5rem)}.tk-modal__footer--with-content{padding-right:var(--tk-spacing-paddingX-l, 1.25rem)}\n"] }]
|
|
230
245
|
}], ctorParameters: () => [], propDecorators: { contentHost: [{ type: i0.ViewChild, args: ['contentHost', { ...{
|
|
231
246
|
read: ViewContainerRef,
|
|
232
|
-
}, isSignal: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footerButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerButtons", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], closeOnOutsideClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsideClick", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], interceptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "interceptor", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], isOpened: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpened", required: false }] }, { type: i0.Output, args: ["isOpenedChange"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
247
|
+
}, isSignal: true }] }], dialogRef: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialogRef", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footerButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerButtons", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], closeOnOutsideClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsideClick", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], interceptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "interceptor", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], isOpened: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpened", required: false }] }, { type: i0.Output, args: ["isOpenedChange"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
233
248
|
|
|
234
249
|
/**
|
|
235
250
|
* @service ModalService
|
|
@@ -239,28 +254,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImpor
|
|
|
239
254
|
*/
|
|
240
255
|
class ModalService {
|
|
241
256
|
constructor() {
|
|
242
|
-
this.injector = inject(Injector);
|
|
243
257
|
this.appRef = inject(ApplicationRef);
|
|
244
|
-
/** Reference to the currently open modal
|
|
245
|
-
this.
|
|
258
|
+
/** Reference to the currently open modal dialog ref */
|
|
259
|
+
this.dialogRef = null;
|
|
246
260
|
}
|
|
247
261
|
/** Internal getter for testing purposes */
|
|
248
|
-
get
|
|
249
|
-
return this.
|
|
262
|
+
get modalRefForTesting() {
|
|
263
|
+
return this.dialogRef?.componentRef || null;
|
|
250
264
|
}
|
|
251
265
|
/** Internal setter for testing purposes */
|
|
252
|
-
set
|
|
253
|
-
this.
|
|
266
|
+
set modalRefForTesting(ref) {
|
|
267
|
+
this.dialogRef = ref ? new TkDialogRef(ref) : null;
|
|
254
268
|
}
|
|
255
269
|
/**
|
|
256
270
|
* Opens a modal dialog with the provided configuration.
|
|
257
271
|
* Only one modal can be open at a time.
|
|
258
272
|
* @param config Configuration object for the modal (title, content, buttons, etc.)
|
|
259
|
-
* @returns
|
|
273
|
+
* @returns A TkDialogRef for the opened modal.
|
|
260
274
|
*/
|
|
261
275
|
open(config) {
|
|
262
|
-
if (this.
|
|
263
|
-
return
|
|
276
|
+
if (this.dialogRef) {
|
|
277
|
+
return this.dialogRef;
|
|
264
278
|
}
|
|
265
279
|
const componentRef = createComponent(ModalComponent, {
|
|
266
280
|
environmentInjector: this.appRef.injector,
|
|
@@ -268,6 +282,8 @@ class ModalService {
|
|
|
268
282
|
this.appRef.attachView(componentRef.hostView);
|
|
269
283
|
const domElem = componentRef.hostView.rootNodes[0];
|
|
270
284
|
document.body.appendChild(domElem);
|
|
285
|
+
const dialogRef = new TkDialogRef(componentRef);
|
|
286
|
+
this.dialogRef = dialogRef;
|
|
271
287
|
componentRef.setInput('title', config.title);
|
|
272
288
|
componentRef.setInput('content', config.content);
|
|
273
289
|
componentRef.setInput('footerButtons', config.footerButtons || []);
|
|
@@ -276,17 +292,15 @@ class ModalService {
|
|
|
276
292
|
componentRef.setInput('closeOnOutsideClick', config.closeOnOutsideClick ?? false);
|
|
277
293
|
componentRef.setInput('interceptor', config.interceptor);
|
|
278
294
|
componentRef.setInput('data', config.data || {});
|
|
279
|
-
|
|
295
|
+
componentRef.setInput('dialogRef', dialogRef);
|
|
280
296
|
componentRef.instance.closed.subscribe((value) => {
|
|
281
|
-
|
|
282
|
-
close$.complete();
|
|
297
|
+
dialogRef.emitClose(value);
|
|
283
298
|
this.appRef.detachView(componentRef.hostView);
|
|
284
299
|
componentRef.destroy();
|
|
285
|
-
this.
|
|
300
|
+
this.dialogRef = null;
|
|
286
301
|
});
|
|
287
302
|
componentRef.instance.open();
|
|
288
|
-
|
|
289
|
-
return close$.asObservable();
|
|
303
|
+
return dialogRef;
|
|
290
304
|
}
|
|
291
305
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: ModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
292
306
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: ModalService, providedIn: 'root' }); }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tekus-design-system-components-modal.mjs","sources":["../../../projects/design-system/components/modal/src/modal.component.ts","../../../projects/design-system/components/modal/src/modal.component.html","../../../projects/design-system/components/modal/src/services/modal.service.ts","../../../projects/design-system/components/modal/tekus-design-system-components-modal.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, output, Type, ElementRef, model, viewChild, ViewContainerRef, ComponentRef, effect, OnDestroy, untracked, afterEveryRender, inject } from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DialogModule } from 'primeng/dialog';\nimport { ModalFooterButton, ModalSizeType } from './modal.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n} from '@tekus/design-system/core/types';\n\n/**\n * @component ModalComponent\n * @description\n * A programmatically controlled modal dialog used for displaying dynamic content.\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-modal',\n imports: [DialogModule, ButtonComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n})\nexport class ModalComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The title displayed at the top of the modal */\n title = input<string>('');\n\n /** The main content of the modal. Can be a string or a Component Type. */\n content = input<string | Type<T> | null>(null);\n\n /** Array of footer buttons with label, callback, and return value */\n footerButtons = input<ModalFooterButton[]>([]);\n\n /** Modal size: 'small', 'large', 'medium' or 'full' */\n size = input<ModalSizeType>('small');\n\n /** Whether the modal can be closed by the user via close button */\n closable = input<boolean>(true);\n\n /** Whether clicking outside the modal mask closes the modal */\n closeOnOutsideClick = input<boolean>(false);\n\n /**\n * Optional data to be passed as inputs to the dynamic component.\n */\n data = input<Partial<T>>({});\n\n /**\n * Optional interceptor called before the modal closes.\n * MUST be synchronous. Returns true to allow closing.\n */\n interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n /** Computed: whether the content is a simple string */\n isContentString = computed(() => typeof this.content() === 'string');\n\n /** Computed: whether the modal has footer buttons to display */\n hasFooter = computed(() => (this.footerButtons() ?? []).length > 0);\n\n /** Whether the modal should be responsive on mobile screens */\n responsive = input<boolean>(true);\n\n /** Visibility flag as Model Signal (allows two-way binding) */\n isOpened = model<boolean>(false);\n\n /** Whether the modal content has a scrollbar */\n hasScroll = false;\n\n // --- Internals ---\n /** Emits when the modal closes, passing the return value from footer buttons or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n */\n\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n\n afterEveryRender(() => {\n this.checkScroll();\n });\n }\n\n /** Computed: calculates modal max-width based on `size` */\n modalMaxWidth = computed(() => {\n switch (this.size()) {\n case 'large':\n return '67.5rem';\n case 'medium':\n return '35rem';\n case 'full':\n return '98vw';\n default:\n return '25rem';\n }\n });\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n /**\n * @summary Orchestrates dynamic rendering and destruction based on visibility.\n * @private\n */\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) return;\n this.detachDynamicContent();\n this.componentRef = host.createComponent(type);\n this.syncDynamicInputs(this.data());\n }\n\n /**\n * @summary Synchronizes incoming data record with the dynamic instance @Inputs.\n * @private\n */\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) return;\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n /**\n * @summary Safely destroys the dynamic component and clears references.\n * @private\n */\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the modal content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-dialog-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n /**\n * Opens the modal dialog.\n */\n open(): void {\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /**\n * @summary Main entry point for closure requests.\n * Evaluation is 100% synchronous based on current Signal state.\n * @param returnValue (Optional) Value to emit on close.\n */\n tryClose(returnValue: unknown = null): void {\n if (this.canExecuteClosure()) {\n this.executeClosure(returnValue, arguments.length > 0);\n } else {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n instance?.onBlockedClose?.();\n }\n }\n\n /**\n * @summary Synchronous evaluator of hierarchical guards.\n * @returns true if closure is allowed.\n * @private\n */\n private canExecuteClosure(): boolean {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canClose = instance?.canClose ? instance.canClose() : true;\n if (!canClose) return false;\n\n const configInterceptor = this.interceptor();\n if (configInterceptor && !configInterceptor()) return false;\n\n return true;\n }\n\n /**\n * @summary Unified logic to execute the final closure state change.\n * @private\n */\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n }\n\n /**\n * @summary Handles external visibility changes (from p-dialog 'X' or Escape).\n * Ensures the reactive guard is respected before allowing closure.\n */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n this.tryClose();\n }\n }\n\n /**\n * Handles the close event from the underlying dialog component.\n */\n handleClose(): void {\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n }\n\n /**\n * @summary Handles actions triggered by footer buttons.\n */\n handleAction(action: (() => void) | undefined, returnValue: unknown): void {\n if (action) action();\n this.tryClose(returnValue);\n }\n\n /**\n * @summary Safely closes the modal forcefully without checks.\n */\n close(): void {\n this.tryClose();\n }\n\n /**\n * @private\n * Encapsulates state cleanup to avoid repetitive assignments\n */\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n @if (hasFooter()) {\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"btn.label\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n (clicked)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue)\" />\n }\n </section>\n }\n </ng-template>\n</p-dialog>\n","import { Injectable, ApplicationRef, ComponentRef, Injector, createComponent, EmbeddedViewRef, inject } from '@angular/core';\nimport { outputToObservable } from '@angular/core/rxjs-interop';\nimport { ModalComponent } from '../modal.component';\nimport { Observable, Subject } from 'rxjs';\nimport { ModalConfig } from '../modal.types';\n\n/**\n * @service ModalService\n * @description\n * Service responsible for programmatically opening and managing modal dialogs.\n * It handles component creation, attachment to the document body, and cleanup.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalService {\n private readonly injector = inject(Injector);\n private readonly appRef = inject(ApplicationRef);\n\n /** Reference to the currently open modal component */\n private modalRef: ComponentRef<ModalComponent> | null = null;\n\n /** Internal getter for testing purposes */\n get _modalRefForTesting(): ComponentRef<ModalComponent> | null {\n return this.modalRef;\n }\n /** Internal setter for testing purposes */\n set _modalRefForTesting(ref: ComponentRef<ModalComponent> | null) {\n this.modalRef = ref;\n }\n\n /**\n * Opens a modal dialog with the provided configuration.\n * Only one modal can be open at a time.\n * @param config Configuration object for the modal (title, content, buttons, etc.)\n * @returns An observable that emits the modal's return value when it closes.\n */\n open(config: ModalConfig): Observable<unknown> {\n if (this.modalRef) {\n return outputToObservable(this.modalRef.instance.closed);\n }\n\n const componentRef = createComponent(ModalComponent, {\n environmentInjector: this.appRef.injector,\n });\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content);\n componentRef.setInput('footerButtons', config.footerButtons || []);\n componentRef.setInput('size', config.size || 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('closeOnOutsideClick', config.closeOnOutsideClick ?? false);\n componentRef.setInput('interceptor', config.interceptor);\n componentRef.setInput('data', config.data || {});\n\n const close$ = new Subject<unknown>();\n\n componentRef.instance.closed.subscribe((value: unknown) => {\n close$.next(value);\n close$.complete();\n\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n this.modalRef = null;\n });\n\n componentRef.instance.open();\n this.modalRef = componentRef;\n\n return close$.asObservable();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;AASA;;;;;AAKG;MAQU,cAAc,CAAA;AA0DzB,IAAA,WAAA,GAAA;AACE;;AAEG;AA5DY,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QAE/B,IAAA,CAAA,WAAW,GAAG,SAAS,CAAC,aAAa,mFACpD,IAAI,EAAE,gBAAgB,EAAA,CACtB;;AAIF,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK,CAAS,EAAE,4EAAC;;AAGzB,QAAA,IAAA,CAAA,OAAO,GAAG,KAAK,CAA0B,IAAI,8EAAC;;AAG9C,QAAA,IAAA,CAAA,aAAa,GAAG,KAAK,CAAsB,EAAE,oFAAC;;AAG9C,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAgB,OAAO,2EAAC;;AAGpC,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAU,IAAI,+EAAC;;AAG/B,QAAA,IAAA,CAAA,mBAAmB,GAAG,KAAK,CAAU,KAAK,0FAAC;AAE3C;;AAEG;AACH,QAAA,IAAA,CAAA,IAAI,GAAG,KAAK,CAAa,EAAE,2EAAC;AAE5B;;;AAGG;AACH,QAAA,IAAA,CAAA,WAAW,GAAG,KAAK,CAAiC,SAAS,kFAAC;;AAG9D,QAAA,IAAA,CAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,QAAQ,sFAAC;;AAGpE,QAAA,IAAA,CAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE,MAAM,GAAG,CAAC,gFAAC;;AAGnE,QAAA,IAAA,CAAA,UAAU,GAAG,KAAK,CAAU,IAAI,iFAAC;;AAGjC,QAAA,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,+EAAC;;QAGhC,IAAA,CAAA,SAAS,GAAG,KAAK;;;QAIR,IAAA,CAAA,MAAM,GAAG,MAAM,EAAW;QAC3B,IAAA,CAAA,cAAc,GAAG,KAAK;QACtB,IAAA,CAAA,kBAAkB,GAAY,IAAI;;AA+B1C,QAAA,IAAA,CAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AAC5B,YAAA,QAAQ,IAAI,CAAC,IAAI,EAAE;AACjB,gBAAA,KAAK,OAAO;AACV,oBAAA,OAAO,SAAS;AAClB,gBAAA,KAAK,QAAQ;AACX,oBAAA,OAAO,OAAO;AAChB,gBAAA,KAAK,MAAM;AACT,oBAAA,OAAO,MAAM;AACf,gBAAA;AACE,oBAAA,OAAO,OAAO;;AAEpB,QAAA,CAAC,oFAAC;QAnCA,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC9B,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;YAE/B,SAAS,CAAC,MAAK;AACb,gBAAA,IAAI,MAAM,IAAI,IAAI,EAAE;oBAClB,IAAI,CAAC,oBAAoB,EAAE;gBAC7B;qBAAO,IAAI,CAAC,MAAM,EAAE;oBAClB,IAAI,CAAC,oBAAoB,EAAE;gBAC7B;AACF,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE;YAC/B,SAAS,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACtD,QAAA,CAAC,CAAC;QAEF,gBAAgB,CAAC,MAAK;YACpB,IAAI,CAAC,WAAW,EAAE;AACpB,QAAA,CAAC,CAAC;IACJ;IAgBA,WAAW,GAAA;QACT,IAAI,CAAC,oBAAoB,EAAE;IAC7B;AAEA;;;AAGG;IACK,oBAAoB,GAAA;AAC1B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE;AAC3B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;QAE/B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI;YAAE;QAChD,IAAI,CAAC,oBAAoB,EAAE;QAC3B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;QAC9C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrC;AAEA;;;AAGG;AACK,IAAA,iBAAiB,CAAC,IAAgB,EAAA;QACxC,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE;AACxB,QAAA,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;YAC5C,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC;AACzC,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACK,oBAAoB,GAAA;AAC1B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;AAC3B,YAAA,IAAI,CAAC,YAAY,GAAG,SAAS;QAC/B;IACF;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,MAAM,SAAS,GACb,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,mBAAmB,CAAC;QAClE,IAAI,SAAS,EAAE;YACb,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY;QAClE;IACF;AAEA;;AAEG;IACH,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,iBAAiB,EAAE;IAC1B;AAEA;;;;AAIG;IACH,QAAQ,CAAC,cAAuB,IAAI,EAAA;AAClC,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC5B,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QACxD;aAAO;AACL,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,QAAkC;AACtE,YAAA,QAAQ,EAAE,cAAc,IAAI;QAC9B;IACF;AAEA;;;;AAIG;IACK,iBAAiB,GAAA;AACvB,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,QAAkC;AACtE,QAAA,MAAM,QAAQ,GAAG,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,IAAI;AAChE,QAAA,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,KAAK;AAE3B,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE;AAC5C,QAAA,IAAI,iBAAiB,IAAI,CAAC,iBAAiB,EAAE;AAAE,YAAA,OAAO,KAAK;AAE3D,QAAA,OAAO,IAAI;IACb;AAEA;;;AAGG;IACK,cAAc,CAAC,WAAoB,EAAE,cAAuB,EAAA;QAClE,IAAI,cAAc,EAAE;AAClB,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAC1B,YAAA,IAAI,CAAC,kBAAkB,GAAG,WAAW;QACvC;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAC1B;AAEA;;;AAGG;AACH,IAAA,eAAe,CAAC,OAAgB,EAAA;QAC9B,IAAI,CAAC,OAAO,EAAE;YACZ,IAAI,CAAC,QAAQ,EAAE;QACjB;IACF;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI;AACxE,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;QAC7B,IAAI,CAAC,iBAAiB,EAAE;IAC1B;AAEA;;AAEG;IACH,YAAY,CAAC,MAAgC,EAAE,WAAoB,EAAA;AACjE,QAAA,IAAI,MAAM;AAAE,YAAA,MAAM,EAAE;AACpB,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC5B;AAEA;;AAEG;IACH,KAAK,GAAA;QACH,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;;AAGG;IACK,iBAAiB,GAAA;AACvB,QAAA,IAAI,CAAC,cAAc,GAAG,KAAK;AAC3B,QAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI;IAChC;8GAlPW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAd,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,ugDAIjB,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC1B1B,00CA4CA,EAAA,MAAA,EAAA,CAAA,4uBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED1BY,YAAY,kgCAAE,eAAe,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,UAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,MAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;2FAI5B,cAAc,EAAA,UAAA,EAAA,CAAA;kBAP1B,SAAS;sCACS,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,UAAU,WACX,CAAC,YAAY,EAAE,eAAe,CAAC,EAAA,QAAA,EAAA,00CAAA,EAAA,MAAA,EAAA,CAAA,4uBAAA,CAAA,EAAA;AAOC,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,CAAA,aAAa,EAAA,EAAA,GAAE;AACtD,4BAAA,IAAI,EAAE,gBAAgB;AACvB,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,eAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,mBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,qBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,UAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,YAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AErBH;;;;;AAKG;MAEU,YAAY,CAAA;AADzB,IAAA,WAAA,GAAA;AAEmB,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;;QAGxC,IAAA,CAAA,QAAQ,GAAwC,IAAI;AAwD7D,IAAA;;AArDC,IAAA,IAAI,mBAAmB,GAAA;QACrB,OAAO,IAAI,CAAC,QAAQ;IACtB;;IAEA,IAAI,mBAAmB,CAAC,GAAwC,EAAA;AAC9D,QAAA,IAAI,CAAC,QAAQ,GAAG,GAAG;IACrB;AAEA;;;;;AAKG;AACH,IAAA,IAAI,CAAC,MAAmB,EAAA;AACtB,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;YACjB,OAAO,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC1D;AAEA,QAAA,MAAM,YAAY,GAAG,eAAe,CAAC,cAAc,EAAE;AACnD,YAAA,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC1C,SAAA,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;QAE7C,MAAM,OAAO,GAAI,YAAY,CAAC,QAAqC,CAAC,SAAS,CAAC,CAAC,CAAgB;AAC/F,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;QAElC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;QAC5C,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;QAChD,YAAY,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC;QAClE,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC;QACrD,YAAY,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC;QAC1D,YAAY,CAAC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC,mBAAmB,IAAI,KAAK,CAAC;QACjF,YAAY,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,WAAW,CAAC;QACxD,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;AAEhD,QAAA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAW;QAErC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAc,KAAI;AACxD,YAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YAClB,MAAM,CAAC,QAAQ,EAAE;YAEjB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;YAC7C,YAAY,CAAC,OAAO,EAAE;AACtB,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACtB,QAAA,CAAC,CAAC;AAEF,QAAA,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE;AAC5B,QAAA,IAAI,CAAC,QAAQ,GAAG,YAAY;AAE5B,QAAA,OAAO,MAAM,CAAC,YAAY,EAAE;IAC9B;8GA5DW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAZ,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,YAAY,cADC,MAAM,EAAA,CAAA,CAAA;;2FACnB,YAAY,EAAA,UAAA,EAAA,CAAA;kBADxB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACZlC;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"tekus-design-system-components-modal.mjs","sources":["../../../projects/design-system/components/modal/src/modal.component.ts","../../../projects/design-system/components/modal/src/modal.component.html","../../../projects/design-system/components/modal/src/services/modal.service.ts","../../../projects/design-system/components/modal/tekus-design-system-components-modal.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n Type,\n ElementRef,\n model,\n viewChild,\n ViewContainerRef,\n ComponentRef,\n effect,\n OnDestroy,\n untracked,\n afterEveryRender,\n inject,\n Injector,\n} from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DialogModule } from 'primeng/dialog';\nimport { ModalFooterButton, ModalSizeType } from './modal.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n TkDialogRef,\n} from '@tekus/design-system/core/types';\n\n/**\n * @component ModalComponent\n * @description\n * A programmatically controlled modal dialog used for displaying dynamic content.\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-modal',\n imports: [DialogModule, ButtonComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n})\nexport class ModalComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n private readonly injector = inject(Injector);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The dialog ref associated with this modal */\n dialogRef = input<TkDialogRef<ModalComponent<T>, unknown> | null>(null);\n\n /** The title displayed at the top of the modal */\n title = input<string>('');\n\n /** The main content of the modal. Can be a string or a Component Type. */\n content = input<string | Type<T> | null>(null);\n\n /** Array of footer buttons with label, callback, and return value */\n footerButtons = input<ModalFooterButton[]>([]);\n\n /** Modal size: 'small', 'large', 'medium' or 'full' */\n size = input<ModalSizeType>('small');\n\n /** Whether the modal can be closed by the user via close button */\n closable = input<boolean>(true);\n\n /** Whether clicking outside the modal mask closes the modal */\n closeOnOutsideClick = input<boolean>(false);\n\n /**\n * Optional data to be passed as inputs to the dynamic component.\n */\n data = input<Partial<T>>({});\n\n /**\n * Optional interceptor called before the modal closes.\n * MUST be synchronous. Returns true to allow closing.\n */\n interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n /** Computed: whether the content is a simple string */\n isContentString = computed(() => typeof this.content() === 'string');\n\n /** Computed: whether the modal has footer buttons to display */\n hasFooter = computed(() => (this.footerButtons() ?? []).length > 0);\n\n /** Whether the modal should be responsive on mobile screens */\n responsive = input<boolean>(true);\n\n /** Visibility flag as Model Signal (allows two-way binding) */\n isOpened = model<boolean>(false);\n\n /** Whether the modal content has a scrollbar */\n hasScroll = false;\n\n // --- Internals ---\n /** Emits when the modal closes, passing the return value from footer buttons or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n */\n\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n this.dialogRef(); // Track it to re-run if it's set later\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n\n afterEveryRender(() => {\n this.checkScroll();\n });\n }\n\n /** Computed: calculates modal max-width based on `size` */\n modalMaxWidth = computed(() => {\n switch (this.size()) {\n case 'large':\n return '67.5rem';\n case 'medium':\n return '35rem';\n case 'full':\n return '98vw';\n default:\n return '25rem';\n }\n });\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n /**\n * @summary Orchestrates dynamic rendering and destruction based on visibility.\n * @private\n */\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) return;\n this.detachDynamicContent();\n\n const customInjector = Injector.create({\n providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],\n parent: this.injector,\n });\n\n this.componentRef = host.createComponent(type, {\n injector: customInjector,\n });\n this.syncDynamicInputs(this.data());\n }\n\n /**\n * @summary Synchronizes incoming data record with the dynamic instance @Inputs.\n * @private\n */\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) return;\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n /**\n * @summary Safely destroys the dynamic component and clears references.\n * @private\n */\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the modal content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-dialog-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n private wasOpened = false;\n\n /**\n * Opens the modal dialog.\n */\n open(): void {\n this.wasOpened = true;\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /**\n * @summary Main entry point for closure requests.\n * Evaluation is 100% synchronous based on current Signal state.\n * @param returnValue (Optional) Value to emit on close.\n */\n tryClose(returnValue: unknown = null): void {\n if (this.canExecuteClosure()) {\n this.executeClosure(returnValue, arguments.length > 0);\n } else {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n instance?.onBlockedClose?.();\n }\n }\n\n /**\n * @summary Synchronous evaluator of hierarchical guards.\n * @returns true if closure is allowed.\n * @private\n */\n private canExecuteClosure(): boolean {\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canClose = instance?.canClose ? instance.canClose() : true;\n if (!canClose) return false;\n\n const configInterceptor = this.interceptor();\n if (configInterceptor && !configInterceptor()) return false;\n\n return true;\n }\n\n /**\n * @summary Unified logic to execute the final closure state change.\n * @private\n */\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n }\n\n /**\n * @summary Handles external visibility changes (from p-dialog 'X' or Escape).\n * Ensures the reactive guard is respected before allowing closure.\n */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n this.tryClose();\n }\n }\n\n /**\n * Handles the close event from the underlying dialog component.\n */\n handleClose(): void {\n if (!this.wasOpened || this.isOpened()) {\n return;\n }\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n this.wasOpened = false;\n }\n\n /**\n * @summary Handles actions triggered by footer buttons.\n */\n handleAction(action: (() => void) | undefined, returnValue: unknown): void {\n if (action) action();\n this.tryClose(returnValue);\n }\n\n /**\n * @summary Safely closes the modal forcefully without checks.\n */\n close(): void {\n this.tryClose();\n }\n\n /**\n * @private\n * Encapsulates state cleanup to avoid repetitive assignments\n */\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n @if (hasFooter()) {\n <ng-template pTemplate=\"footer\">\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"btn.label\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n (clicked)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue)\" />\n }\n </section>\n </ng-template>\n }\n</p-dialog>\n","import { Injectable, ApplicationRef, ComponentRef, createComponent, EmbeddedViewRef, inject } from '@angular/core';\nimport { ModalComponent } from '../modal.component';\nimport { ModalConfig } from '../modal.types';\nimport { TkDialogRef } from '@tekus/design-system/core/types';\n\n/**\n * @service ModalService\n * @description\n * Service responsible for programmatically opening and managing modal dialogs.\n * It handles component creation, attachment to the document body, and cleanup.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalService {\n private readonly appRef = inject(ApplicationRef);\n\n /** Reference to the currently open modal dialog ref */\n private dialogRef: TkDialogRef<ModalComponent> | null = null;\n\n /** Internal getter for testing purposes */\n get modalRefForTesting(): ComponentRef<ModalComponent> | null {\n return this.dialogRef?.componentRef || null;\n }\n /** Internal setter for testing purposes */\n set modalRefForTesting(ref: ComponentRef<ModalComponent> | null) {\n this.dialogRef = ref ? new TkDialogRef(ref) : null;\n }\n\n /**\n * Opens a modal dialog with the provided configuration.\n * Only one modal can be open at a time.\n * @param config Configuration object for the modal (title, content, buttons, etc.)\n * @returns A TkDialogRef for the opened modal.\n */\n open<T = unknown, R = unknown>(config: ModalConfig): TkDialogRef<ModalComponent<T>, R> {\n if (this.dialogRef) {\n return this.dialogRef as unknown as TkDialogRef<ModalComponent<T>, R>;\n }\n\n const componentRef = createComponent(ModalComponent, {\n environmentInjector: this.appRef.injector,\n }) as ComponentRef<ModalComponent<T>>;\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n const dialogRef = new TkDialogRef<ModalComponent<T>, R>(componentRef);\n this.dialogRef = dialogRef as unknown as TkDialogRef<ModalComponent>;\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content);\n componentRef.setInput('footerButtons', config.footerButtons || []);\n componentRef.setInput('size', config.size || 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('closeOnOutsideClick', config.closeOnOutsideClick ?? false);\n componentRef.setInput('interceptor', config.interceptor);\n componentRef.setInput('data', config.data || {});\n componentRef.setInput('dialogRef', dialogRef);\n\n componentRef.instance.closed.subscribe((value: unknown) => {\n dialogRef.emitClose(value as R);\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n this.dialogRef = null;\n });\n\n componentRef.instance.open();\n\n return dialogRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { provideAppInitializer, inject, DOCUMENT, signal, Injectable } from '@angular/core';
|
|
2
3
|
import { PrimeNG } from 'primeng/config';
|
|
3
4
|
import { definePreset } from '@primeuix/themes';
|
|
4
5
|
import Aura from '@primeuix/themes/aura';
|
|
6
|
+
import { Subject } from 'rxjs';
|
|
5
7
|
|
|
6
8
|
var GapGutter;
|
|
7
9
|
(function (GapGutter) {
|
|
@@ -303,9 +305,76 @@ function provideTkTheme() {
|
|
|
303
305
|
});
|
|
304
306
|
}
|
|
305
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Reference to a dialog/drawer opened via a service.
|
|
310
|
+
* Supports both Observable-style subscription and Signal-based state.
|
|
311
|
+
*/
|
|
312
|
+
class TkDialogRef {
|
|
313
|
+
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
314
|
+
constructor(componentRef) {
|
|
315
|
+
this.componentRef = componentRef;
|
|
316
|
+
this.closedSubject = new Subject();
|
|
317
|
+
this.resultSignal = signal(undefined, ...(ngDevMode ? [{ debugName: "resultSignal" }] : /* istanbul ignore next */ []));
|
|
318
|
+
this.isClosedSignal = signal(false, ...(ngDevMode ? [{ debugName: "isClosedSignal" }] : /* istanbul ignore next */ []));
|
|
319
|
+
/**
|
|
320
|
+
* Signal that holds the result of the dialog after it closes.
|
|
321
|
+
*/
|
|
322
|
+
this.result = this.resultSignal.asReadonly();
|
|
323
|
+
/**
|
|
324
|
+
* Signal that indicates if the dialog has been closed.
|
|
325
|
+
*/
|
|
326
|
+
this.isClosed = this.isClosedSignal.asReadonly();
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* The instance of the component opened in the dialog.
|
|
330
|
+
*/
|
|
331
|
+
get componentInstance() {
|
|
332
|
+
return this.componentRef.instance;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Closes the dialog, optionally passing a result back.
|
|
336
|
+
* Internal implementation calls the component's tryClose to respect guards.
|
|
337
|
+
*/
|
|
338
|
+
close(result) {
|
|
339
|
+
const instance = this.componentRef.instance;
|
|
340
|
+
if (instance && typeof instance.tryClose === 'function') {
|
|
341
|
+
instance.tryClose(result);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Subscribes to the closure event.
|
|
346
|
+
* This maintains compatibility with existing service.open(...).subscribe() patterns
|
|
347
|
+
* using the modern RxJS signature.
|
|
348
|
+
*/
|
|
349
|
+
subscribe(nextOrObserver) {
|
|
350
|
+
if (typeof nextOrObserver === 'function') {
|
|
351
|
+
return this.closedSubject.subscribe({ next: nextOrObserver });
|
|
352
|
+
}
|
|
353
|
+
return this.closedSubject.subscribe(nextOrObserver);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Internal method to emit the result and update reactive state.
|
|
357
|
+
* Not intended for public use outside the opening service.
|
|
358
|
+
*/
|
|
359
|
+
emitClose(result) {
|
|
360
|
+
if (this.isClosedSignal()) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
this.resultSignal.set(result === null ? undefined : result);
|
|
364
|
+
this.isClosedSignal.set(true);
|
|
365
|
+
this.closedSubject.next(result === null ? undefined : result);
|
|
366
|
+
this.closedSubject.complete();
|
|
367
|
+
}
|
|
368
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: TkDialogRef, deps: [{ token: i0.ComponentRef }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
369
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: TkDialogRef }); }
|
|
370
|
+
}
|
|
371
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: TkDialogRef, decorators: [{
|
|
372
|
+
type: Injectable
|
|
373
|
+
}], ctorParameters: () => [{ type: i0.ComponentRef }] });
|
|
374
|
+
|
|
306
375
|
/**
|
|
307
376
|
* Generated bundle index. Do not edit.
|
|
308
377
|
*/
|
|
309
378
|
|
|
310
|
-
export { Breakpoints, GapGutter, Gutter, PaddingGridContainer, TkPreset, provideTkTheme };
|
|
379
|
+
export { Breakpoints, GapGutter, Gutter, PaddingGridContainer, TkDialogRef, TkPreset, provideTkTheme };
|
|
311
380
|
//# sourceMappingURL=tekus-design-system-core-types.mjs.map
|