@radix-ng/primitives 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/compodoc/documentation.json +16241 -10958
  2. package/core/src/positioning/constants.d.ts +2 -1
  3. package/core/src/positioning/types.d.ts +16 -5
  4. package/fesm2022/radix-ng-primitives-core.mjs +22 -9
  5. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-popover.mjs +22 -29
  7. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-tooltip.mjs +966 -355
  9. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  10. package/package.json +1 -1
  11. package/popover/src/popover-arrow.directive.d.ts +3 -2
  12. package/popover/src/popover-content.directive.d.ts +6 -5
  13. package/popover/src/popover-root.directive.d.ts +8 -8
  14. package/tooltip/README.md +2 -0
  15. package/tooltip/index.d.ts +9 -6
  16. package/tooltip/src/tooltip-anchor.directive.d.ts +28 -0
  17. package/tooltip/src/tooltip-anchor.token.d.ts +3 -0
  18. package/tooltip/src/tooltip-arrow.directive.d.ts +18 -16
  19. package/tooltip/src/tooltip-close.directive.d.ts +18 -0
  20. package/tooltip/src/tooltip-close.token.d.ts +3 -0
  21. package/tooltip/src/tooltip-content-attributes.component.d.ts +17 -0
  22. package/tooltip/src/tooltip-content-attributes.token.d.ts +3 -0
  23. package/tooltip/src/tooltip-content.directive.d.ts +85 -16
  24. package/tooltip/src/tooltip-root.directive.d.ts +121 -59
  25. package/tooltip/src/tooltip-root.inject.d.ts +3 -0
  26. package/tooltip/src/tooltip-trigger.directive.d.ts +11 -11
  27. package/tooltip/src/tooltip.types.d.ts +18 -7
  28. package/tooltip/src/utils/cdk-event.service.d.ts +30 -0
  29. package/tooltip/src/utils/constants.d.ts +1 -0
  30. package/tooltip/src/utils/types.d.ts +7 -0
  31. package/popover/src/popover.constants.d.ts +0 -6
  32. package/tooltip/src/tooltip-content-attributes.directive.d.ts +0 -8
  33. package/tooltip/src/tooltip-content.token.d.ts +0 -3
  34. package/tooltip/src/tooltip.config.d.ts +0 -6
@@ -1,400 +1,952 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, ElementRef, Directive, ViewContainerRef, DestroyRef, PLATFORM_ID, input, output, signal, computed, contentChild, effect, untracked, forwardRef, Renderer2, afterNextRender, TemplateRef, NgModule } from '@angular/core';
3
- import { injectDocument, injectWindow, getArrowPositionParams, getSideAndAlignFromAllPossibleConnectedPositions, RdxPositionSide, RdxPositionAlign, getContentPosition } from '@radix-ng/primitives/core';
4
- import { Overlay } from '@angular/cdk/overlay';
5
- import { TemplatePortal } from '@angular/cdk/portal';
6
- import { isPlatformBrowser } from '@angular/common';
7
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
8
- import { filter, take, asyncScheduler } from 'rxjs';
2
+ import { InjectionToken, inject, TemplateRef, DestroyRef, computed, input, numberAttribute, booleanAttribute, output, effect, untracked, SimpleChange, Directive, ElementRef, NgZone, Renderer2, isDevMode, VERSION, Injectable, makeEnvironmentProviders, signal, contentChild, ViewContainerRef, afterNextRender, assertInInjectionContext, forwardRef, Component, ChangeDetectionStrategy, NgModule } from '@angular/core';
3
+ import * as i1 from '@angular/cdk/overlay';
4
+ import { Overlay, CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
5
+ import { RdxPositionSide, RdxPositionAlign, RDX_POSITIONING_DEFAULTS, getContentPosition, getAllPossibleConnectedPositions, injectDocument, injectWindow, getArrowPositionParams, getSideAndAlignFromAllPossibleConnectedPositions } from '@radix-ng/primitives/core';
6
+ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
7
+ import { filter, tap, Subject, map, debounce, timer } from 'rxjs';
8
+
9
+ const RdxTooltipAnchorToken = new InjectionToken('RdxTooltipAnchorToken');
9
10
 
10
11
  const RdxTooltipArrowToken = new InjectionToken('RdxTooltipArrowToken');
11
12
 
12
- const RdxTooltipContentToken = new InjectionToken('RdxTooltipContentToken');
13
+ const RdxTooltipCloseToken = new InjectionToken('RdxTooltipCloseToken');
13
14
 
14
- class RdxTooltipTriggerDirective {
15
+ const RdxTooltipContentAttributesToken = new InjectionToken('RdxTooltipContentAttributesToken');
16
+
17
+ var RdxTooltipState;
18
+ (function (RdxTooltipState) {
19
+ RdxTooltipState["OPEN"] = "open";
20
+ RdxTooltipState["CLOSED"] = "closed";
21
+ })(RdxTooltipState || (RdxTooltipState = {}));
22
+ var RdxTooltipAction;
23
+ (function (RdxTooltipAction) {
24
+ RdxTooltipAction["OPEN"] = "open";
25
+ RdxTooltipAction["CLOSE"] = "close";
26
+ })(RdxTooltipAction || (RdxTooltipAction = {}));
27
+ var RdxTooltipAttachDetachEvent;
28
+ (function (RdxTooltipAttachDetachEvent) {
29
+ RdxTooltipAttachDetachEvent["ATTACH"] = "attach";
30
+ RdxTooltipAttachDetachEvent["DETACH"] = "detach";
31
+ })(RdxTooltipAttachDetachEvent || (RdxTooltipAttachDetachEvent = {}));
32
+ var RdxTooltipAnimationStatus;
33
+ (function (RdxTooltipAnimationStatus) {
34
+ RdxTooltipAnimationStatus["OPEN_STARTED"] = "open_started";
35
+ RdxTooltipAnimationStatus["OPEN_ENDED"] = "open_ended";
36
+ RdxTooltipAnimationStatus["CLOSED_STARTED"] = "closed_started";
37
+ RdxTooltipAnimationStatus["CLOSED_ENDED"] = "closed_ended";
38
+ })(RdxTooltipAnimationStatus || (RdxTooltipAnimationStatus = {}));
39
+
40
+ class RdxTooltipContentDirective {
15
41
  constructor() {
16
42
  /** @ignore */
17
- this.tooltipRoot = injectTooltipRoot();
43
+ this.rootDirective = injectTooltipRoot();
18
44
  /** @ignore */
19
- this.elementRef = inject((ElementRef));
45
+ this.templateRef = inject(TemplateRef);
20
46
  /** @ignore */
21
- this.isPointerDown = false;
47
+ this.overlay = inject(Overlay);
22
48
  /** @ignore */
23
- this.isPointerInside = false;
49
+ this.destroyRef = inject(DestroyRef);
50
+ /** @ignore */
51
+ this.connectedOverlay = inject(CdkConnectedOverlay);
52
+ /** @ignore */
53
+ this.name = computed(() => `rdx-tooltip-trigger-${this.rootDirective.uniqueId()}`);
54
+ /**
55
+ * @description The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
56
+ * @default top
57
+ */
58
+ this.side = input(RdxPositionSide.Top);
59
+ /**
60
+ * @description The distance in pixels from the trigger.
61
+ * @default undefined
62
+ */
63
+ this.sideOffset = input(NaN, {
64
+ transform: numberAttribute
65
+ });
66
+ /**
67
+ * @description The preferred alignment against the trigger. May change when collisions occur.
68
+ * @default center
69
+ */
70
+ this.align = input(RdxPositionAlign.Center);
71
+ /**
72
+ * @description An offset in pixels from the "start" or "end" alignment options.
73
+ * @default undefined
74
+ */
75
+ this.alignOffset = input(NaN, {
76
+ transform: numberAttribute
77
+ });
78
+ /**
79
+ * @description Whether to add some alternate positions of the content.
80
+ * @default false
81
+ */
82
+ this.alternatePositionsDisabled = input(false, { transform: booleanAttribute });
83
+ /** @description Whether to prevent `onOverlayEscapeKeyDown` handler from calling. */
84
+ this.onOverlayEscapeKeyDownDisabled = input(false, { transform: booleanAttribute });
85
+ /** @description Whether to prevent `onOverlayOutsideClick` handler from calling. */
86
+ this.onOverlayOutsideClickDisabled = input(false, { transform: booleanAttribute });
87
+ /**
88
+ * @description Event handler called when the escape key is down.
89
+ * It can be prevented by setting `onOverlayEscapeKeyDownDisabled` input to `true`.
90
+ */
91
+ this.onOverlayEscapeKeyDown = output();
92
+ /**
93
+ * @description Event handler called when a pointer event occurs outside the bounds of the component.
94
+ * It can be prevented by setting `onOverlayOutsideClickDisabled` input to `true`.
95
+ */
96
+ this.onOverlayOutsideClick = output();
97
+ /**
98
+ * @description Event handler called after the overlay is open
99
+ */
100
+ this.onOpen = output();
101
+ /**
102
+ * @description Event handler called after the overlay is closed
103
+ */
104
+ this.onClosed = output();
105
+ /** @ingore */
106
+ this.positions = computed(() => this.computePositions());
107
+ this.onOriginChangeEffect();
108
+ this.onPositionChangeEffect();
24
109
  }
25
110
  /** @ignore */
26
- onPointerMove(event) {
27
- if (event.pointerType === 'touch') {
111
+ ngOnInit() {
112
+ this.setScrollStrategy();
113
+ this.setHasBackdrop();
114
+ this.setDisableClose();
115
+ this.onAttach();
116
+ this.onDetach();
117
+ this.connectKeydownEscape();
118
+ this.connectOutsideClick();
119
+ }
120
+ /** @ignore */
121
+ open() {
122
+ if (this.connectedOverlay.open) {
28
123
  return;
29
124
  }
30
- if (!this.isPointerInside) {
31
- this.tooltipRoot.onTriggerEnter();
32
- this.isPointerInside = true;
125
+ const prevOpen = this.connectedOverlay.open;
126
+ this.connectedOverlay.open = true;
127
+ this.fireOverlayNgOnChanges('open', this.connectedOverlay.open, prevOpen);
128
+ }
129
+ /** @ignore */
130
+ close() {
131
+ if (!this.connectedOverlay.open) {
132
+ return;
33
133
  }
134
+ const prevOpen = this.connectedOverlay.open;
135
+ this.connectedOverlay.open = false;
136
+ this.fireOverlayNgOnChanges('open', this.connectedOverlay.open, prevOpen);
137
+ }
138
+ /** @ignore */
139
+ positionChange() {
140
+ return this.connectedOverlay.positionChange.asObservable();
141
+ }
142
+ /** @ignore */
143
+ connectKeydownEscape() {
144
+ this.connectedOverlay.overlayKeydown
145
+ .asObservable()
146
+ .pipe(filter(() => !this.onOverlayEscapeKeyDownDisabled() &&
147
+ !this.rootDirective.rdxCdkEventService?.primitivePreventedFromCdkEvent(this.rootDirective, 'cdkOverlayEscapeKeyDown')), filter((event) => event.key === 'Escape'), tap((event) => {
148
+ this.onOverlayEscapeKeyDown.emit(event);
149
+ }), filter(() => !this.rootDirective.firstDefaultOpen()), tap(() => {
150
+ this.rootDirective.handleClose();
151
+ }), takeUntilDestroyed(this.destroyRef))
152
+ .subscribe();
153
+ }
154
+ /** @ignore */
155
+ connectOutsideClick() {
156
+ this.connectedOverlay.overlayOutsideClick
157
+ .asObservable()
158
+ .pipe(filter(() => !this.onOverlayOutsideClickDisabled() &&
159
+ !this.rootDirective.rdxCdkEventService?.primitivePreventedFromCdkEvent(this.rootDirective, 'cdkOverlayOutsideClick')),
160
+ /**
161
+ * Handle the situation when an anchor is added and the anchor becomes the origin of the overlay
162
+ * hence the trigger will be considered the outside element
163
+ */
164
+ filter((event) => {
165
+ return (!this.rootDirective.anchorDirective() ||
166
+ !this.rootDirective
167
+ .triggerDirective()
168
+ .elementRef.nativeElement.contains(event.target));
169
+ }), tap((event) => {
170
+ this.onOverlayOutsideClick.emit(event);
171
+ }), filter(() => !this.rootDirective.firstDefaultOpen()), tap(() => {
172
+ this.rootDirective.handleClose();
173
+ }), takeUntilDestroyed(this.destroyRef))
174
+ .subscribe();
175
+ }
176
+ /** @ignore */
177
+ onAttach() {
178
+ this.connectedOverlay.attach
179
+ .asObservable()
180
+ .pipe(tap(() => {
181
+ /**
182
+ * `this.onOpen.emit();` is being delegated to the rootDirective directive due to the opening animation
183
+ */
184
+ this.rootDirective.attachDetachEvent.set(RdxTooltipAttachDetachEvent.ATTACH);
185
+ }), takeUntilDestroyed(this.destroyRef))
186
+ .subscribe();
187
+ }
188
+ /** @ignore */
189
+ onDetach() {
190
+ this.connectedOverlay.detach
191
+ .asObservable()
192
+ .pipe(tap(() => {
193
+ /**
194
+ * `this.onClosed.emit();` is being delegated to the rootDirective directive due to the closing animation
195
+ */
196
+ this.rootDirective.attachDetachEvent.set(RdxTooltipAttachDetachEvent.DETACH);
197
+ }), takeUntilDestroyed(this.destroyRef))
198
+ .subscribe();
34
199
  }
35
200
  /** @ignore */
36
- onPointerLeave() {
37
- this.isPointerInside = false;
38
- this.tooltipRoot.onTriggerLeave();
201
+ setScrollStrategy() {
202
+ const prevScrollStrategy = this.connectedOverlay.scrollStrategy;
203
+ this.connectedOverlay.scrollStrategy = this.overlay.scrollStrategies.reposition();
204
+ this.fireOverlayNgOnChanges('scrollStrategy', this.connectedOverlay.scrollStrategy, prevScrollStrategy);
39
205
  }
40
206
  /** @ignore */
41
- onPointerDown() {
42
- this.isPointerDown = true;
43
- this.elementRef.nativeElement.addEventListener('pointerup', () => {
44
- this.isPointerDown = false;
45
- }, { once: true });
207
+ setHasBackdrop() {
208
+ const prevHasBackdrop = this.connectedOverlay.hasBackdrop;
209
+ this.connectedOverlay.hasBackdrop = false;
210
+ this.fireOverlayNgOnChanges('hasBackdrop', this.connectedOverlay.hasBackdrop, prevHasBackdrop);
46
211
  }
47
212
  /** @ignore */
48
- onFocus() {
49
- if (!this.isPointerDown) {
50
- this.tooltipRoot.handleOpen();
213
+ setDisableClose() {
214
+ const prevDisableClose = this.connectedOverlay.disableClose;
215
+ this.connectedOverlay.disableClose = true;
216
+ this.fireOverlayNgOnChanges('disableClose', this.connectedOverlay.disableClose, prevDisableClose);
217
+ }
218
+ /** @ignore */
219
+ setOrigin(origin) {
220
+ const prevOrigin = this.connectedOverlay.origin;
221
+ this.connectedOverlay.origin = origin;
222
+ this.fireOverlayNgOnChanges('origin', this.connectedOverlay.origin, prevOrigin);
223
+ }
224
+ /** @ignore */
225
+ setPositions(positions) {
226
+ const prevPositions = this.connectedOverlay.positions;
227
+ this.connectedOverlay.positions = positions;
228
+ this.fireOverlayNgOnChanges('positions', this.connectedOverlay.positions, prevPositions);
229
+ this.connectedOverlay.overlayRef?.updatePosition();
230
+ }
231
+ /** @ignore */
232
+ computePositions() {
233
+ const arrowHeight = this.rootDirective.arrowDirective()?.height() ?? 0;
234
+ const offsets = {
235
+ sideOffset: isNaN(this.sideOffset())
236
+ ? arrowHeight || RDX_POSITIONING_DEFAULTS.offsets.side
237
+ : this.sideOffset(),
238
+ alignOffset: isNaN(this.alignOffset()) ? RDX_POSITIONING_DEFAULTS.offsets.align : this.alignOffset()
239
+ };
240
+ const basePosition = getContentPosition({
241
+ side: this.side(),
242
+ align: this.align(),
243
+ sideOffset: offsets.sideOffset,
244
+ alignOffset: offsets.alignOffset
245
+ });
246
+ const positions = [basePosition];
247
+ if (!this.alternatePositionsDisabled()) {
248
+ /**
249
+ * Alternate positions for better user experience along the X/Y axis (e.g. vertical/horizontal scrolling)
250
+ */
251
+ const allPossibleConnectedPositions = getAllPossibleConnectedPositions();
252
+ allPossibleConnectedPositions.forEach((_, key) => {
253
+ const sideAndAlignArray = key.split('|');
254
+ if (sideAndAlignArray[0] !== this.side() ||
255
+ sideAndAlignArray[1] !== this.align()) {
256
+ positions.push(getContentPosition({
257
+ side: sideAndAlignArray[0],
258
+ align: sideAndAlignArray[1],
259
+ sideOffset: offsets.sideOffset,
260
+ alignOffset: offsets.alignOffset
261
+ }));
262
+ }
263
+ });
51
264
  }
265
+ return positions;
266
+ }
267
+ onOriginChangeEffect() {
268
+ effect(() => {
269
+ const origin = (this.rootDirective.anchorDirective() ?? this.rootDirective.triggerDirective())
270
+ .overlayOrigin;
271
+ untracked(() => {
272
+ this.setOrigin(origin);
273
+ });
274
+ });
52
275
  }
53
276
  /** @ignore */
54
- onBlur() {
55
- this.tooltipRoot.handleClose();
277
+ onPositionChangeEffect() {
278
+ effect(() => {
279
+ const positions = this.positions();
280
+ this.alternatePositionsDisabled();
281
+ untracked(() => {
282
+ this.setPositions(positions);
283
+ });
284
+ });
56
285
  }
57
286
  /** @ignore */
58
- onClick() {
59
- this.tooltipRoot.handleClose();
287
+ fireOverlayNgOnChanges(input, currentValue, previousValue, firstChange = false) {
288
+ this.connectedOverlay.ngOnChanges({
289
+ [input]: new SimpleChange(previousValue, currentValue, firstChange)
290
+ });
291
+ }
292
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
293
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.5", type: RdxTooltipContentDirective, isStandalone: true, selector: "[rdxTooltipContent]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, alternatePositionsDisabled: { classPropertyName: "alternatePositionsDisabled", publicName: "alternatePositionsDisabled", isSignal: true, isRequired: false, transformFunction: null }, onOverlayEscapeKeyDownDisabled: { classPropertyName: "onOverlayEscapeKeyDownDisabled", publicName: "onOverlayEscapeKeyDownDisabled", isSignal: true, isRequired: false, transformFunction: null }, onOverlayOutsideClickDisabled: { classPropertyName: "onOverlayOutsideClickDisabled", publicName: "onOverlayOutsideClickDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onOverlayEscapeKeyDown: "onOverlayEscapeKeyDown", onOverlayOutsideClick: "onOverlayOutsideClick", onOpen: "onOpen", onClosed: "onClosed" }, hostDirectives: [{ directive: i1.CdkConnectedOverlay }], ngImport: i0 }); }
294
+ }
295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentDirective, decorators: [{
296
+ type: Directive,
297
+ args: [{
298
+ selector: '[rdxTooltipContent]',
299
+ hostDirectives: [
300
+ CdkConnectedOverlay
301
+ ]
302
+ }]
303
+ }], ctorParameters: () => [] });
304
+
305
+ class RdxTooltipTriggerDirective {
306
+ constructor() {
307
+ /** @ignore */
308
+ this.rootDirective = injectTooltipRoot();
309
+ /** @ignore */
310
+ this.elementRef = inject(ElementRef);
311
+ /** @ignore */
312
+ this.overlayOrigin = inject(CdkOverlayOrigin);
313
+ /** @ignore */
314
+ this.name = computed(() => `rdx-tooltip-trigger-${this.rootDirective.uniqueId()}`);
315
+ }
316
+ /** @ignore */
317
+ pointerenter() {
318
+ this.rootDirective.handleOpen();
319
+ }
320
+ /** @ignore */
321
+ pointerleave() {
322
+ this.rootDirective.handleClose();
323
+ }
324
+ /** @ignore */
325
+ focus() {
326
+ this.rootDirective.handleOpen();
327
+ }
328
+ /** @ignore */
329
+ blur() {
330
+ this.rootDirective.handleClose();
331
+ }
332
+ /** @ignore */
333
+ click() {
334
+ this.rootDirective.handleClose();
60
335
  }
61
336
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
62
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipTriggerDirective, isStandalone: true, selector: "[rdxTooltipTrigger]", host: { listeners: { "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave()", "pointerdown": "onPointerDown()", "focus": "onFocus()", "blur": "onBlur()", "click": "onClick()" }, properties: { "attr.data-state": "tooltipRoot.state()" } }, ngImport: i0 }); }
337
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipTriggerDirective, isStandalone: true, selector: "[rdxTooltipTrigger]", host: { attributes: { "type": "button" }, listeners: { "pointerenter": "pointerenter()", "pointerleave": "pointerleave()", "focus": "focus()", "blur": "blur()", "click": "click()" }, properties: { "attr.id": "name()", "attr.aria-haspopup": "\"dialog\"", "attr.aria-expanded": "rootDirective.isOpen()", "attr.aria-controls": "rootDirective.contentDirective().name()", "attr.data-state": "rootDirective.state()" } }, hostDirectives: [{ directive: i1.CdkOverlayOrigin }], ngImport: i0 }); }
63
338
  }
64
339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipTriggerDirective, decorators: [{
65
340
  type: Directive,
66
341
  args: [{
67
342
  selector: '[rdxTooltipTrigger]',
68
- standalone: true,
343
+ hostDirectives: [CdkOverlayOrigin],
69
344
  host: {
70
- '[attr.data-state]': 'tooltipRoot.state()',
71
- '(pointermove)': 'onPointerMove($event)',
72
- '(pointerleave)': 'onPointerLeave()',
73
- '(pointerdown)': 'onPointerDown()',
74
- '(focus)': 'onFocus()',
75
- '(blur)': 'onBlur()',
76
- '(click)': 'onClick()'
345
+ type: 'button',
346
+ '[attr.id]': 'name()',
347
+ '[attr.aria-haspopup]': '"dialog"',
348
+ '[attr.aria-expanded]': 'rootDirective.isOpen()',
349
+ '[attr.aria-controls]': 'rootDirective.contentDirective().name()',
350
+ '[attr.data-state]': 'rootDirective.state()',
351
+ '(pointerenter)': 'pointerenter()',
352
+ '(pointerleave)': 'pointerleave()',
353
+ '(focus)': 'focus()',
354
+ '(blur)': 'blur()',
355
+ '(click)': 'click()'
77
356
  }
78
357
  }]
79
358
  }] });
80
359
 
81
- const defaultTooltipConfig = {
82
- delayDuration: 700,
83
- skipDelayDuration: 300
84
- };
85
- const RdxTooltipConfigToken = new InjectionToken('RdxTooltipConfigToken');
86
- function provideRdxTooltipConfig(config) {
87
- return [
88
- {
89
- provide: RdxTooltipConfigToken,
90
- useValue: { ...defaultTooltipConfig, ...config }
91
- }
92
- ];
360
+ const RdxCdkEventServiceWindowKey = Symbol('__RdxCdkEventService__');
361
+
362
+ function eventTypeAsPrimitiveConfigKey(eventType) {
363
+ return `prevent${eventType[0].toUpperCase()}${eventType.slice(1)}`;
93
364
  }
94
- function injectTooltipConfig() {
95
- return inject(RdxTooltipConfigToken, { optional: true }) ?? defaultTooltipConfig;
365
+ class RdxCdkEventService {
366
+ #clickDomRootEventCallbacks;
367
+ constructor() {
368
+ this.document = injectDocument();
369
+ this.destroyRef = inject(DestroyRef);
370
+ this.ngZone = inject(NgZone);
371
+ this.renderer2 = inject(Renderer2);
372
+ this.window = injectWindow();
373
+ this.onDestroyCallbacks = new Set([() => deleteRdxCdkEventServiceWindowKey(this.window)]);
374
+ this.#clickDomRootEventCallbacks = new Set();
375
+ this.#listenToClickDomRootEvent();
376
+ this.#registerOnDestroyCallbacks();
377
+ }
378
+ registerPrimitive(primitiveInstance) {
379
+ if (!this.primitiveConfigs) {
380
+ this.primitiveConfigs = new Map();
381
+ }
382
+ if (!this.primitiveConfigs.has(primitiveInstance)) {
383
+ this.primitiveConfigs.set(primitiveInstance, {});
384
+ }
385
+ }
386
+ deregisterPrimitive(primitiveInstance) {
387
+ if (this.primitiveConfigs?.has(primitiveInstance)) {
388
+ this.primitiveConfigs.delete(primitiveInstance);
389
+ }
390
+ }
391
+ preventPrimitiveFromCdkEvent(primitiveInstance, eventType) {
392
+ this.#setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, true);
393
+ }
394
+ allowPrimitiveForCdkEvent(primitiveInstance, eventType) {
395
+ this.#setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, false);
396
+ }
397
+ preventPrimitiveFromCdkMultiEvents(primitiveInstance, eventTypes) {
398
+ eventTypes.forEach((eventType) => {
399
+ this.#setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, true);
400
+ });
401
+ }
402
+ allowPrimitiveForCdkMultiEvents(primitiveInstance, eventTypes) {
403
+ eventTypes.forEach((eventType) => {
404
+ this.#setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, false);
405
+ });
406
+ }
407
+ setPreventPrimitiveFromCdkMixEvents(primitiveInstance, eventTypes) {
408
+ Object.keys(eventTypes).forEach((eventType) => {
409
+ this.#setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, eventTypes[eventTypeAsPrimitiveConfigKey(eventType)]);
410
+ });
411
+ }
412
+ primitivePreventedFromCdkEvent(primitiveInstance, eventType) {
413
+ return this.primitiveConfigs?.get(primitiveInstance)?.[eventTypeAsPrimitiveConfigKey(eventType)];
414
+ }
415
+ addClickDomRootEventCallback(callback) {
416
+ this.#clickDomRootEventCallbacks.add(callback);
417
+ }
418
+ removeClickDomRootEventCallback(callback) {
419
+ return this.#clickDomRootEventCallbacks.delete(callback);
420
+ }
421
+ #setPreventPrimitiveFromCdkEvent(primitiveInstance, eventType, value) {
422
+ if (!this.primitiveConfigs?.has(primitiveInstance)) {
423
+ isDevMode() &&
424
+ console.error('[RdxCdkEventService.preventPrimitiveFromCdkEvent] RDX Primitive instance has not been registered!', primitiveInstance);
425
+ return;
426
+ }
427
+ switch (eventType) {
428
+ case 'cdkOverlayOutsideClick':
429
+ this.primitiveConfigs.get(primitiveInstance).preventCdkOverlayOutsideClick = value;
430
+ break;
431
+ case 'cdkOverlayEscapeKeyDown':
432
+ this.primitiveConfigs.get(primitiveInstance).preventCdkOverlayEscapeKeyDown = value;
433
+ break;
434
+ }
435
+ }
436
+ #registerOnDestroyCallbacks() {
437
+ this.destroyRef.onDestroy(() => {
438
+ this.onDestroyCallbacks.forEach((onDestroyCallback) => onDestroyCallback());
439
+ this.onDestroyCallbacks.clear();
440
+ });
441
+ }
442
+ #listenToClickDomRootEvent() {
443
+ const target = this.document;
444
+ const eventName = 'click';
445
+ const options = { capture: true };
446
+ const callback = (event) => {
447
+ this.#clickDomRootEventCallbacks.forEach((clickDomRootEventCallback) => clickDomRootEventCallback(event));
448
+ };
449
+ const major = parseInt(VERSION.major);
450
+ const minor = parseInt(VERSION.minor);
451
+ let destroyClickDomRootEventListener;
452
+ /**
453
+ * @see src/cdk/platform/features/backwards-compatibility.ts in @angular/cdk
454
+ */
455
+ if (major > 19 || (major === 19 && minor > 0) || (major === 0 && minor === 0)) {
456
+ destroyClickDomRootEventListener = this.ngZone.runOutsideAngular(() => {
457
+ const destroyClickDomRootEventListenerInternal = this.renderer2.listen(target, eventName, callback,
458
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
459
+ // @ts-expect-error
460
+ options);
461
+ return () => {
462
+ destroyClickDomRootEventListenerInternal();
463
+ this.#clickDomRootEventCallbacks.clear();
464
+ };
465
+ });
466
+ }
467
+ else {
468
+ /**
469
+ * This part can get removed when v19.1 or higher is on the board
470
+ */
471
+ destroyClickDomRootEventListener = this.ngZone.runOutsideAngular(() => {
472
+ target.addEventListener(eventName, callback, options);
473
+ return () => {
474
+ this.ngZone.runOutsideAngular(() => target.removeEventListener(eventName, callback, options));
475
+ this.#clickDomRootEventCallbacks.clear();
476
+ };
477
+ });
478
+ }
479
+ this.onDestroyCallbacks.add(destroyClickDomRootEventListener);
480
+ }
481
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxCdkEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
482
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxCdkEventService }); }
96
483
  }
484
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxCdkEventService, decorators: [{
485
+ type: Injectable
486
+ }], ctorParameters: () => [] });
487
+ const RdxCdkEventServiceToken = new InjectionToken('RdxCdkEventServiceToken');
488
+ const existsErrorMessage = 'RdxCdkEventService should be provided only once!';
489
+ const deleteRdxCdkEventServiceWindowKey = (window) => {
490
+ delete window[RdxCdkEventServiceWindowKey];
491
+ };
492
+ const getProvider = (throwWhenExists = true) => ({
493
+ provide: RdxCdkEventServiceToken,
494
+ useFactory: () => {
495
+ isDevMode() && console.log('providing RdxCdkEventService...');
496
+ const window = injectWindow();
497
+ if (window[RdxCdkEventServiceWindowKey]) {
498
+ if (throwWhenExists) {
499
+ throw Error(existsErrorMessage);
500
+ }
501
+ else {
502
+ isDevMode() && console.warn(existsErrorMessage);
503
+ }
504
+ }
505
+ window[RdxCdkEventServiceWindowKey] ??= new RdxCdkEventService();
506
+ return window[RdxCdkEventServiceWindowKey];
507
+ }
508
+ });
509
+ const provideRdxCdkEventServiceInRoot = () => makeEnvironmentProviders([getProvider()]);
510
+ const provideRdxCdkEventService = () => getProvider(false);
511
+ const injectRdxCdkEventService = () => inject(RdxCdkEventServiceToken, { optional: true });
97
512
 
98
- const RdxTooltipRootToken = new InjectionToken('RdxTooltipRootToken');
99
- function injectTooltipRoot() {
100
- return inject(RdxTooltipRootToken);
101
- }
513
+ let nextId = 0;
102
514
  class RdxTooltipRootDirective {
103
515
  constructor() {
104
516
  /** @ignore */
105
- this.viewContainerRef = inject(ViewContainerRef);
106
- /** @ignore */
107
- this.destroyRef = inject(DestroyRef);
108
- /** @ignore */
109
- this.overlay = inject(Overlay);
110
- /** @ignore */
111
- this.platformId = inject(PLATFORM_ID);
112
- /** @ignore */
113
- this.document = injectDocument();
114
- /** @ignore */
115
- this.window = injectWindow();
517
+ this.uniqueId = signal(++nextId);
116
518
  /** @ignore */
117
- this.tooltipConfig = injectTooltipConfig();
519
+ this.name = computed(() => `rdx-tooltip-root-${this.uniqueId()}`);
118
520
  /**
119
- * The open state of the tooltip when it is initially rendered. Use when you do not need to control its open state.
521
+ * @description The anchor directive that comes form outside the tooltip rootDirective
522
+ * @default undefined
120
523
  */
121
- this.defaultOpen = input(false);
524
+ this.anchor = input(void 0);
122
525
  /**
123
- * The controlled open state of the tooltip. Must be used in conjunction with onOpenChange.
526
+ * @description The open state of the tooltip when it is initially rendered. Use when you do not need to control its open state.
527
+ * @default false
124
528
  */
125
- this.open = input();
529
+ this.defaultOpen = input(false, { transform: booleanAttribute });
126
530
  /**
127
- * Override the duration given to the configuration to customise the open delay for a specific tooltip.
531
+ * @description The controlled state of the tooltip. `open` input take precedence of `defaultOpen` input.
532
+ * @default undefined
128
533
  */
129
- this.delayDuration = input(this.tooltipConfig.delayDuration);
130
- /** @ignore */
131
- this.disableHoverableContent = input(this.tooltipConfig.disableHoverableContent ?? false);
534
+ this.open = input(void 0, { transform: booleanAttribute });
535
+ /**
536
+ * To customise the open delay for a specific tooltip.
537
+ */
538
+ this.openDelay = input(500, {
539
+ transform: numberAttribute
540
+ });
541
+ /**
542
+ * To customise the close delay for a specific tooltip.
543
+ */
544
+ this.closeDelay = input(200, {
545
+ transform: numberAttribute
546
+ });
547
+ /**
548
+ * @description Whether to control the state of the tooltip from external. Use in conjunction with `open` input.
549
+ * @default undefined
550
+ */
551
+ this.externalControl = input(void 0, { transform: booleanAttribute });
552
+ /**
553
+ * @description Whether to take into account CSS opening/closing animations.
554
+ * @default false
555
+ */
556
+ this.cssAnimation = input(false, { transform: booleanAttribute });
557
+ /**
558
+ * @description Whether to take into account CSS opening animations. `cssAnimation` input must be set to 'true'
559
+ * @default false
560
+ */
561
+ this.cssOpeningAnimation = input(false, { transform: booleanAttribute });
132
562
  /**
133
- * Event handler called when the open state of the tooltip changes.
563
+ * @description Whether to take into account CSS closing animations. `cssAnimation` input must be set to 'true'
564
+ * @default false
134
565
  */
135
- this.onOpenChange = output();
566
+ this.cssClosingAnimation = input(false, { transform: booleanAttribute });
136
567
  /** @ignore */
137
- this.isOpen = signal(this.defaultOpen());
568
+ this.cssAnimationStatus = signal(null);
138
569
  /** @ignore */
139
- this.isOpenDelayed = signal(true);
570
+ this.contentDirective = contentChild.required(RdxTooltipContentDirective);
140
571
  /** @ignore */
141
- this.wasOpenDelayed = signal(false);
572
+ this.triggerDirective = contentChild.required(RdxTooltipTriggerDirective);
142
573
  /** @ignore */
143
- this.state = computed(() => {
144
- const currentIsOpen = this.isOpen();
145
- const currentWasOpenDelayed = this.wasOpenDelayed();
146
- if (currentIsOpen) {
147
- return currentWasOpenDelayed ? 'delayed-open' : 'instant-open';
148
- }
149
- return 'closed';
150
- });
574
+ this.arrowDirective = contentChild(RdxTooltipArrowToken);
151
575
  /** @ignore */
152
- this.tooltipContentDirective = contentChild.required(RdxTooltipContentToken);
576
+ this.closeDirective = contentChild(RdxTooltipCloseToken);
153
577
  /** @ignore */
154
- this.tooltipTriggerDirective = contentChild.required(RdxTooltipTriggerDirective);
578
+ this.contentAttributesComponent = contentChild(RdxTooltipContentAttributesToken);
155
579
  /** @ignore */
156
- this.openTimer = 0;
580
+ this.internalAnchorDirective = contentChild(RdxTooltipAnchorToken);
157
581
  /** @ignore */
158
- this.skipDelayTimer = 0;
582
+ this.viewContainerRef = inject(ViewContainerRef);
159
583
  /** @ignore */
160
- this.isControlledExternally = false;
584
+ this.rdxCdkEventService = injectRdxCdkEventService();
161
585
  /** @ignore */
162
- this.onIsOpenChangeEffect = effect(() => {
163
- const isOpen = this.isOpen();
164
- untracked(() => {
165
- if (isOpen) {
166
- this.show();
167
- }
168
- else {
169
- this.hide();
170
- }
171
- });
172
- });
586
+ this.destroyRef = inject(DestroyRef);
173
587
  /** @ignore */
174
- this.onPositionChangeEffect = effect(() => {
175
- const position = this.tooltipContentDirective().position();
176
- if (this.overlayRef) {
177
- const positionStrategy = this.getPositionStrategy(position);
178
- this.overlayRef.updatePositionStrategy(positionStrategy);
179
- }
180
- });
588
+ this.state = signal(RdxTooltipState.CLOSED);
181
589
  /** @ignore */
182
- this.onOpenChangeEffect = effect(() => {
183
- const currentOpen = this.open();
184
- this.isControlledExternally = currentOpen !== undefined;
185
- untracked(() => {
186
- if (this.isControlledExternally) {
187
- this.setOpen(currentOpen);
188
- }
590
+ this.attachDetachEvent = signal(RdxTooltipAttachDetachEvent.DETACH);
591
+ /** @ignore */
592
+ this.isFirstDefaultOpen = signal(false);
593
+ /** @ignore */
594
+ this.anchorDirective = computed(() => this.internalAnchorDirective() ?? this.anchor());
595
+ /** @ignore */
596
+ this.actionSubject$ = new Subject();
597
+ /** @ignore */
598
+ this.onAnchorChangeEffect = () => {
599
+ effect(() => {
600
+ const anchor = this.anchor();
601
+ untracked(() => {
602
+ if (anchor) {
603
+ anchor.setRoot(this);
604
+ }
605
+ });
189
606
  });
607
+ };
608
+ this.rdxCdkEventService?.registerPrimitive(this);
609
+ this.destroyRef.onDestroy(() => this.rdxCdkEventService?.deregisterPrimitive(this));
610
+ this.actionSubscription();
611
+ this.onStateChangeEffect();
612
+ this.onCssAnimationStatusChangeChangeEffect();
613
+ this.onOpenChangeEffect();
614
+ this.onIsFirstDefaultOpenChangeEffect();
615
+ this.onAnchorChangeEffect();
616
+ this.emitOpenOrClosedEventEffect();
617
+ afterNextRender({
618
+ write: () => {
619
+ if (this.defaultOpen() && !this.open()) {
620
+ this.isFirstDefaultOpen.set(true);
621
+ }
622
+ }
190
623
  });
191
624
  }
192
625
  /** @ignore */
193
- ngOnInit() {
194
- if (this.defaultOpen()) {
195
- this.handleOpen();
196
- }
197
- this.isControlledExternally = this.open() !== undefined;
626
+ getAnimationParamsSnapshot() {
627
+ return {
628
+ cssAnimation: this.cssAnimation(),
629
+ cssOpeningAnimation: this.cssOpeningAnimation(),
630
+ cssClosingAnimation: this.cssClosingAnimation(),
631
+ cssAnimationStatus: this.cssAnimationStatus(),
632
+ attachDetachEvent: this.attachDetachEvent(),
633
+ state: this.state(),
634
+ canEmitOnOpenOrOnClosed: this.canEmitOnOpenOrOnClosed()
635
+ };
198
636
  }
199
637
  /** @ignore */
200
- onTriggerEnter() {
201
- if (this.isControlledExternally) {
202
- return;
203
- }
204
- if (this.isOpenDelayed()) {
205
- this.handleDelayedOpen();
206
- }
207
- else {
208
- this.handleOpen();
209
- }
210
- }
211
- /** @ignore */
212
- onTriggerLeave() {
213
- this.clearTimeout(this.openTimer);
214
- this.handleClose();
215
- }
216
- /** @ignore */
217
- onOpen() {
218
- this.clearTimeout(this.skipDelayTimer);
219
- this.isOpenDelayed.set(false);
638
+ controlledExternally() {
639
+ return this.externalControl;
220
640
  }
221
641
  /** @ignore */
222
- onClose() {
223
- this.clearTimeout(this.skipDelayTimer);
224
- if (isPlatformBrowser(this.platformId)) {
225
- this.skipDelayTimer = this.window.setTimeout(() => {
226
- this.isOpenDelayed.set(true);
227
- }, this.tooltipConfig.skipDelayDuration);
228
- }
642
+ firstDefaultOpen() {
643
+ return this.isFirstDefaultOpen();
229
644
  }
230
645
  /** @ignore */
231
646
  handleOpen() {
232
- if (this.isControlledExternally) {
647
+ if (this.externalControl()) {
233
648
  return;
234
649
  }
235
- this.wasOpenDelayed.set(false);
236
- this.setOpen(true);
650
+ this.actionSubject$.next(RdxTooltipAction.OPEN);
237
651
  }
238
652
  /** @ignore */
239
- handleClose() {
240
- if (this.isControlledExternally) {
653
+ handleClose(closeButton) {
654
+ if (this.isFirstDefaultOpen()) {
655
+ this.isFirstDefaultOpen.set(false);
656
+ }
657
+ if (!closeButton && this.externalControl()) {
241
658
  return;
242
659
  }
243
- this.clearTimeout(this.openTimer);
244
- this.setOpen(false);
660
+ this.actionSubject$.next(RdxTooltipAction.CLOSE);
245
661
  }
246
662
  /** @ignore */
247
- handleOverlayKeydown() {
248
- if (!this.overlayRef) {
663
+ handleToggle() {
664
+ if (this.externalControl()) {
249
665
  return;
250
666
  }
251
- this.overlayRef
252
- .keydownEvents()
253
- .pipe(filter((event) => event.key === 'Escape'), takeUntilDestroyed(this.destroyRef))
254
- .subscribe((event) => {
255
- this.tooltipContentDirective().onEscapeKeyDown.emit(event);
256
- if (!event.defaultPrevented) {
257
- this.handleClose();
258
- }
259
- });
667
+ this.isOpen() ? this.handleClose() : this.handleOpen();
668
+ }
669
+ /** @ignore */
670
+ isOpen(state) {
671
+ return (state ?? this.state()) === RdxTooltipState.OPEN;
260
672
  }
261
673
  /** @ignore */
262
- handlePointerDownOutside() {
263
- if (!this.overlayRef) {
674
+ setState(state = RdxTooltipState.CLOSED) {
675
+ if (state === this.state()) {
264
676
  return;
265
677
  }
266
- this.overlayRef
267
- .outsidePointerEvents()
268
- .pipe(takeUntilDestroyed(this.destroyRef))
269
- .subscribe((event) => this.tooltipContentDirective().onPointerDownOutside.emit(event));
270
- }
271
- /** @ignore */
272
- handleDelayedOpen() {
273
- this.clearTimeout(this.openTimer);
274
- if (isPlatformBrowser(this.platformId)) {
275
- this.openTimer = this.window.setTimeout(() => {
276
- this.wasOpenDelayed.set(true);
277
- this.setOpen(true);
278
- }, this.delayDuration());
279
- }
678
+ this.state.set(state);
280
679
  }
281
680
  /** @ignore */
282
- setOpen(open = false) {
283
- if (open) {
284
- this.onOpen();
285
- this.document.dispatchEvent(new CustomEvent('tooltip.open'));
681
+ openContent() {
682
+ this.contentDirective().open();
683
+ if (!this.cssAnimation() || !this.cssOpeningAnimation()) {
684
+ this.cssAnimationStatus.set(null);
286
685
  }
287
- else {
288
- this.onClose();
289
- }
290
- this.isOpen.set(open);
291
- this.onOpenChange.emit(open);
292
686
  }
293
687
  /** @ignore */
294
- createOverlayRef() {
295
- if (this.overlayRef) {
296
- return this.overlayRef;
688
+ closeContent() {
689
+ this.contentDirective().close();
690
+ if (!this.cssAnimation() || !this.cssClosingAnimation()) {
691
+ this.cssAnimationStatus.set(null);
297
692
  }
298
- this.overlayRef = this.overlay.create({
299
- direction: undefined,
300
- positionStrategy: this.getPositionStrategy(this.tooltipContentDirective().position()),
301
- scrollStrategy: this.overlay.scrollStrategies.close()
693
+ }
694
+ /** @ignore */
695
+ emitOnOpen() {
696
+ this.contentDirective().onOpen.emit();
697
+ }
698
+ /** @ignore */
699
+ emitOnClosed() {
700
+ this.contentDirective().onClosed.emit();
701
+ }
702
+ /** @ignore */
703
+ ifOpenOrCloseWithoutAnimations(state) {
704
+ return (!this.contentAttributesComponent() ||
705
+ !this.cssAnimation() ||
706
+ (this.cssAnimation() && !this.cssClosingAnimation() && state === RdxTooltipState.CLOSED) ||
707
+ (this.cssAnimation() && !this.cssOpeningAnimation() && state === RdxTooltipState.OPEN) ||
708
+ // !this.cssAnimationStatus() ||
709
+ (this.cssOpeningAnimation() &&
710
+ state === RdxTooltipState.OPEN &&
711
+ [RdxTooltipAnimationStatus.OPEN_STARTED].includes(this.cssAnimationStatus())) ||
712
+ (this.cssClosingAnimation() &&
713
+ state === RdxTooltipState.CLOSED &&
714
+ [RdxTooltipAnimationStatus.CLOSED_STARTED].includes(this.cssAnimationStatus())));
715
+ }
716
+ /** @ignore */
717
+ ifOpenOrCloseWithAnimations(cssAnimationStatus) {
718
+ return (this.contentAttributesComponent() &&
719
+ this.cssAnimation() &&
720
+ cssAnimationStatus &&
721
+ ((this.cssOpeningAnimation() &&
722
+ this.state() === RdxTooltipState.OPEN &&
723
+ [RdxTooltipAnimationStatus.OPEN_ENDED].includes(cssAnimationStatus)) ||
724
+ (this.cssClosingAnimation() &&
725
+ this.state() === RdxTooltipState.CLOSED &&
726
+ [RdxTooltipAnimationStatus.CLOSED_ENDED].includes(cssAnimationStatus))));
727
+ }
728
+ /** @ignore */
729
+ openOrClose(state) {
730
+ const isOpen = this.isOpen(state);
731
+ isOpen ? this.openContent() : this.closeContent();
732
+ }
733
+ /** @ignore */
734
+ emitOnOpenOrOnClosed(state) {
735
+ this.isOpen(state)
736
+ ? this.attachDetachEvent() === RdxTooltipAttachDetachEvent.ATTACH && this.emitOnOpen()
737
+ : this.attachDetachEvent() === RdxTooltipAttachDetachEvent.DETACH && this.emitOnClosed();
738
+ }
739
+ /** @ignore */
740
+ canEmitOnOpenOrOnClosed() {
741
+ return (!this.cssAnimation() ||
742
+ (!this.cssOpeningAnimation() && this.state() === RdxTooltipState.OPEN) ||
743
+ (this.cssOpeningAnimation() &&
744
+ this.state() === RdxTooltipState.OPEN &&
745
+ this.cssAnimationStatus() === RdxTooltipAnimationStatus.OPEN_ENDED) ||
746
+ (!this.cssClosingAnimation() && this.state() === RdxTooltipState.CLOSED) ||
747
+ (this.cssClosingAnimation() &&
748
+ this.state() === RdxTooltipState.CLOSED &&
749
+ this.cssAnimationStatus() === RdxTooltipAnimationStatus.CLOSED_ENDED));
750
+ }
751
+ /** @ignore */
752
+ onStateChangeEffect() {
753
+ let isFirst = true;
754
+ effect(() => {
755
+ const state = this.state();
756
+ untracked(() => {
757
+ if (isFirst) {
758
+ isFirst = false;
759
+ return;
760
+ }
761
+ if (!this.ifOpenOrCloseWithoutAnimations(state)) {
762
+ return;
763
+ }
764
+ this.openOrClose(state);
765
+ });
766
+ }, {});
767
+ }
768
+ /** @ignore */
769
+ onCssAnimationStatusChangeChangeEffect() {
770
+ let isFirst = true;
771
+ effect(() => {
772
+ const cssAnimationStatus = this.cssAnimationStatus();
773
+ untracked(() => {
774
+ if (isFirst) {
775
+ isFirst = false;
776
+ return;
777
+ }
778
+ if (!this.ifOpenOrCloseWithAnimations(cssAnimationStatus)) {
779
+ return;
780
+ }
781
+ this.openOrClose(this.state());
782
+ });
302
783
  });
303
- this.overlayRef
304
- .detachments()
305
- .pipe(take(1), takeUntilDestroyed(this.destroyRef))
306
- .subscribe(() => this.detach());
307
- this.handleOverlayKeydown();
308
- this.handlePointerDownOutside();
309
- return this.overlayRef;
310
- }
311
- /** @ignore */
312
- show() {
313
- this.overlayRef = this.createOverlayRef();
314
- this.detach();
315
- this.portal =
316
- this.portal ||
317
- new TemplatePortal(this.tooltipContentDirective().templateRef, this.viewContainerRef, {
318
- state: this.state,
319
- side: this.tooltipContentDirective().side
320
- });
321
- this.instance = this.overlayRef.attach(this.portal);
322
784
  }
323
785
  /** @ignore */
324
- detach() {
325
- if (this.overlayRef?.hasAttached()) {
326
- this.overlayRef.detach();
327
- }
786
+ emitOpenOrClosedEventEffect() {
787
+ let isFirst = true;
788
+ effect(() => {
789
+ this.attachDetachEvent();
790
+ this.cssAnimationStatus();
791
+ untracked(() => {
792
+ if (isFirst) {
793
+ isFirst = false;
794
+ return;
795
+ }
796
+ const canEmitOpenClose = untracked(() => this.canEmitOnOpenOrOnClosed());
797
+ if (!canEmitOpenClose) {
798
+ return;
799
+ }
800
+ this.emitOnOpenOrOnClosed(this.state());
801
+ });
802
+ });
328
803
  }
329
804
  /** @ignore */
330
- hide() {
331
- if (this.isControlledExternally && this.open()) {
332
- return;
333
- }
334
- asyncScheduler.schedule(() => {
335
- this.instance?.destroy();
336
- }, this.tooltipConfig.hideDelayDuration ?? 0);
805
+ onOpenChangeEffect() {
806
+ effect(() => {
807
+ const open = this.open();
808
+ untracked(() => {
809
+ this.setState(open ? RdxTooltipState.OPEN : RdxTooltipState.CLOSED);
810
+ });
811
+ });
337
812
  }
338
813
  /** @ignore */
339
- getPositionStrategy(connectedPosition) {
340
- return this.overlay
341
- .position()
342
- .flexibleConnectedTo(this.tooltipTriggerDirective().elementRef)
343
- .withFlexibleDimensions(false)
344
- .withPositions([
345
- connectedPosition
346
- ])
347
- .withLockedPosition();
814
+ onIsFirstDefaultOpenChangeEffect() {
815
+ const effectRef = effect(() => {
816
+ const defaultOpen = this.defaultOpen();
817
+ untracked(() => {
818
+ if (!defaultOpen || this.open()) {
819
+ effectRef.destroy();
820
+ return;
821
+ }
822
+ this.handleOpen();
823
+ });
824
+ });
348
825
  }
349
826
  /** @ignore */
350
- clearTimeout(timeoutId) {
351
- if (isPlatformBrowser(this.platformId)) {
352
- this.window.clearTimeout(timeoutId);
353
- }
827
+ actionSubscription() {
828
+ this.actionSubject$
829
+ .asObservable()
830
+ .pipe(map((action) => {
831
+ console.log(action);
832
+ switch (action) {
833
+ case RdxTooltipAction.OPEN:
834
+ return { action, duration: this.openDelay() };
835
+ case RdxTooltipAction.CLOSE:
836
+ return { action, duration: this.closeDelay() };
837
+ }
838
+ }), debounce((config) => timer(config.duration)), tap((config) => {
839
+ switch (config.action) {
840
+ case RdxTooltipAction.OPEN:
841
+ this.setState(RdxTooltipState.OPEN);
842
+ break;
843
+ case RdxTooltipAction.CLOSE:
844
+ this.setState(RdxTooltipState.CLOSED);
845
+ break;
846
+ }
847
+ }), takeUntilDestroyed())
848
+ .subscribe();
354
849
  }
355
850
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipRootDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
356
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "19.0.5", type: RdxTooltipRootDirective, isStandalone: true, selector: "[rdxTooltipRoot]", inputs: { defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, delayDuration: { classPropertyName: "delayDuration", publicName: "delayDuration", isSignal: true, isRequired: false, transformFunction: null }, disableHoverableContent: { classPropertyName: "disableHoverableContent", publicName: "disableHoverableContent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onOpenChange: "onOpenChange" }, providers: [
357
- {
358
- provide: RdxTooltipRootToken,
359
- useExisting: forwardRef(() => RdxTooltipRootDirective)
360
- }
361
- ], queries: [{ propertyName: "tooltipContentDirective", first: true, predicate: RdxTooltipContentToken, descendants: true, isSignal: true }, { propertyName: "tooltipTriggerDirective", first: true, predicate: RdxTooltipTriggerDirective, descendants: true, isSignal: true }], exportAs: ["rdxTooltipRoot"], ngImport: i0 }); }
851
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "19.0.5", type: RdxTooltipRootDirective, isStandalone: true, selector: "[rdxTooltipRoot]", inputs: { anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, externalControl: { classPropertyName: "externalControl", publicName: "externalControl", isSignal: true, isRequired: false, transformFunction: null }, cssAnimation: { classPropertyName: "cssAnimation", publicName: "cssAnimation", isSignal: true, isRequired: false, transformFunction: null }, cssOpeningAnimation: { classPropertyName: "cssOpeningAnimation", publicName: "cssOpeningAnimation", isSignal: true, isRequired: false, transformFunction: null }, cssClosingAnimation: { classPropertyName: "cssClosingAnimation", publicName: "cssClosingAnimation", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "contentDirective", first: true, predicate: RdxTooltipContentDirective, descendants: true, isSignal: true }, { propertyName: "triggerDirective", first: true, predicate: RdxTooltipTriggerDirective, descendants: true, isSignal: true }, { propertyName: "arrowDirective", first: true, predicate: RdxTooltipArrowToken, descendants: true, isSignal: true }, { propertyName: "closeDirective", first: true, predicate: RdxTooltipCloseToken, descendants: true, isSignal: true }, { propertyName: "contentAttributesComponent", first: true, predicate: RdxTooltipContentAttributesToken, descendants: true, isSignal: true }, { propertyName: "internalAnchorDirective", first: true, predicate: RdxTooltipAnchorToken, descendants: true, isSignal: true }], exportAs: ["rdxTooltipRoot"], ngImport: i0 }); }
362
852
  }
363
853
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipRootDirective, decorators: [{
364
854
  type: Directive,
365
855
  args: [{
366
856
  selector: '[rdxTooltipRoot]',
367
- standalone: true,
857
+ exportAs: 'rdxTooltipRoot'
858
+ }]
859
+ }], ctorParameters: () => [] });
860
+
861
+ function injectTooltipRoot(optional = false) {
862
+ isDevMode() && assertInInjectionContext(injectTooltipRoot);
863
+ return inject(RdxTooltipRootDirective, { optional });
864
+ }
865
+
866
+ class RdxTooltipAnchorDirective {
867
+ constructor() {
868
+ /**
869
+ * @ignore
870
+ * If outside the rootDirective then null, otherwise the rootDirective directive - with optional `true` passed in as the first param.
871
+ * If outside the rootDirective and non-null value that means the html structure is wrong - tooltip inside tooltip.
872
+ * */
873
+ this.rootDirective = injectTooltipRoot(true);
874
+ /** @ignore */
875
+ this.elementRef = inject(ElementRef);
876
+ /** @ignore */
877
+ this.overlayOrigin = inject(CdkOverlayOrigin);
878
+ /** @ignore */
879
+ this.document = injectDocument();
880
+ /** @ignore */
881
+ this.name = computed(() => `rdx-tooltip-external-anchor-${this.rootDirective?.uniqueId()}`);
882
+ }
883
+ /** @ignore */
884
+ click() {
885
+ this.emitOutsideClick();
886
+ }
887
+ /** @ignore */
888
+ setRoot(root) {
889
+ this.rootDirective = root;
890
+ }
891
+ emitOutsideClick() {
892
+ if (!this.rootDirective?.isOpen() || this.rootDirective?.contentDirective().onOverlayOutsideClickDisabled()) {
893
+ return;
894
+ }
895
+ const clickEvent = new MouseEvent('click', {
896
+ view: this.document.defaultView,
897
+ bubbles: true,
898
+ cancelable: true,
899
+ relatedTarget: this.elementRef.nativeElement
900
+ });
901
+ this.rootDirective?.triggerDirective().elementRef.nativeElement.dispatchEvent(clickEvent);
902
+ }
903
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipAnchorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
904
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipAnchorDirective, isStandalone: true, selector: "[rdxTooltipAnchor]", host: { attributes: { "type": "button" }, listeners: { "click": "click()" }, properties: { "attr.id": "name()", "attr.aria-haspopup": "\"dialog\"" } }, providers: [
905
+ {
906
+ provide: RdxTooltipAnchorToken,
907
+ useExisting: forwardRef(() => RdxTooltipAnchorDirective)
908
+ }
909
+ ], exportAs: ["rdxTooltipAnchor"], hostDirectives: [{ directive: i1.CdkOverlayOrigin }], ngImport: i0 }); }
910
+ }
911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipAnchorDirective, decorators: [{
912
+ type: Directive,
913
+ args: [{
914
+ selector: '[rdxTooltipAnchor]',
915
+ exportAs: 'rdxTooltipAnchor',
916
+ hostDirectives: [CdkOverlayOrigin],
917
+ host: {
918
+ type: 'button',
919
+ '[attr.id]': 'name()',
920
+ '[attr.aria-haspopup]': '"dialog"',
921
+ '(click)': 'click()'
922
+ },
368
923
  providers: [
369
924
  {
370
- provide: RdxTooltipRootToken,
371
- useExisting: forwardRef(() => RdxTooltipRootDirective)
925
+ provide: RdxTooltipAnchorToken,
926
+ useExisting: forwardRef(() => RdxTooltipAnchorDirective)
372
927
  }
373
- ],
374
- exportAs: 'rdxTooltipRoot'
928
+ ]
375
929
  }]
376
930
  }] });
377
931
 
378
932
  class RdxTooltipArrowDirective {
379
933
  constructor() {
380
- /** @ignore */
381
- this.tooltipRoot = injectTooltipRoot();
382
934
  /** @ignore */
383
935
  this.renderer = inject(Renderer2);
384
936
  /** @ignore */
385
- this.contentDirective = inject(RdxTooltipContentToken);
937
+ this.rootDirective = injectTooltipRoot();
386
938
  /** @ignore */
387
939
  this.elementRef = inject(ElementRef);
388
940
  /**
389
- * The width of the arrow in pixels.
941
+ * @description The width of the arrow in pixels.
942
+ * @default 10
390
943
  */
391
- this.width = input(10);
944
+ this.width = input(RDX_POSITIONING_DEFAULTS.arrow.width, { transform: numberAttribute });
392
945
  /**
393
- * The height of the arrow in pixels.
946
+ * @description The height of the arrow in pixels.
947
+ * @default 5
394
948
  */
395
- this.height = input(5);
396
- /** @ignore */
397
- this.currentArrowSvgElement = signal(void 0);
949
+ this.height = input(RDX_POSITIONING_DEFAULTS.arrow.height, { transform: numberAttribute });
398
950
  /** @ignore */
399
951
  this.arrowSvgElement = computed(() => {
400
952
  const width = this.width();
@@ -410,30 +962,9 @@ class RdxTooltipArrowDirective {
410
962
  return svgElement;
411
963
  });
412
964
  /** @ignore */
413
- this.onArrowSvgElementChangeEffect = effect(() => {
414
- const arrowElement = this.arrowSvgElement();
415
- untracked(() => {
416
- const currentArrowSvgElement = this.currentArrowSvgElement();
417
- if (currentArrowSvgElement) {
418
- this.renderer.removeChild(this.elementRef.nativeElement, currentArrowSvgElement);
419
- }
420
- this.currentArrowSvgElement.set(arrowElement);
421
- this.renderer.setStyle(this.elementRef.nativeElement, 'width', `${this.width()}px`);
422
- this.renderer.setStyle(this.elementRef.nativeElement, 'height', `${this.height()}px`);
423
- this.renderer.appendChild(this.elementRef.nativeElement, this.currentArrowSvgElement());
424
- });
425
- });
965
+ this.currentArrowSvgElement = signal(void 0);
426
966
  /** @ignore */
427
- this.onContentPositionAndArrowDimensionsChangeEffect = effect(() => {
428
- const position = this.contentDirective.position();
429
- const arrowDimensions = { width: this.width(), height: this.height() };
430
- untracked(() => {
431
- if (!position) {
432
- return;
433
- }
434
- this.setPosition(position, arrowDimensions);
435
- });
436
- });
967
+ this.position = toSignal(this.rootDirective.contentDirective().positionChange());
437
968
  afterNextRender({
438
969
  write: () => {
439
970
  if (this.elementRef.nativeElement.parentElement) {
@@ -444,20 +975,52 @@ class RdxTooltipArrowDirective {
444
975
  this.renderer.setStyle(this.elementRef.nativeElement, 'fontSize', '0px');
445
976
  }
446
977
  });
978
+ this.onArrowSvgElementChangeEffect();
979
+ this.onContentPositionAndArrowDimensionsChangeEffect();
447
980
  }
448
981
  /** @ignore */
449
- setTriggerRect() {
450
- this.triggerRect = this.tooltipRoot.tooltipTriggerDirective().elementRef.nativeElement.getBoundingClientRect();
982
+ setAnchorOrTriggerRect() {
983
+ this.anchorOrTriggerRect = (this.rootDirective.anchorDirective() ?? this.rootDirective.triggerDirective()).elementRef.nativeElement.getBoundingClientRect();
451
984
  }
452
985
  /** @ignore */
453
986
  setPosition(position, arrowDimensions) {
454
- this.setTriggerRect();
455
- const posParams = getArrowPositionParams(getSideAndAlignFromAllPossibleConnectedPositions(position), { width: arrowDimensions.width, height: arrowDimensions.height }, { width: this.triggerRect.width, height: this.triggerRect.height });
987
+ this.setAnchorOrTriggerRect();
988
+ const posParams = getArrowPositionParams(getSideAndAlignFromAllPossibleConnectedPositions(position.connectionPair), { width: arrowDimensions.width, height: arrowDimensions.height }, { width: this.anchorOrTriggerRect.width, height: this.anchorOrTriggerRect.height });
456
989
  this.renderer.setStyle(this.elementRef.nativeElement, 'top', posParams.top);
457
990
  this.renderer.setStyle(this.elementRef.nativeElement, 'bottom', '');
458
991
  this.renderer.setStyle(this.elementRef.nativeElement, 'left', posParams.left);
459
992
  this.renderer.setStyle(this.elementRef.nativeElement, 'right', '');
460
993
  this.renderer.setStyle(this.elementRef.nativeElement, 'transform', posParams.transform);
994
+ this.renderer.setStyle(this.elementRef.nativeElement, 'transformOrigin', posParams.transformOrigin);
995
+ }
996
+ /** @ignore */
997
+ onArrowSvgElementChangeEffect() {
998
+ effect(() => {
999
+ const arrowElement = this.arrowSvgElement();
1000
+ untracked(() => {
1001
+ const currentArrowSvgElement = this.currentArrowSvgElement();
1002
+ if (currentArrowSvgElement) {
1003
+ this.renderer.removeChild(this.elementRef.nativeElement, currentArrowSvgElement);
1004
+ }
1005
+ this.currentArrowSvgElement.set(arrowElement);
1006
+ this.renderer.setStyle(this.elementRef.nativeElement, 'width', `${this.width()}px`);
1007
+ this.renderer.setStyle(this.elementRef.nativeElement, 'height', `${this.height()}px`);
1008
+ this.renderer.appendChild(this.elementRef.nativeElement, this.currentArrowSvgElement());
1009
+ });
1010
+ });
1011
+ }
1012
+ /** @ignore */
1013
+ onContentPositionAndArrowDimensionsChangeEffect() {
1014
+ effect(() => {
1015
+ const position = this.position();
1016
+ const arrowDimensions = { width: this.width(), height: this.height() };
1017
+ untracked(() => {
1018
+ if (!position) {
1019
+ return;
1020
+ }
1021
+ this.setPosition(position, arrowDimensions);
1022
+ });
1023
+ });
461
1024
  }
462
1025
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipArrowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
463
1026
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.5", type: RdxTooltipArrowDirective, isStandalone: true, selector: "[rdxTooltipArrow]", inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
@@ -471,7 +1034,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
471
1034
  type: Directive,
472
1035
  args: [{
473
1036
  selector: '[rdxTooltipArrow]',
474
- standalone: true,
475
1037
  providers: [
476
1038
  {
477
1039
  provide: RdxTooltipArrowToken,
@@ -481,92 +1043,141 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
481
1043
  }]
482
1044
  }], ctorParameters: () => [] });
483
1045
 
484
- class RdxTooltipContentAttributesDirective {
1046
+ /**
1047
+ * TODO: to be removed? But it seems to be useful when controlled from outside
1048
+ */
1049
+ class RdxTooltipCloseDirective {
485
1050
  constructor() {
486
- this.tooltipRoot = inject(RdxTooltipRootDirective);
487
- this.tooltipContent = inject(RdxTooltipContentToken);
1051
+ /** @ignore */
1052
+ this.rootDirective = injectTooltipRoot();
1053
+ /** @ignore */
1054
+ this.elementRef = inject(ElementRef);
1055
+ /** @ignore */
1056
+ this.renderer = inject(Renderer2);
1057
+ this.onIsControlledExternallyEffect();
1058
+ }
1059
+ /** @ignore */
1060
+ onIsControlledExternallyEffect() {
1061
+ effect(() => {
1062
+ const isControlledExternally = this.rootDirective.controlledExternally()();
1063
+ untracked(() => {
1064
+ this.renderer.setStyle(this.elementRef.nativeElement, 'display', isControlledExternally ? null : 'none');
1065
+ });
1066
+ });
488
1067
  }
489
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentAttributesDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
490
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipContentAttributesDirective, isStandalone: true, selector: "[rdxTooltipContentAttributes]", host: { properties: { "attr.data-state": "tooltipRoot.state()", "attr.data-side": "tooltipContent.side()" } }, ngImport: i0 }); }
1068
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipCloseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1069
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipCloseDirective, isStandalone: true, selector: "[rdxTooltipClose]", host: { attributes: { "type": "button" }, listeners: { "click": "rootDirective.handleClose(true)" } }, providers: [
1070
+ {
1071
+ provide: RdxTooltipCloseToken,
1072
+ useExisting: forwardRef(() => RdxTooltipCloseDirective)
1073
+ }
1074
+ ], ngImport: i0 }); }
491
1075
  }
492
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentAttributesDirective, decorators: [{
1076
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipCloseDirective, decorators: [{
493
1077
  type: Directive,
494
1078
  args: [{
495
- selector: '[rdxTooltipContentAttributes]',
496
- standalone: true,
1079
+ selector: '[rdxTooltipClose]',
497
1080
  host: {
498
- '[attr.data-state]': 'tooltipRoot.state()',
499
- '[attr.data-side]': 'tooltipContent.side()'
500
- }
1081
+ type: 'button',
1082
+ '(click)': 'rootDirective.handleClose(true)'
1083
+ },
1084
+ providers: [
1085
+ {
1086
+ provide: RdxTooltipCloseToken,
1087
+ useExisting: forwardRef(() => RdxTooltipCloseDirective)
1088
+ }
1089
+ ]
501
1090
  }]
502
- }] });
1091
+ }], ctorParameters: () => [] });
503
1092
 
504
- class RdxTooltipContentDirective {
1093
+ class RdxTooltipContentAttributesComponent {
505
1094
  constructor() {
506
1095
  /** @ignore */
507
- this.templateRef = inject(TemplateRef);
508
- /**
509
- * The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
510
- */
511
- this.side = input(RdxPositionSide.Top);
512
- /**
513
- * The distance in pixels from the trigger.
514
- */
515
- this.sideOffset = input(0);
516
- /**
517
- * The preferred alignment against the trigger. May change when collisions occur.
518
- */
519
- this.align = input(RdxPositionAlign.Center);
520
- /**
521
- * An offset in pixels from the "start" or "end" alignment options.
522
- */
523
- this.alignOffset = input(0);
524
- /** @ingore */
525
- this.position = computed(() => getContentPosition({
526
- side: this.side(),
527
- align: this.align(),
528
- sideOffset: this.sideOffset(),
529
- alignOffset: this.alignOffset()
530
- }));
531
- /**
532
- * Event handler called when the escape key is down. It can be prevented by calling event.preventDefault.
533
- */
534
- this.onEscapeKeyDown = output();
535
- /**
536
- * Event handler called when a pointer event occurs outside the bounds of the component. It can be prevented by calling event.preventDefault.
537
- */
538
- this.onPointerDownOutside = output();
1096
+ this.rootDirective = injectTooltipRoot();
1097
+ /** @ignore */
1098
+ this.name = computed(() => `rdx-tooltip-content-attributes-${this.rootDirective.uniqueId()}`);
1099
+ /** @ignore */
1100
+ this.disableAnimation = computed(() => !this.canAnimate());
539
1101
  }
540
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
541
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.5", type: RdxTooltipContentDirective, isStandalone: true, selector: "[rdxTooltipContent]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onEscapeKeyDown: "onEscapeKeyDown", onPointerDownOutside: "onPointerDownOutside" }, providers: [{ provide: RdxTooltipContentToken, useExisting: forwardRef(() => RdxTooltipContentDirective) }], ngImport: i0 }); }
1102
+ /** @ignore */
1103
+ onAnimationStart(_) {
1104
+ this.rootDirective.cssAnimationStatus.set(this.rootDirective.state() === RdxTooltipState.OPEN
1105
+ ? RdxTooltipAnimationStatus.OPEN_STARTED
1106
+ : RdxTooltipAnimationStatus.CLOSED_STARTED);
1107
+ }
1108
+ /** @ignore */
1109
+ onAnimationEnd(_) {
1110
+ this.rootDirective.cssAnimationStatus.set(this.rootDirective.state() === RdxTooltipState.OPEN
1111
+ ? RdxTooltipAnimationStatus.OPEN_ENDED
1112
+ : RdxTooltipAnimationStatus.CLOSED_ENDED);
1113
+ }
1114
+ /** @ignore */
1115
+ canAnimate() {
1116
+ return (this.rootDirective.cssAnimation() &&
1117
+ ((this.rootDirective.cssOpeningAnimation() && this.rootDirective.state() === RdxTooltipState.OPEN) ||
1118
+ (this.rootDirective.cssClosingAnimation() && this.rootDirective.state() === RdxTooltipState.CLOSED)));
1119
+ }
1120
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentAttributesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1121
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: RdxTooltipContentAttributesComponent, isStandalone: true, selector: "[rdxTooltipContentAttributes]", host: { listeners: { "animationstart": "onAnimationStart($event)", "animationend": "onAnimationEnd($event)" }, properties: { "attr.role": "\"dialog\"", "attr.id": "name()", "attr.data-state": "rootDirective.state()", "attr.data-side": "rootDirective.contentDirective().side()", "attr.data-align": "rootDirective.contentDirective().align()", "style": "disableAnimation() ? {animation: \"none !important\"} : null" } }, providers: [
1122
+ {
1123
+ provide: RdxTooltipContentAttributesToken,
1124
+ useExisting: forwardRef(() => RdxTooltipContentAttributesComponent)
1125
+ }
1126
+ ], ngImport: i0, template: `
1127
+ <ng-content />
1128
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
542
1129
  }
543
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentDirective, decorators: [{
544
- type: Directive,
1130
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipContentAttributesComponent, decorators: [{
1131
+ type: Component,
545
1132
  args: [{
546
- selector: '[rdxTooltipContent]',
547
- standalone: true,
548
- providers: [{ provide: RdxTooltipContentToken, useExisting: forwardRef(() => RdxTooltipContentDirective) }]
1133
+ selector: '[rdxTooltipContentAttributes]',
1134
+ template: `
1135
+ <ng-content />
1136
+ `,
1137
+ host: {
1138
+ '[attr.role]': '"dialog"',
1139
+ '[attr.id]': 'name()',
1140
+ '[attr.data-state]': 'rootDirective.state()',
1141
+ '[attr.data-side]': 'rootDirective.contentDirective().side()',
1142
+ '[attr.data-align]': 'rootDirective.contentDirective().align()',
1143
+ '[style]': 'disableAnimation() ? {animation: "none !important"} : null',
1144
+ '(animationstart)': 'onAnimationStart($event)',
1145
+ '(animationend)': 'onAnimationEnd($event)'
1146
+ },
1147
+ providers: [
1148
+ {
1149
+ provide: RdxTooltipContentAttributesToken,
1150
+ useExisting: forwardRef(() => RdxTooltipContentAttributesComponent)
1151
+ }
1152
+ ],
1153
+ changeDetection: ChangeDetectionStrategy.OnPush
549
1154
  }]
550
1155
  }] });
551
1156
 
552
1157
  const _imports = [
553
1158
  RdxTooltipArrowDirective,
1159
+ RdxTooltipCloseDirective,
554
1160
  RdxTooltipContentDirective,
555
1161
  RdxTooltipTriggerDirective,
556
- RdxTooltipContentAttributesDirective,
557
- RdxTooltipRootDirective
1162
+ RdxTooltipRootDirective,
1163
+ RdxTooltipAnchorDirective,
1164
+ RdxTooltipContentAttributesComponent
558
1165
  ];
559
1166
  class RdxTooltipModule {
560
1167
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
561
1168
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipModule, imports: [RdxTooltipArrowDirective,
1169
+ RdxTooltipCloseDirective,
562
1170
  RdxTooltipContentDirective,
563
1171
  RdxTooltipTriggerDirective,
564
- RdxTooltipContentAttributesDirective,
565
- RdxTooltipRootDirective], exports: [RdxTooltipArrowDirective,
1172
+ RdxTooltipRootDirective,
1173
+ RdxTooltipAnchorDirective,
1174
+ RdxTooltipContentAttributesComponent], exports: [RdxTooltipArrowDirective,
1175
+ RdxTooltipCloseDirective,
566
1176
  RdxTooltipContentDirective,
567
1177
  RdxTooltipTriggerDirective,
568
- RdxTooltipContentAttributesDirective,
569
- RdxTooltipRootDirective] }); }
1178
+ RdxTooltipRootDirective,
1179
+ RdxTooltipAnchorDirective,
1180
+ RdxTooltipContentAttributesComponent] }); }
570
1181
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipModule }); }
571
1182
  }
572
1183
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: RdxTooltipModule, decorators: [{
@@ -581,5 +1192,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
581
1192
  * Generated bundle index. Do not edit.
582
1193
  */
583
1194
 
584
- export { RdxTooltipArrowDirective, RdxTooltipContentAttributesDirective, RdxTooltipContentDirective, RdxTooltipModule, RdxTooltipRootDirective, RdxTooltipRootToken, RdxTooltipTriggerDirective, injectTooltipRoot };
1195
+ export { RdxTooltipAnchorDirective, RdxTooltipArrowDirective, RdxTooltipCloseDirective, RdxTooltipContentAttributesComponent, RdxTooltipContentDirective, RdxTooltipModule, RdxTooltipRootDirective, RdxTooltipTriggerDirective };
585
1196
  //# sourceMappingURL=radix-ng-primitives-tooltip.mjs.map