66 * found in the LICENSE file at https://angular.dev/license
77 */
88
9- import { AnimationEvent } from '@angular/animations' ;
109import { CdkDialogContainer } from '@angular/cdk/dialog' ;
1110import { BreakpointObserver , Breakpoints } from '@angular/cdk/layout' ;
1211import {
12+ ANIMATION_MODULE_TYPE ,
1313 ChangeDetectionStrategy ,
1414 Component ,
1515 EventEmitter ,
@@ -18,9 +18,11 @@ import {
1818 inject ,
1919} from '@angular/core' ;
2020import { Subscription } from 'rxjs' ;
21- import { matBottomSheetAnimations } from './bottom-sheet-animations' ;
2221import { CdkPortalOutlet } from '@angular/cdk/portal' ;
2322
23+ const ENTER_ANIMATION = '_mat-bottom-sheet-enter' ;
24+ const EXIT_ANIMATION = '_mat-bottom-sheet-exit' ;
25+
2426/**
2527 * Internal component that wraps user-provided bottom sheet content.
2628 * @docs -private
@@ -35,27 +37,34 @@ import {CdkPortalOutlet} from '@angular/cdk/portal';
3537 // tslint:disable-next-line:validate-decorators
3638 changeDetection : ChangeDetectionStrategy . Default ,
3739 encapsulation : ViewEncapsulation . None ,
38- animations : [ matBottomSheetAnimations . bottomSheetState ] ,
3940 host : {
4041 'class' : 'mat-bottom-sheet-container' ,
42+ '[class.mat-bottom-sheet-container-animations-enabled]' : '!_animationsDisabled' ,
43+ '[class.mat-bottom-sheet-container-enter]' : '_animationState === "visible"' ,
44+ '[class.mat-bottom-sheet-container-exit]' : '_animationState === "hidden"' ,
4145 'tabindex' : '-1' ,
4246 '[attr.role]' : '_config.role' ,
4347 '[attr.aria-modal]' : '_config.ariaModal' ,
4448 '[attr.aria-label]' : '_config.ariaLabel' ,
45- '[@state] ' : '_animationState ' ,
46- '(@state.start )' : '_onAnimationStart( $event)' ,
47- '(@state.done )' : '_onAnimationDone( $event)' ,
49+ '(animationstart) ' : '_handleAnimationEvent(true, $event.animationName) ' ,
50+ '(animationend )' : '_handleAnimationEvent(false, $event.animationName )' ,
51+ '(animationcancel )' : '_handleAnimationEvent(false, $event.animationName )' ,
4852 } ,
4953 imports : [ CdkPortalOutlet ] ,
5054} )
5155export class MatBottomSheetContainer extends CdkDialogContainer implements OnDestroy {
5256 private _breakpointSubscription : Subscription ;
57+ protected _animationsDisabled =
58+ inject ( ANIMATION_MODULE_TYPE , { optional : true } ) === 'NoopAnimations' ;
5359
5460 /** The state of the bottom sheet animations. */
5561 _animationState : 'void' | 'visible' | 'hidden' = 'void' ;
5662
5763 /** Emits whenever the state of the animation changes. */
58- _animationStateChanged = new EventEmitter < AnimationEvent > ( ) ;
64+ _animationStateChanged = new EventEmitter < {
65+ toState : 'visible' | 'hidden' ;
66+ phase : 'start' | 'done' ;
67+ } > ( ) ;
5968
6069 /** Whether the component has been destroyed. */
6170 private _destroyed : boolean ;
@@ -93,14 +102,21 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
93102 this . _animationState = 'visible' ;
94103 this . _changeDetectorRef . markForCheck ( ) ;
95104 this . _changeDetectorRef . detectChanges ( ) ;
105+ if ( this . _animationsDisabled ) {
106+ this . _simulateAnimation ( ENTER_ANIMATION ) ;
107+ }
96108 }
97109 }
98110
99111 /** Begin animation of the bottom sheet exiting from view. */
100112 exit ( ) : void {
101113 if ( ! this . _destroyed ) {
114+ this . _elementRef . nativeElement . setAttribute ( 'mat-exit' , '' ) ;
102115 this . _animationState = 'hidden' ;
103116 this . _changeDetectorRef . markForCheck ( ) ;
117+ if ( this . _animationsDisabled ) {
118+ this . _simulateAnimation ( EXIT_ANIMATION ) ;
119+ }
104120 }
105121 }
106122
@@ -110,16 +126,27 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
110126 this . _destroyed = true ;
111127 }
112128
113- _onAnimationDone ( event : AnimationEvent ) {
114- if ( event . toState === 'visible' ) {
129+ private _simulateAnimation ( name : typeof ENTER_ANIMATION | typeof EXIT_ANIMATION ) {
130+ this . _ngZone . run ( ( ) => {
131+ this . _handleAnimationEvent ( true , name ) ;
132+ setTimeout ( ( ) => this . _handleAnimationEvent ( false , name ) ) ;
133+ } ) ;
134+ }
135+
136+ protected _handleAnimationEvent ( isStart : boolean , animationName : string ) {
137+ const isEnter = animationName === ENTER_ANIMATION ;
138+ const isExit = animationName === EXIT_ANIMATION ;
139+
140+ if ( isEnter ) {
115141 this . _trapFocus ( ) ;
116142 }
117143
118- this . _animationStateChanged . emit ( event ) ;
119- }
120-
121- _onAnimationStart ( event : AnimationEvent ) {
122- this . _animationStateChanged . emit ( event ) ;
144+ if ( isEnter || isExit ) {
145+ this . _animationStateChanged . emit ( {
146+ toState : isEnter ? 'visible' : 'hidden' ,
147+ phase : isStart ? 'start' : 'done' ,
148+ } ) ;
149+ }
123150 }
124151
125152 protected override _captureInitialFocus ( ) : void { }
0 commit comments