Skip to content

Commit bca83bb

Browse files
committed
fix(tooltip): not closing if escape is pressed while trigger isn't focused
Currently the tooltip's `keydown` handler is on the trigger, which means that it won't fire if the trigger doesn't have focus. This could happen when a tooltip was opened by hovering over the trigger. These changes use the `OverlayKeyboardDispatcher` to handle the events instead. Fixes #14278.
1 parent 14c4dba commit bca83bb

File tree

2 files changed

+35
-18
lines changed

2 files changed

+35
-18
lines changed

src/material/tooltip/tooltip.spec.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -640,9 +640,28 @@ describe('MatTooltip', () => {
640640
expect(overlayContainerElement.textContent).toContain(initialTooltipMessage);
641641
}));
642642

643+
it('should hide when pressing escape', fakeAsync(() => {
644+
tooltipDirective.show();
645+
tick(0);
646+
fixture.detectChanges();
647+
tick(500);
648+
649+
expect(tooltipDirective._isTooltipVisible()).toBe(true);
650+
expect(overlayContainerElement.textContent).toContain(initialTooltipMessage);
651+
652+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
653+
tick(0);
654+
fixture.detectChanges();
655+
tick(500);
656+
fixture.detectChanges();
657+
658+
expect(tooltipDirective._isTooltipVisible()).toBe(false);
659+
expect(overlayContainerElement.textContent).toBe('');
660+
}));
661+
643662
it('should not throw when pressing ESCAPE', fakeAsync(() => {
644663
expect(() => {
645-
dispatchKeyboardEvent(buttonElement, 'keydown', ESCAPE);
664+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
646665
fixture.detectChanges();
647666
}).not.toThrow();
648667

@@ -655,7 +674,7 @@ describe('MatTooltip', () => {
655674
tick(0);
656675
fixture.detectChanges();
657676

658-
const event = dispatchKeyboardEvent(buttonElement, 'keydown', ESCAPE);
677+
const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
659678
fixture.detectChanges();
660679
flush();
661680

@@ -669,7 +688,7 @@ describe('MatTooltip', () => {
669688

670689
const event = createKeyboardEvent('keydown', ESCAPE);
671690
Object.defineProperty(event, 'altKey', {get: () => true});
672-
dispatchEvent(buttonElement, event);
691+
dispatchEvent(document.body, event);
673692
fixture.detectChanges();
674693
flush();
675694

src/material/tooltip/tooltip.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -360,18 +360,6 @@ export class MatTooltip implements OnDestroy, OnInit {
360360
return !!this._tooltipInstance && this._tooltipInstance.isVisible();
361361
}
362362

363-
/**
364-
* Handles the keydown events on the host element.
365-
* Needs to be an arrow function so that we can use it in addEventListener.
366-
*/
367-
private _handleKeydown = (event: KeyboardEvent) => {
368-
if (this._isTooltipVisible() && event.keyCode === ESCAPE && !hasModifierKey(event)) {
369-
event.preventDefault();
370-
event.stopPropagation();
371-
this._ngZone.run(() => this.hide(0));
372-
}
373-
}
374-
375363
/** Create the overlay config and position strategy */
376364
private _createOverlay(): OverlayRef {
377365
if (this._overlayRef) {
@@ -399,7 +387,7 @@ export class MatTooltip implements OnDestroy, OnInit {
399387
}
400388
});
401389

402-
this._overlayRef = this._overlay.create({
390+
const overlayRef = this._overlayRef = this._overlay.create({
403391
direction: this._dir,
404392
positionStrategy: strategy,
405393
panelClass: TOOLTIP_PANEL_CLASS,
@@ -408,11 +396,21 @@ export class MatTooltip implements OnDestroy, OnInit {
408396

409397
this._updatePosition();
410398

411-
this._overlayRef.detachments()
399+
overlayRef.keydownEvents()
400+
.pipe(takeUntil(this._destroyed))
401+
.subscribe(event => {
402+
if (this._isTooltipVisible() && event.keyCode === ESCAPE && !hasModifierKey(event)) {
403+
event.preventDefault();
404+
event.stopPropagation();
405+
this._ngZone.run(() => this.hide(0));
406+
}
407+
});
408+
409+
overlayRef.detachments()
412410
.pipe(takeUntil(this._destroyed))
413411
.subscribe(() => this._detach());
414412

415-
return this._overlayRef;
413+
return overlayRef;
416414
}
417415

418416
/** Detaches the currently-attached tooltip. */

0 commit comments

Comments
 (0)