2
2
AfterViewInit ,
3
3
ChangeDetectorRef ,
4
4
ComponentRef ,
5
+ computed ,
5
6
DestroyRef ,
6
7
Directive ,
7
8
effect ,
@@ -10,75 +11,95 @@ import {
10
11
inject ,
11
12
Inject ,
12
13
input ,
13
- Input ,
14
- OnChanges ,
14
+ model ,
15
15
OnDestroy ,
16
16
OnInit ,
17
17
Renderer2 ,
18
- SimpleChanges ,
19
18
TemplateRef ,
20
- ViewContainerRef
19
+ ViewContainerRef ,
21
20
} from '@angular/core' ;
22
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
23
21
import { DOCUMENT } from '@angular/common' ;
24
- import { debounceTime , filter , finalize } from 'rxjs/operators' ;
25
22
import { createPopper , Instance , Options } from '@popperjs/core' ;
26
23
27
24
import { Triggers } from '../coreui.types' ;
28
25
import { 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' ;
31
30
32
31
@Directive ( {
33
32
selector : '[cTooltip]' ,
34
33
exportAs : 'cTooltip' ,
35
34
providers : [ ListenersService , IntersectionService ] ,
36
- standalone : true
35
+ standalone : true ,
37
36
} )
38
- export class TooltipDirective implements OnChanges , OnDestroy , OnInit , AfterViewInit {
39
-
37
+ export class TooltipDirective implements OnDestroy , OnInit , AfterViewInit {
40
38
/**
41
39
* Content of tooltip
42
40
* @type {string | TemplateRef }
43
41
*/
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
+ } ) ;
45
49
46
50
/**
47
51
* Optional popper Options object, takes precedence over cPopoverPlacement prop
48
52
* @type Partial<Options>
49
53
*/
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' } ) ;
54
55
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
+ } ) ;
58
67
59
68
/**
60
69
* 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
61
81
*/
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
+
63
88
/**
64
89
* 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[]
66
91
*/
67
- @ Input ( 'cTooltipTrigger' ) trigger : Triggers | Triggers [ ] = 'hover' ;
92
+ readonly trigger = input < Triggers | Triggers [ ] > ( 'hover' , { alias : 'cTooltipTrigger' } ) ;
68
93
69
94
/**
70
95
* Toggle the visibility of tooltip component.
96
+ * @type boolean
71
97
*/
72
- @Input ( 'cTooltipVisible' )
73
- set visible ( value : boolean ) {
74
- this . _visible = value ;
75
- }
98
+ readonly visible = model ( false , { alias : 'cTooltipVisible' } ) ;
76
99
77
- get visible ( ) {
78
- return this . _visible ;
79
- }
80
-
81
- private _visible = false ;
100
+ visibleEffect = effect ( ( ) => {
101
+ this . visible ( ) ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
102
+ } ) ;
82
103
83
104
@HostBinding ( 'attr.aria-describedby' ) get ariaDescribedBy ( ) : string | null {
84
105
return this . tooltipId ? this . tooltipId : null ;
@@ -94,10 +115,10 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
94
115
{
95
116
name : 'offset' ,
96
117
options : {
97
- offset : [ 0 , 5 ]
98
- }
99
- }
100
- ]
118
+ offset : [ 0 , 5 ] ,
119
+ } ,
120
+ } ,
121
+ ] ,
101
122
} ;
102
123
103
124
readonly #destroyRef = inject ( DestroyRef ) ;
@@ -109,24 +130,13 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
109
130
private viewContainerRef : ViewContainerRef ,
110
131
private listenersService : ListenersService ,
111
132
private changeDetectorRef : ChangeDetectorRef ,
112
- private intersectionService : IntersectionService
133
+ private intersectionService : IntersectionService ,
113
134
) { }
114
135
115
- contentEffect = effect ( ( ) => {
116
- this . destroyTooltipElement ( ) ;
117
- this . content ( ) ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
118
- } ) ;
119
-
120
136
ngAfterViewInit ( ) : void {
121
137
this . intersectionServiceSubscribe ( ) ;
122
138
}
123
139
124
- ngOnChanges ( changes : SimpleChanges ) : void {
125
- if ( changes [ 'visible' ] ) {
126
- changes [ 'visible' ] . currentValue ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
127
- }
128
- }
129
-
130
140
ngOnDestroy ( ) : void {
131
141
this . clearListeners ( ) ;
132
142
this . destroyTooltipElement ( ) ;
@@ -139,19 +149,16 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
139
149
private setListeners ( ) : void {
140
150
const config : IListenersConfig = {
141
151
hostElement : this . hostElement ,
142
- trigger : this . trigger ,
152
+ trigger : this . trigger ( ) ,
143
153
callbackToggle : ( ) => {
144
- this . visible = ! this . visible ;
145
- this . visible ? this . addTooltipElement ( ) : this . removeTooltipElement ( ) ;
154
+ this . visible . set ( ! this . visible ( ) ) ;
146
155
} ,
147
156
callbackOff : ( ) => {
148
- this . visible = false ;
149
- this . removeTooltipElement ( ) ;
157
+ this . visible . set ( false ) ;
150
158
} ,
151
159
callbackOn : ( ) => {
152
- this . visible = true ;
153
- this . addTooltipElement ( ) ;
154
- }
160
+ this . visible . set ( true ) ;
161
+ } ,
155
162
} ;
156
163
this . listenersService . setListeners ( config ) ;
157
164
}
@@ -161,19 +168,18 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
161
168
}
162
169
163
170
private intersectionServiceSubscribe ( ) : void {
164
- this . intersectionService . createIntersectionObserver ( this . hostElement ) ;
171
+ this . intersectionService . createIntersectionObserver ( this . referenceRef ( ) ) ;
165
172
this . intersectionService . intersecting$
166
173
. pipe (
167
- filter ( next => next . hostElement === this . hostElement ) ,
174
+ filter ( ( next ) => next . hostElement === this . referenceRef ( ) ) ,
168
175
debounceTime ( 100 ) ,
169
176
finalize ( ( ) => {
170
- this . intersectionService . unobserve ( this . hostElement ) ;
177
+ this . intersectionService . unobserve ( this . referenceRef ( ) ) ;
171
178
} ) ,
172
- takeUntilDestroyed ( this . #destroyRef)
179
+ takeUntilDestroyed ( this . #destroyRef) ,
173
180
)
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 ) ;
177
183
} ) ;
178
184
}
179
185
@@ -205,6 +211,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
205
211
206
212
private addTooltipElement ( ) : void {
207
213
if ( ! this . content ( ) ) {
214
+ this . destroyTooltipElement ( ) ;
208
215
return ;
209
216
}
210
217
@@ -214,7 +221,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
214
221
215
222
this . tooltipId = this . getUID ( 'tooltip' ) ;
216
223
this . tooltipRef . instance . id = this . tooltipId ;
217
- this . tooltipRef . instance . content = this . content ( ) ;
224
+ this . tooltipRef . instance . content = this . content ( ) ?? '' ;
218
225
219
226
this . tooltip = this . tooltipRef . location . nativeElement ;
220
227
this . renderer . addClass ( this . tooltip , 'd-none' ) ;
@@ -225,24 +232,21 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterView
225
232
this . viewContainerRef . insert ( this . tooltipRef . hostView ) ;
226
233
this . renderer . appendChild ( this . document . body , this . tooltip ) ;
227
234
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 ( ) ) {
234
239
this . removeTooltipElement ( ) ;
235
240
return ;
236
241
}
237
242
this . renderer . removeClass ( this . tooltip , 'd-none' ) ;
238
243
this . changeDetectorRef . markForCheck ( ) ;
239
244
240
245
setTimeout ( ( ) => {
241
- this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ) ;
246
+ this . tooltipRef && ( this . tooltipRef . instance . visible = this . visible ( ) ) ;
242
247
this . popperInstance ?. forceUpdate ( ) ;
243
248
this . changeDetectorRef ?. markForCheck ( ) ;
244
249
} , 100 ) ;
245
-
246
250
}
247
251
248
252
private removeTooltipElement ( ) : void {
0 commit comments