@radix-ng/primitives 1.0.0-beta.4 → 1.0.1

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 (83) hide show
  1. package/composite/README.md +3 -0
  2. package/fesm2022/radix-ng-primitives-accordion.mjs +12 -36
  3. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  4. package/fesm2022/radix-ng-primitives-checkbox.mjs +33 -18
  5. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-composite.mjs +515 -0
  7. package/fesm2022/radix-ng-primitives-composite.mjs.map +1 -0
  8. package/fesm2022/radix-ng-primitives-core.mjs +7 -0
  9. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-dialog.mjs +54 -12
  11. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-drawer.mjs +442 -2
  13. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  14. package/fesm2022/radix-ng-primitives-editable.mjs +12 -7
  15. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +294 -8
  17. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-focus-scope.mjs +9 -0
  19. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-menu.mjs +71 -20
  21. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  22. package/fesm2022/radix-ng-primitives-menubar.mjs +68 -36
  23. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +281 -88
  25. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-number-field.mjs +7 -2
  27. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-popover.mjs +117 -35
  29. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-popper.mjs +73 -65
  31. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-radio.mjs +77 -36
  33. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-roving-focus.mjs +40 -8
  35. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-scroll-area.mjs +56 -25
  37. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  38. package/fesm2022/radix-ng-primitives-select.mjs +62 -37
  39. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-slider.mjs +259 -28
  41. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  42. package/fesm2022/radix-ng-primitives-stepper.mjs +11 -7
  43. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  44. package/fesm2022/radix-ng-primitives-switch.mjs +10 -5
  45. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-tabs.mjs +64 -30
  47. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-toggle-group.mjs +69 -19
  49. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  50. package/fesm2022/radix-ng-primitives-toggle.mjs +37 -13
  51. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-toolbar.mjs +50 -24
  53. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-tooltip.mjs +180 -35
  55. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  56. package/navigation-menu/README.md +5 -2
  57. package/package.json +5 -1
  58. package/types/radix-ng-primitives-accordion.d.ts +9 -13
  59. package/types/radix-ng-primitives-checkbox.d.ts +27 -15
  60. package/types/radix-ng-primitives-composite.d.ts +152 -0
  61. package/types/radix-ng-primitives-core.d.ts +2 -0
  62. package/types/radix-ng-primitives-dialog.d.ts +13 -2
  63. package/types/radix-ng-primitives-drawer.d.ts +40 -2
  64. package/types/radix-ng-primitives-editable.d.ts +11 -5
  65. package/types/radix-ng-primitives-floating-focus-manager.d.ts +113 -16
  66. package/types/radix-ng-primitives-menu.d.ts +13 -5
  67. package/types/radix-ng-primitives-menubar.d.ts +10 -5
  68. package/types/radix-ng-primitives-navigation-menu.d.ts +65 -33
  69. package/types/radix-ng-primitives-number-field.d.ts +8 -3
  70. package/types/radix-ng-primitives-popover.d.ts +26 -10
  71. package/types/radix-ng-primitives-popper.d.ts +1 -0
  72. package/types/radix-ng-primitives-radio.d.ts +22 -13
  73. package/types/radix-ng-primitives-roving-focus.d.ts +15 -1
  74. package/types/radix-ng-primitives-scroll-area.d.ts +4 -1
  75. package/types/radix-ng-primitives-select.d.ts +16 -20
  76. package/types/radix-ng-primitives-slider.d.ts +60 -9
  77. package/types/radix-ng-primitives-stepper.d.ts +11 -4
  78. package/types/radix-ng-primitives-switch.d.ts +10 -4
  79. package/types/radix-ng-primitives-tabs.d.ts +20 -11
  80. package/types/radix-ng-primitives-toggle-group.d.ts +34 -17
  81. package/types/radix-ng-primitives-toggle.d.ts +14 -7
  82. package/types/radix-ng-primitives-toolbar.d.ts +22 -14
  83. package/types/radix-ng-primitives-tooltip.d.ts +38 -14
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, signal, numberAttribute, DestroyRef, input, Directive, ElementRef, model, booleanAttribute, output, computed, effect, untracked, isDevMode, afterNextRender } from '@angular/core';
3
3
  import * as i1$2 from '@radix-ng/primitives/core';
4
- import { createContext, createFloatingRootContext, injectId, watch, provideFloatingTree, provideFloatingRootContext, rdxDevError, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useGraceArea, RdxFloatingNodeRegistration } from '@radix-ng/primitives/core';
4
+ import { createContext, createFloatingRootContext, injectId, watch, createCancelableChangeEventDetails, provideFloatingTree, provideFloatingRootContext, rdxDevError, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useGraceArea, RdxFloatingNodeRegistration } from '@radix-ng/primitives/core';
5
5
  import * as i1 from '@radix-ng/primitives/popper';
6
6
  import { RdxPopper, RdxPopperContentWrapper, RdxPopperArrow, RdxPopperContent, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
7
7
  import { RdxVisuallyHiddenDirective } from '@radix-ng/primitives/visually-hidden';
@@ -9,6 +9,7 @@ import * as i1$1 from '@radix-ng/primitives/portal';
9
9
  import { RdxPortalPresence } from '@radix-ng/primitives/portal';
10
10
  import { provideRdxPresenceContext } from '@radix-ng/primitives/presence';
11
11
  import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
12
+ import { createRdxTriggerInteraction } from '@radix-ng/primitives/floating-focus-manager';
12
13
 
13
14
  const defaultTooltipConfig = {
14
15
  delay: 600,
@@ -184,7 +185,10 @@ class RdxTooltip {
184
185
  this.triggers = signal([], ...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
185
186
  this.payload = signal(undefined, ...(ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []));
186
187
  this.cursorPosition = signal(undefined, ...(ngDevMode ? [{ debugName: "cursorPosition" }] : /* istanbul ignore next */ []));
188
+ this.openChangeReason = signal('none', ...(ngDevMode ? [{ debugName: "openChangeReason" }] : /* istanbul ignore next */ []));
189
+ this.preventUnmountOnClose = signal(false, ...(ngDevMode ? [{ debugName: "preventUnmountOnClose" }] : /* istanbul ignore next */ []));
187
190
  this.openedInstant = signal(false, ...(ngDevMode ? [{ debugName: "openedInstant" }] : /* istanbul ignore next */ []));
191
+ this.suppressNextOpenChangeEmit = false;
188
192
  /** Local instant window used when this tooltip is not inside a provider. */
189
193
  this.localInstant = createTooltipInstantController(() => this.defaultConfig.timeout, this.destroyRef);
190
194
  this.instantGroup = this.provider ?? this.localInstant;
@@ -198,6 +202,7 @@ class RdxTooltip {
198
202
  this.defaultConfig.closeDelay, ...(ngDevMode ? [{ debugName: "resolvedCloseDelay" }] : /* istanbul ignore next */ []));
199
203
  /** Whether the most recent open happened without the delay. */
200
204
  this.instant = this.openedInstant.asReadonly();
205
+ this.present = computed(() => this.open() || this.preventUnmountOnClose(), ...(ngDevMode ? [{ debugName: "present" }] : /* istanbul ignore next */ []));
201
206
  this.virtualAnchor = computed(() => {
202
207
  const axis = this.trackCursorAxis();
203
208
  const element = this.trigger();
@@ -221,7 +226,7 @@ class RdxTooltip {
221
226
  }
222
227
  };
223
228
  }, ...(ngDevMode ? [{ debugName: "virtualAnchor" }] : /* istanbul ignore next */ []));
224
- this.openTimer = useTimeoutFn(() => this.applyOpen(false), () => this.resolvedDelay(), { immediate: false }, this.destroyRef);
229
+ this.openTimer = useTimeoutFn(() => this.applyOpen(false, this.trigger(), this.payload(), 'trigger-hover'), () => this.resolvedDelay(), { immediate: false }, this.destroyRef);
225
230
  this.closeTimer = useTimeoutFn(() => this.applyClose(), () => this.resolvedCloseDelay(), { immediate: false }, this.destroyRef);
226
231
  effect(() => {
227
232
  const defaultOpen = this.defaultOpen();
@@ -242,8 +247,15 @@ class RdxTooltip {
242
247
  // as "inside" and never dismisses (ADR 0015).
243
248
  effect(() => this.floatingContext.setReferenceElement(this.trigger() ?? null));
244
249
  watch([this.open], ([isOpen]) => {
245
- this.onOpenChange.emit(isOpen);
250
+ if (this.suppressNextOpenChangeEmit) {
251
+ this.suppressNextOpenChangeEmit = false;
252
+ }
253
+ else {
254
+ const { eventDetails } = createCancelableChangeEventDetails(this.openChangeReason(), new Event('tooltip.open-change'), this.trigger());
255
+ this.onOpenChange.emit({ open: isOpen, eventDetails });
256
+ }
246
257
  if (isOpen) {
258
+ this.preventUnmountOnClose.set(false);
247
259
  this.instantGroup.onOpen();
248
260
  }
249
261
  else {
@@ -253,26 +265,36 @@ class RdxTooltip {
253
265
  }, { defer: true });
254
266
  }
255
267
  /** Opens immediately, optionally switching the active trigger/payload. */
256
- show(trigger = this.trigger(), payload) {
257
- this.applyOpen(true, trigger, payload);
268
+ show(trigger = this.trigger(), payload, event) {
269
+ this.applyOpen(true, trigger, payload, 'trigger-focus', event);
258
270
  }
259
- close() {
271
+ close(reason = 'none', event) {
260
272
  this.openTimer.stop();
261
273
  this.closeTimer.stop();
262
- this.applyClose();
274
+ this.applyClose(reason, event);
275
+ }
276
+ cancelPendingOpen() {
277
+ this.openTimer.stop();
278
+ }
279
+ closeHoverOpen(event) {
280
+ this.openTimer.stop();
281
+ this.closeTimer.stop();
282
+ if (this.open() && this.openChangeReason() === 'trigger-hover') {
283
+ this.applyClose('trigger-hover', event);
284
+ }
263
285
  }
264
286
  /** Closes after the resolved close delay, e.g. when the pointer or focus leaves. */
265
- scheduleClose() {
287
+ scheduleClose(event) {
266
288
  this.openTimer.stop();
267
289
  if (this.resolvedCloseDelay() <= 0) {
268
- this.applyClose();
290
+ this.applyClose('trigger-hover', event);
269
291
  }
270
292
  else {
271
293
  this.closeTimer.start();
272
294
  }
273
295
  }
274
296
  /** Hover/focus entered — open after the delay, or instantly within the instant window. */
275
- onTriggerEnter(trigger = this.trigger(), payload) {
297
+ onTriggerEnter(trigger = this.trigger(), payload, event) {
276
298
  if (this.disabled()) {
277
299
  return;
278
300
  }
@@ -282,7 +304,7 @@ class RdxTooltip {
282
304
  this.payload.set(payload);
283
305
  this.closeTimer.stop();
284
306
  if (this.instantGroup.isInstant() || this.resolvedDelay() <= 0) {
285
- this.applyOpen(true, trigger, payload);
307
+ this.applyOpen(true, trigger, payload, 'trigger-hover', event);
286
308
  }
287
309
  else {
288
310
  this.openTimer.start();
@@ -308,7 +330,7 @@ class RdxTooltip {
308
330
  const nextTrigger = this.triggers()[0];
309
331
  this.trigger.set(nextTrigger);
310
332
  if (!nextTrigger && !this.destroyRef.destroyed) {
311
- this.applyClose();
333
+ this.applyClose('none');
312
334
  }
313
335
  }
314
336
  };
@@ -321,12 +343,21 @@ class RdxTooltip {
321
343
  this.triggerDelay.set(delay);
322
344
  this.triggerCloseDelay.set(closeDelay);
323
345
  }
324
- applyOpen(instant, trigger = this.trigger(), payload) {
346
+ applyOpen(instant, trigger = this.trigger(), payload, reason = 'none', event) {
325
347
  if (this.disabled()) {
326
348
  return;
327
349
  }
350
+ const wasOpen = this.open();
328
351
  this.openTimer.stop();
329
352
  this.closeTimer.stop();
353
+ if (!wasOpen) {
354
+ const { eventDetails } = createCancelableChangeEventDetails(reason, event ?? new Event('tooltip.open-change'), trigger);
355
+ this.onOpenChange.emit({ open: true, eventDetails });
356
+ if (eventDetails.isCanceled()) {
357
+ return;
358
+ }
359
+ this.suppressNextOpenChangeEmit = true;
360
+ }
330
361
  if (trigger) {
331
362
  this.trigger.set(trigger);
332
363
  }
@@ -334,10 +365,24 @@ class RdxTooltip {
334
365
  this.payload.set(payload);
335
366
  }
336
367
  this.openedInstant.set(instant || this.instantGroup.isInstant());
368
+ this.preventUnmountOnClose.set(false);
369
+ this.openChangeReason.set(reason);
337
370
  this.open.set(true);
338
371
  }
339
- applyClose() {
372
+ applyClose(reason = 'none', event) {
373
+ if (!this.open()) {
374
+ return;
375
+ }
376
+ const change = createCancelableChangeEventDetails(reason, event ?? new Event('tooltip.open-change'), this.trigger());
377
+ const { eventDetails } = change;
378
+ this.onOpenChange.emit({ open: false, eventDetails });
379
+ if (eventDetails.isCanceled()) {
380
+ return;
381
+ }
382
+ this.suppressNextOpenChangeEmit = true;
383
+ this.preventUnmountOnClose.set(change.shouldPreventUnmountOnClose());
340
384
  this.openedInstant.set(this.instantGroup.isInstant());
385
+ this.openChangeReason.set(reason);
341
386
  this.open.set(false);
342
387
  }
343
388
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -364,6 +409,7 @@ function contextFor(root) {
364
409
  return {
365
410
  contentId: root.contentId,
366
411
  isOpen: root.open,
412
+ present: root.present,
367
413
  instant: root.instant,
368
414
  disabled: root.disabled,
369
415
  disableHoverablePopup: root.disableHoverablePopup,
@@ -371,11 +417,14 @@ function contextFor(root) {
371
417
  trigger: root.trigger.asReadonly(),
372
418
  triggers: root.triggers.asReadonly(),
373
419
  payload: root.payload.asReadonly(),
374
- open: (trigger, payload) => root.show(trigger, payload),
375
- close: () => root.close(),
376
- closeDelayed: () => root.scheduleClose(),
420
+ openChangeReason: root.openChangeReason.asReadonly(),
421
+ open: (trigger, payload, event) => root.show(trigger, payload, event),
422
+ close: (reason, event) => root.close(reason, event),
423
+ cancelPendingOpen: () => root.cancelPendingOpen(),
424
+ closeHoverOpen: (event) => root.closeHoverOpen(event),
425
+ closeDelayed: (event) => root.scheduleClose(event),
377
426
  registerTrigger: (trigger) => root.registerTrigger(trigger),
378
- onTriggerEnter: (trigger, payload) => root.onTriggerEnter(trigger, payload),
427
+ onTriggerEnter: (trigger, payload, event) => root.onTriggerEnter(trigger, payload, event),
379
428
  onTriggerLeave: () => root.onTriggerLeave(),
380
429
  setCursorPosition: (position) => root.setCursorPosition(position),
381
430
  setDelays: (delay, closeDelay) => root.setDelays(delay, closeDelay)
@@ -452,7 +501,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
452
501
  */
453
502
  class RdxTooltipPortal {
454
503
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTooltipPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
455
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxTooltipPortal, isStandalone: true, selector: "ng-template[rdxTooltipPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxTooltipContext().isOpen }))], exportAs: ["rdxTooltipPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
504
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxTooltipPortal, isStandalone: true, selector: "ng-template[rdxTooltipPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxTooltipContext().present }))], exportAs: ["rdxTooltipPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
456
505
  }
457
506
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTooltipPortal, decorators: [{
458
507
  type: Directive,
@@ -460,7 +509,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
460
509
  selector: 'ng-template[rdxTooltipPortal]',
461
510
  exportAs: 'rdxTooltipPortal',
462
511
  hostDirectives: [{ directive: RdxPortalPresence, inputs: ['container'] }],
463
- providers: [provideRdxPresenceContext(() => ({ present: injectRdxTooltipContext().isOpen }))]
512
+ providers: [provideRdxPresenceContext(() => ({ present: injectRdxTooltipContext().present }))]
464
513
  }]
465
514
  }] });
466
515
  /**
@@ -522,7 +571,7 @@ class RdxTooltipPositioner extends RdxPopperContentWrapper {
522
571
  const target = event.target;
523
572
  const trigger = this.rootContext.trigger();
524
573
  if (trigger && target?.contains(trigger)) {
525
- this.rootContext.close();
574
+ this.rootContext.close('none', event);
526
575
  }
527
576
  };
528
577
  window.addEventListener('scroll', handleScroll, { capture: true });
@@ -550,7 +599,7 @@ class RdxTooltipPositioner extends RdxPopperContentWrapper {
550
599
  focusOutside: () => false,
551
600
  onEscapeKeyDown: (event) => this.escapeKeyDown.emit(event),
552
601
  onPointerDownOutside: (event) => this.pointerDownOutside.emit(event),
553
- onDismiss: () => this.rootContext.close()
602
+ onDismiss: (reason, event) => this.rootContext.close(reason === 'escape-key' ? 'escape-key' : 'outside-press', event)
554
603
  });
555
604
  // While following the cursor the popup sits right under the pointer; if it could intercept
556
605
  // the pointer it would steal hover from the trigger and the tooltip would flicker. Render it
@@ -581,6 +630,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
581
630
  }]
582
631
  }], ctorParameters: () => [], propDecorators: { escapeKeyDown: [{ type: i0.Output, args: ["escapeKeyDown"] }], pointerDownOutside: [{ type: i0.Output, args: ["pointerDownOutside"] }] } });
583
632
 
633
+ const TOOLTIP_TRIGGER_ATTR = 'data-rdx-tooltip-trigger';
634
+ function getTargetElement(event) {
635
+ if ('composedPath' in event) {
636
+ for (const target of event.composedPath()) {
637
+ if (target instanceof Element) {
638
+ return target;
639
+ }
640
+ }
641
+ }
642
+ return event.target instanceof Element ? event.target : null;
643
+ }
644
+ function closestEnabledTooltipTrigger(element) {
645
+ let current = element;
646
+ while (current) {
647
+ if (current.hasAttribute(TOOLTIP_TRIGGER_ATTR)) {
648
+ return current;
649
+ }
650
+ if (current.parentElement) {
651
+ current = current.parentElement;
652
+ continue;
653
+ }
654
+ const root = current.getRootNode();
655
+ current = 'host' in root && root.host instanceof Element ? root.host : null;
656
+ }
657
+ return null;
658
+ }
659
+ function isMouseLikePointerType(pointerType) {
660
+ return pointerType !== 'touch';
661
+ }
584
662
  class RdxTooltipTrigger {
585
663
  constructor() {
586
664
  this.parentRootContext = injectRdxTooltipContext(true);
@@ -623,8 +701,16 @@ class RdxTooltipTrigger {
623
701
  this.isDisabled = computed(() => (this.rootContext()?.disabled() ?? false) || this.disabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
624
702
  /** Whether this specific trigger is the active anchor of an open tooltip. */
625
703
  this.isOpen = computed(() => this.rootContext()?.isOpen() === true && this.rootContext()?.trigger() === this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
704
+ this.triggerInteraction = createRdxTriggerInteraction({
705
+ trigger: () => this.elementRef.nativeElement,
706
+ activeTrigger: () => this.rootContext()?.trigger(),
707
+ open: () => this.rootContext()?.isOpen() ?? false,
708
+ disabled: () => this.isDisabled(),
709
+ contentId: () => this.rootContext()?.contentId
710
+ });
626
711
  this.isPointerDown = signal(false, ...(ngDevMode ? [{ debugName: "isPointerDown" }] : /* istanbul ignore next */ []));
627
712
  this.hasPointerMoveOpened = signal(false, ...(ngDevMode ? [{ debugName: "hasPointerMoveOpened" }] : /* istanbul ignore next */ []));
713
+ this.isNestedTriggerHovered = signal(false, ...(ngDevMode ? [{ debugName: "isNestedTriggerHovered" }] : /* istanbul ignore next */ []));
628
714
  effect((onCleanup) => {
629
715
  const handle = this.handle();
630
716
  if (handle) {
@@ -635,23 +721,30 @@ class RdxTooltipTrigger {
635
721
  }
636
722
  });
637
723
  }
638
- handleFocus() {
724
+ handleFocus(event) {
639
725
  const rootContext = this.rootContext();
640
726
  if (!rootContext || this.isDisabled() || this.isPointerDown()) {
641
727
  return;
642
728
  }
643
729
  rootContext.setDelays(this.delay(), this.closeDelay());
644
- rootContext.open(this.elementRef.nativeElement, this.payload());
730
+ rootContext.open(this.elementRef.nativeElement, this.payload(), event);
645
731
  }
646
- handleBlur() {
647
- this.rootContext()?.closeDelayed();
732
+ handleBlur(event) {
733
+ this.rootContext()?.closeDelayed(event);
648
734
  }
649
- handleClick() {
735
+ handleClick(event) {
650
736
  const rootContext = this.rootContext();
651
737
  if (rootContext?.isOpen() && this.closeOnClick()) {
652
- rootContext.close();
738
+ rootContext.close('trigger-press', event);
739
+ return;
740
+ }
741
+ if (rootContext && this.closeOnClick()) {
742
+ rootContext.cancelPendingOpen();
653
743
  }
654
744
  }
745
+ handlePointerEnter(event) {
746
+ this.pointerType = event.pointerType;
747
+ }
655
748
  handlePointerMove(event) {
656
749
  if (event.pointerType === 'touch') {
657
750
  return;
@@ -660,12 +753,16 @@ class RdxTooltipTrigger {
660
753
  if (!rootContext || this.isDisabled()) {
661
754
  return;
662
755
  }
756
+ this.pointerType = event.pointerType;
757
+ if (this.detectNestedTriggerHover(getTargetElement(event))) {
758
+ return;
759
+ }
663
760
  if (rootContext.trackCursorAxis() !== 'none') {
664
761
  rootContext.setCursorPosition({ x: event.clientX, y: event.clientY });
665
762
  }
666
763
  if (!this.hasPointerMoveOpened()) {
667
764
  rootContext.setDelays(this.delay(), this.closeDelay());
668
- rootContext.onTriggerEnter(this.elementRef.nativeElement, this.payload());
765
+ rootContext.onTriggerEnter(this.elementRef.nativeElement, this.payload(), event);
669
766
  this.hasPointerMoveOpened.set(true);
670
767
  }
671
768
  }
@@ -673,6 +770,35 @@ class RdxTooltipTrigger {
673
770
  this.rootContext()?.onTriggerLeave();
674
771
  this.hasPointerMoveOpened.set(false);
675
772
  }
773
+ handleMouseOver(event) {
774
+ const wasNestedTriggerHovered = this.isNestedTriggerHovered();
775
+ const target = getTargetElement(event);
776
+ const nestedTriggerHovered = this.detectNestedTriggerHover(target);
777
+ const trigger = this.elementRef.nativeElement;
778
+ const targetInsideTrigger = target ? trigger.contains(target) : false;
779
+ const rootContext = this.rootContext();
780
+ if (!rootContext) {
781
+ return;
782
+ }
783
+ if (nestedTriggerHovered && rootContext.isOpen() && rootContext.openChangeReason() === 'trigger-hover') {
784
+ rootContext.closeHoverOpen();
785
+ return;
786
+ }
787
+ if (wasNestedTriggerHovered &&
788
+ !nestedTriggerHovered &&
789
+ targetInsideTrigger &&
790
+ !this.isDisabled() &&
791
+ !rootContext.isOpen() &&
792
+ isMouseLikePointerType(this.pointerType)) {
793
+ rootContext.setDelays(this.delay(), this.closeDelay());
794
+ rootContext.onTriggerEnter(trigger, this.payload(), event);
795
+ this.hasPointerMoveOpened.set(true);
796
+ }
797
+ }
798
+ handleMouseLeave() {
799
+ this.isNestedTriggerHovered.set(false);
800
+ this.pointerType = undefined;
801
+ }
676
802
  async handlePointerDown(event) {
677
803
  const user = this.userOnPointerDown();
678
804
  let result;
@@ -685,13 +811,28 @@ class RdxTooltipTrigger {
685
811
  return;
686
812
  }
687
813
  this.isPointerDown.set(true);
814
+ this.triggerInteraction.recordPointerDown(event);
815
+ this.pointerType = event.pointerType;
816
+ if (this.closeOnClick() && !this.rootContext()?.isOpen()) {
817
+ this.rootContext()?.cancelPendingOpen();
818
+ }
688
819
  const handlePointerUp = () => {
689
820
  setTimeout(() => this.isPointerDown.set(false), 1);
690
821
  };
691
822
  document.addEventListener('pointerup', handlePointerUp, { once: true });
692
823
  }
824
+ detectNestedTriggerHover(target) {
825
+ const trigger = this.elementRef.nativeElement;
826
+ const nearestTrigger = closestEnabledTooltipTrigger(target);
827
+ const nestedTriggerHovered = nearestTrigger !== null && nearestTrigger !== trigger && trigger.contains(nearestTrigger);
828
+ this.isNestedTriggerHovered.set(nestedTriggerHovered);
829
+ if (nestedTriggerHovered) {
830
+ this.rootContext()?.cancelPendingOpen();
831
+ }
832
+ return nestedTriggerHovered;
833
+ }
693
834
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTooltipTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
694
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTooltipTrigger, isStandalone: true, selector: "[rdxTooltipTrigger]", inputs: { handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, userOnPointerDown: { classPropertyName: "userOnPointerDown", publicName: "rdxOnPointerDown", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button", "data-grace-area-trigger": "''" }, listeners: { "pointermove": "handlePointerMove($event)", "pointerleave": "handlePointerLeave()", "pointerdown": "handlePointerDown($event)", "focus": "handleFocus()", "blur": "handleBlur()", "click": "handleClick()" }, properties: { "id": "triggerId()", "attr.aria-describedby": "isOpen() ? rootContext()?.contentId : undefined", "attr.data-popup-open": "isOpen() ? \"\" : undefined", "attr.data-trigger-disabled": "isDisabled() ? \"\" : undefined" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
835
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxTooltipTrigger, isStandalone: true, selector: "[rdxTooltipTrigger]", inputs: { handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, userOnPointerDown: { classPropertyName: "userOnPointerDown", publicName: "rdxOnPointerDown", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button", "data-grace-area-trigger": "''" }, listeners: { "pointerenter": "handlePointerEnter($event)", "pointermove": "handlePointerMove($event)", "pointerleave": "handlePointerLeave()", "mouseover": "handleMouseOver($event)", "mouseleave": "handleMouseLeave()", "pointerdown": "handlePointerDown($event)", "focus": "handleFocus($event)", "blur": "handleBlur($event)", "click": "handleClick($event)" }, properties: { "id": "triggerId()", "attr.aria-describedby": "isOpen() ? rootContext()?.contentId : undefined", "attr.data-popup-open": "triggerInteraction.dataPopupOpen()", "attr.data-trigger-disabled": "triggerInteraction.disabled() ? \"\" : undefined", "attr.data-rdx-tooltip-trigger": "isDisabled() ? undefined : \"\"" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
695
836
  }
696
837
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxTooltipTrigger, decorators: [{
697
838
  type: Directive,
@@ -703,14 +844,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
703
844
  'data-grace-area-trigger': "''",
704
845
  '[id]': 'triggerId()',
705
846
  '[attr.aria-describedby]': 'isOpen() ? rootContext()?.contentId : undefined',
706
- '[attr.data-popup-open]': 'isOpen() ? "" : undefined',
707
- '[attr.data-trigger-disabled]': 'isDisabled() ? "" : undefined',
847
+ '[attr.data-popup-open]': 'triggerInteraction.dataPopupOpen()',
848
+ '[attr.data-trigger-disabled]': 'triggerInteraction.disabled() ? "" : undefined',
849
+ '[attr.data-rdx-tooltip-trigger]': 'isDisabled() ? undefined : ""',
850
+ '(pointerenter)': 'handlePointerEnter($event)',
708
851
  '(pointermove)': 'handlePointerMove($event)',
709
852
  '(pointerleave)': 'handlePointerLeave()',
853
+ '(mouseover)': 'handleMouseOver($event)',
854
+ '(mouseleave)': 'handleMouseLeave()',
710
855
  '(pointerdown)': 'handlePointerDown($event)',
711
- '(focus)': 'handleFocus()',
712
- '(blur)': 'handleBlur()',
713
- '(click)': 'handleClick()'
856
+ '(focus)': 'handleFocus($event)',
857
+ '(blur)': 'handleBlur($event)',
858
+ '(click)': 'handleClick($event)'
714
859
  }
715
860
  }]
716
861
  }], ctorParameters: () => [], propDecorators: { handle: [{ type: i0.Input, args: [{ isSignal: true, alias: "handle", required: false }] }], payload: [{ type: i0.Input, args: [{ isSignal: true, alias: "payload", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], userOnPointerDown: [{ type: i0.Input, args: [{ isSignal: true, alias: "rdxOnPointerDown", required: false }] }] } });