22AfterViewInit ,
33ChangeDetectorRef ,
44ComponentRef ,
5+ computed ,
56DestroyRef ,
67Directive ,
78effect ,
@@ -10,75 +11,95 @@ import {
1011inject ,
1112Inject ,
1213input ,
13- Input ,
14- OnChanges ,
14+ model ,
1515OnDestroy ,
1616OnInit ,
1717Renderer2 ,
18- SimpleChanges ,
1918TemplateRef ,
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 ( {
3332selector :'[cTooltip]' ,
3433exportAs :'cTooltip' ,
3534providers :[ 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 {
84105return this . tooltipId ?this . tooltipId :null ;
@@ -94,10 +115,10 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
94115{
95116name :'offset' ,
96117options :{
97- offset :[ 0 , 5 ]
98- }
99- }
100- ]
118+ offset :[ 0 , 5 ] ,
119+ } ,
120+ } ,
121+ ] ,
101122} ;
102123
103124readonly #destroyRef= inject ( DestroyRef ) ;
@@ -109,24 +130,13 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
109130private viewContainerRef :ViewContainerRef ,
110131private listenersService :ListenersService ,
111132private 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-
120136ngAfterViewInit ( ) :void {
121137this . intersectionServiceSubscribe ( ) ;
122138}
123139
124- ngOnChanges ( changes :SimpleChanges ) :void {
125- if ( changes [ 'visible' ] ) {
126- changes [ 'visible' ] . currentValue ?this . addTooltipElement ( ) :this . removeTooltipElement ( ) ;
127- }
128- }
129-
130140ngOnDestroy ( ) :void {
131141this . clearListeners ( ) ;
132142this . destroyTooltipElement ( ) ;
@@ -139,19 +149,16 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
139149private setListeners ( ) :void {
140150const config :IListenersConfig = {
141151hostElement :this . hostElement ,
142- trigger :this . trigger ,
152+ trigger :this . trigger ( ) ,
143153callbackToggle :( ) => {
144- this . visible = ! this . visible ;
145- this . visible ?this . addTooltipElement ( ) :this . removeTooltipElement ( ) ;
154+ this . visible . set ( ! this . visible ( ) ) ;
146155} ,
147156callbackOff :( ) => {
148- this . visible = false ;
149- this . removeTooltipElement ( ) ;
157+ this . visible . set ( false ) ;
150158} ,
151159callbackOn :( ) => {
152- this . visible = true ;
153- this . addTooltipElement ( ) ;
154- }
160+ this . visible . set ( true ) ;
161+ } ,
155162} ;
156163this . listenersService . setListeners ( config ) ;
157164}
@@ -161,19 +168,18 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
161168}
162169
163170private intersectionServiceSubscribe ( ) :void {
164- this . intersectionService . createIntersectionObserver ( this . hostElement ) ;
171+ this . intersectionService . createIntersectionObserver ( this . referenceRef ( ) ) ;
165172this . intersectionService . intersecting$
166173. pipe (
167- filter ( next => next . hostElement === this . hostElement ) ,
174+ filter ( ( next ) => next . hostElement === this . referenceRef ( ) ) ,
168175debounceTime ( 100 ) ,
169176finalize ( ( ) => {
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
206212private addTooltipElement ( ) :void {
207213if ( ! this . content ( ) ) {
214+ this . destroyTooltipElement ( ) ;
208215return ;
209216}
210217
@@ -214,7 +221,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
214221
215222this . tooltipId = this . getUID ( 'tooltip' ) ;
216223this . tooltipRef . instance . id = this . tooltipId ;
217- this . tooltipRef . instance . content = this . content ( ) ;
224+ this . tooltipRef . instance . content = this . content ( ) ?? '' ;
218225
219226this . tooltip = this . tooltipRef . location . nativeElement ;
220227this . renderer . addClass ( this . tooltip , 'd-none' ) ;
@@ -225,24 +232,21 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
225232this . viewContainerRef . insert ( this . tooltipRef . hostView ) ;
226233this . 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 ( ) ) {
234239this . removeTooltipElement ( ) ;
235240return ;
236241}
237242this . renderer . removeClass ( this . tooltip , 'd-none' ) ;
238243this . changeDetectorRef . markForCheck ( ) ;
239244
240245setTimeout ( ( ) => {
241- this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ) ;
246+ this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ( ) ) ;
242247this . popperInstance ?. forceUpdate ( ) ;
243248this . changeDetectorRef ?. markForCheck ( ) ;
244249} , 100 ) ;
245-
246250}
247251
248252private removeTooltipElement ( ) :void {