22 AfterViewInit ,
33 ChangeDetectorRef ,
44 ComponentRef ,
5+ computed ,
56 DestroyRef ,
67 Directive ,
78 effect ,
@@ -10,75 +11,95 @@ import {
1011 inject ,
1112 Inject ,
1213 input ,
13- Input ,
14- OnChanges ,
14+ model ,
1515 OnDestroy ,
1616 OnInit ,
1717 Renderer2 ,
18- SimpleChanges ,
1918 TemplateRef ,
20- ViewContainerRef
19+ ViewContainerRef ,
2120} from '@angular/core' ;
22- import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
2321import { DOCUMENT } from '@angular/common' ;
24- import { debounceTime , filter , finalize } from 'rxjs/operators' ;
2522import { createPopper , Instance , Options } from '@popperjs/core' ;
2623
2724import { Triggers } from '../coreui.types' ;
2825import { TooltipComponent } from './tooltip/tooltip.component' ;
29- import { IListenersConfig , ListenersService } from '../services/listeners.service' ;
30- import { IntersectionService } from '../services' ;
26+ import { IListenersConfig , IntersectionService , ListenersService } from '../services' ;
27+ import { debounceTime , filter , finalize } from 'rxjs/operators' ;
28+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
29+ import { ElementRefDirective } from '../shared' ;
3130
3231@Directive ( {
3332 selector : '[cTooltip]' ,
3433 exportAs : 'cTooltip' ,
3534 providers : [ ListenersService , IntersectionService ] ,
36- standalone : true
35+ standalone : true ,
3736} )
38- export class TooltipDirective implements OnChanges , OnDestroy , OnInit , AfterViewInit {
39-
37+ export class TooltipDirective implements OnDestroy , OnInit , AfterViewInit {
4038 /**
4139 * Content of tooltip
4240 * @type {string | TemplateRef }
4341 */
44- readonly content = input < string | TemplateRef < any > > ( '' , { alias : 'cTooltip' } ) ;
42+ readonly content = input < string | TemplateRef < any > | undefined > ( undefined , { alias : 'cTooltip' } ) ;
43+
44+ contentEffect = effect ( ( ) => {
45+ if ( this . content ( ) ) {
46+ this . destroyTooltipElement ( ) ;
47+ }
48+ } ) ;
4549
4650 /**
4751 * Optional popper Options object, takes precedence over cPopoverPlacement prop
4852 * @type Partial<Options>
4953 */
50- @Input ( 'cTooltipOptions' )
51- set popperOptions ( value : Partial < Options > ) {
52- this . _popperOptions = { ...this . _popperOptions , placement : this . placement , ...value } ;
53- } ;
54+ readonly popperOptions = input < Partial < Options > > ( { } , { alias : 'cTooltipOptions' } ) ;
5455
55- get popperOptions ( ) : Partial < Options > {
56- return { placement : this . placement , ...this . _popperOptions } ;
57- }
56+ popperOptionsEffect = effect ( ( ) => {
57+ this . _popperOptions = {
58+ ...this . _popperOptions ,
59+ placement : this . placement ( ) ,
60+ ...this . popperOptions ( ) ,
61+ } ;
62+ } ) ;
63+
64+ popperOptionsComputed = computed ( ( ) => {
65+ return { placement : this . placement ( ) , ...this . _popperOptions } ;
66+ } ) ;
5867
5968 /**
6069 * Describes the placement of your component after Popper.js has applied all the modifiers that may have flipped or altered the originally provided placement property.
70+ * @type : 'top' | 'bottom' | 'left' | 'right'
71+ * @default : 'top'
72+ */
73+ readonly placement = input < 'top' | 'bottom' | 'left' | 'right' > ( 'top' , {
74+ alias : 'cTooltipPlacement' ,
75+ } ) ;
76+
77+ /**
78+ * ElementRefDirective for positioning the tooltip on reference element
79+ * @type : ElementRefDirective
80+ * @default : undefined
6181 */
62- @Input ( 'cTooltipPlacement' ) placement : 'top' | 'bottom' | 'left' | 'right' = 'top' ;
82+ readonly reference = input < ElementRefDirective | undefined > ( undefined , {
83+ alias : 'cTooltipRef' ,
84+ } ) ;
85+
86+ readonly referenceRef = computed ( ( ) => this . reference ( ) ?. elementRef ?? this . hostElement ) ;
87+
6388 /**
6489 * Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them.
65- * @type { 'hover' | 'focus' | 'click' }
90+ * @type : 'Triggers | Triggers[]
6691 */
67- @ Input ( 'cTooltipTrigger' ) trigger : Triggers | Triggers [ ] = 'hover' ;
92+ readonly trigger = input < Triggers | Triggers [ ] > ( 'hover' , { alias : 'cTooltipTrigger' } ) ;
6893
6994 /**
7095 * Toggle the visibility of tooltip component.
96+ * @type boolean
7197 */
72- @Input ( 'cTooltipVisible' )
73- set visible ( value : boolean ) {
74- this . _visible = value ;
75- }
98+ readonly visible = model ( false , { alias : 'cTooltipVisible' } ) ;
7699
77- get visible ( ) {
78- return this . _visible ;
79- }
80-
81- private _visible = false ;
100+ visibleEffect = effect ( ( ) => {
101+ this . visible ( ) ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
102+ } ) ;
82103
83104 @HostBinding ( 'attr.aria-describedby' ) get ariaDescribedBy ( ) : string | null {
84105 return this . tooltipId ? this . tooltipId : null ;
@@ -94,10 +115,10 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
94115 {
95116 name : 'offset' ,
96117 options : {
97- offset : [ 0 , 5 ]
98- }
99- }
100- ]
118+ offset : [ 0 , 5 ] ,
119+ } ,
120+ } ,
121+ ] ,
101122 } ;
102123
103124 readonly #destroyRef = inject ( DestroyRef ) ;
@@ -109,24 +130,13 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
109130 private viewContainerRef : ViewContainerRef ,
110131 private listenersService : ListenersService ,
111132 private changeDetectorRef : ChangeDetectorRef ,
112- private intersectionService : IntersectionService
133+ private intersectionService : IntersectionService ,
113134 ) { }
114135
115- contentEffect = effect ( ( ) => {
116- this . destroyTooltipElement ( ) ;
117- this . content ( ) ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
118- } ) ;
119-
120136 ngAfterViewInit ( ) : void {
121137 this . intersectionServiceSubscribe ( ) ;
122138 }
123139
124- ngOnChanges ( changes : SimpleChanges ) : void {
125- if ( changes [ 'visible' ] ) {
126- changes [ 'visible' ] . currentValue ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
127- }
128- }
129-
130140 ngOnDestroy ( ) : void {
131141 this . clearListeners ( ) ;
132142 this . destroyTooltipElement ( ) ;
@@ -139,19 +149,16 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
139149 private setListeners ( ) : void {
140150 const config : IListenersConfig = {
141151 hostElement : this . hostElement ,
142- trigger : this . trigger ,
152+ trigger : this . trigger ( ) ,
143153 callbackToggle : ( ) => {
144- this . visible = ! this . visible ;
145- this . visible ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
154+ this . visible . set ( ! this . visible ( ) ) ;
146155 } ,
147156 callbackOff : ( ) => {
148- this . visible = false ;
149- this . removeTooltipElement ( ) ;
157+ this . visible . set ( false ) ;
150158 } ,
151159 callbackOn : ( ) => {
152- this . visible = true ;
153- this . addTooltipElement ( ) ;
154- }
160+ this . visible . set ( true ) ;
161+ } ,
155162 } ;
156163 this . listenersService . setListeners ( config ) ;
157164 }
@@ -161,19 +168,18 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
161168 }
162169
163170 private intersectionServiceSubscribe ( ) : void {
164- this . intersectionService . createIntersectionObserver ( this . hostElement ) ;
171+ this . intersectionService . createIntersectionObserver ( this . referenceRef ( ) ) ;
165172 this . intersectionService . intersecting$
166173 . pipe (
167- filter ( next => next . hostElement === this . hostElement ) ,
174+ filter ( ( next ) => next . hostElement === this . referenceRef ( ) ) ,
168175 debounceTime ( 100 ) ,
169176 finalize ( ( ) => {
170- this . intersectionService . unobserve ( this . hostElement ) ;
177+ this . intersectionService . unobserve ( this . referenceRef ( ) ) ;
171178 } ) ,
172- takeUntilDestroyed ( this . #destroyRef)
179+ takeUntilDestroyed ( this . #destroyRef) ,
173180 )
174- . subscribe ( next => {
175- this . visible = next . isIntersecting ? this . visible : false ;
176- ! this . visible && this . removeTooltipElement ( ) ;
181+ . subscribe ( ( next ) => {
182+ this . visible . set ( next . isIntersecting ? this . visible ( ) : false ) ;
177183 } ) ;
178184 }
179185
@@ -205,6 +211,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
205211
206212 private addTooltipElement ( ) : void {
207213 if ( ! this . content ( ) ) {
214+ this . destroyTooltipElement ( ) ;
208215 return ;
209216 }
210217
@@ -214,7 +221,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
214221
215222 this . tooltipId = this . getUID ( 'tooltip' ) ;
216223 this . tooltipRef . instance . id = this . tooltipId ;
217- this . tooltipRef . instance . content = this . content ( ) ;
224+ this . tooltipRef . instance . content = this . content ( ) ?? '' ;
218225
219226 this . tooltip = this . tooltipRef . location . nativeElement ;
220227 this . renderer . addClass ( this . tooltip , 'd-none' ) ;
@@ -225,24 +232,21 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
225232 this . viewContainerRef . insert ( this . tooltipRef . hostView ) ;
226233 this . renderer . appendChild ( this . document . body , this . tooltip ) ;
227234
228- this . popperInstance = createPopper (
229- this . hostElement . nativeElement ,
230- this . tooltip ,
231- { ...this . popperOptions }
232- ) ;
233- if ( ! this . visible ) {
235+ this . popperInstance = createPopper ( this . referenceRef ( ) . nativeElement , this . tooltip , {
236+ ...this . popperOptionsComputed ( ) ,
237+ } ) ;
238+ if ( ! this . visible ( ) ) {
234239 this . removeTooltipElement ( ) ;
235240 return ;
236241 }
237242 this . renderer . removeClass ( this . tooltip , 'd-none' ) ;
238243 this . changeDetectorRef . markForCheck ( ) ;
239244
240245 setTimeout ( ( ) => {
241- this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ) ;
246+ this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ( ) ) ;
242247 this . popperInstance ?. forceUpdate ( ) ;
243248 this . changeDetectorRef ?. markForCheck ( ) ;
244249 } , 100 ) ;
245-
246250 }
247251
248252 private removeTooltipElement ( ) : void {
0 commit comments