Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export interface ITooltipHideEventArgs extends IBaseEventArgs {
cancel: boolean;
}

const HOVER_SHOW_TRIGGERS = new Set(['mouseenter', 'mouseover', 'pointerenter', 'pointerover']);

/**
* **Ignite UI for Angular Tooltip Target** -
* [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip)
Expand Down Expand Up @@ -564,8 +566,14 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
this._pendingShowTrigger = triggerEvent?.type ?? null;

this.target.timeoutId = setTimeout(() => {
// Call open() of IgxTooltipDirective
const isHoverTrigger = this._pendingShowTrigger && HOVER_SHOW_TRIGGERS.has(this._pendingShowTrigger);
this._pendingShowTrigger = null;
this.target.timeoutId = null;

if (isHoverTrigger && !this.nativeElement.matches(':hover')) {
return;
}

this.target.open(this._mergedOverlaySettings);
}, withDelay ? this.showDelay : 0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const SHOW_DELAY = 200;
const HIDE_DELAY = 300;
const AUTO_HIDE_DELAY = 180;
const TOOLTIP_ARROW_SELECTOR = '[data-arrow="true"]';
const hoveredElements = new WeakSet<Element>();

describe('IgxTooltip', () => {
let fix: ComponentFixture<any>;
Expand All @@ -23,6 +24,11 @@ describe('IgxTooltip', () => {
let button: DebugElement;

beforeEach(waitForAsync(() => {
const matches = Element.prototype.matches;
spyOn(Element.prototype, 'matches').and.callFake(function(this: Element, selectors: string): boolean {
return selectors === ':hover' ? hoveredElements.has(this) : matches.call(this, selectors);
} as typeof Element.prototype.matches);

TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
Expand Down Expand Up @@ -532,6 +538,22 @@ describe('IgxTooltip', () => {
tick(300);
verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false);
}));

for (const trigger of ['mouseenter', 'mouseover', 'pointerenter', 'pointerover']) {
it(`should not open after the delay when the target is no longer hovered using ${trigger}`, fakeAsync(() => {
tooltipTarget.showDelay = 500;
tooltipTarget.showTriggers = trigger;
tooltipTarget.hideTriggers = 'click';
fix.detectChanges();

hoverElement(button, trigger);
tick(300);
unhoverElement(button);
tick(200);

verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false);
}));
}
});
});

Expand Down Expand Up @@ -1169,9 +1191,15 @@ interface ElementRefLike {
nativeElement: HTMLElement
}

const hoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('pointerenter'));
const hoverElement = (element: ElementRefLike, event = 'pointerenter') => {
hoveredElements.add(element.nativeElement);
element.nativeElement.dispatchEvent(new MouseEvent(event));
};

const unhoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('pointerleave'));
const unhoverElement = (element: ElementRefLike) => {
hoveredElements.delete(element.nativeElement);
element.nativeElement.dispatchEvent(new MouseEvent('pointerleave'));
};

const simulateTriggerEvent = (element: ElementRefLike, event: string) => element.nativeElement.dispatchEvent(new Event(event, { bubbles: true }));

Expand All @@ -1188,7 +1216,7 @@ const alignmentTolerance = 2;
export const verifyTooltipPosition = (
tooltipNativeElement: HTMLElement,
actualTarget: { nativeElement: HTMLElement },
shouldAlign:boolean = true,
shouldAlign: boolean = true,
placement: Placement = Placement.Bottom,
offset: number = 6
) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ describe('IgxGrid - Validation #grid', () => {
expect(cell.errorTooltip.first.collapsed).toBeTrue();

const element = fixture.debugElement.query(By.directive(IgxTooltipTargetDirective)).nativeElement;
spyOn(element, 'matches').and.returnValue(true);
element.dispatchEvent(new MouseEvent('pointerenter'));
flush();
fixture.detectChanges();
Expand Down
Loading