Skip to content

Commit a9d3bc5

Browse files
authored
fix(material/tooltip): animations running when timeouts haven't elapsed (#25699) (#25701)
After the tooltips were switched to CSS animations, a regression was introduced where the opposite animation is shown even if the tooltip didn't actually reach its target state. These changes are an alternate take on the fix from #24652 which had to be reverted due to internal failures. Fixes #24614.
1 parent 8c3d791 commit a9d3bc5

File tree

4 files changed

+19
-21
lines changed

4 files changed

+19
-21
lines changed

src/material-experimental/mdc-tooltip/tooltip.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,6 @@ describe('MDC-based MatTooltip', () => {
519519
const tooltipDelay = 1000;
520520
tooltipDirective.hide();
521521
tick(tooltipDelay); // Change the tooltip state to hidden and trigger animation start
522-
finishCurrentTooltipAnimation(overlayContainerElement, false);
523522

524523
fixture.componentInstance.showButton = false;
525524
fixture.detectChanges();
@@ -538,7 +537,6 @@ describe('MDC-based MatTooltip', () => {
538537
tooltipDirective.hide(0);
539538
tick(0);
540539
fixture.detectChanges();
541-
finishCurrentTooltipAnimation(overlayContainerElement, false);
542540

543541
expect(spy).toHaveBeenCalled();
544542
subscription.unsubscribe();

src/material/tooltip/tooltip.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,6 @@ describe('MatTooltip', () => {
515515
const tooltipDelay = 1000;
516516
tooltipDirective.hide();
517517
tick(tooltipDelay); // Change the tooltip state to hidden and trigger animation start
518-
finishCurrentTooltipAnimation(overlayContainerElement, false);
519518

520519
fixture.componentInstance.showButton = false;
521520
fixture.detectChanges();
@@ -534,7 +533,6 @@ describe('MatTooltip', () => {
534533
tooltipDirective.hide(0);
535534
tick(0);
536535
fixture.detectChanges();
537-
finishCurrentTooltipAnimation(overlayContainerElement, false);
538536

539537
expect(spy).toHaveBeenCalled();
540538
subscription.unsubscribe();

src/material/tooltip/tooltip.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,8 @@ export abstract class _MatTooltipBase<T extends _TooltipComponentBase>
377377

378378
/** Shows the tooltip after the delay in ms, defaults to tooltip-delay-show or 0ms if no input */
379379
show(delay: number = this.showDelay): void {
380-
if (
381-
this.disabled ||
382-
!this.message ||
383-
(this._isTooltipVisible() &&
384-
!this._tooltipInstance!._showTimeoutId &&
385-
!this._tooltipInstance!._hideTimeoutId)
386-
) {
380+
if (this.disabled || !this.message || this._isTooltipVisible()) {
381+
this._tooltipInstance?._cancelPendingHide();
387382
return;
388383
}
389384

@@ -405,8 +400,14 @@ export abstract class _MatTooltipBase<T extends _TooltipComponentBase>
405400

406401
/** Hides the tooltip after the delay in ms, defaults to tooltip-delay-hide or 0ms if no input */
407402
hide(delay: number = this.hideDelay): void {
408-
if (this._tooltipInstance) {
409-
this._tooltipInstance.hide(delay);
403+
const instance = this._tooltipInstance;
404+
405+
if (instance) {
406+
if (instance.isVisible()) {
407+
instance.hide(delay);
408+
} else {
409+
this._detach();
410+
}
410411
}
411412
}
412413

@@ -845,13 +846,10 @@ export abstract class _TooltipComponentBase implements OnDestroy {
845846
tooltipClass: string | string[] | Set<string> | {[key: string]: any};
846847

847848
/** The timeout ID of any current timer set to show the tooltip */
848-
_showTimeoutId: number | undefined;
849+
private _showTimeoutId: number | undefined;
849850

850851
/** The timeout ID of any current timer set to hide the tooltip */
851-
_hideTimeoutId: number | undefined;
852-
853-
/** Property watched by the animation framework to show or hide the tooltip */
854-
_visibility: TooltipVisibility = 'initial';
852+
private _hideTimeoutId: number | undefined;
855853

856854
/** Element that caused the tooltip to open. */
857855
_triggerElement: HTMLElement;
@@ -972,6 +970,12 @@ export abstract class _TooltipComponentBase implements OnDestroy {
972970
}
973971
}
974972

973+
/** Cancels any pending hiding sequences. */
974+
_cancelPendingHide() {
975+
clearTimeout(this._hideTimeoutId);
976+
this._hideTimeoutId = undefined;
977+
}
978+
975979
/** Handles the cleanup after an animation has finished. */
976980
private _finalizeAnimation(toVisible: boolean) {
977981
if (toVisible) {

tools/public_api_guard/material/tooltip.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,13 @@ export class TooltipComponent extends _TooltipComponentBase {
174174
export abstract class _TooltipComponentBase implements OnDestroy {
175175
constructor(_changeDetectorRef: ChangeDetectorRef, animationMode?: string);
176176
afterHidden(): Observable<void>;
177+
_cancelPendingHide(): void;
177178
_handleAnimationEnd({ animationName }: AnimationEvent): void;
178179
_handleBodyInteraction(): void;
179180
// (undocumented)
180181
_handleMouseLeave({ relatedTarget }: MouseEvent): void;
181182
hide(delay: number): void;
182183
protected abstract readonly _hideAnimation: string;
183-
_hideTimeoutId: number | undefined;
184184
isVisible(): boolean;
185185
_markForCheck(): void;
186186
message: string;
@@ -190,13 +190,11 @@ export abstract class _TooltipComponentBase implements OnDestroy {
190190
protected _onShow(): void;
191191
show(delay: number): void;
192192
protected abstract readonly _showAnimation: string;
193-
_showTimeoutId: number | undefined;
194193
abstract _tooltip: ElementRef<HTMLElement>;
195194
tooltipClass: string | string[] | Set<string> | {
196195
[key: string]: any;
197196
};
198197
_triggerElement: HTMLElement;
199-
_visibility: TooltipVisibility;
200198
// (undocumented)
201199
static ɵdir: i0.ɵɵDirectiveDeclaration<_TooltipComponentBase, never, never, {}, {}, never, never, false>;
202200
// (undocumented)

0 commit comments

Comments
 (0)