From 88babfd1f61feda18a7356d497a7bb85a178746f Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Tue, 20 Jun 2023 14:44:03 +0300 Subject: [PATCH] RED-3800 add dialog components --- .../iqser-dialog-component.directive.ts | 44 +++++++++++++++++++ src/lib/dialog/iqser-dialog.service.ts | 44 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/lib/dialog/iqser-dialog-component.directive.ts create mode 100644 src/lib/dialog/iqser-dialog.service.ts diff --git a/src/lib/dialog/iqser-dialog-component.directive.ts b/src/lib/dialog/iqser-dialog-component.directive.ts new file mode 100644 index 0000000..7f10939 --- /dev/null +++ b/src/lib/dialog/iqser-dialog-component.directive.ts @@ -0,0 +1,44 @@ +import { Directive, HostListener, inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; + +const DATA_TYPE_SYMBOL = Symbol.for('DATA_TYPE'); +const RETURN_TYPE_SYMBOL = Symbol.for('RETURN_TYPE'); + +export type DATA_TYPE = typeof DATA_TYPE_SYMBOL; +export type RETURN_TYPE = typeof RETURN_TYPE_SYMBOL; + +@Directive() +export abstract class IqserDialogComponent { + readonly [DATA_TYPE_SYMBOL]!: DataType; + readonly [RETURN_TYPE_SYMBOL]!: ReturnType; + + readonly dialogRef = inject(MatDialogRef); + readonly data = inject(MAT_DIALOG_DATA); + readonly dialog = inject(MatDialog); + + constructor() { + this.dialogRef + .backdropClick() + .pipe(takeUntilDestroyed()) + // eslint-disable-next-line rxjs/no-ignored-subscription + .subscribe(() => this.close()); + } + + @HostListener('window:keydown.Escape', ['$event']) + onEscape(): void { + if (this.dialog.openDialogs.length === 1) { + this.close(); + } + } + + close(dialogResult?: ReturnType) { + this.dialogRef.close(dialogResult); + } +} + +/** + * This is for testing only + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +class DialogComponentImpl extends IqserDialogComponent {} diff --git a/src/lib/dialog/iqser-dialog.service.ts b/src/lib/dialog/iqser-dialog.service.ts new file mode 100644 index 0000000..760adc9 --- /dev/null +++ b/src/lib/dialog/iqser-dialog.service.ts @@ -0,0 +1,44 @@ +import { inject, Injectable } from '@angular/core'; +import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; +import { ComponentType } from '@angular/cdk/portal'; +import { firstValueFrom } from 'rxjs'; +import { DATA_TYPE, IqserDialogComponent, RETURN_TYPE } from './iqser-dialog-component.directive'; +import { defaultDialogConfig, largeDialogConfig } from './dialog.service'; + +@Injectable({ + providedIn: 'root', +}) +export class IqserDialog { + protected readonly _dialog = inject(MatDialog); + + open< + Component extends IqserDialogComponent, + Data extends Component[DATA_TYPE], + Return extends Component[RETURN_TYPE], + >(dialog: ComponentType, config?: MatDialogConfig) { + const ref = this._dialog.open(dialog, config); + return { + ...ref, + result() { + console.log('result'); + return firstValueFrom(ref.afterClosed()); + }, + } as MatDialogRef & { result(): Promise }; + } + + openLarge< + Component extends IqserDialogComponent, + Data extends Component[DATA_TYPE], + Return extends Component[RETURN_TYPE], + >(dialog: ComponentType, config?: MatDialogConfig) { + return this.open(dialog, { ...largeDialogConfig, ...config }); + } + + openDefault< + Component extends IqserDialogComponent, + Data extends Component[DATA_TYPE], + Return extends Component[RETURN_TYPE], + >(dialog: ComponentType, config?: MatDialogConfig) { + return this.open(dialog, { ...defaultDialogConfig, ...config }); + } +}