fix(expansion-panel,menu,select): nested animations not working (#9134)

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.
Fixes #8953.
This commit is contained in:
Kristiyan Kostadinov
2018-02-20 19:21:42 +01:00
committed by Andrew Seguin
parent 959804b26b
commit 1e2b79af82
6 changed files with 48 additions and 31 deletions
+7 -1
View File
@@ -7,10 +7,13 @@
*/
import {
animate,
animateChild,
group,
state,
style,
transition,
trigger,
query,
AnimationTriggerMetadata,
} from '@angular/animations';
@@ -42,7 +45,10 @@ export const matExpansionAnimations: {
}), {
params: {expandedHeight: '64px'}
}),
transition('expanded <=> collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)),
transition('expanded <=> collapsed', group([
query('@indicatorRotate', animateChild(), {optional: true}),
animate(EXPANSION_PANEL_ANIMATION_TIMING),
])),
]),
/** Animation that expands and collapses the panel content. */
+15 -10
View File
@@ -12,6 +12,9 @@ import{
style,
animate,
transition,
query,
group,
sequence,
AnimationTriggerMetadata,
} from '@angular/animations';
@@ -33,22 +36,22 @@ export const matMenuAnimations: {
* delay to display the ripple.
*/
transformMenu: trigger('transformMenu', [
// TODO(kara): switch to :enter and :leave once Mobile Safari is sorted out.
state('void', style({
opacity: 0,
// This starts off from 0.01, instead of 0, because there's an issue in the Angular animations
// as of 4.2, which causes the animation to be skipped if it starts from 0.
transform: 'scale(0.01, 0.01)'
})),
state('enter-start', style({
opacity: 1,
transform: 'scale(1, 0.5)'
})),
state('enter', style({
transform: 'scale(1, 1)'
})),
transition('void => enter-start', animate('100ms linear')),
transition('enter-start => enter', animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)')),
transition('void => enter', sequence([
query('.mat-menu-content', style({opacity: 0})),
animate('100ms linear', style({opacity: 1, transform: 'scale(1, 0.5)'})),
group([
query('.mat-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
style({opacity: 1})
)),
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({transform: 'scale(1, 1)'})),
])
])),
transition('* => void', animate('150ms 50ms linear', style({opacity: 0})))
]),
@@ -58,6 +61,8 @@ export const matMenuAnimations: {
* after its containing element is scaled in.
*/
fadeInItems: trigger('fadeInItems', [
// TODO(crisbeto): this is inside the `transformMenu`
// now. Remove next time we do breaking changes.
state('showing', style({opacity: 1})),
transition('void => *', [
style({opacity: 0}),
+12 -9
View File
@@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationEvent} from '@angular/animations';
import {FocusKeyManager} from '@angular/cdk/a11y';
import {Direction} from '@angular/cdk/bidi';
import {ESCAPE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes';
@@ -31,6 +30,7 @@ import {
ViewChild,
ViewEncapsulation,
NgZone,
OnInit,
} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {merge} from 'rxjs/observable/merge';
@@ -82,7 +82,7 @@ const MAT_MENU_BASE_ELEVATION = 2;
],
exportAs: 'matMenu'
})
export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestroy {
private _keyManager: FocusKeyManager<MatMenuItem>;
private _xPosition: MenuPositionX = this._defaultOptions.xPosition;
private _yPosition: MenuPositionY = this._defaultOptions.yPosition;
@@ -95,7 +95,7 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
_classList: {[key: string]: boolean} = {};
/** Current state of the panel animation. */
_panelAnimationState: 'void' | 'enter-start' | 'enter' = 'void';
_panelAnimationState: 'void' | 'enter' = 'void';
/** Parent menu of the current menu panel. */
parentMenu: MatMenuPanel | undefined;
@@ -191,6 +191,10 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
private _ngZone: NgZone,
@Inject(MAT_MENU_DEFAULT_OPTIONS) private _defaultOptions: MatMenuDefaultOptions) { }
ngOnInit() {
this.setPositionClasses();
}
ngAfterContentInit() {
this._keyManager = new FocusKeyManager<MatMenuItem>(this.items).withWrap().withTypeAhead();
this._tabSubscription = this._keyManager.tabOut.subscribe(() => this.close.emit('keydown'));
@@ -292,19 +296,18 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
/** Starts the enter animation. */
_startAnimation() {
this._panelAnimationState = 'enter-start';
// @deletion-target 6.0.0 Combine with _resetAnimation.
this._panelAnimationState = 'enter';
}
/** Resets the panel animation to its initial state. */
_resetAnimation() {
// @deletion-target 6.0.0 Combine with _startAnimation.
this._panelAnimationState = 'void';
}
/** Callback that is invoked when the panel animation completes. */
_onAnimationDone(event: AnimationEvent) {
// After the initial expansion is done, trigger the second phase of the enter animation.
if (event.toState === 'enter-start') {
this._panelAnimationState = 'enter';
}
_onAnimationDone(_event: AnimationEvent) {
// @deletion-target 6.0.0 Not being used anymore. To be removed.
}
}
+1 -2
View File
@@ -5,10 +5,9 @@
(keydown)="_handleKeydown($event)"
(click)="closed.emit('click')"
[@transformMenu]="_panelAnimationState"
(@transformMenu.done)="_onAnimationDone($event)"
tabindex="-1"
role="menu">
<div class="mat-menu-content" [@fadeInItems]="'showing'">
<div class="mat-menu-content">
<ng-content></ng-content>
</div>
</div>
+7 -7
View File
@@ -16,13 +16,6 @@ $mat-menu-submenu-indicator-size: 10px !default;
border-radius: $mat-menu-border-radius;
outline: 0;
// Prevent the user from interacting while the panel is still animating.
// This avoids issues where the user could accidentally open a sub-menu,
// because of the `overlapTrigger` option.
&.ng-animating {
pointer-events: none;
}
@include cdk-high-contrast {
outline: solid 1px;
}
@@ -70,6 +63,13 @@ $mat-menu-submenu-indicator-size: 10px !default;
transform: rotateY(180deg) translateY(-50%);
}
}
// Prevent the user from interacting while the panel is still animating.
// This avoids issues where the user could accidentally open a sub-menu,
// because of the `overlapTrigger` option.
.mat-menu-panel.ng-animating & {
pointer-events: none;
}
}
button.mat-menu-item {
+6 -2
View File
@@ -13,6 +13,9 @@ import {
style,
transition,
trigger,
query,
animateChild,
group,
} from '@angular/animations';
/**
@@ -45,14 +48,15 @@ export const matSelectAnimations: {
minWidth: 'calc(100% + 64px)', // 64px = 48px padding on the left + 16px padding on the right
transform: 'scaleY(1)'
})),
transition('void => *', [
transition('void => *', group([
query('@fadeInContent', animateChild()),
style({
opacity: 0,
minWidth: '100%',
transform: 'scaleY(0)'
}),
animate('150ms cubic-bezier(0.25, 0.8, 0.25, 1)')
]),
])),
transition('* => void', [
animate('250ms 100ms linear', style({opacity: 0}))
])