license import { Component , ComponentRef , ElementRef , EmbeddedViewRef , EventEmitter , Inject , Optional , ChangeDetectorRef , ViewChild , ViewEncapsulation , ChangeDetectionStrategy , } from '@angular/core' ; import { DOCUMENT } from '@angular/common' ; import { AnimationEvent } from '@angular/animations' ; import { matDialogAnimations } from './dialog-animations' ; import { BasePortalOutlet , ComponentPortal , CdkPortalOutlet , TemplatePortal } from '@angular/cdk/portal' ; import { FocusTrap , FocusTrapFactory } from '@angular/cdk/a11y' ; import { MatDialogConfig } from './dialog-config' ; docs-private export function throwMatDialogContentAlreadyAttachedError ( ) { throw Error ( 'Attempting to attach dialog content after content is already attached' ) ; } docs-private @ Component ( { moduleId : module . id , selector : 'mat-dialog-container' , templateUrl : 'dialog-container.html' , styleUrls : [ 'dialog.css' ] , encapsulation : ViewEncapsulation . None , changeDetection : ChangeDetectionStrategy . Default , animations : [ matDialogAnimations . dialogContainer ] , host : { 'class' : 'mat-dialog-container' , 'tabindex' : '-1' , 'aria-modal' : 'true' , '[attr.id]' : '_id' , '[attr.role]' : '_config.role' , '[attr.aria-labelledby]' : '_config.ariaLabel ? null : _ariaLabelledBy' , '[attr.aria-label]' : '_config.ariaLabel' , '[attr.aria-describedby]' : '_config.ariaDescribedBy || null' , '[@dialogContainer]' : '_state' , '(@dialogContainer.start)' : '_onAnimationStart($event)' , '(@dialogContainer.done)' : '_onAnimationDone($event)' , } , } ) export class MatDialogContainer extends BasePortalOutlet { /** The portal outlet inside of this container into which the dialog content will be loaded. */ @ ViewChild ( CdkPortalOutlet ) _portalOutlet : CdkPortalOutlet ; /** The class that traps and manages focus within the dialog. */ private _focusTrap : FocusTrap ; /** Element that was focused before the dialog was opened. Save this to restore upon close. */ private _elementFocusedBeforeDialogWasOpened : HTMLElement | null = null ; /** State of the dialog animation. */ _state : 'void' | 'enter' | 'exit' = 'enter' ; /** Emits when an animation state changes. */ _animationStateChanged = new EventEmitter < AnimationEvent > ( ) ; /** ID of the element that should be considered as the dialog's label. */ _ariaLabelledBy : string | null = null ; /** ID for the container DOM element. */ _id : string ; constructor ( private _elementRef , private _focusTrapFactory , private _changeDetectorRef , @ Optional ( ) @ Inject ( DOCUMENT ) private _document , /** The dialog configuration. */ public _config ) { super ( ) ; } param portal attachComponentPortal < T > ( portal ) { if ( this . _portalOutlet . hasAttached ( ) ) { throwMatDialogContentAlreadyAttachedError ( ) ; } this . _savePreviouslyFocusedElement ( ) ; return this . _portalOutlet . attachComponentPortal ( portal ) ; } param portal attachTemplatePortal < C > ( portal ) { if ( this . _portalOutlet . hasAttached ( ) ) { throwMatDialogContentAlreadyAttachedError ( ) ; } this . _savePreviouslyFocusedElement ( ) ; return this . _portalOutlet . attachTemplatePortal ( portal ) ; } /** Moves the focus inside the focus trap. */ private _trapFocus ( ) { if ( ! this . _focusTrap ) { this . _focusTrap = this . _focusTrapFactory . create ( this . _elementRef . nativeElement ) ; } if ( this . _config . autoFocus ) { this . _focusTrap . focusInitialElementWhenReady ( ) ; } } /** Restores focus to the element that was focused before the dialog opened. */ private _restoreFocus ( ) { const toFocus = this . _elementFocusedBeforeDialogWasOpened ; if ( this . _config . restoreFocus && toFocus && typeof toFocus . focus === 'function' ) { toFocus . focus ( ) ; } if ( this . _focusTrap ) { this . _focusTrap . destroy ( ) ; } } /** Saves a reference to the element that was focused before the dialog was opened. */ private _savePreviouslyFocusedElement ( ) { if ( this . _document ) { this . _elementFocusedBeforeDialogWasOpened = this . _document . activeElement as HTMLElement ; if ( this . _elementRef . nativeElement . focus ) { Promise . resolve ( ) . then ( ( ) => this . _elementRef . nativeElement . focus ( ) ) ; } } } /** Callback, invoked whenever an animation on the host completes. */ _onAnimationDone ( event ) { if ( event . toState === 'enter' ) { this . _trapFocus ( ) ; } else if ( event . toState === 'exit' ) { this . _restoreFocus ( ) ; } this . _animationStateChanged . emit ( event ) ; } /** Callback, invoked when an animation on the host starts. */ _onAnimationStart ( event ) { this . _animationStateChanged . emit ( event ) ; } /** Starts the dialog exit animation. */ _startExitAnimation ( ) { this . _state = 'exit' ; this . _changeDetectorRef . markForCheck ( ) ; } }