import { FocusOrigin } from '@angular/cdk/a11y' ; import { ESCAPE , hasModifierKey } from '@angular/cdk/keycodes' ; import { GlobalPositionStrategy , OverlayRef } from '@angular/cdk/overlay' ; import { Observable , Subject } from 'rxjs' ; import { filter , take } from 'rxjs/operators' ; import { SbbDialogPosition } from './dialog-config' ; import { _SbbDialogContainerBase } from './dialog-container' ; let uniqueId = 0 ; /** Possible states of the lifecycle of a dialog. */ export const enum SbbDialogState { OPEN , CLOSING , CLOSED } /**
 * Reference to a dialog opened via the SbbDialog service.
 */ export class SbbDialogRef < T , R = any > { /** The instance of component opened into the dialog. */ componentInstance : T ; /** Whether the user is allowed to close the dialog. */ disableClose : boolean | undefined = this . _containerInstance . _config . disableClose ; /** Subject for notifying the user that the dialog has finished opening. */ private readonly _afterOpened = new Subject < void > ( ) ; /** Subject for notifying the user that the dialog has finished closing. */ private readonly _afterClosed = new Subject < R | undefined > ( ) ; /** Subject for notifying the user that the dialog has started closing. */ private readonly _beforeClosed = new Subject < R | undefined > ( ) ; /** Result to be passed to afterClosed. */ private _result : R | undefined ; /** Handle to the timeout that's running as a fallback in case the exit animation doesn't fire. */ private _closeFallbackTimeout : number ; /** Current state of the dialog. */ private _state = SbbDialogState . OPEN ; constructor ( private _overlayRef , public _containerInstance , /** Id of the dialog. */ readonly id = `sbb-dialog-${ uniqueId ++ }` ) { _containerInstance . _id = id ; _containerInstance . _animationStateChanged . pipe ( filter ( ( event ) => event . state === 'opened' ) , take ( 1 ) ) . subscribe ( ( ) => { this . _afterOpened . next ( ) ; this . _afterOpened . complete ( ) ; } ) ; _containerInstance . _animationStateChanged . pipe ( filter ( ( event ) => event . state === 'closed' ) , take ( 1 ) ) . subscribe ( ( ) => { clearTimeout ( this . _closeFallbackTimeout ) ; this . _finishDialogClose ( ) ; } ) ; _overlayRef . detachments ( ) . subscribe ( ( ) => { this . _beforeClosed . next ( this . _result ) ; this . _beforeClosed . complete ( ) ; this . _afterClosed . next ( this . _result ) ; this . _afterClosed . complete ( ) ; this . componentInstance = null ! ; this . _overlayRef . dispose ( ) ; } ) ; _overlayRef . keydownEvents ( ) . pipe ( filter ( ( event ) => { return event . keyCode === ESCAPE && ! this . disableClose && ! hasModifierKey ( event ) ; } ) ) . subscribe ( ( event ) => { event . preventDefault ( ) ; _closeDialogVia ( this , 'keyboard' ) ; } ) ; _overlayRef . backdropClick ( ) . subscribe ( ( ) => { if ( this . disableClose ) { this . _containerInstance . _recaptureFocus ( ) ; } else { _closeDialogVia ( this , 'mouse' ) ; } } ) ; } param dialogResult close ( dialogResult ? ) { this . _result = dialogResult ; this . _containerInstance . _animationStateChanged . pipe ( filter ( ( event ) => event . state === 'closing' ) , take ( 1 ) ) . subscribe ( ( event ) => { this . _beforeClosed . next ( dialogResult ) ; this . _beforeClosed . complete ( ) ; this . _overlayRef . detachBackdrop ( ) ; this . _closeFallbackTimeout = setTimeout ( ( ) => this . _finishDialogClose ( ) , event . totalTime + 100 ) ; } ) ; this . _state = SbbDialogState . CLOSING ; this . _containerInstance . _startExitAnimation ( ) ; } /**
     * Gets an observable that is notified when the dialog is finished opening.
     */ afterOpened ( ) { return this . _afterOpened ; } /**
     * Gets an observable that is notified when the dialog is finished closing.
     */ afterClosed ( ) { return this . _afterClosed ; } /**
     * Gets an observable that is notified when the dialog has started closing.
     */ beforeClosed ( ) { return this . _beforeClosed ; } /**
     * Gets an observable that emits when the overlay's backdrop has been clicked.
     */ backdropClick ( ) { return this . _overlayRef . backdropClick ( ) ; } /**
     * Gets an observable that emits when keydown events are targeted on the overlay.
     */ keydownEvents ( ) { return this . _overlayRef . keydownEvents ( ) ; } param position updatePosition ( position ? ) { const strategy = this . _getPositionStrategy ( ) ; if ( position && ( position . left || position . right ) ) { position . left ? strategy . left ( position . left ) : strategy . right ( position . right ) ; } else { strategy . centerHorizontally ( ) ; } if ( position && ( position . top || position . bottom ) ) { position . top ? strategy . top ( position . top ) : strategy . bottom ( position . bottom ) ; } else { strategy . centerVertically ( ) ; } this . _overlayRef . updatePosition ( ) ; return this ; } param width param height updateSize ( width = '' , height = '' ) { this . _overlayRef . updateSize ( { width , height } ) ; this . _overlayRef . updatePosition ( ) ; return this ; } /** Add a CSS class or an array of classes to the overlay pane. */ addPanelClass ( classes ) { this . _overlayRef . addPanelClass ( classes ) ; return this ; } /** Remove a CSS class or an array of classes from the overlay pane. */ removePanelClass ( classes ) { this . _overlayRef . removePanelClass ( classes ) ; return this ; } /** Gets the current state of the dialog's lifecycle. */ getState ( ) { return this . _state ; } /**
     * Finishes the dialog close by updating the state of the dialog
     * and disposing the overlay.
     */ private _finishDialogClose ( ) { this . _state = SbbDialogState . CLOSED ; this . _overlayRef . dispose ( ) ; } /** Fetches the position strategy object from the overlay ref. */ private _getPositionStrategy ( ) { return this . _overlayRef . getConfig ( ) . positionStrategy as GlobalPositionStrategy ; } } /**
 * Closes the dialog with the specified interaction type. This is currently not part of
 * `SbbDialogRef` as that would conflict with custom dialog ref mocks provided in tests.
 * More details. See: https://github.com/angular/components/pull/9257#issuecomment-651342226.
 */ export function _closeDialogVia < R > ( ref , interactionType , result ? ) { if ( ref . _containerInstance !== undefined ) { ref . _containerInstance . _closeInteractionType = interactionType ; } return ref . close ( result ) ; }