From 4cdc0956f9bafcbf36dded49c076c4b2b9a9ff6c Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 29 Aug 2022 13:19:07 -0700 Subject: [PATCH] fix(material/dialog): allow customizing animation duration (#25524) * fix(material/dialog): allow customizing animation duration BREAKING CHANGE: - Passing strings for MatDialogConfig.enterAnimationDuration and MatDialogConfig.exitAnimationDuration is deprecated, pass numbers in ms instead * deprecate the string animation durations in favor of numbers --- src/material/dialog/dialog-animations.ts | 6 +-- src/material/dialog/dialog-config.ts | 18 ++++++--- src/material/dialog/dialog-container.ts | 40 ++++++++++++++++++- src/material/dialog/dialog.scss | 4 ++ src/material/dialog/dialog.ts | 3 +- src/material/dialog/public-api.ts | 2 +- src/material/legacy-dialog/dialog-config.ts | 17 ++++++++ .../legacy-dialog/dialog-container.ts | 9 ++--- src/material/legacy-dialog/dialog.ts | 9 +++-- src/material/legacy-dialog/public-api.ts | 2 +- tools/public_api_guard/material/dialog.md | 14 ++++++- .../material/legacy-dialog.md | 14 +++++-- 12 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 src/material/legacy-dialog/dialog-config.ts diff --git a/src/material/dialog/dialog-animations.ts b/src/material/dialog/dialog-animations.ts index f1bf8f03e25d..97f0f516971c 100644 --- a/src/material/dialog/dialog-animations.ts +++ b/src/material/dialog/dialog-animations.ts @@ -21,7 +21,7 @@ import { * Default parameters for the animation for backwards compatibility. * @docs-private */ -export const defaultParams = { +export const _defaultParams = { params: {enterAnimationDuration: '150ms', exitAnimationDuration: '75ms'}, }; @@ -48,7 +48,7 @@ export const matDialogAnimations: { ), query('@*', animateChild(), {optional: true}), ]), - defaultParams, + _defaultParams, ), transition( '* => void, * => exit', @@ -56,7 +56,7 @@ export const matDialogAnimations: { animate('{{exitAnimationDuration}} cubic-bezier(0.4, 0.0, 0.2, 1)', style({opacity: 0})), query('@*', animateChild(), {optional: true}), ]), - defaultParams, + _defaultParams, ), ]), }; diff --git a/src/material/dialog/dialog-config.ts b/src/material/dialog/dialog-config.ts index b0709eb26466..e4f1f378af7e 100644 --- a/src/material/dialog/dialog-config.ts +++ b/src/material/dialog/dialog-config.ts @@ -9,7 +9,7 @@ import {ViewContainerRef, ComponentFactoryResolver, Injector} from '@angular/core'; import {Direction} from '@angular/cdk/bidi'; import {ScrollStrategy} from '@angular/cdk/overlay'; -import {defaultParams} from './dialog-animations'; +import {_defaultParams} from './dialog-animations'; /** Options for where to set focus to automatically on dialog open */ export type AutoFocusTarget = 'dialog' | 'first-tabbable' | 'first-heading'; @@ -133,11 +133,19 @@ export class MatDialogConfig { /** 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 = defaultParams.params.enterAnimationDuration; + /** + * Duration of the enter animation in ms. + * Should be a number, string type is deprecated. + * @breaking-change 17.0.0 Remove string signature. + */ + enterAnimationDuration?: string | number; - /** Duration of the exit animation. Has to be a valid CSS value (e.g. 50ms). */ - exitAnimationDuration?: string = defaultParams.params.exitAnimationDuration; + /** + * Duration of the exit animation in ms. + * Should be a number, string type is deprecated. + * @breaking-change 17.0.0 Remove string signature. + */ + exitAnimationDuration?: string | number; // TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling. } diff --git a/src/material/dialog/dialog-container.ts b/src/material/dialog/dialog-container.ts index 9ac5179a5832..44426db57c98 100644 --- a/src/material/dialog/dialog-container.ts +++ b/src/material/dialog/dialog-container.ts @@ -24,6 +24,7 @@ import {MatDialogConfig} from './dialog-config'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {cssClasses, numbers} from '@material/dialog'; import {CdkDialogContainer} from '@angular/cdk/dialog'; +import {coerceNumberProperty} from '@angular/cdk/coercion'; /** Event that captures the state of dialog container animations. */ interface LegacyDialogAnimationEvent { @@ -85,6 +86,33 @@ export abstract class _MatDialogContainerBase extends CdkDialogContainer implemen private _scrollStrategy: () => ScrollStrategy; protected _idPrefix = 'mat-dialog-'; private _dialog: Dialog; + protected dialogConfigClass = MatDialogConfig; /** Keeps track of the currently-open dialogs. */ get openDialogs(): MatDialogRef[] { @@ -175,7 +176,7 @@ export abstract class _MatDialogBase implemen // Provide our config as the CDK config as well since it has the same interface as the // CDK one, but it contains the actual values passed in by the user for things like // `disableClose` which we disable for the CDK dialog since we handle it ourselves. - {provide: MatDialogConfig, useValue: config}, + {provide: this.dialogConfigClass, useValue: config}, {provide: DialogConfig, useValue: config}, ], }, diff --git a/src/material/dialog/public-api.ts b/src/material/dialog/public-api.ts index 35273a8bcc3e..6ae392a95278 100644 --- a/src/material/dialog/public-api.ts +++ b/src/material/dialog/public-api.ts @@ -12,4 +12,4 @@ export * from './dialog-ref'; export * from './dialog-content-directives'; export * from './dialog-container'; export * from './module'; -export {matDialogAnimations} from './dialog-animations'; +export {matDialogAnimations, _defaultParams} from './dialog-animations'; diff --git a/src/material/legacy-dialog/dialog-config.ts b/src/material/legacy-dialog/dialog-config.ts new file mode 100644 index 000000000000..2457a3ce4884 --- /dev/null +++ b/src/material/legacy-dialog/dialog-config.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {MatDialogConfig as DialogConfigBase, _defaultParams} from '@angular/material/dialog'; + +export class MatLegacyDialogConfig extends DialogConfigBase { + /** Duration of the enter animation. Has to be a valid CSS value (e.g. 100ms). */ + override enterAnimationDuration?: string = _defaultParams.params.enterAnimationDuration; + + /** Duration of the exit animation. Has to be a valid CSS value (e.g. 50ms). */ + override exitAnimationDuration?: string = _defaultParams.params.exitAnimationDuration; +} diff --git a/src/material/legacy-dialog/dialog-container.ts b/src/material/legacy-dialog/dialog-container.ts index c6d2e87134c1..39d0e04bd41d 100644 --- a/src/material/legacy-dialog/dialog-container.ts +++ b/src/material/legacy-dialog/dialog-container.ts @@ -21,11 +21,8 @@ import { ViewEncapsulation, } from '@angular/core'; import {defaultParams} from './dialog-animations'; -import { - _MatDialogContainerBase, - MatDialogConfig, - matDialogAnimations, -} from '@angular/material/dialog'; +import {MatLegacyDialogConfig} from './dialog-config'; +import {_MatDialogContainerBase, matDialogAnimations} from '@angular/material/dialog'; /** * Internal component that wraps user-provided dialog content. @@ -90,7 +87,7 @@ export class MatLegacyDialogContainer extends _MatDialogContainerBase { elementRef: ElementRef, focusTrapFactory: FocusTrapFactory, @Optional() @Inject(DOCUMENT) document: any, - dialogConfig: MatDialogConfig, + dialogConfig: MatLegacyDialogConfig, checker: InteractivityChecker, ngZone: NgZone, overlayRef: OverlayRef, diff --git a/src/material/legacy-dialog/dialog.ts b/src/material/legacy-dialog/dialog.ts index 2b391ee990c8..6f09f0274ed9 100644 --- a/src/material/legacy-dialog/dialog.ts +++ b/src/material/legacy-dialog/dialog.ts @@ -11,14 +11,15 @@ import {Location} from '@angular/common'; import {Inject, Injectable, InjectionToken, Injector, Optional, SkipSelf} from '@angular/core'; import {MatLegacyDialogContainer} from './dialog-container'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; -import {_MatDialogBase, MatDialogConfig} from '@angular/material/dialog'; +import {_MatDialogBase} from '@angular/material/dialog'; import {MatLegacyDialogRef} from './dialog-ref'; +import {MatLegacyDialogConfig} from './dialog-config'; /** Injection token that can be used to access the data that was passed in to a dialog. */ export const MAT_LEGACY_DIALOG_DATA = new InjectionToken('MatDialogData'); /** Injection token that can be used to specify default dialog options. */ -export const MAT_LEGACY_DIALOG_DEFAULT_OPTIONS = new InjectionToken( +export const MAT_LEGACY_DIALOG_DEFAULT_OPTIONS = new InjectionToken( 'mat-dialog-default-options', ); @@ -46,6 +47,8 @@ export const MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER = { */ @Injectable() export class MatLegacyDialog extends _MatDialogBase { + protected override dialogConfigClass = MatLegacyDialogConfig; + constructor( overlay: Overlay, injector: Injector, @@ -54,7 +57,7 @@ export class MatLegacyDialog extends _MatDialogBase { * @breaking-change 10.0.0 */ @Optional() _location: Location, - @Optional() @Inject(MAT_LEGACY_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatDialogConfig, + @Optional() @Inject(MAT_LEGACY_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatLegacyDialogConfig, @Inject(MAT_LEGACY_DIALOG_SCROLL_STRATEGY) scrollStrategy: any, @Optional() @SkipSelf() parentDialog: MatLegacyDialog, /** diff --git a/src/material/legacy-dialog/public-api.ts b/src/material/legacy-dialog/public-api.ts index c8d2989c8c80..43ae5c39b463 100644 --- a/src/material/legacy-dialog/public-api.ts +++ b/src/material/legacy-dialog/public-api.ts @@ -11,13 +11,13 @@ export * from './dialog'; export * from './dialog-container'; export * from './dialog-content-directives'; export * from './dialog-ref'; +export * from './dialog-config'; export { _MatDialogBase as _MatLegacyDialogBase, _MatDialogContainerBase as _MatLegacyDialogContainerBase, AutoFocusTarget as LegacyAutoFocusTarget, DialogRole as LegacyDialogRole, DialogPosition as LegacyDialogPosition, - MatDialogConfig as MatLegacyDialogConfig, _closeDialogVia as _closeLegacyDialogVia, MatDialogState as MatLegacyDialogState, matDialogAnimations as matLegacyDialogAnimations, diff --git a/tools/public_api_guard/material/dialog.md b/tools/public_api_guard/material/dialog.md index a4c5d2b42336..d8b3be82873d 100644 --- a/tools/public_api_guard/material/dialog.md +++ b/tools/public_api_guard/material/dialog.md @@ -45,6 +45,14 @@ export type AutoFocusTarget = 'dialog' | 'first-tabbable' | 'first-heading'; // @public export function _closeDialogVia(ref: MatDialogRef, interactionType: FocusOrigin, result?: R): void; +// @public +export const _defaultParams: { + params: { + enterAnimationDuration: string; + exitAnimationDuration: string; + }; +}; + // @public export interface DialogPosition { bottom?: string; @@ -112,6 +120,8 @@ export abstract class _MatDialogBase implemen readonly afterAllClosed: Observable; get afterOpened(): Subject>; closeAll(): void; + // (undocumented) + protected dialogConfigClass: typeof MatDialogConfig; getDialogById(id: string): MatDialogRef | undefined; // (undocumented) protected _idPrefix: string; @@ -163,8 +173,8 @@ export class MatDialogConfig { delayFocusTrap?: boolean; direction?: Direction; disableClose?: boolean; - enterAnimationDuration?: string; - exitAnimationDuration?: string; + enterAnimationDuration?: string | number; + exitAnimationDuration?: string | number; hasBackdrop?: boolean; height?: string; id?: string; diff --git a/tools/public_api_guard/material/legacy-dialog.md b/tools/public_api_guard/material/legacy-dialog.md index 4ab5315f2ec8..e1f309bec971 100644 --- a/tools/public_api_guard/material/legacy-dialog.md +++ b/tools/public_api_guard/material/legacy-dialog.md @@ -23,10 +23,10 @@ import { DialogPosition as LegacyDialogPosition } from '@angular/material/dialog import { DialogRole as LegacyDialogRole } from '@angular/material/dialog'; import { Location as Location_2 } from '@angular/common'; import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY as MAT_LEGACY_DIALOG_SCROLL_STRATEGY_FACTORY } from '@angular/material/dialog'; +import { MatDialogConfig } from '@angular/material/dialog'; import { MatDialogRef } from '@angular/material/dialog'; import { matDialogAnimations as matLegacyDialogAnimations } from '@angular/material/dialog'; import { _MatDialogBase as _MatLegacyDialogBase } from '@angular/material/dialog'; -import { MatDialogConfig as MatLegacyDialogConfig } from '@angular/material/dialog'; import { _MatDialogContainerBase as _MatLegacyDialogContainerBase } from '@angular/material/dialog'; import { MatDialogState as MatLegacyDialogState } from '@angular/material/dialog'; import { NgZone } from '@angular/core'; @@ -74,6 +74,8 @@ export class MatLegacyDialog extends _MatLegacyDialogBase; // (undocumented) static ɵprov: i0.ɵɵInjectableDeclaration; @@ -115,7 +117,11 @@ export class MatLegacyDialogClose implements OnInit, OnChanges { static ɵfac: i0.ɵɵFactoryDeclaration; } -export { MatLegacyDialogConfig } +// @public (undocumented) +export class MatLegacyDialogConfig extends MatDialogConfig { + enterAnimationDuration?: string; + exitAnimationDuration?: string; +} // @public export class MatLegacyDialogContainer extends _MatLegacyDialogContainerBase { @@ -124,8 +130,8 @@ export class MatLegacyDialogContainer extends _MatLegacyDialogContainerBase { _getAnimationState(): { value: "void" | "enter" | "exit"; params: { - enterAnimationDuration: string; - exitAnimationDuration: string; + enterAnimationDuration: string | number; + exitAnimationDuration: string | number; }; }; _onAnimationDone({ toState, totalTime }: AnimationEvent_2): void;