Skip to content

Commit 8ef3125

Browse files
authored
feat(material/dialog): add the ability to control the animation duration (#13466)
Since the dialog animation is on the `MatDialogContainer`, consumers aren't able to disable the animation. These changes add properties to the dialog config that allow consumers to set the duration of the dialog's enter and exit animations. Fixes #3616.
1 parent fc5f8b0 commit 8ef3125

File tree

13 files changed

+136
-3
lines changed

13 files changed

+136
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<h1 mat-dialog-title>Delete file</h1>
2+
<div mat-dialog-content>
3+
Would you like to delete cat.jpeg?
4+
</div>
5+
<div mat-dialog-actions>
6+
<button mat-button mat-dialog-close>No</button>
7+
<button mat-button mat-dialog-close cdkFocusInitial>Ok</button>
8+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
button {
2+
margin-right: 8px;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<button mat-raised-button (click)="openDialog('0ms', '0ms')">Open dialog without animation</button>
2+
<button mat-raised-button (click)="openDialog('3000ms', '1500ms')">Open dialog slowly</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {Component} from '@angular/core';
2+
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
3+
4+
/**
5+
* @title Dialog Animations
6+
*/
7+
@Component({
8+
selector: 'dialog-animations-example',
9+
styleUrls: ['dialog-animations-example.css'],
10+
templateUrl: 'dialog-animations-example.html',
11+
})
12+
export class DialogAnimationsExample {
13+
constructor(public dialog: MatDialog) {}
14+
15+
openDialog(enterAnimationDuration: string, exitAnimationDuration: string): void {
16+
this.dialog.open(DialogAnimationsExampleDialog, {
17+
width: '250px',
18+
enterAnimationDuration,
19+
exitAnimationDuration,
20+
});
21+
}
22+
}
23+
24+
@Component({
25+
selector: 'dialog-animations-example-dialog',
26+
templateUrl: 'dialog-animations-example-dialog.html',
27+
})
28+
export class DialogAnimationsExampleDialog {
29+
constructor(public dialogRef: MatDialogRef<DialogAnimationsExampleDialog>) {}
30+
}

src/components-examples/material/dialog/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ import {
2323
DialogFromMenuExampleDialog,
2424
} from './dialog-from-menu/dialog-from-menu-example';
2525
import {DialogHarnessExample} from './dialog-harness/dialog-harness-example';
26+
import {
27+
DialogAnimationsExample,
28+
DialogAnimationsExampleDialog,
29+
} from './dialog-animations/dialog-animations-example';
2630

2731
export {
2832
DialogContentExample,
@@ -36,6 +40,8 @@ export {
3640
DialogHarnessExample,
3741
DialogOverviewExample,
3842
DialogOverviewExampleDialog,
43+
DialogAnimationsExample,
44+
DialogAnimationsExampleDialog,
3945
};
4046

4147
const EXAMPLES = [
@@ -50,6 +56,8 @@ const EXAMPLES = [
5056
DialogHarnessExample,
5157
DialogOverviewExample,
5258
DialogOverviewExampleDialog,
59+
DialogAnimationsExample,
60+
DialogAnimationsExampleDialog,
5361
];
5462

5563
@NgModule({

src/dev-app/dialog/dialog-demo.html

+11
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ <h2>Other options</h2>
102102
</mat-form-field>
103103
</p>
104104

105+
<p>
106+
<mat-form-field>
107+
<mat-label>Enter duration</mat-label>
108+
<input matInput [(ngModel)]="config.enterAnimationDuration">
109+
</mat-form-field>
110+
<mat-form-field>
111+
<mat-label>Exit duration</mat-label>
112+
<input matInput [(ngModel)]="config.exitAnimationDuration">
113+
</mat-form-field>
114+
</p>
115+
105116
<p>
106117
<mat-checkbox [(ngModel)]="config.disableClose">Disable close</mat-checkbox>
107118
</p>

src/dev-app/dialog/dialog-demo.ts

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export class DialogDemo {
3131
height: '',
3232
minWidth: '',
3333
minHeight: '',
34+
enterAnimationDuration: defaultDialogConfig.enterAnimationDuration,
35+
exitAnimationDuration: defaultDialogConfig.exitAnimationDuration,
3436
maxWidth: defaultDialogConfig.maxWidth,
3537
maxHeight: '',
3638
position: {

src/material/dialog/dialog-animations.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,17 @@ export const matDialogAnimations: {
3434
transition(
3535
'* => enter',
3636
group([
37-
animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({transform: 'none', opacity: 1})),
37+
animate(
38+
'{{enterAnimationDuration}} cubic-bezier(0, 0, 0.2, 1)',
39+
style({transform: 'none', opacity: 1}),
40+
),
3841
query('@*', animateChild(), {optional: true}),
3942
]),
4043
),
4144
transition(
4245
'* => void, * => exit',
4346
group([
44-
animate('75ms cubic-bezier(0.4, 0.0, 0.2, 1)', style({opacity: 0})),
47+
animate('{{exitAnimationDuration}} cubic-bezier(0.4, 0.0, 0.2, 1)', style({opacity: 0})),
4548
query('@*', animateChild(), {optional: true}),
4649
]),
4750
),

src/material/dialog/dialog-config.ts

+6
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,11 @@ export class MatDialogConfig<D = any> {
126126
/** Alternate `ComponentFactoryResolver` to use when resolving the associated component. */
127127
componentFactoryResolver?: ComponentFactoryResolver;
128128

129+
/** Duration of the enter animation. Has to be a valid CSS value (e.g. 100ms). */
130+
enterAnimationDuration?: string = '150ms';
131+
132+
/** Duration of the exit animation. Has to be a valid CSS value (e.g. 50ms). */
133+
exitAnimationDuration?: string = '75ms';
134+
129135
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
130136
}

src/material/dialog/dialog-container.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet {
312312
'[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledBy',
313313
'[attr.aria-label]': '_config.ariaLabel',
314314
'[attr.aria-describedby]': '_config.ariaDescribedBy || null',
315-
'[@dialogContainer]': '_state',
315+
'[@dialogContainer]': `_getAnimationState()`,
316316
'(@dialogContainer.start)': '_onAnimationStart($event)',
317317
'(@dialogContainer.done)': '_onAnimationDone($event)',
318318
},
@@ -360,4 +360,14 @@ export class MatDialogContainer extends _MatDialogContainerBase {
360360
this._trapFocus();
361361
}
362362
}
363+
364+
_getAnimationState() {
365+
return {
366+
value: this._state,
367+
params: {
368+
enterAnimationDuration: this._config.enterAnimationDuration || '150ms',
369+
exitAnimationDuration: this._config.exitAnimationDuration || '75ms',
370+
},
371+
};
372+
}
363373
}

src/material/dialog/dialog.md

+38
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,44 @@ You can control which elements are tab stops with the `tabindex` attribute
118118

119119
<!-- example(dialog-content) -->
120120

121+
### Configuring dialog content via `entryComponents`
122+
123+
Because `MatDialog` instantiates components at run-time, the Angular compiler needs extra
124+
information to create the necessary `ComponentFactory` for your dialog content component.
125+
126+
For any component loaded into a dialog, you must include your component class in the list of
127+
`entryComponents` in your NgModule definition so that the Angular compiler knows to create
128+
the `ComponentFactory` for it.
129+
130+
```ts
131+
@NgModule({
132+
imports: [
133+
// ...
134+
MatDialogModule
135+
],
136+
137+
declarations: [
138+
AppComponent,
139+
ExampleDialogComponent
140+
],
141+
142+
entryComponents: [
143+
ExampleDialogComponent
144+
],
145+
146+
providers: [],
147+
bootstrap: [AppComponent]
148+
})
149+
export class AppModule {}
150+
```
151+
152+
### Controlling the dialog animation
153+
You can control the duration of the dialog's enter and exit animations using the
154+
`enterAnimationDuration` and `exitAnimationDuration` options. If you want to disable the dialog's
155+
animation completely, you can do so by setting the properties to `0ms`.
156+
157+
<!-- example(dialog-animations) -->
158+
121159
### Accessibility
122160

123161
`MatDialog` creates modal dialogs that implements the ARIA `role="dialog"` pattern by default.

src/material/dialog/dialog.spec.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,8 @@ describe('MatDialog with default options', () => {
19591959
minHeight: '50px',
19601960
maxWidth: '150px',
19611961
maxHeight: '150px',
1962+
enterAnimationDuration: '100ms',
1963+
exitAnimationDuration: '50ms',
19621964
autoFocus: false,
19631965
};
19641966

tools/public_api_guard/material/dialog.md

+10
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ export class MatDialogConfig<D = any> {
168168
delayFocusTrap?: boolean;
169169
direction?: Direction;
170170
disableClose?: boolean;
171+
enterAnimationDuration?: string;
172+
exitAnimationDuration?: string;
171173
hasBackdrop?: boolean;
172174
height?: string;
173175
id?: string;
@@ -186,6 +188,14 @@ export class MatDialogConfig<D = any> {
186188

187189
// @public
188190
export class MatDialogContainer extends _MatDialogContainerBase {
191+
// (undocumented)
192+
_getAnimationState(): {
193+
value: "enter" | "void" | "exit";
194+
params: {
195+
enterAnimationDuration: string;
196+
exitAnimationDuration: string;
197+
};
198+
};
189199
// (undocumented)
190200
_initializeWithAttachedContent(): void;
191201
_onAnimationDone({ toState, totalTime }: AnimationEvent_2): void;

0 commit comments

Comments
 (0)