diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts index 37d0ebbd195..7900e1d4422 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts @@ -607,5 +607,5 @@ export function openCollectionDialog( dialogService: DialogService, config: DialogConfig>, ) { - return dialogService.open(CollectionDialogComponent, config); + return dialogService.open(CollectionDialogComponent, config); } diff --git a/libs/components/src/dialog/dialog.service.ts b/libs/components/src/dialog/dialog.service.ts index 8fb15becf56..b6326a220a6 100644 --- a/libs/components/src/dialog/dialog.service.ts +++ b/libs/components/src/dialog/dialog.service.ts @@ -1,13 +1,13 @@ import { Dialog as CdkDialog, - DialogConfig, - DialogRef as CdkDialogRef, + DialogConfig as CdkDialogConfig, + DialogRef as CdkDialogRefBase, DIALOG_DATA, DialogCloseOptions, } from "@angular/cdk/dialog"; import { ComponentType, ScrollStrategy } from "@angular/cdk/overlay"; import { ComponentPortal, Portal } from "@angular/cdk/portal"; -import { Injectable, InjectionToken, Injector, TemplateRef, inject } from "@angular/core"; +import { Injectable, Injector, TemplateRef, inject } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { NavigationEnd, Router } from "@angular/router"; import { filter, firstValueFrom, map, Observable, Subject, switchMap } from "rxjs"; @@ -42,13 +42,14 @@ class CustomBlockScrollStrategy implements ScrollStrategy { detach() {} } -export const IS_DRAWER_TOKEN = new InjectionToken("IS_DRAWER"); - export abstract class DialogRef implements Pick, "close" | "closed" | "disableClose" | "componentInstance"> { + abstract readonly isDrawer?: boolean; + + // --- From CdkDialogRef --- abstract close(result?: R, options?: DialogCloseOptions): void; - abstract closed: Observable; + abstract readonly closed: Observable; abstract disableClose: boolean | undefined; /** * @deprecated @@ -57,7 +58,14 @@ export abstract class DialogRef abstract componentInstance: C | null; } +export type DialogConfig = Pick< + CdkDialogConfig, + "data" | "disableClose" | "ariaModal" | "positionStrategy" | "height" | "width" +>; + class DrawerDialogRef implements DialogRef { + readonly isDrawer = true; + private _closed = new Subject(); closed = this._closed.asObservable(); disableClose = false; @@ -79,6 +87,38 @@ class DrawerDialogRef implements DialogRef { componentInstance: C | null = null; } +/** + * DialogRef that delegates functionality to the CDK implementation + **/ +export class CdkDialogRef implements DialogRef { + readonly isDrawer = false; // This is not a drawer dialog + + /** This is not available until after construction, as it is returned by `Dialog.open`. */ + cdkDialogRef!: CdkDialogRefBase; + + // --- Delegated to CdkDialogRefBase --- + + close(result?: R, options?: DialogCloseOptions): void { + this.cdkDialogRef.close(result, options); + } + + get closed(): Observable { + return this.cdkDialogRef.closed; + } + + get disableClose(): boolean | undefined { + return this.cdkDialogRef.disableClose; + } + set disableClose(value: boolean | undefined) { + this.cdkDialogRef.disableClose = value; + } + + // Delegate the `componentInstance` property to the CDK DialogRef + get componentInstance(): C | null { + return this.cdkDialogRef.componentInstance; + } +} + @Injectable() export class DialogService { private dialog = inject(CdkDialog); @@ -107,17 +147,27 @@ export class DialogService { } } - open( + open( componentOrTemplateRef: ComponentType | TemplateRef, - config?: DialogConfig>, + config?: DialogConfig>, ): DialogRef { - config = { + // Create the injector with the custom DialogRef + const ref = new CdkDialogRef(); + const injector = this.createInjector({ + data: config?.data, + dialogRef: ref, + }); + + // Merge the custom config with the default config + const _config = { backdropClass: this.backDropClasses, scrollStrategy: this.defaultScrollStrategy, + injector, ...config, }; - return this.dialog.open(componentOrTemplateRef, config); + ref.cdkDialogRef = this.dialog.open(componentOrTemplateRef, _config); + return ref; } /** Opens a dialog in the side drawer */ @@ -130,27 +180,7 @@ export class DialogService { const portal = new ComponentPortal( component, null, - Injector.create({ - providers: [ - { - provide: DIALOG_DATA, - useValue: config?.data, - }, - { - provide: CdkDialogRef, - useValue: this.activeDrawer, - }, - { - provide: DialogRef, - useValue: this.activeDrawer, - }, - { - provide: IS_DRAWER_TOKEN, - useValue: true, - }, - ], - parent: this.injector, - }), + this.createInjector({ data: config?.data, dialogRef: this.activeDrawer }), ); this.activeDrawer.portal = portal; this.drawerService.open(portal); @@ -189,4 +219,25 @@ export class DialogService { closeAll(): void { return this.dialog.closeAll(); } + + /** The injector that is passed to the opened dialog */ + private createInjector(opts: { data: unknown; dialogRef: DialogRef }): Injector { + return Injector.create({ + providers: [ + { + provide: DIALOG_DATA, + useValue: opts.data, + }, + { + provide: DialogRef, + useValue: opts.dialogRef, + }, + { + provide: CdkDialogRefBase, + useValue: opts.dialogRef, + }, + ], + parent: this.injector, + }); + } } diff --git a/libs/components/src/dialog/dialog/dialog.component.html b/libs/components/src/dialog/dialog/dialog.component.html index 4db8c32be2f..fa36add2040 100644 --- a/libs/components/src/dialog/dialog/dialog.component.html +++ b/libs/components/src/dialog/dialog/dialog.component.html @@ -1,3 +1,4 @@ +@let isDrawer = dialogRef.isDrawer;