Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -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 separate string of different event triggers.
* Defaults to `pointerenter`.
* ```html
* <igx-icon [igxTooltipTarget]="tooltipRef" [showTriggers]="'click,focus'">info</igx-icon>
* <span #tooltipRef="tooltip" igxTooltip>Hello there, I am a tooltip!</span>
* ```
*/
@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 separate string of different event triggers.
* Defaults to `pointerleave` and `click`.
* ```html
* <igx-icon [igxTooltipTarget]="tooltipRef" [hideTriggers]="'keypress,blur'">info</igx-icon>
* <span #tooltipRef="tooltip" igxTooltip>Hello there, I am a tooltip!</span>
* ```
*/
@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
*/
Expand All @@ -253,8 +294,11 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
}

/**
* @hidden
*/
* Specifies a plain text as tooltip content.
* ```html
* <igx-icon igxTooltipTarget [tooltip]="'Infragistics Inc. HQ'">info</igx-icon>
* ```
*/
@Input()
public set tooltip(content: any) {
if (!this.target && (typeof content === 'string' || content instanceof String)) {
Expand Down Expand Up @@ -323,6 +367,12 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
@Output()
public tooltipHide = new EventEmitter<ITooltipHideEventArgs>();

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<void>();
private _autoHideDelay = 180;
private _isForceClosed = false;
Expand All @@ -331,25 +381,20 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
private _closeTemplate: TemplateRef<any>;
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;
}
Expand All @@ -358,46 +403,22 @@ 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;
}

this._checkOutletAndOutsideClick();
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
*/
Expand All @@ -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();
}

/**
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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$/,

Expand Down Expand Up @@ -330,3 +333,9 @@ export const PositionsMap = new Map<Placement, PositionSettings>([
verticalStartPoint: VerticalAlignment.Bottom,
}]
]);

export function parseTriggers(triggers: string): Set<string> {
return new Set(
(triggers ?? '').split(TooltipRegexes.triggers).filter((s) => s.trim())
);
}
Loading
Loading