From c140638d4b932fd317f02dd058dbe84a8989011f Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 2 Dec 2017 20:48:12 +0100 Subject: [PATCH] fix(expansion-panel): expand animation jumping Fixes the expansion panel jumping towards the end of the animation due to the overflow going from `visible` to `hidden`. --- src/lib/expansion/expansion-panel.html | 7 +++++-- src/lib/expansion/expansion-panel.scss | 8 +++----- src/lib/expansion/expansion-panel.ts | 17 +++++++++++++++++ src/lib/expansion/expansion.spec.ts | 21 ++++++++++++--------- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/lib/expansion/expansion-panel.html b/src/lib/expansion/expansion-panel.html index de6e62ed0000..7b1f7ccdc645 100644 --- a/src/lib/expansion/expansion-panel.html +++ b/src/lib/expansion/expansion-panel.html @@ -1,10 +1,13 @@
+ #body>
diff --git a/src/lib/expansion/expansion-panel.scss b/src/lib/expansion/expansion-panel.scss index c242181478ee..5dd26f80b2ab 100644 --- a/src/lib/expansion/expansion-panel.scss +++ b/src/lib/expansion/expansion-panel.scss @@ -11,12 +11,10 @@ } .mat-expansion-panel-content { - .mat-expanded & { - overflow: visible; - } + overflow: hidden; - &, &.ng-animating { - overflow: hidden; + &.mat-expanded { + overflow: visible; } } diff --git a/src/lib/expansion/expansion-panel.ts b/src/lib/expansion/expansion-panel.ts index 45e8be1468ab..960e47270351 100644 --- a/src/lib/expansion/expansion-panel.ts +++ b/src/lib/expansion/expansion-panel.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {AnimationEvent} from '@angular/animations'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -139,6 +140,22 @@ export class MatExpansionPanel extends CdkAccordionItem super.ngOnDestroy(); this._inputChanges.complete(); } + + _bodyAnimation(event: AnimationEvent) { + const classList = event.element.classList; + const cssClass = 'mat-expanded'; + const {phaseName, toState} = event; + + // Toggle the body's `overflow: hidden` class when closing starts or when expansion ends in + // order to prevent the cases where switching too early would cause the animation to jump. + // Note that we do it directly on the DOM element to avoid the slight delay that comes + // with doing it via change detection. + if (phaseName === 'done' && toState === 'expanded') { + classList.add(cssClass); + } else if (phaseName === 'start' && toState === 'collapsed') { + classList.remove(cssClass); + } + } } @Directive({ diff --git a/src/lib/expansion/expansion.spec.ts b/src/lib/expansion/expansion.spec.ts index 29a279fa651f..f2017beaf9e9 100644 --- a/src/lib/expansion/expansion.spec.ts +++ b/src/lib/expansion/expansion.spec.ts @@ -1,4 +1,4 @@ -import {async, TestBed, fakeAsync, tick, ComponentFixture} from '@angular/core/testing'; +import {async, TestBed, fakeAsync, tick, ComponentFixture, flush} from '@angular/core/testing'; import {Component, ViewChild} from '@angular/core'; import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -26,19 +26,22 @@ describe('MatExpansionPanel', () => { TestBed.compileComponents(); })); - it('should expand and collapse the panel', () => { + it('should expand and collapse the panel', fakeAsync(() => { const fixture = TestBed.createComponent(PanelWithContent); - const contentEl = fixture.debugElement.query(By.css('.mat-expansion-panel-content')); - const headerEl = fixture.debugElement.query(By.css('.mat-expansion-panel-header')); + const contentEl = fixture.nativeElement.querySelector('.mat-expansion-panel-content'); + const headerEl = fixture.nativeElement.querySelector('.mat-expansion-panel-header'); fixture.detectChanges(); - expect(headerEl.classes['mat-expanded']).toBeFalsy(); - expect(contentEl.classes['mat-expanded']).toBeFalsy(); + + expect(headerEl.classList).not.toContain('mat-expanded'); + expect(contentEl.classList).not.toContain('mat-expanded'); fixture.componentInstance.expanded = true; fixture.detectChanges(); - expect(headerEl.classes['mat-expanded']).toBeTruthy(); - expect(contentEl.classes['mat-expanded']).toBeTruthy(); - }); + flush(); + + expect(headerEl.classList).toContain('mat-expanded'); + expect(contentEl.classList).toContain('mat-expanded'); + })); it('should be able to render panel content lazily', fakeAsync(() => { let fixture = TestBed.createComponent(LazyPanelWithContent);