Skip to content

Commit 4b79804

Browse files
committed
fix(expansion-panel,menu,select): nested animations not working
Fixes issues with the expansion panel, menu and select animations where the child animations were being blocked by the parent ones. **Note:** the menu animations needed a bit more refactoring since the old approach wasn't very idiomatic and made it harder to run the parallel animations. Fixes #8814, #8953.
1 parent c3d7cd9 commit 4b79804

File tree

6 files changed

+52
-36
lines changed

6 files changed

+52
-36
lines changed

src/lib/expansion/expansion-panel-header.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {animate, state, style, transition, trigger} from '@angular/animations';
9+
import {
10+
animate,
11+
state,
12+
style,
13+
transition,
14+
trigger,
15+
query,
16+
animateChild,
17+
group,
18+
} from '@angular/animations';
1019
import {FocusMonitor} from '@angular/cdk/a11y';
1120
import {ENTER, SPACE} from '@angular/cdk/keycodes';
1221
import {filter} from 'rxjs/operators/filter';
@@ -76,7 +85,10 @@ import {EXPANSION_PANEL_ANIMATION_TIMING, MatExpansionPanel} from './expansion-p
7685
}), {
7786
params: {expandedHeight: '64px'}
7887
}),
79-
transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)),
88+
transition('expanded <=> collapsed', group([
89+
query('@indicatorRotate', animateChild(), {optional: true}),
90+
animate(EXPANSION_PANEL_ANIMATION_TIMING),
91+
])),
8092
]),
8193
],
8294
})

src/lib/menu/menu-animations.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import{
1212
style,
1313
animate,
1414
transition,
15+
query,
16+
group,
17+
sequence,
1518
AnimationTriggerMetadata,
1619
} from '@angular/animations';
1720

@@ -39,24 +42,28 @@ export const transformMenu: AnimationTriggerMetadata = trigger('transformMenu',
3942
// as of 4.2, which causes the animation to be skipped if it starts from 0.
4043
transform: 'scale(0.01, 0.01)'
4144
})),
42-
state('enter-start', style({
43-
opacity: 1,
44-
transform: 'scale(1, 0.5)'
45-
})),
46-
state('enter', style({
47-
transform: 'scale(1, 1)'
48-
})),
49-
transition('void => enter-start', animate('100ms linear')),
50-
transition('enter-start => enter', animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)')),
45+
transition('void => enter', sequence([
46+
query('.mat-menu-content', style({opacity: 0})),
47+
animate('100ms linear', style({opacity: 1, transform: 'scale(1, 0.5)'})),
48+
group([
49+
query('.mat-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
50+
style({opacity: 1})
51+
)),
52+
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({transform: 'scale(1, 1)'})),
53+
])
54+
])),
5155
transition('* => void', animate('150ms 50ms linear', style({opacity: 0})))
5256
]);
5357

5458

5559
/**
5660
* This animation fades in the background color and content of the menu panel
5761
* after its containing element is scaled in.
62+
* @deprecated
5863
*/
5964
export const fadeInItems: AnimationTriggerMetadata = trigger('fadeInItems', [
65+
// TODO(crisbeto): this is inside the `transformMenu`
66+
// now. Remove next time we do breaking changes.
6067
state('showing', style({opacity: 1})),
6168
transition('void => *', [
6269
style({opacity: 0}),

src/lib/menu/menu-directive.ts

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {AnimationEvent} from '@angular/animations';
109
import {FocusKeyManager} from '@angular/cdk/a11y';
1110
import {Direction} from '@angular/cdk/bidi';
1211
import {ESCAPE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes';
@@ -30,6 +29,7 @@ import {
3029
ViewChild,
3130
ViewEncapsulation,
3231
NgZone,
32+
OnInit,
3333
} from '@angular/core';
3434
import {Observable} from 'rxjs/Observable';
3535
import {merge} from 'rxjs/observable/merge';
@@ -79,7 +79,7 @@ const MAT_MENU_BASE_ELEVATION = 2;
7979
],
8080
exportAs: 'matMenu'
8181
})
82-
export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
82+
export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestroy {
8383
private _keyManager: FocusKeyManager<MatMenuItem>;
8484
private _xPosition: MenuPositionX = this._defaultOptions.xPosition;
8585
private _yPosition: MenuPositionY = this._defaultOptions.yPosition;
@@ -92,7 +92,7 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
9292
_classList: {[key: string]: boolean} = {};
9393

9494
/** Current state of the panel animation. */
95-
_panelAnimationState: 'void' | 'enter-start' | 'enter' = 'void';
95+
_panelAnimationState: 'void' | 'enter' = 'void';
9696

9797
/** Parent menu of the current menu panel. */
9898
parentMenu: MatMenuPanel | undefined;
@@ -181,6 +181,10 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
181181
private _ngZone: NgZone,
182182
@Inject(MAT_MENU_DEFAULT_OPTIONS) private _defaultOptions: MatMenuDefaultOptions) { }
183183

184+
ngOnInit() {
185+
this.setPositionClasses();
186+
}
187+
184188
ngAfterContentInit() {
185189
this._keyManager = new FocusKeyManager<MatMenuItem>(this.items).withWrap().withTypeAhead();
186190
this._tabSubscription = this._keyManager.tabOut.subscribe(() => this.close.emit('keydown'));
@@ -273,21 +277,11 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
273277
}
274278
}
275279

276-
/** Starts the enter animation. */
277-
_startAnimation() {
278-
this._panelAnimationState = 'enter-start';
279-
}
280-
281-
/** Resets the panel animation to its initial state. */
282-
_resetAnimation() {
283-
this._panelAnimationState = 'void';
284-
}
285-
286-
/** Callback that is invoked when the panel animation completes. */
287-
_onAnimationDone(event: AnimationEvent) {
288-
// After the initial expansion is done, trigger the second phase of the enter animation.
289-
if (event.toState === 'enter-start') {
290-
this._panelAnimationState = 'enter';
291-
}
280+
/**
281+
* Toggles the animation state of the menu panel.
282+
* @param isOpen Whether the menu should be open.
283+
*/
284+
_toggleAnimation(isOpen: boolean) {
285+
this._panelAnimationState = isOpen ? 'enter' : 'void';
292286
}
293287
}

src/lib/menu/menu-trigger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
197197
this._initMenu();
198198

199199
if (this.menu instanceof MatMenu) {
200-
this.menu._startAnimation();
200+
this.menu._toggleAnimation(true);
201201
}
202202
}
203203
}
@@ -220,7 +220,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
220220
this._overlayRef.detach();
221221

222222
if (this.menu instanceof MatMenu) {
223-
this.menu._resetAnimation();
223+
this.menu._toggleAnimation(false);
224224
}
225225
}
226226
}

src/lib/menu/menu.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
(keydown)="_handleKeydown($event)"
66
(click)="closed.emit('click')"
77
[@transformMenu]="_panelAnimationState"
8-
(@transformMenu.done)="_onAnimationDone($event)"
98
tabindex="-1"
109
role="menu">
11-
<div class="mat-menu-content" [@fadeInItems]="'showing'">
10+
<div class="mat-menu-content">
1211
<ng-content></ng-content>
1312
</div>
1413
</div>

src/lib/select/select-animations.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import {
1313
style,
1414
transition,
1515
trigger,
16+
query,
17+
animateChild,
18+
group,
1619
} from '@angular/animations';
1720

1821
/**
@@ -42,14 +45,15 @@ export const transformPanel: AnimationTriggerMetadata = trigger('transformPanel'
4245
minWidth: 'calc(100% + 64px)', // 64px = 48px padding on the left + 16px padding on the right
4346
transform: 'scaleY(1)'
4447
})),
45-
transition('void => *', [
48+
transition('void => *', group([
49+
query('@fadeInContent', animateChild()),
4650
style({
4751
opacity: 0,
4852
minWidth: '100%',
4953
transform: 'scaleY(0)'
5054
}),
5155
animate('150ms cubic-bezier(0.25, 0.8, 0.25, 1)')
52-
]),
56+
])),
5357
transition('* => void', [
5458
animate('250ms 100ms linear', style({opacity: 0}))
5559
])

0 commit comments

Comments
 (0)