diff --git a/src/material/expansion/expansion-panel.html b/src/material/expansion/expansion-panel.html index 81b6153001fe..32f660e63840 100644 --- a/src/material/expansion/expansion-panel.html +++ b/src/material/expansion/expansion-panel.html @@ -1,11 +1,15 @@ -
+
diff --git a/src/material/expansion/expansion-panel.scss b/src/material/expansion/expansion-panel.scss index 7af49c54126b..fdd020424de5 100644 --- a/src/material/expansion/expansion-panel.scss +++ b/src/material/expansion/expansion-panel.scss @@ -62,6 +62,10 @@ } } +.mat-expansion-panel-hidden { + height: 0; +} + .mat-expansion-panel-body { padding: 0 24px 16px; } diff --git a/src/material/expansion/expansion-panel.ts b/src/material/expansion/expansion-panel.ts index 539366df4f7f..50446966345f 100644 --- a/src/material/expansion/expansion-panel.ts +++ b/src/material/expansion/expansion-panel.ts @@ -95,6 +95,7 @@ export const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS = '[class.mat-expanded]': 'expanded', '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"', '[class.mat-expansion-panel-spacing]': '_hasSpacing()', + '[@.disabled]': '_animationsDisabled', }, }) export class MatExpansionPanel @@ -150,6 +151,12 @@ export class MatExpansionPanel /** Stream of body animation done events. */ readonly _bodyAnimationDone = new Subject(); + /** Whether Angular animations in the panel body should be disabled. */ + _animationsDisabled = false; + + /** Whether panel body should be hidden. */ + _panelHidden = false; + constructor( @Optional() @SkipSelf() @Inject(MAT_ACCORDION) accordion: MatAccordionBase, _changeDetectorRef: ChangeDetectorRef, @@ -218,6 +225,9 @@ export class MatExpansionPanel ngAfterContentInit() { if (this._lazyContent && this._lazyContent._expansionPanel === this) { + this._panelHidden = !this.expanded; + this._animationsDisabled = !this.expanded; + // Render the content as soon as the panel becomes open. this.opened .pipe( @@ -227,6 +237,7 @@ export class MatExpansionPanel ) .subscribe(() => { this._portal = new TemplatePortal(this._lazyContent._template, this._viewContainerRef); + this._hidePanel(); }); } } @@ -251,6 +262,31 @@ export class MatExpansionPanel return false; } + + _animationStarted() { + // Currently the `bodyExpansion` animation has a `void => collapsed` transition which is + // there to work around a bug in Angular (see #13088), however this introduces a different + // issue. The new transition will cause to flicker in certain situations (see #22715), if the + // consumer has set a inner lazy-loaded expansion panel's header height that is different from the + // default one. + // Part of work around is to disable animations on the body and re-enabling them after the first animation has run. + // Ideally this wouldn't be necessary if we remove the `void => collapsed` transition, but we have + // to wait for https://github.com/angular/angular/issues/18847 to be resolved. + this._animationsDisabled = false; + } + + private _hidePanel(): void { + // Currently the `bodyExpansion` animation has a `void => collapsed` transition which is + // there to work around a bug in Angular (see #13088), however this introduces a different + // issue. The new transition will cause to flicker in certain situations (see #22715), if the + // consumer has set a inner lazy-loaded expansion panel's header height that is different from the + // default one. + // Part of work around is to set non-expanded panel's height to 0px with class on init + // so that outer expansion panel can calculate height of its body properly. + // Ideally this wouldn't be necessary if we remove the `void => collapsed` transition, but we have + // to wait for https://github.com/angular/angular/issues/18847 to be resolved. + this._panelHidden = false; + } } /** diff --git a/tools/public_api_guard/material/expansion.md b/tools/public_api_guard/material/expansion.md index 0782491f8e1e..0a206494a9c3 100644 --- a/tools/public_api_guard/material/expansion.md +++ b/tools/public_api_guard/material/expansion.md @@ -107,6 +107,9 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI readonly afterExpand: EventEmitter; // (undocumented) _animationMode: string; + _animationsDisabled: boolean; + // (undocumented) + _animationStarted(): void; _body: ElementRef; readonly _bodyAnimationDone: Subject; close(): void; @@ -125,6 +128,7 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI // (undocumented) ngOnDestroy(): void; open(): void; + _panelHidden: boolean; _portal: TemplatePortal; toggle(): void; get togglePosition(): MatAccordionTogglePosition;