11import {
2- Directive , ElementRef , Input , ChangeDetectorRef , Optional , HostBinding , Inject
2+ Directive , ElementRef , Input , ChangeDetectorRef , Optional , HostBinding , Inject ,
3+ TemplateRef ,
4+ ViewContainerRef , OnInit , OnDestroy , AfterViewInit ,
35} from '@angular/core' ;
46import { IgxOverlayService } from '../../services/overlay/overlay' ;
5- import { OverlaySettings } from '../../services/public_api' ;
7+ import { HorizontalAlignment , OverlaySettings , VerticalAlignment } from '../../services/public_api' ;
68import { IgxNavigationService } from '../../core/navigation' ;
79import { IgxToggleDirective } from '../toggle/toggle.directive' ;
10+ import { takeUntil } from 'rxjs' ;
11+ import { TooltipCloseButtonComponent } from './tooltip-close-button.component' ;
812
913let NEXT_ID = 0 ;
1014/**
@@ -26,7 +30,13 @@ let NEXT_ID = 0;
2630 selector : '[igxTooltip]' ,
2731 standalone : true
2832} )
29- export class IgxTooltipDirective extends IgxToggleDirective {
33+ export class IgxTooltipDirective extends IgxToggleDirective implements OnInit , OnDestroy , AfterViewInit {
34+ private _arrowEl : HTMLElement ;
35+ private _customCloseTemplate : TemplateRef < any > ;
36+ private _disableArrow = false ;
37+ private _sticky = false ;
38+ private _offset = 6 ;
39+
3040 /**
3141 * @hidden
3242 */
@@ -107,11 +117,36 @@ export class IgxTooltipDirective extends IgxToggleDirective {
107117 elementRef : ElementRef ,
108118 cdr : ChangeDetectorRef ,
109119 @Inject ( IgxOverlayService ) overlayService : IgxOverlayService ,
110- @Optional ( ) navigationService : IgxNavigationService ) {
120+ @Optional ( ) navigationService : IgxNavigationService ,
121+ private viewContainerRef : ViewContainerRef ) {
111122 // D.P. constructor duplication due to es6 compilation, might be obsolete in the future
112123 super ( elementRef , cdr , overlayService , navigationService ) ;
113124 }
114125
126+ public override ngOnInit ( ) {
127+ super . ngOnInit ( ) ;
128+ this . createArrowElement ( ) ;
129+
130+ this . opened . pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( ) => {
131+ this . _arrowEl . style . display = this . _disableArrow ? 'none' : 'block' ;
132+ this . positionArrow ( this . overlayService . getOverlayById ( this . _overlayId ) . settings ) ;
133+ } ) ;
134+ }
135+
136+
137+ public ngAfterViewInit ( ) {
138+ if ( this . _sticky && ! this . _customCloseTemplate ) {
139+ this . appendDefaultCloseIcon ( ) ;
140+ }
141+ }
142+
143+
144+ public override ngOnDestroy ( ) {
145+ super . ngOnDestroy ( ) ;
146+ this . removeArrow ( ) ;
147+ this . removeCloseButton ( ) ;
148+ }
149+
115150 /**
116151 * If there is open animation in progress this method will finish is.
117152 * If there is no open animation in progress this method will open the toggle with no animation.
@@ -154,4 +189,108 @@ export class IgxTooltipDirective extends IgxToggleDirective {
154189 overlaySettings . positionStrategy . settings . closeAnimation = animation ;
155190 }
156191 }
192+
193+ private setOffsetTooltip ( settings : OverlaySettings ) {
194+ const pos = settings . positionStrategy . settings ;
195+ if ( ! pos ) return ;
196+
197+ if ( pos . verticalDirection === VerticalAlignment . Top ) {
198+ this . setOffset ( 0 , - this . _offset ) ;
199+ } else if ( pos . verticalDirection === VerticalAlignment . Bottom ) {
200+ this . setOffset ( 0 , this . _offset ) ;
201+ } else if ( pos . horizontalDirection === HorizontalAlignment . Left ) {
202+ this . setOffset ( this . _offset , 0 ) ;
203+ } else if ( pos . horizontalDirection === HorizontalAlignment . Right ) {
204+ this . setOffset ( - this . _offset , 0 ) ;
205+ }
206+ }
207+
208+ //TO DO:
209+ // Fix arrow flicker on animation played
210+ public positionArrow ( settings ?: OverlaySettings ) {
211+ const pos = settings ?. positionStrategy ?. settings ;
212+ if ( ! pos || ! this . _arrowEl ) return ;
213+
214+ const style = this . _arrowEl . style ;
215+ const offset = 4 ;
216+
217+ // Reset all directions and transforms
218+ style . top = '' ;
219+ style . bottom = '' ;
220+ style . left = '' ;
221+ style . right = '' ;
222+ style . transform = '' ;
223+
224+ const set = ( s : Partial < CSSStyleDeclaration > ) => Object . assign ( style , s ) ;
225+
226+ if ( pos . verticalDirection === VerticalAlignment . Top ) {
227+ set ( {
228+ bottom : `-${ offset } px` ,
229+ left : '50%' ,
230+ transform : 'translateX(-50%)'
231+ } ) ;
232+ } else if ( pos . verticalDirection === VerticalAlignment . Bottom ) {
233+ set ( {
234+ top : `-${ offset } px` ,
235+ left : '50%' ,
236+ transform : 'translateX(-50%)' ,
237+ } ) ;
238+ } else if ( pos . horizontalDirection === HorizontalAlignment . Left ) {
239+ set ( {
240+ right : `-${ offset } px` ,
241+ top : '50%' ,
242+ transform : 'translateY(-50%)'
243+ } ) ;
244+ } else if ( pos . horizontalDirection === HorizontalAlignment . Right ) {
245+ set ( {
246+ left : `-${ offset } px` ,
247+ top : '50%' ,
248+ transform : 'translateY(-50%)'
249+ } ) ;
250+ }
251+ }
252+
253+ private createArrowElement ( ) {
254+ this . _arrowEl = document . createElement ( 'div' ) ;
255+ this . _arrowEl . classList . add ( 'igx-tooltip--arrow' ) ;
256+ this . _arrowEl . style . position = 'absolute' ;
257+ this . _arrowEl . style . width = '8px' ;
258+ this . _arrowEl . style . height = '8px' ;
259+ this . _arrowEl . style . transform = 'rotate(45deg)' ;
260+ this . _arrowEl . style . background = 'inherit' ;
261+ this . element . appendChild ( this . _arrowEl ) ;
262+ }
263+
264+ protected renderCustomCloseTemplate ( ) : void {
265+ this . removeCloseButton ( ) ;
266+
267+ const view = this . viewContainerRef . createEmbeddedView ( this . _customCloseTemplate ) ;
268+ view . detectChanges ( ) ;
269+
270+ for ( const node of view . rootNodes ) {
271+ if ( node instanceof HTMLElement ) {
272+ node . classList . add ( 'close-button' ) ;
273+ this . element . appendChild ( node ) ;
274+ }
275+ }
276+ }
277+
278+ protected appendDefaultCloseIcon ( ) : void {
279+ this . removeCloseButton ( ) ;
280+ const buttonRef = this . viewContainerRef . createComponent ( TooltipCloseButtonComponent ) ;
281+ buttonRef . instance . clicked . pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( ) => this . close ( ) ) ;
282+ this . element . appendChild ( buttonRef . location . nativeElement ) ;
283+ }
284+
285+ private removeCloseButton ( ) {
286+ const closeButton = this . element . querySelector ( '.close-button' ) ;
287+ if ( closeButton ) {
288+ closeButton . remove ( ) ;
289+ }
290+ }
291+
292+ private removeArrow ( ) {
293+ this . _arrowEl . remove ( ) ;
294+ this . _arrowEl = null ;
295+ }
157296}
0 commit comments