@radix-ng/primitives 1.0.0-beta.3 → 1.0.0-beta.5

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 (118) hide show
  1. package/README.md +1 -1
  2. package/fesm2022/radix-ng-primitives-accordion.mjs +5 -3
  3. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  4. package/fesm2022/radix-ng-primitives-alert-dialog.mjs +3 -2
  5. package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
  6. package/fesm2022/radix-ng-primitives-autocomplete.mjs +617 -659
  7. package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
  8. package/fesm2022/radix-ng-primitives-calendar.mjs +5 -3
  9. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  10. package/fesm2022/radix-ng-primitives-checkbox.mjs +33 -18
  11. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-combobox.mjs +1305 -572
  13. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  14. package/fesm2022/radix-ng-primitives-config.mjs +13 -4
  15. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-context-menu.mjs +51 -10
  17. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-core.mjs +1352 -64
  19. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-date-field.mjs +5 -3
  21. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  22. package/fesm2022/radix-ng-primitives-dialog.mjs +290 -120
  23. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  24. package/fesm2022/radix-ng-primitives-direction-provider.mjs +70 -0
  25. package/fesm2022/radix-ng-primitives-direction-provider.mjs.map +1 -0
  26. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +519 -184
  27. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-drawer.mjs +3 -3
  29. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-editable.mjs +12 -7
  31. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  32. package/fesm2022/radix-ng-primitives-field.mjs +3 -2
  33. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +803 -0
  35. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -0
  36. package/fesm2022/radix-ng-primitives-focus-scope.mjs +305 -70
  37. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  38. package/fesm2022/radix-ng-primitives-menu.mjs +893 -289
  39. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-menubar.mjs +32 -4
  41. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  42. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +144 -159
  43. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  44. package/fesm2022/radix-ng-primitives-number-field.mjs +7 -2
  45. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-popover.mjs +284 -212
  47. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-popper.mjs +94 -51
  49. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  50. package/fesm2022/radix-ng-primitives-presence.mjs +1 -1
  51. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-preview-card.mjs +141 -173
  53. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-radio.mjs +19 -14
  55. package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-roving-focus.mjs +4 -2
  57. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  58. package/fesm2022/radix-ng-primitives-scroll-area.mjs +5 -4
  59. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-select.mjs +241 -164
  61. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-slider.mjs +262 -29
  63. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-stepper.mjs +16 -10
  65. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-switch.mjs +10 -5
  67. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  68. package/fesm2022/radix-ng-primitives-tabs.mjs +15 -10
  69. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  70. package/fesm2022/radix-ng-primitives-time-field.mjs +5 -3
  71. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  72. package/fesm2022/radix-ng-primitives-toast.mjs +15 -36
  73. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
  74. package/fesm2022/radix-ng-primitives-toggle-group.mjs +14 -7
  75. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  76. package/fesm2022/radix-ng-primitives-toggle.mjs +12 -6
  77. package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
  78. package/fesm2022/radix-ng-primitives-toolbar.mjs +5 -3
  79. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  80. package/fesm2022/radix-ng-primitives-tooltip.mjs +251 -143
  81. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  82. package/package.json +10 -1
  83. package/types/radix-ng-primitives-accordion.d.ts +4 -3
  84. package/types/radix-ng-primitives-autocomplete.d.ts +217 -152
  85. package/types/radix-ng-primitives-calendar.d.ts +5 -3
  86. package/types/radix-ng-primitives-checkbox.d.ts +27 -15
  87. package/types/radix-ng-primitives-combobox.d.ts +672 -283
  88. package/types/radix-ng-primitives-config.d.ts +1 -1
  89. package/types/radix-ng-primitives-context-menu.d.ts +15 -5
  90. package/types/radix-ng-primitives-core.d.ts +764 -14
  91. package/types/radix-ng-primitives-date-field.d.ts +3 -2
  92. package/types/radix-ng-primitives-dialog.d.ts +88 -32
  93. package/types/radix-ng-primitives-direction-provider.d.ts +41 -0
  94. package/types/radix-ng-primitives-dismissable-layer.d.ts +147 -99
  95. package/types/radix-ng-primitives-editable.d.ts +11 -5
  96. package/types/radix-ng-primitives-field.d.ts +1 -0
  97. package/types/radix-ng-primitives-floating-focus-manager.d.ts +272 -0
  98. package/types/radix-ng-primitives-focus-scope.d.ts +132 -1
  99. package/types/radix-ng-primitives-menu.d.ts +192 -103
  100. package/types/radix-ng-primitives-navigation-menu.d.ts +37 -75
  101. package/types/radix-ng-primitives-number-field.d.ts +8 -3
  102. package/types/radix-ng-primitives-popover.d.ts +71 -92
  103. package/types/radix-ng-primitives-popper.d.ts +39 -9
  104. package/types/radix-ng-primitives-preview-card.d.ts +39 -72
  105. package/types/radix-ng-primitives-radio.d.ts +13 -6
  106. package/types/radix-ng-primitives-roving-focus.d.ts +7 -6
  107. package/types/radix-ng-primitives-scroll-area.d.ts +2 -2
  108. package/types/radix-ng-primitives-select.d.ts +142 -109
  109. package/types/radix-ng-primitives-slider.d.ts +64 -12
  110. package/types/radix-ng-primitives-stepper.d.ts +15 -7
  111. package/types/radix-ng-primitives-switch.d.ts +10 -4
  112. package/types/radix-ng-primitives-tabs.d.ts +12 -6
  113. package/types/radix-ng-primitives-time-field.d.ts +3 -2
  114. package/types/radix-ng-primitives-toast.d.ts +7 -7
  115. package/types/radix-ng-primitives-toggle-group.d.ts +15 -8
  116. package/types/radix-ng-primitives-toggle.d.ts +10 -3
  117. package/types/radix-ng-primitives-toolbar.d.ts +3 -2
  118. package/types/radix-ng-primitives-tooltip.d.ts +61 -80
@@ -1,13 +1,14 @@
1
1
  import * as i0 from '@angular/core';
2
- import { booleanAttribute, inject, DestroyRef, signal, model, input, output, computed, effect, untracked, Directive, ElementRef, isDevMode, numberAttribute, afterNextRender, NgModule } from '@angular/core';
2
+ import { booleanAttribute, inject, DestroyRef, ElementRef, signal, model, input, output, computed, effect, untracked, Directive, isDevMode, numberAttribute, afterNextRender, NgModule } from '@angular/core';
3
3
  import * as i1 from '@radix-ng/primitives/popper';
4
- import { RdxPopper, RdxPopperContentWrapper, RdxPopperArrow, RdxPopperContent, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
5
- import { createContext, useTransitionStatus, injectId, useScrollLock, useGraceArea } from '@radix-ng/primitives/core';
4
+ import { RdxPopper, RdxPopperContentWrapper, RdxPopperArrow, RdxPopperContent, legacyPopperVars, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
5
+ import * as i2 from '@radix-ng/primitives/core';
6
+ import { createContext, createFloatingRootContext, useTransitionStatus, injectId, createCancelableChangeEventDetails, provideFloatingTree, provideFloatingRootContext, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError, useGraceArea } from '@radix-ng/primitives/core';
7
+ import * as i3 from '@radix-ng/primitives/floating-focus-manager';
8
+ import { getInteractionTypeFromEvent, RdxFloatingFocusManager, provideFloatingFocusManagerConfig, createRdxTriggerInteraction, useTriggerFocusGuards } from '@radix-ng/primitives/floating-focus-manager';
6
9
  import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
7
- import * as i2 from '@radix-ng/primitives/dismissable-layer';
8
- import { RdxDismissableLayer, provideRdxDismissableLayerConfig } from '@radix-ng/primitives/dismissable-layer';
9
- import * as i3 from '@radix-ng/primitives/focus-scope';
10
- import { RdxFocusScope, provideRdxFocusScopeConfig } from '@radix-ng/primitives/focus-scope';
10
+ import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
11
+ import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
11
12
  import * as i1$1 from '@radix-ng/primitives/portal';
12
13
  import { RdxPortalPresence } from '@radix-ng/primitives/portal';
13
14
  import { provideRdxPresenceContext } from '@radix-ng/primitives/presence';
@@ -22,6 +23,11 @@ class RdxPopoverRoot {
22
23
  constructor() {
23
24
  this.popper = inject(RdxPopper);
24
25
  this.destroyRef = inject(DestroyRef);
26
+ /** Shared per-popup floating context (ADR 0015 §1): `open`, trigger registry, reference / floating els. */
27
+ this.floatingContext = createFloatingRootContext({
28
+ ownerDocument: inject(ElementRef).nativeElement.ownerDocument,
29
+ open: () => this.open()
30
+ });
25
31
  this.hasAppliedDefaultOpen = false;
26
32
  this.hasAppliedDefaultTriggerId = false;
27
33
  this.hoverDelay = 300;
@@ -59,51 +65,70 @@ class RdxPopoverRoot {
59
65
  */
60
66
  this.handle = input(...(ngDevMode ? [undefined, { debugName: "handle" }] : /* istanbul ignore next */ []));
61
67
  this.contentId = injectId('rdx-popover-content-');
68
+ this.beforeContentFocusGuard = signal(null, ...(ngDevMode ? [{ debugName: "beforeContentFocusGuard" }] : /* istanbul ignore next */ []));
62
69
  this.descriptionId = signal(undefined, ...(ngDevMode ? [{ debugName: "descriptionId" }] : /* istanbul ignore next */ []));
63
70
  this.titleId = signal(undefined, ...(ngDevMode ? [{ debugName: "titleId" }] : /* istanbul ignore next */ []));
64
71
  this.trigger = signal(undefined, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
65
72
  this.triggers = signal([], ...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
66
73
  this.payload = signal(undefined, ...(ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []));
67
74
  this.isPointerDownOnTrigger = signal(false, ...(ngDevMode ? [{ debugName: "isPointerDownOnTrigger" }] : /* istanbul ignore next */ []));
75
+ /** Whether the current open was initiated by touch (ADR 0016 §3 — gates the anchored scroll lock). */
76
+ this.openedByTouch = signal(false, ...(ngDevMode ? [{ debugName: "openedByTouch" }] : /* istanbul ignore next */ []));
77
+ this.openInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "openInteractionType" }] : /* istanbul ignore next */ []));
78
+ this.closeInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "closeInteractionType" }] : /* istanbul ignore next */ []));
68
79
  this.popupCloseCount = signal(0, ...(ngDevMode ? [{ debugName: "popupCloseCount" }] : /* istanbul ignore next */ []));
80
+ this.preventUnmountOnClose = signal(false, ...(ngDevMode ? [{ debugName: "preventUnmountOnClose" }] : /* istanbul ignore next */ []));
81
+ this.pendingTriggerOpenInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "pendingTriggerOpenInteractionType" }] : /* istanbul ignore next */ []));
69
82
  this.onOpenChange = output();
70
83
  this.onOpenChangeComplete = output();
71
84
  this.registeredTriggers = new Map();
72
85
  this.viewportTriggerChange = new Set();
73
- this.state = computed(() => (this.open() ? 'open' : 'closed'), ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
86
+ this.state = computed(() => (this.open() ? 'open' : 'closed'), { debugName: 'RdxPopoverRoot.state' });
87
+ this.present = computed(() => this.open() || this.preventUnmountOnClose(), {
88
+ debugName: 'RdxPopoverRoot.present'
89
+ });
74
90
  let previousOpen = this.open();
91
+ // Keep the floating context's reference element in sync with the active trigger.
92
+ effect(() => this.floatingContext.setReferenceElement(this.trigger() ?? null));
93
+ effect(() => {
94
+ if (this.open() && this.preventUnmountOnClose()) {
95
+ this.preventUnmountOnClose.set(false);
96
+ }
97
+ }, { debugName: 'RdxPopoverRoot.clearPreventUnmountOnOpen' });
75
98
  effect(() => {
76
99
  const defaultOpen = this.defaultOpen();
77
100
  if (!this.hasAppliedDefaultOpen && defaultOpen) {
78
101
  this.hasAppliedDefaultOpen = true;
79
102
  this.open.set(defaultOpen);
80
103
  }
81
- });
104
+ }, { debugName: 'RdxPopoverRoot.applyDefaultOpen' });
82
105
  effect(() => {
83
106
  const defaultTriggerId = this.defaultTriggerId();
84
107
  if (!this.hasAppliedDefaultTriggerId && defaultTriggerId !== null) {
85
108
  this.hasAppliedDefaultTriggerId = true;
86
109
  this.triggerId.set(defaultTriggerId);
87
110
  }
88
- });
111
+ }, { debugName: 'RdxPopoverRoot.applyDefaultTriggerId' });
89
112
  effect(() => {
90
113
  const triggerId = this.triggerId();
91
114
  untracked(() => this.syncTriggerId(triggerId));
92
- });
115
+ }, { debugName: 'RdxPopoverRoot.syncTriggerId' });
93
116
  effect(() => {
94
117
  const open = this.open();
95
118
  if (open !== previousOpen) {
96
119
  previousOpen = open;
97
120
  untracked(() => this.transition.start(open));
98
121
  }
99
- });
122
+ }, { debugName: 'RdxPopoverRoot.startTransition' });
100
123
  effect((onCleanup) => {
101
124
  const handle = this.handle();
102
125
  if (handle) {
103
126
  onCleanup(untracked(() => handle.registerRoot(contextFor(this))));
104
127
  }
128
+ }, { debugName: 'RdxPopoverRoot.registerHandle' });
129
+ effect(() => this.popper.anchorOverride.set(this.trigger()), {
130
+ debugName: 'RdxPopoverRoot.syncAnchorOverride'
105
131
  });
106
- effect(() => this.popper.anchorOverride.set(this.trigger()));
107
132
  this.destroyRef.onDestroy(() => {
108
133
  this.clearHoverTimers();
109
134
  if (this.instantFrame !== undefined) {
@@ -111,12 +136,31 @@ class RdxPopoverRoot {
111
136
  }
112
137
  });
113
138
  }
114
- show(trigger = this.trigger(), payload, triggerId, reason = 'none', event = new Event('popover.open-change'), fromHover = false) {
139
+ show(trigger = this.trigger(), payload, triggerId, reason = 'none', event, fromHover = false) {
115
140
  this.clearHoverTimers();
116
- this.isHoverActive.set(fromHover);
117
- this.openChangeReason.set(reason);
118
141
  const previousTrigger = this.trigger();
119
142
  const changedTriggerWhileOpen = this.open() && previousTrigger !== trigger;
143
+ const changed = !this.open() || previousTrigger !== trigger;
144
+ if (!changed) {
145
+ this.isHoverActive.set(fromHover);
146
+ this.openChangeReason.set(reason);
147
+ if (triggerId !== undefined) {
148
+ this.triggerId.set(triggerId);
149
+ }
150
+ this.payload.set(payload);
151
+ return;
152
+ }
153
+ const resolvedEvent = event ?? new Event('popover.open-change');
154
+ const change = this.createOpenChangeEvent(true, reason, resolvedEvent, trigger, triggerId ?? this.triggerId());
155
+ this.onOpenChange.emit(change.payload);
156
+ if (change.eventDetails.isCanceled()) {
157
+ return;
158
+ }
159
+ const interactionType = this.consumeOpenInteractionType(event);
160
+ this.openInteractionType.set(interactionType);
161
+ this.openedByTouch.set(interactionType === 'touch');
162
+ this.isHoverActive.set(fromHover);
163
+ this.openChangeReason.set(reason);
120
164
  this.instant.set(changedTriggerWhileOpen || reason === 'trigger-focus');
121
165
  if (changedTriggerWhileOpen) {
122
166
  this.scheduleInstantReset();
@@ -131,22 +175,30 @@ class RdxPopoverRoot {
131
175
  this.triggerId.set(triggerId);
132
176
  }
133
177
  this.payload.set(payload);
134
- const changed = !this.open() || previousTrigger !== trigger;
178
+ this.preventUnmountOnClose.set(false);
135
179
  this.open.set(true);
136
- if (changed) {
137
- this.emitOpenChange(true, reason, event);
138
- }
180
+ this.floatingContext.events.emit('openchange', { open: true, reason, event: change.eventDetails.event });
139
181
  }
140
- close(reason = 'none', event = new Event('popover.open-change')) {
182
+ close(reason = 'none', event) {
141
183
  this.clearHoverTimers();
142
- this.isHoverActive.set(false);
143
184
  if (!this.open()) {
144
185
  return;
145
186
  }
187
+ const resolvedEvent = event ?? new Event('popover.open-change');
188
+ const change = this.createOpenChangeEvent(false, reason, resolvedEvent, this.trigger(), this.triggerId());
189
+ this.onOpenChange.emit(change.payload);
190
+ if (change.eventDetails.isCanceled()) {
191
+ return;
192
+ }
193
+ this.pendingTriggerOpenInteractionType.set(null);
194
+ this.closeInteractionType.set(getInteractionTypeFromEvent(event));
195
+ this.isHoverActive.set(false);
196
+ this.openedByTouch.set(false);
146
197
  this.instant.set(reason !== 'none' && reason !== 'trigger-hover');
147
198
  this.openChangeReason.set(reason);
199
+ this.preventUnmountOnClose.set(change.shouldPreventUnmountOnClose());
148
200
  this.open.set(false);
149
- this.emitOpenChange(false, reason, event);
201
+ this.floatingContext.events.emit('openchange', { open: false, reason, event: change.eventDetails.event });
150
202
  }
151
203
  toggle(triggerId, trigger, payload, event) {
152
204
  this.clearHoverTimers();
@@ -183,9 +235,14 @@ class RdxPopoverRoot {
183
235
  this.hoverDelay = delay;
184
236
  this.hoverCloseDelay = closeDelay;
185
237
  }
238
+ setTriggerOpenInteractionType(type) {
239
+ this.pendingTriggerOpenInteractionType.set(type);
240
+ }
186
241
  registerTrigger(id, trigger, payload) {
187
242
  this.registeredTriggers.set(id, { element: trigger, payload });
188
243
  this.triggers.update((triggers) => (triggers.includes(trigger) ? triggers : [...triggers, trigger]));
244
+ // Bridge into the floating context's trigger registry (new dismissal/focus inside-element checks).
245
+ this.floatingContext.triggers.add(trigger);
189
246
  if (this.triggerId() === id) {
190
247
  this.trigger.set(trigger);
191
248
  this.payload.set(payload());
@@ -199,6 +256,7 @@ class RdxPopoverRoot {
199
256
  this.registeredTriggers.delete(id);
200
257
  }
201
258
  this.triggers.update((triggers) => triggers.filter((candidate) => candidate !== trigger));
259
+ this.floatingContext.triggers.delete(trigger);
202
260
  if (this.destroyRef.destroyed) {
203
261
  return;
204
262
  }
@@ -219,6 +277,9 @@ class RdxPopoverRoot {
219
277
  this.viewportTriggerChange.add(onTriggerChange);
220
278
  return () => this.viewportTriggerChange.delete(onTriggerChange);
221
279
  }
280
+ setBeforeContentFocusGuard(element) {
281
+ this.beforeContentFocusGuard.set(element);
282
+ }
222
283
  registerTransitionElement(element) {
223
284
  return this.transition.registerElement(element);
224
285
  }
@@ -244,14 +305,20 @@ class RdxPopoverRoot {
244
305
  this.trigger.set(trigger.element);
245
306
  this.payload.set(trigger.payload());
246
307
  }
247
- emitOpenChange(open, reason, event) {
248
- this.onOpenChange.emit({
249
- open,
250
- triggerId: this.triggerId(),
251
- trigger: this.trigger(),
252
- reason,
253
- event
254
- });
308
+ createOpenChangeEvent(open, reason, event, trigger, triggerId) {
309
+ const change = createCancelableChangeEventDetails(reason, event, trigger);
310
+ return {
311
+ eventDetails: change.eventDetails,
312
+ shouldPreventUnmountOnClose: change.shouldPreventUnmountOnClose,
313
+ payload: {
314
+ open,
315
+ triggerId,
316
+ trigger: change.eventDetails.trigger,
317
+ reason: change.eventDetails.reason,
318
+ event: change.eventDetails.event,
319
+ eventDetails: change.eventDetails
320
+ }
321
+ };
255
322
  }
256
323
  clearHoverTimers() {
257
324
  this.clearOpenTimer();
@@ -280,15 +347,32 @@ class RdxPopoverRoot {
280
347
  }
281
348
  });
282
349
  }
350
+ consumeOpenInteractionType(event) {
351
+ const pending = this.pendingTriggerOpenInteractionType();
352
+ this.pendingTriggerOpenInteractionType.set(null);
353
+ return pending ?? getInteractionTypeFromEvent(event);
354
+ }
283
355
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
284
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverRoot, isStandalone: true, selector: "[rdxPopoverRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, triggerId: { classPropertyName: "triggerId", publicName: "triggerId", isSignal: true, isRequired: false, transformFunction: null }, defaultTriggerId: { classPropertyName: "defaultTriggerId", publicName: "defaultTriggerId", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", triggerId: "triggerIdChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [provideRdxPopoverRootContext(context)], exportAs: ["rdxPopoverRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
356
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverRoot, isStandalone: true, selector: "[rdxPopoverRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, triggerId: { classPropertyName: "triggerId", publicName: "triggerId", isSignal: true, isRequired: false, transformFunction: null }, defaultTriggerId: { classPropertyName: "defaultTriggerId", publicName: "defaultTriggerId", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", triggerId: "triggerIdChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
357
+ provideRdxPopoverRootContext(context),
358
+ // New floating foundation (ADR 0015/0017 migration). Inherit-or-create tree (nested sharing);
359
+ // the per-popup root context bridges open / triggers / reference.
360
+ provideFloatingTree(),
361
+ provideFloatingRootContext(() => inject(RdxPopoverRoot).floatingContext)
362
+ ], exportAs: ["rdxPopoverRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
285
363
  }
286
364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverRoot, decorators: [{
287
365
  type: Directive,
288
366
  args: [{
289
367
  selector: '[rdxPopoverRoot]',
290
368
  exportAs: 'rdxPopoverRoot',
291
- providers: [provideRdxPopoverRootContext(context)],
369
+ providers: [
370
+ provideRdxPopoverRootContext(context),
371
+ // New floating foundation (ADR 0015/0017 migration). Inherit-or-create tree (nested sharing);
372
+ // the per-popup root context bridges open / triggers / reference.
373
+ provideFloatingTree(),
374
+ provideFloatingRootContext(() => inject(RdxPopoverRoot).floatingContext)
375
+ ],
292
376
  hostDirectives: [RdxPopper]
293
377
  }]
294
378
  }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], triggerId: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerId", required: false }] }, { type: i0.Output, args: ["triggerIdChange"] }], defaultTriggerId: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultTriggerId", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], handle: [{ type: i0.Input, args: [{ isSignal: true, alias: "handle", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
@@ -297,6 +381,7 @@ function contextFor(root) {
297
381
  contentId: root.contentId,
298
382
  descriptionId: root.descriptionId.asReadonly(),
299
383
  isOpen: root.open,
384
+ present: root.present,
300
385
  modal: root.modal,
301
386
  titleId: root.titleId.asReadonly(),
302
387
  trigger: root.trigger.asReadonly(),
@@ -307,6 +392,9 @@ function contextFor(root) {
307
392
  instant: root.instant.asReadonly(),
308
393
  openChangeReason: root.openChangeReason.asReadonly(),
309
394
  isPointerDownOnTrigger: root.isPointerDownOnTrigger.asReadonly(),
395
+ openedByTouch: root.openedByTouch.asReadonly(),
396
+ openInteractionType: root.openInteractionType.asReadonly(),
397
+ closeInteractionType: root.closeInteractionType.asReadonly(),
310
398
  close: (reason, event) => root.close(reason, event),
311
399
  cancelHoverClose: () => root.cancelHoverClose(),
312
400
  cancelHoverOpen: () => root.cancelHoverOpen(),
@@ -317,6 +405,8 @@ function contextFor(root) {
317
405
  setDescriptionId: (id) => root.descriptionId.set(id),
318
406
  setTitleId: (id) => root.titleId.set(id),
319
407
  setPointerDownOnTrigger: (pointerDown) => root.isPointerDownOnTrigger.set(pointerDown),
408
+ setOpenedByTouch: (value) => root.openedByTouch.set(value),
409
+ setTriggerOpenInteractionType: (type) => root.setTriggerOpenInteractionType(type),
320
410
  setHoverDelays: (delay, closeDelay) => root.setHoverDelays(delay, closeDelay),
321
411
  registerPopupClose: () => {
322
412
  root.popupCloseCount.update((count) => count + 1);
@@ -324,7 +414,9 @@ function contextFor(root) {
324
414
  },
325
415
  registerTransitionElement: (element) => root.registerTransitionElement(element),
326
416
  transitionStatus: root.transitionStatus,
417
+ beforeContentFocusGuard: root.beforeContentFocusGuard.asReadonly(),
327
418
  registerViewport: (onTriggerChange) => root.registerViewport(onTriggerChange),
419
+ setBeforeContentFocusGuard: (element) => root.setBeforeContentFocusGuard(element),
328
420
  toggle: (triggerId, trigger, payload, event) => root.toggle(triggerId, trigger, payload, event)
329
421
  };
330
422
  }
@@ -364,6 +456,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
364
456
  class RdxPopoverBackdrop {
365
457
  constructor() {
366
458
  this.rootContext = injectRdxPopoverRootContext();
459
+ // Register the backdrop as owned DOM footprint for primitive-specific checks. The focus manager's
460
+ // marker keep-set stays narrow and does not keep sibling backdrop roots.
461
+ const floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT, { optional: true });
462
+ if (floatingContext) {
463
+ const host = inject(ElementRef).nativeElement;
464
+ floatingContext.addFloatingElement(host);
465
+ inject(DestroyRef).onDestroy(() => floatingContext.removeFloatingElement(host));
466
+ }
367
467
  }
368
468
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
369
469
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverBackdrop, isStandalone: true, selector: "[rdxPopoverBackdrop]", host: { properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"" } }, ngImport: i0 }); }
@@ -381,109 +481,136 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
381
481
  '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"'
382
482
  }
383
483
  }]
384
- }] });
484
+ }], ctorParameters: () => [] });
385
485
 
386
486
  /**
387
487
  * A container for the popover contents.
488
+ *
489
+ * **ADR 0015/0017 Phase-4 migration** onto the new floating dismissal + focus engine (same pattern as
490
+ * Dialog; browser-verified via `popover.behavior` Playwright). Popover-specific:
491
+ * - **Hover-open disables the manager** (`enabled = isOpen && !isHoverActive`) — Base UI parity
492
+ * (`disabled={!mounted || openReason === triggerHover}`); a hover-opened popover does not trap / mark.
493
+ * (The legacy only suppressed auto-focus while still trapping — that Radix divergence is dropped.)
494
+ * - Trap = `'trap-focus' || (modal === true && hasPopupClose())`; scroll lock + real outside `inert`
495
+ * isolation key off the full modal (`modal === true`).
496
+ * - No `disablePointerDismissal` — outside-press + focus-out always close.
497
+ *
498
+ * Note: a positioned popover does **not** auto-focus into the popup on open (pre-existing — the legacy
499
+ * behaved the same; verified). The trap holds focus once it is inside; portal tab-order handoff is owned
500
+ * by `RdxFloatingFocusManager` and anchored to the active trigger below.
388
501
  */
389
502
  class RdxPopoverPopup {
390
503
  constructor() {
391
504
  this.rootContext = injectRdxPopoverRootContext();
392
- this.dismissableLayer = inject(RdxDismissableLayer);
505
+ this.host = inject(ElementRef).nativeElement;
506
+ this.floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT);
507
+ this.registration = inject(RDX_FLOATING_REGISTRATION, { optional: true });
508
+ this.focusManager = inject(RdxFloatingFocusManager);
393
509
  this.focusScope = inject(RdxFocusScope);
394
510
  this.wrapper = inject(RdxPopperContentWrapper, { optional: true });
395
511
  this.align = computed(() => this.wrapper?.placedAlign(), ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
396
512
  this.side = computed(() => this.wrapper?.placedSide(), ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
397
- this.dismissDetails = {
398
- reason: 'none',
399
- event: new Event('popover.dismiss')
400
- };
401
- /**
402
- * Event handler called when the escape key is down. Can be prevented.
403
- */
404
- this.escapeKeyDown = outputFromObservable(outputToObservable(this.dismissableLayer.escapeKeyDown));
405
- /**
406
- * Event handler called when a pointerdown event happens outside of the popup. Can be prevented.
407
- */
408
- this.pointerDownOutside = outputFromObservable(outputToObservable(this.dismissableLayer.pointerDownOutside));
409
- /**
410
- * Event handler called when focus moves outside of the popup. Can be prevented.
411
- */
412
- this.focusOutside = outputFromObservable(outputToObservable(this.dismissableLayer.focusOutside));
413
- /**
414
- * Event handler called when an interaction happens outside of the popup. Can be prevented.
415
- */
416
- this.interactOutside = outputFromObservable(outputToObservable(this.dismissableLayer.interactOutside));
417
- /**
418
- * Event handler called before focus moves into the popup. Can be prevented.
419
- */
513
+ /** Event handler called when the escape key is down. Can be prevented. */
514
+ this.escapeKeyDown = output();
515
+ /** Event handler called when a pointerdown event happens outside of the popup. Can be prevented. */
516
+ this.pointerDownOutside = output();
517
+ /** Event handler called when focus moves outside of the popup. Can be prevented. */
518
+ this.focusOutside = output();
519
+ /** Event handler called when an interaction (pointer / focus) happens outside of the popup. */
520
+ this.interactOutside = output();
521
+ /** Event handler called before focus moves into the popup. Can be prevented. */
420
522
  this.openAutoFocus = outputFromObservable(outputToObservable(this.focusScope.mountAutoFocus));
421
- /**
422
- * Event handler called before focus returns after the popup is removed. Can be prevented.
423
- */
523
+ /** Event handler called before focus returns after the popup is removed. Can be prevented. */
424
524
  this.closeAutoFocus = outputFromObservable(outputToObservable(this.focusScope.unmountAutoFocus));
425
- useScrollLock(computed(() => this.rootContext.modal() === true));
426
- const unregisterTransitionElement = this.rootContext.registerTransitionElement(inject(ElementRef).nativeElement);
525
+ this.floatingContext.setFloatingElement(this.host);
526
+ // Background pointer/AT isolation for a full modal is the focus manager's `inert` pass (finding
527
+ // #4), not a global body lock; only the page scroll lock stays here. Activation policy (ADR 0016
528
+ // §2): lock only while a `modal === true` popover is OPEN and was **not** hover-opened, gated on
529
+ // `open` (not mounted) so it releases at close-start. For a **touch** open the anchored helper only
530
+ // locks when the popup is effectively viewport-width (a small popover stays swipe-to-dismissable on
531
+ // mobile, §3).
532
+ useAnchoredScrollLock(computed(() => this.rootContext.isOpen() && this.rootContext.modal() === true && !this.rootContext.isHoverActive()), {
533
+ touchOpen: () => this.rootContext.openedByTouch(),
534
+ element: () => this.host
535
+ });
536
+ const unregisterTransitionElement = this.rootContext.registerTransitionElement(this.host);
427
537
  inject(DestroyRef).onDestroy(unregisterTransitionElement);
428
- this.dismissableLayer.pointerDownOutside.subscribe((event) => {
429
- this.dismissDetails = { reason: 'outside-press', event };
430
- if (this.rootContext.triggers().some((trigger) => trigger.contains(event.target))) {
538
+ // A hover-opened popover must not steal focus — suppress the composed focus scope's auto-focus.
539
+ this.focusScope.mountAutoFocus.subscribe((event) => {
540
+ if (this.rootContext.isHoverActive()) {
431
541
  event.preventDefault();
432
542
  }
433
543
  });
434
- this.dismissableLayer.focusOutside.subscribe((event) => {
435
- this.dismissDetails = { reason: 'focus-out', event };
436
- if (this.rootContext.isPointerDownOnTrigger()) {
437
- event.preventDefault();
544
+ // Dismissal: Escape + outside-press always close (no pointer-dismissal opt-out). Focus-out is
545
+ // owned by the focus manager (below), so the capability's own focus-out is disabled.
546
+ new RdxDismiss(this.floatingContext, () => this.registration?.node() ?? null, {
547
+ escapeKey: () => true,
548
+ outsidePress: () => true,
549
+ focusOutside: () => false,
550
+ onEscapeKeyDown: (event) => this.escapeKeyDown.emit(event),
551
+ onPointerDownOutside: (event) => {
552
+ this.pointerDownOutside.emit(event);
553
+ this.interactOutside.emit(event);
554
+ },
555
+ onDismiss: (reason, event) => {
556
+ this.rootContext.close(reason === 'escape-key' ? 'escape-key' : 'outside-press', event);
438
557
  }
439
558
  });
440
- this.dismissableLayer.escapeKeyDown.subscribe((event) => {
441
- this.dismissDetails = { reason: 'escape-key', event };
442
- });
443
- this.focusScope.mountAutoFocus.subscribe((event) => {
444
- if (this.rootContext.isHoverActive()) {
445
- event.preventDefault();
559
+ // Focus-out close (ADR 0017 §3) — re-expose as `focusOutside` (preventable) and close unless vetoed.
560
+ this.focusManager.focusOut.subscribe((event) => {
561
+ this.focusOutside.emit(event);
562
+ this.interactOutside.emit(event);
563
+ if (!event.defaultPrevented) {
564
+ this.rootContext.close('focus-out', event);
446
565
  }
447
566
  });
448
- this.dismissableLayer.dismiss.subscribe(() => {
449
- this.rootContext.close(this.dismissDetails.reason, this.dismissDetails.event);
450
- this.dismissDetails = { reason: 'none', event: new Event('popover.dismiss') };
451
- });
452
567
  }
453
568
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
454
569
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverPopup, isStandalone: true, selector: "[rdxPopoverPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", openAutoFocus: "openAutoFocus", closeAutoFocus: "closeAutoFocus" }, host: { attributes: { "role": "dialog" }, listeners: { "pointerenter": "rootContext.cancelHoverClose()" }, properties: { "attr.aria-describedby": "rootContext.descriptionId()", "attr.aria-labelledby": "rootContext.titleId()", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-align": "align()", "attr.data-side": "side()", "id": "rootContext.contentId" } }, providers: [
455
- provideRdxDismissableLayerConfig(() => {
456
- const rootContext = injectRdxPopoverRootContext();
457
- return {
458
- disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
459
- };
460
- }),
461
- provideRdxFocusScopeConfig(() => {
570
+ provideFloatingFocusManagerConfig(() => {
462
571
  const rootContext = injectRdxPopoverRootContext();
463
572
  return {
464
- trapped: computed(() => rootContext.modal() === 'trap-focus' ||
465
- (rootContext.modal() === true && rootContext.hasPopupClose()))
573
+ modal: () => rootContext.modal() === 'trap-focus' ||
574
+ (rootContext.modal() === true && rootContext.hasPopupClose()),
575
+ // Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
576
+ inert: () => rootContext.modal() === true && rootContext.hasPopupClose(),
577
+ restoreFocus: () => 'popup',
578
+ previousFocusableElement: () => rootContext.trigger() ?? null,
579
+ beforeContentFocusGuardRef: () => (element) => rootContext.setBeforeContentFocusGuard(element),
580
+ // Active for the whole MOUNTED lifetime (Base UI `disabled={!mounted}`, not `open`) for
581
+ // trap/return-focus — including an explicit `preventUnmountOnClose()` cycle after the
582
+ // exit transition. Marker + isolation are additionally gated on `open` inside the
583
+ // manager. Still suppressed while hover-opened.
584
+ enabled: () => rootContext.present() && !rootContext.isHoverActive(),
585
+ openInteractionType: () => rootContext.openInteractionType(),
586
+ closeInteractionType: () => rootContext.closeInteractionType()
466
587
  };
467
588
  })
468
- ], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxDismissableLayer }, { directive: i3.RdxFocusScope }], ngImport: i0 }); }
589
+ ], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFloatingNodeRegistration }, { directive: i3.RdxFloatingFocusManager }], ngImport: i0 }); }
469
590
  }
470
591
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPopup, decorators: [{
471
592
  type: Directive,
472
593
  args: [{
473
594
  selector: '[rdxPopoverPopup]',
474
- hostDirectives: [RdxPopperContent, RdxDismissableLayer, RdxFocusScope],
595
+ hostDirectives: [RdxPopperContent, RdxFloatingNodeRegistration, RdxFloatingFocusManager],
475
596
  providers: [
476
- provideRdxDismissableLayerConfig(() => {
597
+ provideFloatingFocusManagerConfig(() => {
477
598
  const rootContext = injectRdxPopoverRootContext();
478
599
  return {
479
- disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
480
- };
481
- }),
482
- provideRdxFocusScopeConfig(() => {
483
- const rootContext = injectRdxPopoverRootContext();
484
- return {
485
- trapped: computed(() => rootContext.modal() === 'trap-focus' ||
486
- (rootContext.modal() === true && rootContext.hasPopupClose()))
600
+ modal: () => rootContext.modal() === 'trap-focus' ||
601
+ (rootContext.modal() === true && rootContext.hasPopupClose()),
602
+ // Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
603
+ inert: () => rootContext.modal() === true && rootContext.hasPopupClose(),
604
+ restoreFocus: () => 'popup',
605
+ previousFocusableElement: () => rootContext.trigger() ?? null,
606
+ beforeContentFocusGuardRef: () => (element) => rootContext.setBeforeContentFocusGuard(element),
607
+ // Active for the whole MOUNTED lifetime (Base UI `disabled={!mounted}`, not `open`) for
608
+ // trap/return-focus — including an explicit `preventUnmountOnClose()` cycle after the
609
+ // exit transition. Marker + isolation are additionally gated on `open` inside the
610
+ // manager. Still suppressed while hover-opened.
611
+ enabled: () => rootContext.present() && !rootContext.isHoverActive(),
612
+ openInteractionType: () => rootContext.openInteractionType(),
613
+ closeInteractionType: () => rootContext.closeInteractionType()
487
614
  };
488
615
  })
489
616
  ],
@@ -563,7 +690,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
563
690
  */
564
691
  class RdxPopoverPortal {
565
692
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
566
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverPortal, isStandalone: true, selector: "ng-template[rdxPopoverPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxPopoverRootContext().isOpen }))], exportAs: ["rdxPopoverPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
693
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverPortal, isStandalone: true, selector: "ng-template[rdxPopoverPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxPopoverRootContext().present }))], exportAs: ["rdxPopoverPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
567
694
  }
568
695
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPortal, decorators: [{
569
696
  type: Directive,
@@ -571,7 +698,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
571
698
  selector: 'ng-template[rdxPopoverPortal]',
572
699
  exportAs: 'rdxPopoverPortal',
573
700
  hostDirectives: [{ directive: RdxPortalPresence, inputs: ['container'] }],
574
- providers: [provideRdxPresenceContext(() => ({ present: injectRdxPopoverRootContext().isOpen }))]
701
+ providers: [provideRdxPresenceContext(() => ({ present: injectRdxPopoverRootContext().present }))]
575
702
  }]
576
703
  }] });
577
704
  /**
@@ -582,9 +709,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
582
709
  class RdxPopoverPortalMisuseGuard {
583
710
  constructor() {
584
711
  if (isDevMode()) {
585
- throw new Error('[rdxPopoverPortal] is now a structural directive. ' +
712
+ rdxDevError('popover/portal-on-element', '`rdxPopoverPortal` is now a structural directive. ' +
586
713
  'Use `*rdxPopoverPortal` on the positioner element or `<ng-template rdxPopoverPortal>`. ' +
587
- 'rdxPopoverPortalPresence has been removed. See https://radix-ng.com/components/popover.md');
714
+ 'rdxPopoverPortalPresence has been removed.', 'components/popover');
588
715
  }
589
716
  }
590
717
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPortalMisuseGuard, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -599,132 +726,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
599
726
 
600
727
  /**
601
728
  * Positions the popover against its trigger.
729
+ *
730
+ * A "thin" positioner (ADR 0012): it inherits the popper positioning surface (inputs, `placed`
731
+ * output, unified vars + placement attrs) from {@link RdxPopperContentWrapper} and adds popover's own
732
+ * concerns — Base UI-aligned defaults via the config provider, the open/closed/instant state
733
+ * attributes, the deprecated `--radix-popover-*` aliases, and the grace-area hover bridge.
602
734
  */
603
- class RdxPopoverPositioner {
735
+ class RdxPopoverPositioner extends RdxPopperContentWrapper {
604
736
  constructor() {
737
+ super();
605
738
  this.rootContext = injectRdxPopoverRootContext();
606
- this.wrapper = inject(RdxPopperContentWrapper);
607
- this.elementRef = inject(ElementRef);
739
+ this.legacyVars = legacyPopperVars('popover');
740
+ this.containerRef = inject(ElementRef);
608
741
  this.triggerEl = signal(null, ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
609
- this.containerEl = signal(this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "containerEl" }] : /* istanbul ignore next */ []));
742
+ this.containerEl = signal(this.containerRef.nativeElement, ...(ngDevMode ? [{ debugName: "containerEl" }] : /* istanbul ignore next */ []));
610
743
  this.graceArea = useGraceArea(this.triggerEl, this.containerEl);
611
- /**
612
- * An element to position the popup against. Defaults to the trigger.
613
- */
614
- this.anchor = input(...(ngDevMode ? [undefined, { debugName: "anchor" }] : /* istanbul ignore next */ []));
615
- /**
616
- * The preferred side of the trigger to render against when open.
617
- */
618
- this.side = input('bottom', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
619
- /**
620
- * Distance between the trigger and the popup in pixels.
621
- */
622
- this.sideOffset = input(0, { ...(ngDevMode ? { debugName: "sideOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
623
- /**
624
- * How to align the popup relative to the specified side.
625
- */
626
- this.align = input('center', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
627
- /**
628
- * An offset in pixels from the `start` or `end` alignment options.
629
- */
630
- this.alignOffset = input(0, { ...(ngDevMode ? { debugName: "alignOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
631
- /**
632
- * Minimum distance to maintain between the arrow and the edges of the popup.
633
- */
634
- this.arrowPadding = input(5, { ...(ngDevMode ? { debugName: "arrowPadding" } : /* istanbul ignore next */ {}), transform: numberAttribute });
635
- /**
636
- * Whether to override side and alignment preferences to prevent collisions.
637
- */
638
- this.avoidCollisions = input(true, { ...(ngDevMode ? { debugName: "avoidCollisions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
639
- /**
640
- * The element used as the collision boundary.
641
- */
642
- this.collisionBoundary = input(...(ngDevMode ? [undefined, { debugName: "collisionBoundary" }] : /* istanbul ignore next */ []));
643
- /**
644
- * Distance in pixels from the boundary edges where collision detection should occur.
645
- */
646
- this.collisionPadding = input(5, ...(ngDevMode ? [{ debugName: "collisionPadding" }] : /* istanbul ignore next */ []));
647
- /**
648
- * The sticky behavior on the alignment axis.
649
- */
650
- this.sticky = input('partial', ...(ngDevMode ? [{ debugName: "sticky" }] : /* istanbul ignore next */ []));
651
- /**
652
- * Whether to hide the popup when the trigger becomes fully occluded.
653
- */
654
- this.hideWhenDetached = input(false, { ...(ngDevMode ? { debugName: "hideWhenDetached" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
655
- /**
656
- * The CSS position strategy used by Floating UI.
657
- */
658
- this.positionStrategy = input('fixed', ...(ngDevMode ? [{ debugName: "positionStrategy" }] : /* istanbul ignore next */ []));
659
- /**
660
- * Whether to update position on every animation frame.
661
- */
662
- this.updatePositionStrategy = input('always', ...(ngDevMode ? [{ debugName: "updatePositionStrategy" }] : /* istanbul ignore next */ []));
663
- /**
664
- * Emits when the popup has been placed.
665
- */
666
- this.placed = outputFromObservable(outputToObservable(inject(RdxPopperContentWrapper).placed));
667
744
  effect(() => this.triggerEl.set(this.rootContext.trigger() ?? null));
668
745
  this.graceArea.onPointerExit(() => {
669
746
  this.rootContext.closeOnHover();
670
747
  });
671
748
  }
672
749
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPositioner, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
673
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverPositioner, isStandalone: true, selector: "[rdxPopoverPositioner]", inputs: { anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, 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 }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionBoundary: { classPropertyName: "collisionBoundary", publicName: "collisionBoundary", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, positionStrategy: { classPropertyName: "positionStrategy", publicName: "positionStrategy", isSignal: true, isRequired: false, transformFunction: null }, updatePositionStrategy: { classPropertyName: "updatePositionStrategy", publicName: "updatePositionStrategy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { placed: "placed" }, host: { properties: { "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-anchor-hidden": "wrapper.anchorHidden() ? \"\" : undefined", "attr.data-align": "wrapper.placedAlign()", "attr.data-side": "wrapper.placedSide()", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "style": "{\n '--anchor-width': 'var(--radix-popper-anchor-width)',\n '--anchor-height': 'var(--radix-popper-anchor-height)',\n '--available-width': 'var(--radix-popper-available-width)',\n '--available-height': 'var(--radix-popper-available-height)',\n '--positioner-width': 'var(--radix-popper-content-wrapper-width)',\n '--positioner-height': 'var(--radix-popper-content-wrapper-height)',\n '--transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-popover-content-transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-popover-content-available-width': 'var(--radix-popper-available-width)',\n '--radix-popover-content-available-height': 'var(--radix-popper-available-height)',\n '--radix-popover-trigger-width': 'var(--radix-popper-anchor-width)',\n '--radix-popover-trigger-height': 'var(--radix-popper-anchor-height)'\n }" } }, providers: [
750
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverPositioner, isStandalone: true, selector: "[rdxPopoverPositioner]", host: { properties: { "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "style": "legacyVars" } }, providers: [
751
+ ...provideRdxPopperContentWrapper(RdxPopoverPositioner),
674
752
  provideRdxPopperContentConfig({ arrowPadding: 5, collisionPadding: 5, updatePositionStrategy: 'always' })
675
- ], hostDirectives: [{ directive: i1.RdxPopperContentWrapper, inputs: ["anchor", "anchor", "side", "side", "sideOffset", "sideOffset", "align", "align", "alignOffset", "alignOffset", "arrowPadding", "arrowPadding", "avoidCollisions", "avoidCollisions", "collisionBoundary", "collisionBoundary", "collisionPadding", "collisionPadding", "sticky", "sticky", "hideWhenDetached", "hideWhenDetached", "positionStrategy", "positionStrategy", "updatePositionStrategy", "updatePositionStrategy"] }], ngImport: i0 }); }
753
+ ], usesInheritance: true, ngImport: i0 }); }
676
754
  }
677
755
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPositioner, decorators: [{
678
756
  type: Directive,
679
757
  args: [{
680
758
  selector: '[rdxPopoverPositioner]',
681
759
  providers: [
760
+ ...provideRdxPopperContentWrapper(RdxPopoverPositioner),
682
761
  provideRdxPopperContentConfig({ arrowPadding: 5, collisionPadding: 5, updatePositionStrategy: 'always' })
683
762
  ],
684
- hostDirectives: [
685
- {
686
- directive: RdxPopperContentWrapper,
687
- inputs: [
688
- 'anchor',
689
- 'side',
690
- 'sideOffset',
691
- 'align',
692
- 'alignOffset',
693
- 'arrowPadding',
694
- 'avoidCollisions',
695
- 'collisionBoundary',
696
- 'collisionPadding',
697
- 'sticky',
698
- 'hideWhenDetached',
699
- 'positionStrategy',
700
- 'updatePositionStrategy'
701
- ]
702
- }
703
- ],
704
763
  host: {
705
764
  '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
706
765
  '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
707
- '[attr.data-anchor-hidden]': 'wrapper.anchorHidden() ? "" : undefined',
708
- '[attr.data-align]': 'wrapper.placedAlign()',
709
- '[attr.data-side]': 'wrapper.placedSide()',
710
766
  '[attr.data-instant]': 'rootContext.instant() ? "" : undefined',
711
- '[style]': `{
712
- '--anchor-width': 'var(--radix-popper-anchor-width)',
713
- '--anchor-height': 'var(--radix-popper-anchor-height)',
714
- '--available-width': 'var(--radix-popper-available-width)',
715
- '--available-height': 'var(--radix-popper-available-height)',
716
- '--positioner-width': 'var(--radix-popper-content-wrapper-width)',
717
- '--positioner-height': 'var(--radix-popper-content-wrapper-height)',
718
- '--transform-origin': 'var(--radix-popper-transform-origin)',
719
- '--radix-popover-content-transform-origin': 'var(--radix-popper-transform-origin)',
720
- '--radix-popover-content-available-width': 'var(--radix-popper-available-width)',
721
- '--radix-popover-content-available-height': 'var(--radix-popper-available-height)',
722
- '--radix-popover-trigger-width': 'var(--radix-popper-anchor-width)',
723
- '--radix-popover-trigger-height': 'var(--radix-popper-anchor-height)'
724
- }`
767
+ // `data-side`/`data-align`/`data-anchor-hidden` and the unified `--anchor-*`/`--available-*`/
768
+ // `--transform-origin` vars come from the inherited wrapper (ADR 0012); only the deprecated
769
+ // `--radix-popover-*` aliases remain, for one release of back-compat.
770
+ '[style]': 'legacyVars'
725
771
  }
726
772
  }]
727
- }], ctorParameters: () => [], propDecorators: { anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], alignOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignOffset", required: false }] }], arrowPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowPadding", required: false }] }], avoidCollisions: [{ type: i0.Input, args: [{ isSignal: true, alias: "avoidCollisions", required: false }] }], collisionBoundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionBoundary", required: false }] }], collisionPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionPadding", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], hideWhenDetached: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideWhenDetached", required: false }] }], positionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionStrategy", required: false }] }], updatePositionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "updatePositionStrategy", required: false }] }], placed: [{ type: i0.Output, args: ["placed"] }] } });
773
+ }], ctorParameters: () => [] });
728
774
 
729
775
  /**
730
776
  * An accessible title for the popover.
@@ -787,7 +833,14 @@ class RdxPopoverTrigger {
787
833
  this.triggerId = computed(() => this.id() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
788
834
  this.rootContext = computed(() => this.handle()?.context() ?? this.parentRootContext, ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
789
835
  this.isOpen = computed(() => this.rootContext()?.isOpen() === true && this.rootContext()?.trigger() === this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
790
- this.isPressed = computed(() => this.isOpen() && this.rootContext()?.openChangeReason() === 'trigger-press', ...(ngDevMode ? [{ debugName: "isPressed" }] : /* istanbul ignore next */ []));
836
+ this.triggerInteraction = createRdxTriggerInteraction({
837
+ trigger: () => this.elementRef.nativeElement,
838
+ activeTrigger: () => this.rootContext()?.trigger(),
839
+ open: () => this.rootContext()?.isOpen() ?? false,
840
+ disabled: () => this.disabled(),
841
+ contentId: () => this.rootContext()?.contentId
842
+ });
843
+ this.isPressed = computed(() => this.triggerInteraction.isActive() && this.rootContext()?.openChangeReason() === 'trigger-press', ...(ngDevMode ? [{ debugName: "isPressed" }] : /* istanbul ignore next */ []));
791
844
  this.generatedId = injectId('rdx-popover-trigger-');
792
845
  effect((onCleanup) => {
793
846
  const handle = this.handle();
@@ -798,11 +851,29 @@ class RdxPopoverTrigger {
798
851
  onCleanup(untracked(() => this.parentRootContext.registerTrigger(this.triggerId(), this.elementRef.nativeElement, () => this.payload())));
799
852
  }
800
853
  });
854
+ useTriggerFocusGuards({
855
+ trigger: () => this.elementRef.nativeElement,
856
+ close: (event) => this.rootContext()?.close('focus-out', event),
857
+ beforeContentFocusGuard: () => this.rootContext()?.beforeContentFocusGuard(),
858
+ contentId: () => this.rootContext()?.contentId,
859
+ enabled: () => this.triggerInteraction.isActive(),
860
+ popupElement: () => {
861
+ const contentId = this.rootContext()?.contentId;
862
+ return contentId
863
+ ? this.elementRef.nativeElement.ownerDocument.getElementById(contentId)
864
+ : null;
865
+ }
866
+ });
801
867
  }
802
868
  handleClick(event) {
803
869
  if (this.disabled()) {
804
870
  return;
805
871
  }
872
+ // Record whether this open is a touch tap (ADR 0016 §3). `detail === 0` is a keyboard-activated
873
+ // click (no preceding pointerdown), which must read non-touch regardless of the last pointer type.
874
+ const interactionType = this.triggerInteraction.clickInteractionType(event);
875
+ this.rootContext()?.setOpenedByTouch(interactionType === 'touch');
876
+ this.rootContext()?.setTriggerOpenInteractionType(interactionType);
806
877
  this.rootContext()?.setPointerDownOnTrigger(false);
807
878
  if (this.handle()) {
808
879
  this.handle().toggle(this.triggerId(), event);
@@ -825,14 +896,15 @@ class RdxPopoverTrigger {
825
896
  }
826
897
  this.rootContext()?.cancelHoverOpen();
827
898
  }
828
- handlePointerDown() {
899
+ handlePointerDown(event) {
900
+ this.triggerInteraction.recordPointerDown(event);
829
901
  this.rootContext()?.setPointerDownOnTrigger(true);
830
902
  }
831
903
  handlePointerUp() {
832
904
  this.rootContext()?.setPointerDownOnTrigger(false);
833
905
  }
834
906
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
835
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverTrigger, isStandalone: true, selector: "button[rdxPopoverTrigger]", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, openOnHover: { classPropertyName: "openOnHover", publicName: "openOnHover", 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 } }, host: { attributes: { "type": "button" }, listeners: { "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointerleave": "handlePointerLeave($event)", "pointerdown": "handlePointerDown()", "pointerup": "handlePointerUp()", "pointercancel": "handlePointerUp()" }, properties: { "attr.aria-controls": "rootContext()?.contentId", "attr.aria-expanded": "isOpen()", "attr.aria-haspopup": "\"dialog\"", "attr.data-state": "isOpen() ? \"open\" : \"closed\"", "attr.data-popup-open": "isOpen() ? \"\" : undefined", "attr.data-pressed": "isPressed() ? \"\" : undefined", "attr.disabled": "disabled() ? \"\" : undefined", "id": "triggerId()" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
907
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverTrigger, isStandalone: true, selector: "button[rdxPopoverTrigger]", 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, openOnHover: { classPropertyName: "openOnHover", publicName: "openOnHover", 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 } }, host: { attributes: { "type": "button" }, listeners: { "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointerleave": "handlePointerLeave($event)", "pointerdown": "handlePointerDown($event)", "pointerup": "handlePointerUp()", "pointercancel": "handlePointerUp()" }, properties: { "attr.aria-controls": "rootContext()?.contentId", "attr.aria-expanded": "triggerInteraction.ariaExpanded()", "attr.aria-haspopup": "\"dialog\"", "attr.data-state": "triggerInteraction.dataState()", "attr.data-popup-open": "triggerInteraction.dataPopupOpen()", "attr.data-pressed": "isPressed() ? \"\" : undefined", "attr.disabled": "triggerInteraction.disabled() ? \"\" : undefined", "id": "triggerId()" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
836
908
  }
837
909
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTrigger, decorators: [{
838
910
  type: Directive,
@@ -842,17 +914,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
842
914
  host: {
843
915
  type: 'button',
844
916
  '[attr.aria-controls]': 'rootContext()?.contentId',
845
- '[attr.aria-expanded]': 'isOpen()',
917
+ '[attr.aria-expanded]': 'triggerInteraction.ariaExpanded()',
846
918
  '[attr.aria-haspopup]': '"dialog"',
847
- '[attr.data-state]': 'isOpen() ? "open" : "closed"',
848
- '[attr.data-popup-open]': 'isOpen() ? "" : undefined',
919
+ '[attr.data-state]': 'triggerInteraction.dataState()',
920
+ '[attr.data-popup-open]': 'triggerInteraction.dataPopupOpen()',
849
921
  '[attr.data-pressed]': 'isPressed() ? "" : undefined',
850
- '[attr.disabled]': 'disabled() ? "" : undefined',
922
+ '[attr.disabled]': 'triggerInteraction.disabled() ? "" : undefined',
851
923
  '[id]': 'triggerId()',
852
924
  '(click)': 'handleClick($event)',
853
925
  '(pointerenter)': 'handlePointerEnter($event)',
854
926
  '(pointerleave)': 'handlePointerLeave($event)',
855
- '(pointerdown)': 'handlePointerDown()',
927
+ '(pointerdown)': 'handlePointerDown($event)',
856
928
  '(pointerup)': 'handlePointerUp()',
857
929
  '(pointercancel)': 'handlePointerUp()'
858
930
  }