mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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:
committed by
Andrew Seguin
parent
959804b26b
commit
1e2b79af82
@@ -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. */
|
||||
|
||||
@@ -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}),
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}))
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user