diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3bc419e7c..2280ca85615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes for each version of this project will be documented in this file. +## 20.2.0 + +### New Features + +- `IgxTooltipTarget` + - Added new properties: + - `showTriggers` - Which event triggers will show the tooltip. Expects a comma-separated string of different event triggers. Defaults to `pointerenter`. + - `hideTriggers` - Which event triggers will hide the tooltip. Expects a comma-separated string of different event triggers. Defaults to `pointerleave` and `click`. + + ```html + info + Hello there, I am a tooltip! + ``` + ## 20.1.0 ### New Features diff --git a/projects/igniteui-angular/src/lib/directives/tooltip/README.md b/projects/igniteui-angular/src/lib/directives/tooltip/README.md index 90684e30b8e..831f44e35bb 100644 --- a/projects/igniteui-angular/src/lib/directives/tooltip/README.md +++ b/projects/igniteui-angular/src/lib/directives/tooltip/README.md @@ -104,6 +104,11 @@ Since the **IgxTooltip** directive extends the **IgxToggle** directive and there | hasArrow | boolean | Controls whether to display an arrow indicator for the tooltip. Defaults to `false`. | | sticky | boolean | When set to `true`, the tooltip renders a default close icon `x`. The tooltip remains visible until the user closes it via the close icon `x` or `Esc` key. Defaults to `false`. | | closeButtonTemplate | TemplateRef | Allows templating the default close icon `x`. | +| showTriggers | string | Which event triggers will show the tooltip. Expects a comma-separated string of different event triggers. Defaults to `pointerenter`. | +| hideTriggers | string | Which event triggers will hide the tooltip. Expects a comma-separated string of different event triggers. Defaults to `pointerleave` and `click`. | + + +> Note: Setting `showTriggers` and `hideTriggers` only has effect when interacting with the target, not the tooltip itself. Default event triggers for the tooltip are `pointerenter` and `pointerleave`. #### Templating the close button diff --git a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip-target.directive.ts b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip-target.directive.ts index 33a59cbf661..ba03ee153ed 100644 --- a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip-target.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip-target.directive.ts @@ -1,9 +1,10 @@ import { - Directive, OnInit, OnDestroy, Output, ElementRef, Optional, ViewContainerRef, HostListener, + Directive, OnInit, OnDestroy, Output, ElementRef, ViewContainerRef, Input, EventEmitter, booleanAttribute, TemplateRef, ComponentRef, Renderer2, EnvironmentInjector, createComponent, AfterViewInit, + inject, } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -14,7 +15,7 @@ import { IgxToggleActionDirective } from '../toggle/toggle.directive'; import { IgxTooltipComponent } from './tooltip.component'; import { IgxTooltipDirective } from './tooltip.directive'; import { IgxTooltipCloseButtonComponent } from './tooltip-close-button.component'; -import { TooltipPositionSettings, TooltipPositionStrategy } from './tooltip.common'; +import { parseTriggers, TooltipPositionSettings, TooltipPositionStrategy } from './tooltip.common'; export interface ITooltipShowEventArgs extends IBaseEventArgs { target: IgxTooltipTargetDirective; @@ -232,6 +233,46 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen @Input({ transform: booleanAttribute }) public tooltipDisabled = false; + /** + * Which event triggers will show the tooltip. + * Expects a comma-separated string of different event triggers. + * Defaults to `pointerenter`. + * ```html + * info + * Hello there, I am a tooltip! + * ``` + */ + @Input() + public get showTriggers(): string { + return Array.from(this._showTriggers).join(); + } + + public set showTriggers(value: string) { + this._showTriggers = parseTriggers(value); + this.removeEventListeners(); + this.addEventListeners(); + } + + /** + * Which event triggers will hide the tooltip. + * Expects a comma-separated string of different event triggers. + * Defaults to `pointerleave` and `click`. + * ```html + * info + * Hello there, I am a tooltip! + * ``` + */ + @Input() + public get hideTriggers(): string { + return Array.from(this._hideTriggers).join(); + } + + public set hideTriggers(value: string) { + this._hideTriggers = parseTriggers(value); + this.removeEventListeners(); + this.addEventListeners(); + } + /** * @hidden */ @@ -253,8 +294,11 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen } /** - * @hidden - */ + * Specifies a plain text as tooltip content. + * ```html + * info + * ``` + */ @Input() public set tooltip(content: any) { if (!this.target && (typeof content === 'string' || content instanceof String)) { @@ -323,6 +367,12 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen @Output() public tooltipHide = new EventEmitter(); + private _element = inject(ElementRef); + private _navigationService = inject(IgxNavigationService, { optional: true }); + private _viewContainerRef = inject(ViewContainerRef); + private _renderer = inject(Renderer2); + private _envInjector = inject(EnvironmentInjector); + private _destroy$ = new Subject(); private _autoHideDelay = 180; private _isForceClosed = false; @@ -331,25 +381,20 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen private _closeTemplate: TemplateRef; private _sticky = false; private _positionSettings: PositionSettings = TooltipPositionSettings; + private _showTriggers = new Set(['pointerenter']); + private _hideTriggers = new Set(['pointerleave', 'click']); - constructor( - private _element: ElementRef, - @Optional() private _navigationService: IgxNavigationService, - private _viewContainerRef: ViewContainerRef, - private _renderer: Renderer2, - private _envInjector: EnvironmentInjector - ) { - super(_element, _navigationService); - } + private _abortController = new AbortController(); /** * @hidden */ - @HostListener('click') public override onClick() { - if (!this.target.collapsed) { - this._hideOnInteraction(); - } else if (this.target.timeoutId) { + if ( + this.target.timeoutId && + this.target.collapsed && + !this._showTriggers.has('click') + ) { clearTimeout(this.target.timeoutId); this.target.timeoutId = null; } @@ -358,17 +403,15 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen /** * @hidden */ - @HostListener('mouseenter') - public onMouseEnter() { + public onShow(): void { this._checksBeforeShowing(() => this._showOnInteraction()); } /** * @hidden */ - @HostListener('mouseleave') - public onMouseLeave() { - if (this.tooltipDisabled) { + public onHide(): void { + if (this.tooltipDisabled || this.target.collapsed) { return; } @@ -376,28 +419,6 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen this._hideOnInteraction(); } - /** - * @hidden - */ - public onTouchStart() { - this._checksBeforeShowing(() => this._showOnInteraction()); - } - - /** - * @hidden - */ - public onDocumentTouchStart(event) { - if (this.tooltipDisabled || this?.target?.tooltipTarget !== this) { - return; - } - - if (this.nativeElement !== event.target && - !this.nativeElement.contains(event.target) - ) { - this._hideOnInteraction(); - } - } - /** * @hidden */ @@ -421,7 +442,8 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen } }); - this.nativeElement.addEventListener('touchstart', this.onTouchStart = this.onTouchStart.bind(this), { passive: true }); + this.removeEventListeners(); + this.addEventListeners(); } /** @@ -438,7 +460,7 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen */ public ngOnDestroy() { this.hideTooltip(); - this.nativeElement.removeEventListener('touchstart', this.onTouchStart); + this.removeEventListeners(); this._destroyCloseButton(); this._destroy$.next(); this._destroy$.complete(); @@ -470,6 +492,24 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen return Object.assign({}, this._overlayDefaults, this.overlaySettings); } + private addEventListeners(): void { + const options = { passive: true, signal: this._abortController.signal }; + + this.onShow = this.onShow.bind(this); + for (const each of this._showTriggers) { + this.nativeElement.addEventListener(each, this.onShow, options); + } + this.onHide = this.onHide.bind(this); + for (const each of this._hideTriggers) { + this.nativeElement.addEventListener(each, this.onHide, options); + } + } + + private removeEventListeners(): void { + this._abortController.abort(); + this._abortController = new AbortController(); + } + private _checkOutletAndOutsideClick(): void { if (this.outlet) { this._overlayDefaults.outlet = this.outlet; diff --git a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.common.ts b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.common.ts index 6f25d0403fd..31e4461f01a 100644 --- a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.common.ts +++ b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.common.ts @@ -5,6 +5,9 @@ import { useAnimation } from '@angular/animations'; import { fadeOut, scaleInCenter } from 'igniteui-angular/animations'; export const TooltipRegexes = Object.freeze({ + /** Used for parsing the strings passed in the tooltip `show/hide-trigger` properties. */ + triggers: /[,\s]+/, + /** Matches horizontal `Placement` end positions. `left-end` | `right-end` */ horizontalEnd: /^(left|right)-end$/, @@ -330,3 +333,9 @@ export const PositionsMap = new Map([ verticalStartPoint: VerticalAlignment.Bottom, }] ]); + +export function parseTriggers(triggers: string): Set { + return new Set( + (triggers ?? '').split(TooltipRegexes.triggers).filter((s) => s.trim()) + ); +} diff --git a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.spec.ts index 1cd84369e48..f14ee51b6de 100644 --- a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.spec.ts @@ -2,7 +2,7 @@ import { DebugElement } from '@angular/core'; import { fakeAsync, TestBed, tick, flush, waitForAsync, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { IgxTooltipSingleTargetComponent, IgxTooltipMultipleTargetsComponent, IgxTooltipPlainStringComponent, IgxTooltipWithToggleActionComponent, IgxTooltipMultipleTooltipsComponent, IgxTooltipWithCloseButtonComponent, IgxTooltipWithNestedContentComponent } from '../../test-utils/tooltip-components.spec'; +import { IgxTooltipSingleTargetComponent, IgxTooltipMultipleTargetsComponent, IgxTooltipPlainStringComponent, IgxTooltipWithToggleActionComponent, IgxTooltipWithCloseButtonComponent, IgxTooltipWithNestedContentComponent } from '../../test-utils/tooltip-components.spec'; import { UIInteractions } from '../../test-utils/ui-interactions.spec'; import { HorizontalAlignment, VerticalAlignment, AutoPositionStrategy } from '../../services/public_api'; import { IgxTooltipDirective } from './tooltip.directive'; @@ -11,7 +11,9 @@ import { Placement, PositionsMap } from './tooltip.common'; const HIDDEN_TOOLTIP_CLASS = 'igx-tooltip--hidden'; const TOOLTIP_CLASS = 'igx-tooltip'; -const HIDE_DELAY = 180; +const SHOW_DELAY = 200; +const HIDE_DELAY = 300; +const AUTO_HIDE_DELAY = 180; const TOOLTIP_ARROW_SELECTOR = '[data-arrow="true"]'; describe('IgxTooltip', () => { @@ -172,7 +174,7 @@ describe('IgxTooltip', () => { flush(); unhoverElement(button); - tick(HIDE_DELAY); + tick(AUTO_HIDE_DELAY); tick(400); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); @@ -407,69 +409,113 @@ describe('IgxTooltip', () => { })); }); - describe('Tooltip touch', () => { - it('IgxTooltip is shown/hidden when touching/untouching its target', fakeAsync(() => { - touchElement(button); + describe('Tooltip show/hide triggers', () => { + it('should override default triggers', fakeAsync(() => { + tooltipTarget.showTriggers = 'focus'; + tooltipTarget.hideTriggers = 'keypress'; + fix.detectChanges(); + + hoverElement(button); flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); + simulateTriggerEvent(button, 'focus'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); - const dummyDiv = fix.debugElement.query(By.css('.dummyDiv')); - touchElement(dummyDiv); + unhoverElement(button); flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); + simulateTriggerEvent(button, 'keypress'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); })); - it('IgxTooltip is not shown when is disabled and touching its target', fakeAsync(() => { - tooltipTarget.tooltipDisabled = true; + it('should add multiple show triggers', fakeAsync(() => { + tooltipTarget.showTriggers = 'focus, keypress'; fix.detectChanges(); - touchElement(button); + simulateTriggerEvent(button, 'focus'); flush(); - verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); - tooltipTarget.tooltipDisabled = false; - fix.detectChanges(); + unhoverElement(button); + flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); - touchElement(button); + simulateTriggerEvent(button, 'keypress'); flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); })); - it('IgxTooltip touch interaction respects showDelay', fakeAsync(() => { - tooltipTarget.showDelay = 900; + it('should add multiple hide triggers', fakeAsync(() => { + tooltipTarget.showTriggers = 'focus'; + tooltipTarget.hideTriggers = 'blur, keypress'; fix.detectChanges(); - touchElement(button); + simulateTriggerEvent(button, 'focus'); + flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); + simulateTriggerEvent(button, 'blur'); + flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); - tick(500); + simulateTriggerEvent(button, 'focus'); + flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); + simulateTriggerEvent(button, 'keypress'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); + })); - tick(300); + it('should respect showDelay and hideDelay', fakeAsync(() => { + tooltipTarget.showTriggers = tooltipTarget.hideTriggers = 'click'; + fix.detectChanges(); + + simulateTriggerEvent(button, 'click'); + tick(SHOW_DELAY - 1); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); + tick(1); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); - tick(100); + simulateTriggerEvent(button, 'click'); + const totalHideDelay = HIDE_DELAY + AUTO_HIDE_DELAY - 1; + tick(totalHideDelay); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); + tick(1); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); })); - it('IgxTooltip touch interaction respects hideDelay', fakeAsync(() => { - tooltipTarget.hideDelay = 700; + it('should not be shown if the tooltip is disabled', fakeAsync(() => { + tooltipTarget.showTriggers = 'focus'; + tooltipTarget.hideTriggers = 'blur'; + tooltipTarget.tooltipDisabled = true; fix.detectChanges(); - touchElement(button); + simulateTriggerEvent(button, 'focus'); flush(); + verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); - const dummyDiv = fix.debugElement.query(By.css('.dummyDiv')); - touchElement(dummyDiv); - tick(HIDE_DELAY); - tick(400); + tooltipTarget.tooltipDisabled = false; + fix.detectChanges(); + + simulateTriggerEvent(button, 'focus'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); - tick(100); + tooltipTarget.tooltipDisabled = true; + fix.detectChanges(); + + simulateTriggerEvent(button, 'blur'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); - tick(200); + tooltipTarget.tooltipDisabled = false; + fix.detectChanges(); + + simulateTriggerEvent(button, 'blur'); + flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); })); }); @@ -637,21 +683,6 @@ describe('IgxTooltip', () => { verifyTooltipPosition(tooltipNativeElement, buttonOne, false); })); - it('Should not call `hideTooltip` multiple times on document:touchstart', fakeAsync(() => { - spyOn(targetOne, '_hideOnInteraction').and.callThrough(); - spyOn(targetTwo, '_hideOnInteraction').and.callThrough(); - - touchElement(buttonOne); - tick(500); - - const dummyDiv = fix.debugElement.query(By.css('.dummyDiv')); - touchElement(dummyDiv); - flush(); - - expect(targetOne['_hideOnInteraction']).toHaveBeenCalledTimes(1); - expect(targetTwo['_hideOnInteraction']).not.toHaveBeenCalled(); - })); - it('should not emit tooltipHide event multiple times', fakeAsync(() => { spyOn(targetOne.tooltipHide, 'emit'); spyOn(targetTwo.tooltipHide, 'emit'); @@ -678,23 +709,6 @@ describe('IgxTooltip', () => { flush(); })); - - it('IgxTooltip hides when touch one target, then another, then outside', fakeAsync(() => { - touchElement(targetOne); - flush(); - verifyTooltipVisibility(tooltipNativeElement, targetOne, true); - verifyTooltipPosition(tooltipNativeElement, targetOne, true); - - touchElement(targetTwo); - flush(); - verifyTooltipVisibility(tooltipNativeElement, targetTwo, true); - verifyTooltipPosition(tooltipNativeElement, targetTwo, true); - - touchElement(fix.debugElement); - flush(); - verifyTooltipVisibility(tooltipNativeElement, targetTwo, false); - })); - it('should show and remove close button depending on active sticky target', fakeAsync(() => { targetOne.sticky = true; fix.detectChanges(); @@ -873,36 +887,6 @@ describe('IgxTooltip', () => { })); }); - describe('Multiple tooltips', () => { - let targetOne: IgxTooltipTargetDirective; - - let tooltipOne: IgxTooltipDirective; - let tooltipTwo: IgxTooltipDirective; - - beforeEach(waitForAsync(() => { - fix = TestBed.createComponent(IgxTooltipMultipleTooltipsComponent); - fix.detectChanges(); - targetOne = fix.componentInstance.targetOne; - tooltipOne = fix.componentInstance.tooltipOne; - tooltipTwo = fix.componentInstance.tooltipTwo; - })); - - it('should not add multiple document:touchstart event listeners when having multiple igxTooltip instances - #16100', fakeAsync(() => { - spyOn(tooltipOne, 'onDocumentTouchStart').and.callThrough(); - spyOn(tooltipTwo, 'onDocumentTouchStart').and.callThrough(); - - touchElement(targetOne); - tick(500); - - const dummyDiv = fix.debugElement.query(By.css('.dummyDiv')); - touchElement(dummyDiv); - flush(); - - expect(tooltipOne['onDocumentTouchStart']).toHaveBeenCalledTimes(1); - expect(tooltipTwo['onDocumentTouchStart']).not.toHaveBeenCalled(); - })); - }); - describe('Tooltip integration', () => { beforeEach(waitForAsync(() => { fix = TestBed.createComponent(IgxTooltipWithToggleActionComponent); @@ -922,7 +906,7 @@ describe('IgxTooltip', () => { verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); UIInteractions.simulateClickEvent(button.nativeElement); - tick(HIDE_DELAY); + tick(AUTO_HIDE_DELAY); tick(300); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false); @@ -1027,10 +1011,12 @@ describe('IgxTooltip', () => { verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false) })); - it('should correctly display a sticky tooltip on touchstart', fakeAsync(() => { + it('should correctly display a sticky tooltip on custom show trigger', fakeAsync(() => { tooltipTarget.sticky = true; + tooltipTarget.showTriggers = 'focus'; fix.detectChanges(); - touchElement(button); + + simulateTriggerEvent(button, 'focus'); flush(); verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, true); @@ -1106,11 +1092,11 @@ interface ElementRefLike { nativeElement: HTMLElement } -const hoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('mouseenter')); +const hoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('pointerenter')); -const unhoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('mouseleave')); +const unhoverElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new MouseEvent('pointerleave')); -const touchElement = (element: ElementRefLike) => element.nativeElement.dispatchEvent(new TouchEvent('touchstart', { bubbles: true })); +const simulateTriggerEvent = (element: ElementRefLike, event: string) => element.nativeElement.dispatchEvent(new Event(event, { bubbles: true })); const verifyTooltipVisibility = (tooltipNativeElement, tooltipTarget, shouldBeVisible: boolean) => { expect(tooltipNativeElement.classList.contains(TOOLTIP_CLASS)).toBe(shouldBeVisible); diff --git a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.ts b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.ts index e04f71ba426..b5d3b0a9a20 100644 --- a/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/tooltip/tooltip.directive.ts @@ -1,15 +1,12 @@ import { - Directive, ElementRef, Input, ChangeDetectorRef, Optional, HostBinding, Inject, - OnDestroy, inject, DOCUMENT, HostListener, + Directive, Input, HostBinding, + OnDestroy, inject, HostListener, Renderer2, AfterViewInit, } from '@angular/core'; -import { IgxOverlayService } from '../../services/overlay/overlay'; import { OverlaySettings } from '../../services/overlay/utilities'; -import { IgxNavigationService } from '../../core/navigation'; import { IgxToggleDirective } from '../toggle/toggle.directive'; import { IgxTooltipTargetDirective } from './tooltip-target.directive'; -import { Subject, takeUntil } from 'rxjs'; import { PlatformUtil } from '../../core/utils'; let NEXT_ID = 0; @@ -118,29 +115,9 @@ export class IgxTooltipDirective extends IgxToggleDirective implements AfterView private _arrowEl: HTMLElement; private _role: 'tooltip' | 'status' = 'tooltip'; - private _destroy$ = new Subject(); - private _document = inject(DOCUMENT); private _renderer = inject(Renderer2); private _platformUtil = inject(PlatformUtil); - /** @hidden */ - constructor( - elementRef: ElementRef, - cdr: ChangeDetectorRef, - @Inject(IgxOverlayService) overlayService: IgxOverlayService, - @Optional() navigationService: IgxNavigationService) { - // D.P. constructor duplication due to es6 compilation, might be obsolete in the future - super(elementRef, cdr, overlayService, navigationService); - - this.onDocumentTouchStart = this.onDocumentTouchStart.bind(this); - this.opening.pipe(takeUntil(this._destroy$)).subscribe(() => { - this._document.addEventListener('touchstart', this.onDocumentTouchStart, { passive: true }); - }); - this.closed.pipe(takeUntil(this._destroy$)).subscribe(() => { - this._document.removeEventListener('touchstart', this.onDocumentTouchStart); - }); - } - /** @hidden */ public ngAfterViewInit(): void { if (this._platformUtil.isBrowser) { @@ -152,10 +129,6 @@ export class IgxTooltipDirective extends IgxToggleDirective implements AfterView public override ngOnDestroy() { super.ngOnDestroy(); - this._document.removeEventListener('touchstart', this.onDocumentTouchStart); - this._destroy$.next(true); - this._destroy$.complete(); - if (this.arrow) { this._removeArrow(); } @@ -164,17 +137,21 @@ export class IgxTooltipDirective extends IgxToggleDirective implements AfterView /** * @hidden */ - @HostListener('mouseenter') - public onMouseEnter() { - this.tooltipTarget?.onMouseEnter(); + @HostListener('pointerenter') + protected onPointerEnter() { + if (this.tooltipTarget) { + this.tooltipTarget.onShow(); + } } /** * @hidden */ - @HostListener('mouseleave') - public onMouseLeave() { - this.tooltipTarget?.onMouseLeave(); + @HostListener('pointerleave') + protected onPointerLeave() { + if (this.tooltipTarget) { + this.tooltipTarget.onHide(); + } } /** @@ -230,8 +207,4 @@ export class IgxTooltipDirective extends IgxToggleDirective implements AfterView this._arrowEl.remove(); this._arrowEl = null; } - - private onDocumentTouchStart(event) { - this.tooltipTarget?.onDocumentTouchStart(event); - } } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-validation.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-validation.spec.ts index 9b660e56674..36201922672 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-validation.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-validation.spec.ts @@ -225,7 +225,7 @@ describe('IgxGrid - Validation #grid', () => { expect(cell.errorTooltip.first.collapsed).toBeTrue(); const element = fixture.debugElement.query(By.directive(IgxTooltipTargetDirective)).nativeElement; - element.dispatchEvent(new MouseEvent('mouseenter')); + element.dispatchEvent(new MouseEvent('pointerenter')); flush(); fixture.detectChanges(); expect(cell.errorTooltip.first.collapsed).toBeFalse();