@@ -5,30 +5,51 @@ import {
5
5
ViewEncapsulation ,
6
6
NgZone ,
7
7
OnDestroy ,
8
+ animate ,
9
+ state ,
10
+ style ,
11
+ transition ,
12
+ trigger ,
13
+ AnimationTransitionEvent ,
14
+ EventEmitter ,
8
15
} from '@angular/core' ;
9
16
import { BasePortalHost , ComponentPortal , PortalHostDirective , TemplatePortal } from '../core' ;
10
17
import { MdDialogConfig } from './dialog-config' ;
11
- import { MdDialogRef } from './dialog-ref' ;
12
18
import { MdDialogContentAlreadyAttachedError } from './dialog-errors' ;
13
19
import { FocusTrap } from '../core/a11y/focus-trap' ;
14
20
import 'rxjs/add/operator/first' ;
15
21
16
22
23
+ /** Possible states for the dialog container animation. */
24
+ export type MdDialogContainerAnimationState = 'void' | 'enter' | 'exit' | 'exit-start' ;
25
+
26
+
17
27
/**
18
28
* Internal component that wraps user-provided dialog content.
29
+ * Animation is based on https://material.io/guidelines/motion/choreography.html.
19
30
* @docs -private
20
31
*/
21
32
@Component ( {
22
33
moduleId : module . id ,
23
34
selector : 'md-dialog-container, mat-dialog-container' ,
24
35
templateUrl : 'dialog-container.html' ,
25
36
styleUrls : [ 'dialog.css' ] ,
37
+ encapsulation : ViewEncapsulation . None ,
38
+ animations : [
39
+ trigger ( 'slideDialog' , [
40
+ state ( 'void' , style ( { transform : 'translateY(25%) scale(0.9)' , opacity : 0 } ) ) ,
41
+ state ( 'enter' , style ( { transform : 'translateY(0%) scale(1)' , opacity : 1 } ) ) ,
42
+ state ( 'exit' , style ( { transform : 'translateY(25%)' , opacity : 0 } ) ) ,
43
+ transition ( '* => *' , animate ( '400ms cubic-bezier(0.25, 0.8, 0.25, 1)' ) ) ,
44
+ ] )
45
+ ] ,
26
46
host : {
27
47
'class' : 'md-dialog-container' ,
28
48
'[attr.role]' : 'dialogConfig?.role' ,
29
- '(keydown.escape)' : 'handleEscapeKey()' ,
49
+ '(keydown.escape)' : '_handleEscapeKey()' ,
50
+ '[@slideDialog]' : '_state' ,
51
+ '(@slideDialog.done)' : '_onAnimationDone($event)' ,
30
52
} ,
31
- encapsulation : ViewEncapsulation . None ,
32
53
} )
33
54
export class MdDialogContainer extends BasePortalHost implements OnDestroy {
34
55
/** The portal host inside of this container into which the dialog content will be loaded. */
@@ -43,8 +64,11 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
43
64
/** The dialog configuration. */
44
65
dialogConfig : MdDialogConfig ;
45
66
46
- /** Reference to the open dialog. */
47
- dialogRef : MdDialogRef < any > ;
67
+ /** State of the dialog animation. */
68
+ _state : MdDialogContainerAnimationState = 'enter' ;
69
+
70
+ /** Emits the current animation state whenever it changes. */
71
+ _onAnimationStateChange = new EventEmitter < MdDialogContainerAnimationState > ( ) ;
48
72
49
73
constructor ( private _ngZone : NgZone ) {
50
74
super ( ) ;
@@ -77,22 +101,40 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
77
101
throw Error ( 'Not yet implemented' ) ;
78
102
}
79
103
104
+ ngOnDestroy ( ) {
105
+ // When the dialog is destroyed, return focus to the element that originally had it before
106
+ // the dialog was opened. Wait for the DOM to finish settling before changing the focus so
107
+ // that it doesn't end up back on the <body>.
108
+ this . _ngZone . onMicrotaskEmpty . first ( ) . subscribe ( ( ) => {
109
+ ( this . _elementFocusedBeforeDialogWasOpened as HTMLElement ) . focus ( ) ;
110
+ this . _onAnimationStateChange . complete ( ) ;
111
+ } ) ;
112
+ }
113
+
80
114
/**
81
115
* Handles the user pressing the Escape key.
82
116
* @docs -private
83
117
*/
84
- handleEscapeKey ( ) {
118
+ _handleEscapeKey ( ) {
85
119
if ( ! this . dialogConfig . disableClose ) {
86
- this . dialogRef . close ( ) ;
120
+ this . _exit ( ) ;
87
121
}
88
122
}
89
123
90
- ngOnDestroy ( ) {
91
- // When the dialog is destroyed, return focus to the element that originally had it before
92
- // the dialog was opened. Wait for the DOM to finish settling before changing the focus so
93
- // that it doesn't end up back on the <body>.
94
- this . _ngZone . onMicrotaskEmpty . first ( ) . subscribe ( ( ) => {
95
- ( this . _elementFocusedBeforeDialogWasOpened as HTMLElement ) . focus ( ) ;
96
- } ) ;
124
+ /**
125
+ * Kicks off the leave animation.
126
+ * @docs -private
127
+ */
128
+ _exit ( ) : void {
129
+ this . _state = 'exit' ;
130
+ this . _onAnimationStateChange . emit ( 'exit-start' ) ;
131
+ }
132
+
133
+ /**
134
+ * Callback, invoked whenever an animation on the host completes.
135
+ * @docs -private
136
+ */
137
+ _onAnimationDone ( event : AnimationTransitionEvent ) {
138
+ this . _onAnimationStateChange . emit ( event . toState as MdDialogContainerAnimationState ) ;
97
139
}
98
140
}
0 commit comments