From 01eacdc220c0167d95f3ab53c54a590888dd1c5b Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 6 Mar 2022 10:34:33 +0100 Subject: [PATCH] fixup! fix(material/tooltip): decouple removal logic from change detection --- .../mdc-tooltip/tooltip.html | 1 - .../mdc-tooltip/tooltip.scss | 2 +- src/material/tooltip/tooltip.html | 1 - src/material/tooltip/tooltip.scss | 2 +- src/material/tooltip/tooltip.ts | 45 ++++++++++--------- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/material-experimental/mdc-tooltip/tooltip.html b/src/material-experimental/mdc-tooltip/tooltip.html index f0ac5089f20f..28b374a88f8a 100644 --- a/src/material-experimental/mdc-tooltip/tooltip.html +++ b/src/material-experimental/mdc-tooltip/tooltip.html @@ -3,7 +3,6 @@ class="mdc-tooltip mdc-tooltip--shown mat-mdc-tooltip" [ngClass]="tooltipClass" (animationend)="_handleAnimationEnd($event)" - [class._mat-animation-noopable]="_animationsDisabled" [class.mdc-tooltip--multiline]="_isMultiline">
{{message}}
diff --git a/src/material-experimental/mdc-tooltip/tooltip.scss b/src/material-experimental/mdc-tooltip/tooltip.scss index 18b6103cfd9c..5901072294cb 100644 --- a/src/material-experimental/mdc-tooltip/tooltip.scss +++ b/src/material-experimental/mdc-tooltip/tooltip.scss @@ -22,7 +22,7 @@ &._mat-animation-noopable { animation: none; - transform: none; + transform: scale(1); } } diff --git a/src/material/tooltip/tooltip.html b/src/material/tooltip/tooltip.html index e3a3b35031d0..cf6bd74a0592 100644 --- a/src/material/tooltip/tooltip.html +++ b/src/material/tooltip/tooltip.html @@ -2,5 +2,4 @@ class="mat-tooltip" (animationend)="_handleAnimationEnd($event)" [ngClass]="tooltipClass" - [class._mat-animation-noopable]="_animationsDisabled" [class.mat-tooltip-handset]="(_isHandset | async)?.matches">{{message}} diff --git a/src/material/tooltip/tooltip.scss b/src/material/tooltip/tooltip.scss index b5b430d0ca59..1fadd1358a97 100644 --- a/src/material/tooltip/tooltip.scss +++ b/src/material/tooltip/tooltip.scss @@ -20,7 +20,7 @@ $handset-margin: 24px; &._mat-animation-noopable { animation: none; - transform: none; + transform: scale(1); } @include a11y.high-contrast(active, off) { diff --git a/src/material/tooltip/tooltip.ts b/src/material/tooltip/tooltip.ts index 97e7f626948e..77c9a665acb4 100644 --- a/src/material/tooltip/tooltip.ts +++ b/src/material/tooltip/tooltip.ts @@ -860,7 +860,7 @@ export abstract class _TooltipComponentBase implements OnDestroy { _mouseLeaveHideDelay: number; /** Whether animations are currently disabled. */ - _animationsDisabled: boolean; + private _animationsDisabled: boolean; /** Reference to the internal tooltip element. */ abstract _tooltip: ElementRef; @@ -895,15 +895,9 @@ export abstract class _TooltipComponentBase implements OnDestroy { // Cancel the delayed hide if it is scheduled clearTimeout(this._hideTimeoutId); - // Body interactions should cancel the tooltip if there is a delay in showing. - this._closeOnInteraction = true; this._showTimeoutId = setTimeout(() => { - this._toogleVisibility(true); + this._toggleVisibility(true); this._showTimeoutId = undefined; - - // Mark for check so if any parent component has set the - // ChangeDetectionStrategy to OnPush it will be checked anyways - this._markForCheck(); }, delay); } @@ -916,12 +910,8 @@ export abstract class _TooltipComponentBase implements OnDestroy { clearTimeout(this._showTimeoutId); this._hideTimeoutId = setTimeout(() => { - this._toogleVisibility(false); + this._toggleVisibility(false); this._hideTimeoutId = undefined; - - // Mark for check so if any parent component has set the - // ChangeDetectionStrategy to OnPush it will be checked anyways - this._markForCheck(); }, delay); } @@ -984,30 +974,45 @@ export abstract class _TooltipComponentBase implements OnDestroy { /** Handles the cleanup after an animation has finished. */ private _finalizeAnimation(toVisible: boolean) { - if (!toVisible && !this.isVisible()) { + if (toVisible) { + this._closeOnInteraction = true; + } else if (!this.isVisible()) { this._onHide.next(); } - - this._closeOnInteraction = true; } /** Toggles the visibility of the tooltip element. */ - private _toogleVisibility(isVisible: boolean) { + private _toggleVisibility(isVisible: boolean) { // We set the classes directly here ourselves so that toggling the tooltip state // isn't bound by change detection. This allows us to hide it even if the // view ref has been detached from the CD tree. - const classList = this._tooltip.nativeElement.classList; + const tooltip = this._tooltip.nativeElement; const showClass = this._showAnimation; const hideClass = this._hideAnimation; - classList.remove(isVisible ? hideClass : showClass); - classList.add(isVisible ? showClass : hideClass); + tooltip.classList.remove(isVisible ? hideClass : showClass); + tooltip.classList.add(isVisible ? showClass : hideClass); this._isVisible = isVisible; + // It's common for internal apps to disable animations using `* { animation: none !important }` + // which can break the opening sequence. Try to detect such cases and work around them. + if (isVisible && !this._animationsDisabled && typeof getComputedStyle === 'function') { + const styles = getComputedStyle(tooltip); + + // Use `getPropertyValue` to avoid issues with property renaming. + if ( + styles.getPropertyValue('animation-duration') === '0s' || + styles.getPropertyValue('animation-name') === 'none' + ) { + this._animationsDisabled = true; + } + } + if (isVisible) { this._onShow(); } if (this._animationsDisabled) { + tooltip.classList.add('_mat-animation-noopable'); this._finalizeAnimation(isVisible); } }