@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.
- package/README.md +1 -1
- package/fesm2022/radix-ng-primitives-accordion.mjs +5 -3
- package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs +3 -2
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-autocomplete.mjs +617 -659
- package/fesm2022/radix-ng-primitives-autocomplete.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-calendar.mjs +5 -3
- package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-combobox.mjs +1305 -572
- package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-config.mjs +13 -4
- package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-context-menu.mjs +51 -10
- package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-core.mjs +1345 -64
- package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-date-field.mjs +5 -3
- package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-dialog.mjs +240 -112
- package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-direction-provider.mjs +70 -0
- package/fesm2022/radix-ng-primitives-direction-provider.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +519 -184
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-drawer.mjs +3 -3
- package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-field.mjs +3 -2
- package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +517 -0
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-focus-scope.mjs +296 -70
- package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menu.mjs +861 -286
- package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menubar.mjs +32 -4
- package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs +144 -159
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popover.mjs +220 -205
- package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popper.mjs +94 -51
- package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-presence.mjs +1 -1
- package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-preview-card.mjs +141 -173
- package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +4 -2
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-scroll-area.mjs +5 -4
- package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-select.mjs +211 -156
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +5 -3
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-stepper.mjs +5 -3
- package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-time-field.mjs +5 -3
- package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toast.mjs +15 -36
- package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +5 -3
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toolbar.mjs +5 -3
- package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tooltip.mjs +73 -110
- package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
- package/package.json +10 -1
- package/types/radix-ng-primitives-accordion.d.ts +4 -3
- package/types/radix-ng-primitives-autocomplete.d.ts +217 -152
- package/types/radix-ng-primitives-calendar.d.ts +5 -3
- package/types/radix-ng-primitives-combobox.d.ts +672 -283
- package/types/radix-ng-primitives-config.d.ts +1 -1
- package/types/radix-ng-primitives-context-menu.d.ts +15 -5
- package/types/radix-ng-primitives-core.d.ts +762 -14
- package/types/radix-ng-primitives-date-field.d.ts +3 -2
- package/types/radix-ng-primitives-dialog.d.ts +77 -32
- package/types/radix-ng-primitives-direction-provider.d.ts +41 -0
- package/types/radix-ng-primitives-dismissable-layer.d.ts +147 -99
- package/types/radix-ng-primitives-field.d.ts +1 -0
- package/types/radix-ng-primitives-floating-focus-manager.d.ts +175 -0
- package/types/radix-ng-primitives-focus-scope.d.ts +132 -1
- package/types/radix-ng-primitives-menu.d.ts +186 -103
- package/types/radix-ng-primitives-navigation-menu.d.ts +37 -75
- package/types/radix-ng-primitives-popover.d.ts +59 -92
- package/types/radix-ng-primitives-popper.d.ts +39 -9
- package/types/radix-ng-primitives-preview-card.d.ts +39 -72
- package/types/radix-ng-primitives-roving-focus.d.ts +7 -6
- package/types/radix-ng-primitives-scroll-area.d.ts +2 -2
- package/types/radix-ng-primitives-select.d.ts +145 -108
- package/types/radix-ng-primitives-slider.d.ts +5 -4
- package/types/radix-ng-primitives-stepper.d.ts +4 -3
- package/types/radix-ng-primitives-time-field.d.ts +3 -2
- package/types/radix-ng-primitives-toast.d.ts +7 -7
- package/types/radix-ng-primitives-toggle-group.d.ts +5 -4
- package/types/radix-ng-primitives-toolbar.d.ts +3 -2
- 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,
|
|
3
|
-
import
|
|
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
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import { RdxFocusScope
|
|
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
|
-
|
|
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
|
-
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
186
|
+
this.preventUnmountOnClose.set(false);
|
|
152
187
|
this.open.set(true);
|
|
153
|
-
this.
|
|
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.
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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: [
|
|
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: [
|
|
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: "
|
|
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.
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
this.
|
|
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
|
-
//
|
|
371
|
-
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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.
|
|
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: [
|
|
557
|
+
hostDirectives: [RdxFloatingNodeRegistration, RdxFloatingFocusManager],
|
|
434
558
|
providers: [
|
|
435
|
-
|
|
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
|
-
|
|
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().
|
|
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().
|
|
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
|
-
|
|
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.
|
|
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 }); }
|