Skip to content

Commit

Permalink
feat(material/dialog): add the ability to control the animation durat…
Browse files Browse the repository at this point in the history
…ion (#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.
  • Loading branch information
crisbeto authored Mar 14, 2022
1 parent fc5f8b0 commit 8ef3125
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h1 mat-dialog-title>Delete file</h1>
<div mat-dialog-content>
Would you like to delete cat.jpeg?
</div>
<div mat-dialog-actions>
<button mat-button mat-dialog-close>No</button>
<button mat-button mat-dialog-close cdkFocusInitial>Ok</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
button {
margin-right: 8px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<button mat-raised-button (click)="openDialog('0ms', '0ms')">Open dialog without animation</button>
<button mat-raised-button (click)="openDialog('3000ms', '1500ms')">Open dialog slowly</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {Component} from '@angular/core';
import {MatDialog, MatDialogRef} from '@angular/material/dialog';

/**
* @title Dialog Animations
*/
@Component({
selector: 'dialog-animations-example',
styleUrls: ['dialog-animations-example.css'],
templateUrl: 'dialog-animations-example.html',
})
export class DialogAnimationsExample {
constructor(public dialog: MatDialog) {}

openDialog(enterAnimationDuration: string, exitAnimationDuration: string): void {
this.dialog.open(DialogAnimationsExampleDialog, {
width: '250px',
enterAnimationDuration,
exitAnimationDuration,
});
}
}

@Component({
selector: 'dialog-animations-example-dialog',
templateUrl: 'dialog-animations-example-dialog.html',
})
export class DialogAnimationsExampleDialog {
constructor(public dialogRef: MatDialogRef<DialogAnimationsExampleDialog>) {}
}
8 changes: 8 additions & 0 deletions src/components-examples/material/dialog/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import {
DialogFromMenuExampleDialog,
} from './dialog-from-menu/dialog-from-menu-example';
import {DialogHarnessExample} from './dialog-harness/dialog-harness-example';
import {
DialogAnimationsExample,
DialogAnimationsExampleDialog,
} from './dialog-animations/dialog-animations-example';

export {
DialogContentExample,
Expand All @@ -36,6 +40,8 @@ export {
DialogHarnessExample,
DialogOverviewExample,
DialogOverviewExampleDialog,
DialogAnimationsExample,
DialogAnimationsExampleDialog,
};

const EXAMPLES = [
Expand All @@ -50,6 +56,8 @@ const EXAMPLES = [
DialogHarnessExample,
DialogOverviewExample,
DialogOverviewExampleDialog,
DialogAnimationsExample,
DialogAnimationsExampleDialog,
];

@NgModule({
Expand Down
11 changes: 11 additions & 0 deletions src/dev-app/dialog/dialog-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ <h2>Other options</h2>
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-label>Enter duration</mat-label>
<input matInput [(ngModel)]="config.enterAnimationDuration">
</mat-form-field>
<mat-form-field>
<mat-label>Exit duration</mat-label>
<input matInput [(ngModel)]="config.exitAnimationDuration">
</mat-form-field>
</p>

<p>
<mat-checkbox [(ngModel)]="config.disableClose">Disable close</mat-checkbox>
</p>
Expand Down
2 changes: 2 additions & 0 deletions src/dev-app/dialog/dialog-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export class DialogDemo {
height: '',
minWidth: '',
minHeight: '',
enterAnimationDuration: defaultDialogConfig.enterAnimationDuration,
exitAnimationDuration: defaultDialogConfig.exitAnimationDuration,
maxWidth: defaultDialogConfig.maxWidth,
maxHeight: '',
position: {
Expand Down
7 changes: 5 additions & 2 deletions src/material/dialog/dialog-animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,17 @@ export const matDialogAnimations: {
transition(
'* => enter',
group([
animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({transform: 'none', opacity: 1})),
animate(
'{{enterAnimationDuration}} cubic-bezier(0, 0, 0.2, 1)',
style({transform: 'none', opacity: 1}),
),
query('@*', animateChild(), {optional: true}),
]),
),
transition(
'* => void, * => exit',
group([
animate('75ms cubic-bezier(0.4, 0.0, 0.2, 1)', style({opacity: 0})),
animate('{{exitAnimationDuration}} cubic-bezier(0.4, 0.0, 0.2, 1)', style({opacity: 0})),
query('@*', animateChild(), {optional: true}),
]),
),
Expand Down
6 changes: 6 additions & 0 deletions src/material/dialog/dialog-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,11 @@ export class MatDialogConfig<D = any> {
/** Alternate `ComponentFactoryResolver` to use when resolving the associated component. */
componentFactoryResolver?: ComponentFactoryResolver;

/** Duration of the enter animation. Has to be a valid CSS value (e.g. 100ms). */
enterAnimationDuration?: string = '150ms';

/** Duration of the exit animation. Has to be a valid CSS value (e.g. 50ms). */
exitAnimationDuration?: string = '75ms';

// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
}
12 changes: 11 additions & 1 deletion src/material/dialog/dialog-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet {
'[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledBy',
'[attr.aria-label]': '_config.ariaLabel',
'[attr.aria-describedby]': '_config.ariaDescribedBy || null',
'[@dialogContainer]': '_state',
'[@dialogContainer]': `_getAnimationState()`,
'(@dialogContainer.start)': '_onAnimationStart($event)',
'(@dialogContainer.done)': '_onAnimationDone($event)',
},
Expand Down Expand Up @@ -360,4 +360,14 @@ export class MatDialogContainer extends _MatDialogContainerBase {
this._trapFocus();
}
}

_getAnimationState() {
return {
value: this._state,
params: {
enterAnimationDuration: this._config.enterAnimationDuration || '150ms',
exitAnimationDuration: this._config.exitAnimationDuration || '75ms',
},
};
}
}
38 changes: 38 additions & 0 deletions src/material/dialog/dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,44 @@ You can control which elements are tab stops with the `tabindex` attribute

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

### Configuring dialog content via `entryComponents`

Because `MatDialog` instantiates components at run-time, the Angular compiler needs extra
information to create the necessary `ComponentFactory` for your dialog content component.

For any component loaded into a dialog, you must include your component class in the list of
`entryComponents` in your NgModule definition so that the Angular compiler knows to create
the `ComponentFactory` for it.

```ts
@NgModule({
imports: [
// ...
MatDialogModule
],

declarations: [
AppComponent,
ExampleDialogComponent
],

entryComponents: [
ExampleDialogComponent
],

providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
```

### Controlling the dialog animation
You can control the duration of the dialog's enter and exit animations using the
`enterAnimationDuration` and `exitAnimationDuration` options. If you want to disable the dialog's
animation completely, you can do so by setting the properties to `0ms`.

<!-- example(dialog-animations) -->

### Accessibility

`MatDialog` creates modal dialogs that implements the ARIA `role="dialog"` pattern by default.
Expand Down
2 changes: 2 additions & 0 deletions src/material/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,8 @@ describe('MatDialog with default options', () => {
minHeight: '50px',
maxWidth: '150px',
maxHeight: '150px',
enterAnimationDuration: '100ms',
exitAnimationDuration: '50ms',
autoFocus: false,
};

Expand Down
10 changes: 10 additions & 0 deletions tools/public_api_guard/material/dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ export class MatDialogConfig<D = any> {
delayFocusTrap?: boolean;
direction?: Direction;
disableClose?: boolean;
enterAnimationDuration?: string;
exitAnimationDuration?: string;
hasBackdrop?: boolean;
height?: string;
id?: string;
Expand All @@ -186,6 +188,14 @@ export class MatDialogConfig<D = any> {

// @public
export class MatDialogContainer extends _MatDialogContainerBase {
// (undocumented)
_getAnimationState(): {
value: "enter" | "void" | "exit";
params: {
enterAnimationDuration: string;
exitAnimationDuration: string;
};
};
// (undocumented)
_initializeWithAttachedContent(): void;
_onAnimationDone({ toState, totalTime }: AnimationEvent_2): void;
Expand Down

0 comments on commit 8ef3125

Please sign in to comment.