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

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 (97) 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-combobox.mjs +1305 -572
  11. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
  12. package/fesm2022/radix-ng-primitives-config.mjs +13 -4
  13. package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
  14. package/fesm2022/radix-ng-primitives-context-menu.mjs +51 -10
  15. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  16. package/fesm2022/radix-ng-primitives-core.mjs +1345 -64
  17. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  18. package/fesm2022/radix-ng-primitives-date-field.mjs +5 -3
  19. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  20. package/fesm2022/radix-ng-primitives-dialog.mjs +240 -112
  21. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  22. package/fesm2022/radix-ng-primitives-direction-provider.mjs +70 -0
  23. package/fesm2022/radix-ng-primitives-direction-provider.mjs.map +1 -0
  24. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +519 -184
  25. package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
  26. package/fesm2022/radix-ng-primitives-drawer.mjs +3 -3
  27. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  28. package/fesm2022/radix-ng-primitives-field.mjs +3 -2
  29. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  30. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +517 -0
  31. package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -0
  32. package/fesm2022/radix-ng-primitives-focus-scope.mjs +296 -70
  33. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  34. package/fesm2022/radix-ng-primitives-menu.mjs +861 -286
  35. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  36. package/fesm2022/radix-ng-primitives-menubar.mjs +32 -4
  37. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  38. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +144 -159
  39. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  40. package/fesm2022/radix-ng-primitives-popover.mjs +220 -205
  41. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  42. package/fesm2022/radix-ng-primitives-popper.mjs +94 -51
  43. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  44. package/fesm2022/radix-ng-primitives-presence.mjs +1 -1
  45. package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
  46. package/fesm2022/radix-ng-primitives-preview-card.mjs +141 -173
  47. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
  48. package/fesm2022/radix-ng-primitives-roving-focus.mjs +4 -2
  49. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  50. package/fesm2022/radix-ng-primitives-scroll-area.mjs +5 -4
  51. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  52. package/fesm2022/radix-ng-primitives-select.mjs +211 -156
  53. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  54. package/fesm2022/radix-ng-primitives-slider.mjs +5 -3
  55. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  56. package/fesm2022/radix-ng-primitives-stepper.mjs +5 -3
  57. package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
  58. package/fesm2022/radix-ng-primitives-time-field.mjs +5 -3
  59. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  60. package/fesm2022/radix-ng-primitives-toast.mjs +15 -36
  61. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
  62. package/fesm2022/radix-ng-primitives-toggle-group.mjs +5 -3
  63. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  64. package/fesm2022/radix-ng-primitives-toolbar.mjs +5 -3
  65. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  66. package/fesm2022/radix-ng-primitives-tooltip.mjs +73 -110
  67. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  68. package/package.json +10 -1
  69. package/types/radix-ng-primitives-accordion.d.ts +4 -3
  70. package/types/radix-ng-primitives-autocomplete.d.ts +217 -152
  71. package/types/radix-ng-primitives-calendar.d.ts +5 -3
  72. package/types/radix-ng-primitives-combobox.d.ts +672 -283
  73. package/types/radix-ng-primitives-config.d.ts +1 -1
  74. package/types/radix-ng-primitives-context-menu.d.ts +15 -5
  75. package/types/radix-ng-primitives-core.d.ts +762 -14
  76. package/types/radix-ng-primitives-date-field.d.ts +3 -2
  77. package/types/radix-ng-primitives-dialog.d.ts +77 -32
  78. package/types/radix-ng-primitives-direction-provider.d.ts +41 -0
  79. package/types/radix-ng-primitives-dismissable-layer.d.ts +147 -99
  80. package/types/radix-ng-primitives-field.d.ts +1 -0
  81. package/types/radix-ng-primitives-floating-focus-manager.d.ts +175 -0
  82. package/types/radix-ng-primitives-focus-scope.d.ts +132 -1
  83. package/types/radix-ng-primitives-menu.d.ts +186 -103
  84. package/types/radix-ng-primitives-navigation-menu.d.ts +37 -75
  85. package/types/radix-ng-primitives-popover.d.ts +59 -92
  86. package/types/radix-ng-primitives-popper.d.ts +39 -9
  87. package/types/radix-ng-primitives-preview-card.d.ts +39 -72
  88. package/types/radix-ng-primitives-roving-focus.d.ts +7 -6
  89. package/types/radix-ng-primitives-scroll-area.d.ts +2 -2
  90. package/types/radix-ng-primitives-select.d.ts +145 -108
  91. package/types/radix-ng-primitives-slider.d.ts +5 -4
  92. package/types/radix-ng-primitives-stepper.d.ts +4 -3
  93. package/types/radix-ng-primitives-time-field.d.ts +3 -2
  94. package/types/radix-ng-primitives-toast.d.ts +7 -7
  95. package/types/radix-ng-primitives-toggle-group.d.ts +5 -4
  96. package/types/radix-ng-primitives-toolbar.d.ts +3 -2
  97. package/types/radix-ng-primitives-tooltip.d.ts +24 -67
@@ -1,11 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, booleanAttribute, inject, DestroyRef, model, input, output, signal, computed, effect, untracked, Directive, ElementRef, isDevMode, NgModule } from '@angular/core';
3
- import { createContext, useTransitionStatus, injectId, useScrollLock } from '@radix-ng/primitives/core';
2
+ import { InjectionToken, booleanAttribute, inject, DestroyRef, model, input, output, signal, computed, ElementRef, effect, untracked, Directive, Injector, afterNextRender, isDevMode, NgModule } from '@angular/core';
3
+ import * as i1 from '@radix-ng/primitives/core';
4
+ import { createContext, useTransitionStatus, injectId, createFloatingRootContext, createCancelableChangeEventDetails, provideFloatingTree, provideFloatingRootContext, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useScrollLock, setupInternalBackdrop, RdxFloatingNodeRegistration, rdxDevError } from '@radix-ng/primitives/core';
4
5
  import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
5
- import * as i1 from '@radix-ng/primitives/dismissable-layer';
6
- import { RdxDismissableLayer, provideRdxDismissableLayerConfig } from '@radix-ng/primitives/dismissable-layer';
7
- import * as i2 from '@radix-ng/primitives/focus-scope';
8
- import { RdxFocusScope, provideRdxFocusScopeConfig } from '@radix-ng/primitives/focus-scope';
6
+ import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
7
+ import * as i2 from '@radix-ng/primitives/floating-focus-manager';
8
+ import { RdxFloatingFocusManager, provideFloatingFocusManagerConfig } from '@radix-ng/primitives/floating-focus-manager';
9
+ import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
9
10
  import * as i1$1 from '@radix-ng/primitives/portal';
10
11
  import { RdxPortalPresence } from '@radix-ng/primitives/portal';
11
12
  import { provideRdxPresenceContext } from '@radix-ng/primitives/presence';
@@ -85,6 +86,8 @@ class RdxDialogRoot {
85
86
  this.triggers = signal([], ...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
86
87
  this.payload = signal(undefined, ...(ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []));
87
88
  this.nestedOpenCount = signal(0, ...(ngDevMode ? [{ debugName: "nestedOpenCount" }] : /* istanbul ignore next */ []));
89
+ this.preventUnmountOnClose = signal(false, ...(ngDevMode ? [{ debugName: "preventUnmountOnClose" }] : /* istanbul ignore next */ []));
90
+ this.present = computed(() => this.open() || this.preventUnmountOnClose(), ...(ngDevMode ? [{ debugName: "present" }] : /* istanbul ignore next */ []));
88
91
  /** Whether this dialog is rendered inside another dialog. Fixed at construction. */
89
92
  this.nested = !!this.parentRoot;
90
93
  this.nestedDialogOpen = computed(() => this.nestedOpenCount() > 0, ...(ngDevMode ? [{ debugName: "nestedDialogOpen" }] : /* istanbul ignore next */ []));
@@ -94,6 +97,22 @@ class RdxDialogRoot {
94
97
  this.effectiveModal = computed(() => (this.variant.forceModal ? true : this.modal()), ...(ngDevMode ? [{ debugName: "effectiveModal" }] : /* istanbul ignore next */ []));
95
98
  /** Effective dismissal flag: disabled when the input asks, or when the variant forces it (alerts). */
96
99
  this.effectiveDisablePointerDismissal = computed(() => this.disablePointerDismissal() || this.variant.forcePointerDismissalDisabled, ...(ngDevMode ? [{ debugName: "effectiveDisablePointerDismissal" }] : /* istanbul ignore next */ []));
100
+ /**
101
+ * The shared per-popup floating context (ADR 0015 §1) — `open` mirrors the dialog's open state, the
102
+ * trigger registry is bridged from {@link registerTrigger}, and the reference / floating elements are
103
+ * set by the trigger / popup. The new dismissal + focus engines read this once the popup migrates.
104
+ */
105
+ this.floatingContext = createFloatingRootContext({
106
+ ownerDocument: inject(ElementRef).nativeElement.ownerDocument,
107
+ open: () => this.open()
108
+ });
109
+ // Keep the floating context's reference element in sync with the active trigger.
110
+ effect(() => this.floatingContext.setReferenceElement(this.trigger() ?? null));
111
+ effect(() => {
112
+ if (this.open() && this.preventUnmountOnClose()) {
113
+ this.preventUnmountOnClose.set(false);
114
+ }
115
+ });
97
116
  let previousOpen = this.open();
98
117
  effect(() => {
99
118
  const defaultOpen = this.defaultOpen();
@@ -135,29 +154,51 @@ class RdxDialogRoot {
135
154
  });
136
155
  }
137
156
  show(trigger = this.trigger(), payload, triggerId, reason = 'none', event = new Event('dialog.open-change')) {
157
+ const shouldAdoptPayload = trigger !== undefined || payload !== undefined;
158
+ if (this.open()) {
159
+ if (trigger) {
160
+ this.trigger.set(trigger);
161
+ }
162
+ if (triggerId !== undefined) {
163
+ this.triggerId.set(triggerId);
164
+ }
165
+ // Only adopt the payload when a trigger context is actually provided, so a bare
166
+ // imperative re-show on an already-open dialog doesn't clobber the live payload.
167
+ if (shouldAdoptPayload) {
168
+ this.payload.set(payload);
169
+ }
170
+ return;
171
+ }
172
+ const change = this.createOpenChangeEvent(true, reason, event, trigger, triggerId ?? this.triggerId());
173
+ this.onOpenChange.emit(change.payload);
174
+ if (change.eventDetails.isCanceled()) {
175
+ return;
176
+ }
138
177
  if (trigger) {
139
178
  this.trigger.set(trigger);
140
179
  }
141
180
  if (triggerId !== undefined) {
142
181
  this.triggerId.set(triggerId);
143
182
  }
144
- // Only adopt the payload when a trigger context is actually provided, so a bare
145
- // imperative re-show on an already-open dialog doesn't clobber the live payload.
146
- if (trigger !== undefined || payload !== undefined) {
183
+ if (shouldAdoptPayload) {
147
184
  this.payload.set(payload);
148
185
  }
149
- if (this.open()) {
150
- return;
151
- }
186
+ this.preventUnmountOnClose.set(false);
152
187
  this.open.set(true);
153
- this.emitOpenChange(true, reason, event);
188
+ this.floatingContext.events.emit('openchange', { open: true, reason, event: change.eventDetails.event });
154
189
  }
155
190
  close(reason = 'none', event = new Event('dialog.open-change')) {
156
191
  if (!this.open()) {
157
192
  return;
158
193
  }
194
+ const change = this.createOpenChangeEvent(false, reason, event, this.trigger(), this.triggerId());
195
+ this.onOpenChange.emit(change.payload);
196
+ if (change.eventDetails.isCanceled()) {
197
+ return;
198
+ }
199
+ this.preventUnmountOnClose.set(change.shouldPreventUnmountOnClose());
159
200
  this.open.set(false);
160
- this.emitOpenChange(false, reason, event);
201
+ this.floatingContext.events.emit('openchange', { open: false, reason, event: change.eventDetails.event });
161
202
  }
162
203
  toggle(triggerId, trigger, payload, event = new Event('dialog.open-change')) {
163
204
  if (this.open() && this.trigger() === trigger) {
@@ -169,6 +210,9 @@ class RdxDialogRoot {
169
210
  registerTrigger(id, trigger, payload) {
170
211
  this.registeredTriggers.set(id, { element: trigger, payload });
171
212
  this.triggers.update((triggers) => (triggers.includes(trigger) ? triggers : [...triggers, trigger]));
213
+ // Bridge into the floating context's trigger registry — the new dismissal/focus engines read it
214
+ // for inside-element checks (a press/focus on the trigger counts as inside, ADR 0015 §2).
215
+ this.floatingContext.triggers.add(trigger);
172
216
  if (this.triggerId() === id || (!this.trigger() && this.triggerId() === null)) {
173
217
  this.trigger.set(trigger);
174
218
  this.payload.set(payload());
@@ -178,6 +222,7 @@ class RdxDialogRoot {
178
222
  this.registeredTriggers.delete(id);
179
223
  }
180
224
  this.triggers.update((triggers) => triggers.filter((candidate) => candidate !== trigger));
225
+ this.floatingContext.triggers.delete(trigger);
181
226
  if (!this.destroyRef.destroyed && this.trigger() === trigger) {
182
227
  const next = this.registeredTriggers.entries().next().value;
183
228
  if (this.triggerId() !== null) {
@@ -208,14 +253,20 @@ class RdxDialogRoot {
208
253
  this.payload.set(trigger.payload());
209
254
  }
210
255
  }
211
- emitOpenChange(open, reason, event) {
212
- this.onOpenChange.emit({
213
- open,
214
- triggerId: this.triggerId(),
215
- trigger: this.trigger(),
216
- reason,
217
- event
218
- });
256
+ createOpenChangeEvent(open, reason, event, trigger, triggerId) {
257
+ const change = createCancelableChangeEventDetails(reason, event, trigger);
258
+ return {
259
+ eventDetails: change.eventDetails,
260
+ shouldPreventUnmountOnClose: change.shouldPreventUnmountOnClose,
261
+ payload: {
262
+ open,
263
+ triggerId,
264
+ trigger: change.eventDetails.trigger,
265
+ reason: change.eventDetails.reason,
266
+ event: change.eventDetails.event,
267
+ eventDetails: change.eventDetails
268
+ }
269
+ };
219
270
  }
220
271
  emitOpenChangeComplete(open) {
221
272
  if (!this.destroyRef.destroyed) {
@@ -223,14 +274,26 @@ class RdxDialogRoot {
223
274
  }
224
275
  }
225
276
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
226
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogRoot, isStandalone: true, selector: "[rdxDialogRoot]", 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 }, disablePointerDismissal: { classPropertyName: "disablePointerDismissal", publicName: "disablePointerDismissal", 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: [provideRdxDialogRootContext(context)], exportAs: ["rdxDialogRoot"], ngImport: i0 }); }
277
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogRoot, isStandalone: true, selector: "[rdxDialogRoot]", 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 }, disablePointerDismissal: { classPropertyName: "disablePointerDismissal", publicName: "disablePointerDismissal", 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: [
278
+ provideRdxDialogRootContext(context),
279
+ // New floating foundation (ADR 0015/0017 migration). Inherit-or-create tree so a nested dialog
280
+ // shares its parent's tree; the per-popup root context bridges open / triggers / reference.
281
+ provideFloatingTree(),
282
+ provideFloatingRootContext(() => inject(RdxDialogRoot).floatingContext)
283
+ ], exportAs: ["rdxDialogRoot"], ngImport: i0 }); }
227
284
  }
228
285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogRoot, decorators: [{
229
286
  type: Directive,
230
287
  args: [{
231
288
  selector: '[rdxDialogRoot]',
232
289
  exportAs: 'rdxDialogRoot',
233
- providers: [provideRdxDialogRootContext(context)]
290
+ providers: [
291
+ provideRdxDialogRootContext(context),
292
+ // New floating foundation (ADR 0015/0017 migration). Inherit-or-create tree so a nested dialog
293
+ // shares its parent's tree; the per-popup root context bridges open / triggers / reference.
294
+ provideFloatingTree(),
295
+ provideFloatingRootContext(() => inject(RdxDialogRoot).floatingContext)
296
+ ]
234
297
  }]
235
298
  }], 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 }] }], disablePointerDismissal: [{ type: i0.Input, args: [{ isSignal: true, alias: "disablePointerDismissal", 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"] }] } });
236
299
  function contextFor(root) {
@@ -239,6 +302,7 @@ function contextFor(root) {
239
302
  titleId: root.titleId.asReadonly(),
240
303
  descriptionId: root.descriptionId.asReadonly(),
241
304
  isOpen: root.open,
305
+ present: root.present,
242
306
  modal: root.effectiveModal,
243
307
  disablePointerDismissal: root.effectiveDisablePointerDismissal,
244
308
  role: root.role,
@@ -260,13 +324,27 @@ function contextFor(root) {
260
324
 
261
325
  /**
262
326
  * An overlay displayed beneath the dialog popup.
327
+ *
328
+ * Decorative-only, so it carries `role="presentation"` (Base UI `DialogBackdrop`). By default a **nested**
329
+ * dialog renders no backdrop — the parent's already dims the page; stacking a second one double-darkens
330
+ * and intercepts the parent's outside-press. Set `forceRender` to opt back in.
263
331
  */
264
332
  class RdxDialogBackdrop {
265
333
  constructor() {
266
334
  this.rootContext = injectRdxDialogRootContext();
335
+ /** Render the backdrop even for a nested dialog (off by default, matching Base UI). */
336
+ this.forceRender = input(false, { ...(ngDevMode ? { debugName: "forceRender" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
337
+ // The backdrop is a second portal root (a body sibling of the popup). It is registered as owned DOM
338
+ // footprint for primitive-specific checks, but it is not a marker/aria keep-set member.
339
+ const floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT, { optional: true });
340
+ if (floatingContext) {
341
+ const host = inject(ElementRef).nativeElement;
342
+ floatingContext.addFloatingElement(host);
343
+ inject(DestroyRef).onDestroy(() => floatingContext.removeFloatingElement(host));
344
+ }
267
345
  }
268
346
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
269
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogBackdrop, isStandalone: true, selector: "[rdxDialogBackdrop]", host: { properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined" } }, exportAs: ["rdxDialogBackdrop"], ngImport: i0 }); }
347
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogBackdrop, isStandalone: true, selector: "[rdxDialogBackdrop]", inputs: { forceRender: { classPropertyName: "forceRender", publicName: "forceRender", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "presentation" }, properties: { "hidden": "rootContext.nested && !forceRender()", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined" } }, exportAs: ["rdxDialogBackdrop"], ngImport: i0 }); }
270
348
  }
271
349
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogBackdrop, decorators: [{
272
350
  type: Directive,
@@ -274,6 +352,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
274
352
  selector: '[rdxDialogBackdrop]',
275
353
  exportAs: 'rdxDialogBackdrop',
276
354
  host: {
355
+ role: 'presentation',
356
+ '[hidden]': 'rootContext.nested && !forceRender()',
277
357
  '[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
278
358
  '[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
279
359
  '[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
@@ -283,7 +363,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
283
363
  '[attr.data-nested-dialog-open]': 'rootContext.nestedDialogOpen() ? "" : undefined'
284
364
  }
285
365
  }]
286
- }] });
366
+ }], ctorParameters: () => [], propDecorators: { forceRender: [{ type: i0.Input, args: [{ isSignal: true, alias: "forceRender", required: false }] }] } });
287
367
 
288
368
  /**
289
369
  * A button that closes the dialog.
@@ -331,117 +411,164 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
331
411
  }]
332
412
  }], ctorParameters: () => [] });
333
413
 
414
+ /** Composite navigation keys a Dialog popup keeps to itself, so they never reach an enclosing Menu / Composite. */
415
+ const COMPOSITE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End']);
416
+ const DIALOG_INTERNAL_BACKDROP_ATTR = 'data-rdx-dialog-internal-backdrop';
334
417
  /**
335
418
  * A container for the dialog contents.
419
+ *
420
+ * **ADR 0015/0017 Phase-4 migration — Dialog is the PILOT cutover onto the new floating dismissal +
421
+ * focus engine. Browser-verified** by `apps/visual-regression/tests/dialog.behavior.spec.ts` (trap,
422
+ * initial / return focus, Escape / outside-press / focus-out dismissal, nested-Escape deepest-first,
423
+ * backdrop-not-marked).
424
+ *
425
+ * **Mapping (legacy → new):**
426
+ * - `RdxDismissableLayer` (legacy) → `RdxFloatingNodeRegistration` (registers the tree node) +
427
+ * `RdxDismiss` (Escape / outside-press; reads the root context + node).
428
+ * - `RdxFocusScope` (direct) → `RdxFloatingFocusManager` (composes the reworked focus scope; trap +
429
+ * markOthers + close-on-focus-out), driven by `provideFloatingFocusManagerConfig`.
430
+ * - `disableOutsidePointerEvents` → the focus manager's `inert` pass marks outside elements
431
+ * non-interactive for a modal (finding #4), scoped to siblings of the popup's ancestor chain instead
432
+ * of a global `body { pointer-events: none }` lock — so the popup needs no `pointer-events: auto`.
433
+ * - focus-out close moved from the dismissal capability (`focusOutside: () => false`) to the manager
434
+ * (`manager.focusOut`), per ADR 0017 §3.
435
+ * - `isEventOnTrigger` preventDefault → removed: the trigger is in `context.triggers`, so the engine
436
+ * treats a press/focus on it as **inside** (no close-then-reopen).
437
+ *
438
+ * **Parity notes:**
439
+ * - **Lifecycle split (resolved 2026-06-16):** `enabled` is `open || transitionStatus === 'ending'`, so
440
+ * the trap / return-focus machinery survives the exit animation, while the manager's marker + isolation
441
+ * passes additionally key off `open` and release at close-start (Base UI `markOthers` gating).
442
+ * - **`trap-focus` split:** the manager traps focus for `modal === true` and `'trap-focus'`, but applies
443
+ * real `inert` isolation only for `modal === true`, matching Base UI's public contract that
444
+ * `modal="trap-focus"` leaves outside pointer interaction enabled.
445
+ * - **`returnFocus` orchestration (resolved 2026-06-16):** the manager now owns the return-focus *target*
446
+ * via the focus scope's `returnFocus` config seam (the scope owns the *timing* — its queued post-unmount
447
+ * frame). Dialog leaves it at the default (`returnFocus: true` → return to the element focused before
448
+ * open), so behavior is unchanged; a consumer can now also pass `false` / an element / a callback.
336
449
  */
337
450
  class RdxDialogPopup {
338
451
  constructor() {
339
452
  this.rootContext = injectRdxDialogRootContext();
340
- this.dismissableLayer = inject(RdxDismissableLayer);
453
+ this.host = inject(ElementRef).nativeElement;
454
+ this.floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT);
455
+ this.registration = inject(RDX_FLOATING_REGISTRATION, { optional: true });
456
+ this.focusManager = inject(RdxFloatingFocusManager);
341
457
  this.focusScope = inject(RdxFocusScope);
342
- this.dismissDetails = {
343
- reason: 'none',
344
- event: new Event('dialog.dismiss')
345
- };
346
- /**
347
- * Event handler called when the escape key is down. Can be prevented.
348
- */
349
- this.escapeKeyDown = outputFromObservable(outputToObservable(this.dismissableLayer.escapeKeyDown));
350
- /**
351
- * Event handler called when a pointerdown event happens outside of the popup. Can be prevented.
352
- */
353
- this.pointerDownOutside = outputFromObservable(outputToObservable(this.dismissableLayer.pointerDownOutside));
354
- /**
355
- * Event handler called when focus moves outside of the popup. Can be prevented.
356
- */
357
- this.focusOutside = outputFromObservable(outputToObservable(this.dismissableLayer.focusOutside));
358
- /**
359
- * Event handler called when an interaction happens outside of the popup. Can be prevented.
360
- */
361
- this.interactOutside = outputFromObservable(outputToObservable(this.dismissableLayer.interactOutside));
362
- /**
363
- * Event handler called before focus moves into the popup. Can be prevented.
364
- */
458
+ /** Event handler called when the escape key is down. Can be prevented. */
459
+ this.escapeKeyDown = output();
460
+ /** Event handler called when a pointerdown event happens outside of the popup. Can be prevented. */
461
+ this.pointerDownOutside = output();
462
+ /** Event handler called when focus moves outside of the popup. Can be prevented. */
463
+ this.focusOutside = output();
464
+ /** Event handler called when an interaction (pointer / focus) happens outside of the popup. */
465
+ this.interactOutside = output();
466
+ /** Event handler called before focus moves into the popup. Can be prevented. */
365
467
  this.openAutoFocus = outputFromObservable(outputToObservable(this.focusScope.mountAutoFocus));
366
- /**
367
- * Event handler called before focus returns after the popup is removed. Can be prevented.
368
- */
468
+ /** Event handler called before focus returns after the popup is removed. Can be prevented. */
369
469
  this.closeAutoFocus = outputFromObservable(outputToObservable(this.focusScope.unmountAutoFocus));
370
- // Lock for the popup's whole mounted lifetime, not just while `isOpen()`. The popup is kept
371
- // mounted by the portal-presence machine until the exit `@keyframes` finish, then destroyed
372
- // (firing `useScrollLock`'s `onDestroy` unlock). Gating on `isOpen()` would restore the page
373
- // scrollbar the instant the dialog starts closing, reflowing the page by the scrollbar width
374
- // mid-animation a visible judder. Holding the lock until unmount defers that to after the
375
- // animation, when the dialog is already gone.
376
- useScrollLock(computed(() => this.rootContext.modal() === true));
377
- const unregisterTransitionElement = this.rootContext.registerTransitionElement(inject(ElementRef).nativeElement);
470
+ // The popup element is this layer's floating element (inside-surface for containment checks).
471
+ this.floatingContext.setFloatingElement(this.host);
472
+ // Scroll lock follows Base UI (`open && modal === true`): released at close-start so the page is
473
+ // scrollable again as the exit animation plays. Background pointer/AT isolation is no longer a
474
+ // global body lock the focus manager applies real `inert` to outside elements (finding #4).
475
+ useScrollLock(computed(() => this.rootContext.modal() === true && this.rootContext.isOpen()), {
476
+ referenceElement: () => this.host
477
+ });
478
+ const unregisterTransitionElement = this.rootContext.registerTransitionElement(this.host);
378
479
  inject(DestroyRef).onDestroy(unregisterTransitionElement);
379
- this.dismissableLayer.pointerDownOutside.subscribe((event) => {
380
- this.dismissDetails = { reason: 'outside-press', event };
381
- // A pointerdown on the trigger is an "outside" press relative to the portaled popup.
382
- // Let the trigger's own click toggle the dialog instead of dismissing here (which would
383
- // close and then immediately reopen).
384
- if (this.isEventOnTrigger(event)) {
385
- event.preventDefault();
480
+ // Base UI always renders an internal backdrop for a fully modal dialog. It is invisible and exists
481
+ // even when consumers also render `rdxDialogBackdrop`: outside pointer events land on this owned
482
+ // target instead of being swallowed by inert page content.
483
+ const injector = inject(Injector);
484
+ afterNextRender(() => setupInternalBackdrop(this.host, injector, {
485
+ marker: DIALOG_INTERNAL_BACKDROP_ATTR,
486
+ isOpen: () => this.rootContext.isOpen(),
487
+ shouldRender: () => this.rootContext.modal() === true,
488
+ cutout: () => this.host.closest('[rdxDialogViewport]'),
489
+ passThrough: () => this.host.closest('[rdxDialogViewport]') !== null
490
+ }));
491
+ // Dismissal (Base UI Dialog outside-press policy): Escape always closes; an outside press closes
492
+ // only the **topmost** dialog (a parent with an open nested dialog never self-closes) and only when
493
+ // pointer dismissal is enabled. A fully modal dialog uses the internal backdrop and intentional
494
+ // outside-press timing (click, not pointerdown). Focus-out is owned by the focus manager (below).
495
+ new RdxDismiss(this.floatingContext, () => this.registration?.node() ?? null, {
496
+ escapeKey: () => true,
497
+ outsidePress: () => this.isTopmost() && !this.rootContext.disablePointerDismissal(),
498
+ outsidePressEvent: () => (this.rootContext.modal() === true ? 'intentional' : 'sloppy'),
499
+ focusOutside: () => false,
500
+ onEscapeKeyDown: (event) => this.escapeKeyDown.emit(event),
501
+ onPointerDownOutside: (event) => {
502
+ this.pointerDownOutside.emit(event);
503
+ this.interactOutside.emit(event);
504
+ },
505
+ onDismiss: (reason, event) => {
506
+ this.rootContext.close(reason === 'escape-key' ? 'escape-key' : 'outside-press', event);
386
507
  }
387
508
  });
388
- this.dismissableLayer.focusOutside.subscribe((event) => {
389
- this.dismissDetails = { reason: 'focus-out', event };
390
- if (this.isEventOnTrigger(event)) {
391
- event.preventDefault();
509
+ // Focus-out close (ADR 0017 §3) the manager emits when focus leaves a non-modal dialog to an
510
+ // unrelated node; re-expose as `focusOutside` (preventable) and close unless vetoed.
511
+ this.focusManager.focusOut.subscribe((event) => {
512
+ this.focusOutside.emit(event);
513
+ this.interactOutside.emit(event);
514
+ if (!event.defaultPrevented) {
515
+ this.rootContext.close('focus-out', event);
392
516
  }
393
517
  });
394
- this.dismissableLayer.escapeKeyDown.subscribe((event) => {
395
- this.dismissDetails = { reason: 'escape-key', event };
396
- });
397
- this.dismissableLayer.dismiss.subscribe(() => {
398
- const { reason, event } = this.dismissDetails;
399
- this.dismissDetails = { reason: 'none', event: new Event('dialog.dismiss') };
400
- // When pointer dismissal is disabled, keep the dialog open on outside interactions.
401
- // Escape always closes (standard a11y behavior).
402
- if ((reason === 'outside-press' || reason === 'focus-out') && this.rootContext.disablePointerDismissal()) {
403
- return;
404
- }
405
- this.rootContext.close(reason, event);
406
- });
407
518
  }
408
- isEventOnTrigger(event) {
409
- const target = event.target;
410
- return !!target && this.rootContext.triggers().some((trigger) => trigger.contains(target));
519
+ /** This dialog is the topmost (deepest open) one — it has no open nested dialog above it. */
520
+ isTopmost() {
521
+ return this.rootContext.isOpen() && !this.rootContext.nestedDialogOpen();
522
+ }
523
+ /**
524
+ * Composite navigation keys (arrows / Home / End) are kept inside the dialog (Base UI `DialogPopup`):
525
+ * a dialog opened from inside a Menu / Menubar / Composite must not let an arrow press bubble out and
526
+ * move the outer collection's active item.
527
+ */
528
+ onKeyDown(event) {
529
+ if (COMPOSITE_KEYS.has(event.key)) {
530
+ event.stopPropagation();
531
+ }
411
532
  }
412
533
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
413
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogPopup, isStandalone: true, selector: "[rdxDialogPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", openAutoFocus: "openAutoFocus", closeAutoFocus: "closeAutoFocus" }, host: { properties: { "attr.role": "rootContext.role", "attr.aria-modal": "rootContext.modal() === true ? \"true\" : undefined", "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-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined", "id": "rootContext.contentId" } }, providers: [
414
- provideRdxDismissableLayerConfig(() => {
534
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxDialogPopup, isStandalone: true, selector: "[rdxDialogPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", openAutoFocus: "openAutoFocus", closeAutoFocus: "closeAutoFocus" }, host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "attr.role": "rootContext.role", "attr.aria-modal": "rootContext.modal() === true ? \"true\" : undefined", "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-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-nested": "rootContext.nested ? \"\" : undefined", "attr.data-nested-dialog-open": "rootContext.nestedDialogOpen() ? \"\" : undefined", "id": "rootContext.contentId" } }, providers: [
535
+ provideFloatingFocusManagerConfig(() => {
415
536
  const rootContext = injectRdxDialogRootContext();
416
537
  return {
417
- disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
418
- };
419
- }),
420
- provideRdxFocusScopeConfig(() => {
421
- const rootContext = injectRdxDialogRootContext();
422
- return {
423
- trapped: computed(() => rootContext.modal() === 'trap-focus' || rootContext.modal() === true)
538
+ // Trap for a modal or trap-focus dialog (Base UI `modal={modal !== false}`).
539
+ modal: () => rootContext.modal() === true || rootContext.modal() === 'trap-focus',
540
+ // Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
541
+ inert: () => rootContext.modal() === true,
542
+ // Active for the whole MOUNTED lifetime — including an explicit
543
+ // `preventUnmountOnClose()` cycle after the exit transition — matching Base UI's
544
+ // `FloatingFocusManager disabled={!mounted}` (NOT `open`) for trap/return-focus.
545
+ // Marker + isolation are additionally gated on `open` inside the manager.
546
+ enabled: () => rootContext.present(),
547
+ closeOnFocusOut: () => !rootContext.disablePointerDismissal()
424
548
  };
425
549
  })
426
- ], exportAs: ["rdxDialogPopup"], hostDirectives: [{ directive: i1.RdxDismissableLayer }, { directive: i2.RdxFocusScope }], ngImport: i0 }); }
550
+ ], exportAs: ["rdxDialogPopup"], hostDirectives: [{ directive: i1.RdxFloatingNodeRegistration }, { directive: i2.RdxFloatingFocusManager }], ngImport: i0 }); }
427
551
  }
428
552
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPopup, decorators: [{
429
553
  type: Directive,
430
554
  args: [{
431
555
  selector: '[rdxDialogPopup]',
432
556
  exportAs: 'rdxDialogPopup',
433
- hostDirectives: [RdxDismissableLayer, RdxFocusScope],
557
+ hostDirectives: [RdxFloatingNodeRegistration, RdxFloatingFocusManager],
434
558
  providers: [
435
- provideRdxDismissableLayerConfig(() => {
436
- const rootContext = injectRdxDialogRootContext();
437
- return {
438
- disableOutsidePointerEvents: computed(() => rootContext.modal() === true)
439
- };
440
- }),
441
- provideRdxFocusScopeConfig(() => {
559
+ provideFloatingFocusManagerConfig(() => {
442
560
  const rootContext = injectRdxDialogRootContext();
443
561
  return {
444
- trapped: computed(() => rootContext.modal() === 'trap-focus' || rootContext.modal() === true)
562
+ // Trap for a modal or trap-focus dialog (Base UI `modal={modal !== false}`).
563
+ modal: () => rootContext.modal() === true || rootContext.modal() === 'trap-focus',
564
+ // Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
565
+ inert: () => rootContext.modal() === true,
566
+ // Active for the whole MOUNTED lifetime — including an explicit
567
+ // `preventUnmountOnClose()` cycle after the exit transition — matching Base UI's
568
+ // `FloatingFocusManager disabled={!mounted}` (NOT `open`) for trap/return-focus.
569
+ // Marker + isolation are additionally gated on `open` inside the manager.
570
+ enabled: () => rootContext.present(),
571
+ closeOnFocusOut: () => !rootContext.disablePointerDismissal()
445
572
  };
446
573
  })
447
574
  ],
@@ -457,7 +584,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
457
584
  '[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
458
585
  '[attr.data-nested]': 'rootContext.nested ? "" : undefined',
459
586
  '[attr.data-nested-dialog-open]': 'rootContext.nestedDialogOpen() ? "" : undefined',
460
- '[id]': 'rootContext.contentId'
587
+ '[id]': 'rootContext.contentId',
588
+ '(keydown)': 'onKeyDown($event)'
461
589
  }
462
590
  }]
463
591
  }], ctorParameters: () => [], propDecorators: { escapeKeyDown: [{ type: i0.Output, args: ["escapeKeyDown"] }], pointerDownOutside: [{ type: i0.Output, args: ["pointerDownOutside"] }], focusOutside: [{ type: i0.Output, args: ["focusOutside"] }], interactOutside: [{ type: i0.Output, args: ["interactOutside"] }], openAutoFocus: [{ type: i0.Output, args: ["openAutoFocus"] }], closeAutoFocus: [{ type: i0.Output, args: ["closeAutoFocus"] }] } });
@@ -480,7 +608,7 @@ class RdxDialogPortal {
480
608
  this.container = input(...(ngDevMode ? [undefined, { debugName: "container" }] : /* istanbul ignore next */ []));
481
609
  }
482
610
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
483
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogPortal, isStandalone: true, selector: "ng-template[rdxDialogPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideRdxPresenceContext(() => ({ present: injectRdxDialogRootContext().isOpen }))], exportAs: ["rdxDialogPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
611
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxDialogPortal, isStandalone: true, selector: "ng-template[rdxDialogPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideRdxPresenceContext(() => ({ present: injectRdxDialogRootContext().present }))], exportAs: ["rdxDialogPortal"], hostDirectives: [{ directive: i1$1.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
484
612
  }
485
613
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortal, decorators: [{
486
614
  type: Directive,
@@ -488,7 +616,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
488
616
  selector: 'ng-template[rdxDialogPortal]',
489
617
  exportAs: 'rdxDialogPortal',
490
618
  hostDirectives: [{ directive: RdxPortalPresence, inputs: ['container'] }],
491
- providers: [provideRdxPresenceContext(() => ({ present: injectRdxDialogRootContext().isOpen }))]
619
+ providers: [provideRdxPresenceContext(() => ({ present: injectRdxDialogRootContext().present }))]
492
620
  }]
493
621
  }], propDecorators: { container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }] } });
494
622
  /**
@@ -499,9 +627,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
499
627
  class RdxDialogPortalMisuseGuard {
500
628
  constructor() {
501
629
  if (isDevMode()) {
502
- throw new Error('[rdxDialogPortal] is now a structural directive. ' +
630
+ rdxDevError('dialog/portal-on-element', '`rdxDialogPortal` is now a structural directive. ' +
503
631
  'Use `<ng-template rdxDialogPortal>` around the backdrop and popup. ' +
504
- 'rdxDialogPortalPresence has been removed. See https://radix-ng.com/components/dialog.md');
632
+ 'rdxDialogPortalPresence has been removed.', 'components/dialog');
505
633
  }
506
634
  }
507
635
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxDialogPortalMisuseGuard, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }