@radix-ng/primitives 1.0.0-beta.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composite/README.md +3 -0
- package/fesm2022/radix-ng-primitives-accordion.mjs +12 -36
- package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-checkbox.mjs +33 -18
- package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-composite.mjs +515 -0
- package/fesm2022/radix-ng-primitives-composite.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-core.mjs +7 -0
- package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-dialog.mjs +54 -12
- package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-drawer.mjs +442 -2
- package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-editable.mjs +12 -7
- package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs +294 -8
- package/fesm2022/radix-ng-primitives-floating-focus-manager.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-focus-scope.mjs +9 -0
- package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menu.mjs +71 -20
- package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menubar.mjs +68 -36
- package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs +281 -88
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-number-field.mjs +7 -2
- package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popover.mjs +117 -35
- package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popper.mjs +73 -65
- package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-radio.mjs +77 -36
- package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +40 -8
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-scroll-area.mjs +56 -25
- package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-select.mjs +62 -37
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +259 -28
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-stepper.mjs +11 -7
- package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-switch.mjs +10 -5
- package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tabs.mjs +64 -30
- package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +69 -19
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle.mjs +37 -13
- package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toolbar.mjs +50 -24
- package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tooltip.mjs +180 -35
- package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
- package/navigation-menu/README.md +5 -2
- package/package.json +5 -1
- package/types/radix-ng-primitives-accordion.d.ts +9 -13
- package/types/radix-ng-primitives-checkbox.d.ts +27 -15
- package/types/radix-ng-primitives-composite.d.ts +152 -0
- package/types/radix-ng-primitives-core.d.ts +2 -0
- package/types/radix-ng-primitives-dialog.d.ts +13 -2
- package/types/radix-ng-primitives-drawer.d.ts +40 -2
- package/types/radix-ng-primitives-editable.d.ts +11 -5
- package/types/radix-ng-primitives-floating-focus-manager.d.ts +113 -16
- package/types/radix-ng-primitives-menu.d.ts +13 -5
- package/types/radix-ng-primitives-menubar.d.ts +10 -5
- package/types/radix-ng-primitives-navigation-menu.d.ts +65 -33
- package/types/radix-ng-primitives-number-field.d.ts +8 -3
- package/types/radix-ng-primitives-popover.d.ts +26 -10
- package/types/radix-ng-primitives-popper.d.ts +1 -0
- package/types/radix-ng-primitives-radio.d.ts +22 -13
- package/types/radix-ng-primitives-roving-focus.d.ts +15 -1
- package/types/radix-ng-primitives-scroll-area.d.ts +4 -1
- package/types/radix-ng-primitives-select.d.ts +16 -20
- package/types/radix-ng-primitives-slider.d.ts +60 -9
- package/types/radix-ng-primitives-stepper.d.ts +11 -4
- package/types/radix-ng-primitives-switch.d.ts +10 -4
- package/types/radix-ng-primitives-tabs.d.ts +20 -11
- package/types/radix-ng-primitives-toggle-group.d.ts +34 -17
- package/types/radix-ng-primitives-toggle.d.ts +14 -7
- package/types/radix-ng-primitives-toolbar.d.ts +22 -14
- package/types/radix-ng-primitives-tooltip.d.ts +38 -14
|
@@ -4,10 +4,10 @@ import * as i1 from '@radix-ng/primitives/popper';
|
|
|
4
4
|
import { RdxPopper, RdxPopperContentWrapper, RdxPopperArrow, RdxPopperContent, legacyPopperVars, provideRdxPopperContentWrapper, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
|
|
5
5
|
import * as i2 from '@radix-ng/primitives/core';
|
|
6
6
|
import { createContext, createFloatingRootContext, useTransitionStatus, injectId, createCancelableChangeEventDetails, provideFloatingTree, provideFloatingRootContext, RDX_FLOATING_ROOT_CONTEXT, RDX_FLOATING_REGISTRATION, useAnchoredScrollLock, RdxFloatingNodeRegistration, rdxDevError, useGraceArea } from '@radix-ng/primitives/core';
|
|
7
|
+
import * as i3 from '@radix-ng/primitives/floating-focus-manager';
|
|
8
|
+
import { getInteractionTypeFromEvent, RdxFloatingFocusManager, provideFloatingFocusManagerConfig, createRdxTriggerInteraction, useTriggerFocusGuards } from '@radix-ng/primitives/floating-focus-manager';
|
|
7
9
|
import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
|
|
8
10
|
import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
|
|
9
|
-
import * as i3 from '@radix-ng/primitives/floating-focus-manager';
|
|
10
|
-
import { RdxFloatingFocusManager, provideFloatingFocusManagerConfig } from '@radix-ng/primitives/floating-focus-manager';
|
|
11
11
|
import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
|
|
12
12
|
import * as i1$1 from '@radix-ng/primitives/portal';
|
|
13
13
|
import { RdxPortalPresence } from '@radix-ng/primitives/portal';
|
|
@@ -65,6 +65,7 @@ class RdxPopoverRoot {
|
|
|
65
65
|
*/
|
|
66
66
|
this.handle = input(...(ngDevMode ? [undefined, { debugName: "handle" }] : /* istanbul ignore next */ []));
|
|
67
67
|
this.contentId = injectId('rdx-popover-content-');
|
|
68
|
+
this.beforeContentFocusGuard = signal(null, ...(ngDevMode ? [{ debugName: "beforeContentFocusGuard" }] : /* istanbul ignore next */ []));
|
|
68
69
|
this.descriptionId = signal(undefined, ...(ngDevMode ? [{ debugName: "descriptionId" }] : /* istanbul ignore next */ []));
|
|
69
70
|
this.titleId = signal(undefined, ...(ngDevMode ? [{ debugName: "titleId" }] : /* istanbul ignore next */ []));
|
|
70
71
|
this.trigger = signal(undefined, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
|
|
@@ -73,8 +74,11 @@ class RdxPopoverRoot {
|
|
|
73
74
|
this.isPointerDownOnTrigger = signal(false, ...(ngDevMode ? [{ debugName: "isPointerDownOnTrigger" }] : /* istanbul ignore next */ []));
|
|
74
75
|
/** Whether the current open was initiated by touch (ADR 0016 §3 — gates the anchored scroll lock). */
|
|
75
76
|
this.openedByTouch = signal(false, ...(ngDevMode ? [{ debugName: "openedByTouch" }] : /* istanbul ignore next */ []));
|
|
77
|
+
this.openInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "openInteractionType" }] : /* istanbul ignore next */ []));
|
|
78
|
+
this.closeInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "closeInteractionType" }] : /* istanbul ignore next */ []));
|
|
76
79
|
this.popupCloseCount = signal(0, ...(ngDevMode ? [{ debugName: "popupCloseCount" }] : /* istanbul ignore next */ []));
|
|
77
80
|
this.preventUnmountOnClose = signal(false, ...(ngDevMode ? [{ debugName: "preventUnmountOnClose" }] : /* istanbul ignore next */ []));
|
|
81
|
+
this.pendingTriggerOpenInteractionType = signal(null, ...(ngDevMode ? [{ debugName: "pendingTriggerOpenInteractionType" }] : /* istanbul ignore next */ []));
|
|
78
82
|
this.onOpenChange = output();
|
|
79
83
|
this.onOpenChangeComplete = output();
|
|
80
84
|
this.registeredTriggers = new Map();
|
|
@@ -132,7 +136,7 @@ class RdxPopoverRoot {
|
|
|
132
136
|
}
|
|
133
137
|
});
|
|
134
138
|
}
|
|
135
|
-
show(trigger = this.trigger(), payload, triggerId, reason = 'none', event
|
|
139
|
+
show(trigger = this.trigger(), payload, triggerId, reason = 'none', event, fromHover = false) {
|
|
136
140
|
this.clearHoverTimers();
|
|
137
141
|
const previousTrigger = this.trigger();
|
|
138
142
|
const changedTriggerWhileOpen = this.open() && previousTrigger !== trigger;
|
|
@@ -146,11 +150,15 @@ class RdxPopoverRoot {
|
|
|
146
150
|
this.payload.set(payload);
|
|
147
151
|
return;
|
|
148
152
|
}
|
|
149
|
-
const
|
|
153
|
+
const resolvedEvent = event ?? new Event('popover.open-change');
|
|
154
|
+
const change = this.createOpenChangeEvent(true, reason, resolvedEvent, trigger, triggerId ?? this.triggerId());
|
|
150
155
|
this.onOpenChange.emit(change.payload);
|
|
151
156
|
if (change.eventDetails.isCanceled()) {
|
|
152
157
|
return;
|
|
153
158
|
}
|
|
159
|
+
const interactionType = this.consumeOpenInteractionType(event);
|
|
160
|
+
this.openInteractionType.set(interactionType);
|
|
161
|
+
this.openedByTouch.set(interactionType === 'touch');
|
|
154
162
|
this.isHoverActive.set(fromHover);
|
|
155
163
|
this.openChangeReason.set(reason);
|
|
156
164
|
this.instant.set(changedTriggerWhileOpen || reason === 'trigger-focus');
|
|
@@ -171,16 +179,19 @@ class RdxPopoverRoot {
|
|
|
171
179
|
this.open.set(true);
|
|
172
180
|
this.floatingContext.events.emit('openchange', { open: true, reason, event: change.eventDetails.event });
|
|
173
181
|
}
|
|
174
|
-
close(reason = 'none', event
|
|
182
|
+
close(reason = 'none', event) {
|
|
175
183
|
this.clearHoverTimers();
|
|
176
184
|
if (!this.open()) {
|
|
177
185
|
return;
|
|
178
186
|
}
|
|
179
|
-
const
|
|
187
|
+
const resolvedEvent = event ?? new Event('popover.open-change');
|
|
188
|
+
const change = this.createOpenChangeEvent(false, reason, resolvedEvent, this.trigger(), this.triggerId());
|
|
180
189
|
this.onOpenChange.emit(change.payload);
|
|
181
190
|
if (change.eventDetails.isCanceled()) {
|
|
182
191
|
return;
|
|
183
192
|
}
|
|
193
|
+
this.pendingTriggerOpenInteractionType.set(null);
|
|
194
|
+
this.closeInteractionType.set(getInteractionTypeFromEvent(event));
|
|
184
195
|
this.isHoverActive.set(false);
|
|
185
196
|
this.openedByTouch.set(false);
|
|
186
197
|
this.instant.set(reason !== 'none' && reason !== 'trigger-hover');
|
|
@@ -224,6 +235,9 @@ class RdxPopoverRoot {
|
|
|
224
235
|
this.hoverDelay = delay;
|
|
225
236
|
this.hoverCloseDelay = closeDelay;
|
|
226
237
|
}
|
|
238
|
+
setTriggerOpenInteractionType(type) {
|
|
239
|
+
this.pendingTriggerOpenInteractionType.set(type);
|
|
240
|
+
}
|
|
227
241
|
registerTrigger(id, trigger, payload) {
|
|
228
242
|
this.registeredTriggers.set(id, { element: trigger, payload });
|
|
229
243
|
this.triggers.update((triggers) => (triggers.includes(trigger) ? triggers : [...triggers, trigger]));
|
|
@@ -263,6 +277,9 @@ class RdxPopoverRoot {
|
|
|
263
277
|
this.viewportTriggerChange.add(onTriggerChange);
|
|
264
278
|
return () => this.viewportTriggerChange.delete(onTriggerChange);
|
|
265
279
|
}
|
|
280
|
+
setBeforeContentFocusGuard(element) {
|
|
281
|
+
this.beforeContentFocusGuard.set(element);
|
|
282
|
+
}
|
|
266
283
|
registerTransitionElement(element) {
|
|
267
284
|
return this.transition.registerElement(element);
|
|
268
285
|
}
|
|
@@ -330,6 +347,11 @@ class RdxPopoverRoot {
|
|
|
330
347
|
}
|
|
331
348
|
});
|
|
332
349
|
}
|
|
350
|
+
consumeOpenInteractionType(event) {
|
|
351
|
+
const pending = this.pendingTriggerOpenInteractionType();
|
|
352
|
+
this.pendingTriggerOpenInteractionType.set(null);
|
|
353
|
+
return pending ?? getInteractionTypeFromEvent(event);
|
|
354
|
+
}
|
|
333
355
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
334
356
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverRoot, isStandalone: true, selector: "[rdxPopoverRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, triggerId: { classPropertyName: "triggerId", publicName: "triggerId", isSignal: true, isRequired: false, transformFunction: null }, defaultTriggerId: { classPropertyName: "defaultTriggerId", publicName: "defaultTriggerId", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", triggerId: "triggerIdChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
|
|
335
357
|
provideRdxPopoverRootContext(context),
|
|
@@ -371,6 +393,8 @@ function contextFor(root) {
|
|
|
371
393
|
openChangeReason: root.openChangeReason.asReadonly(),
|
|
372
394
|
isPointerDownOnTrigger: root.isPointerDownOnTrigger.asReadonly(),
|
|
373
395
|
openedByTouch: root.openedByTouch.asReadonly(),
|
|
396
|
+
openInteractionType: root.openInteractionType.asReadonly(),
|
|
397
|
+
closeInteractionType: root.closeInteractionType.asReadonly(),
|
|
374
398
|
close: (reason, event) => root.close(reason, event),
|
|
375
399
|
cancelHoverClose: () => root.cancelHoverClose(),
|
|
376
400
|
cancelHoverOpen: () => root.cancelHoverOpen(),
|
|
@@ -382,6 +406,7 @@ function contextFor(root) {
|
|
|
382
406
|
setTitleId: (id) => root.titleId.set(id),
|
|
383
407
|
setPointerDownOnTrigger: (pointerDown) => root.isPointerDownOnTrigger.set(pointerDown),
|
|
384
408
|
setOpenedByTouch: (value) => root.openedByTouch.set(value),
|
|
409
|
+
setTriggerOpenInteractionType: (type) => root.setTriggerOpenInteractionType(type),
|
|
385
410
|
setHoverDelays: (delay, closeDelay) => root.setHoverDelays(delay, closeDelay),
|
|
386
411
|
registerPopupClose: () => {
|
|
387
412
|
root.popupCloseCount.update((count) => count + 1);
|
|
@@ -389,7 +414,9 @@ function contextFor(root) {
|
|
|
389
414
|
},
|
|
390
415
|
registerTransitionElement: (element) => root.registerTransitionElement(element),
|
|
391
416
|
transitionStatus: root.transitionStatus,
|
|
417
|
+
beforeContentFocusGuard: root.beforeContentFocusGuard.asReadonly(),
|
|
392
418
|
registerViewport: (onTriggerChange) => root.registerViewport(onTriggerChange),
|
|
419
|
+
setBeforeContentFocusGuard: (element) => root.setBeforeContentFocusGuard(element),
|
|
393
420
|
toggle: (triggerId, trigger, payload, event) => root.toggle(triggerId, trigger, payload, event)
|
|
394
421
|
};
|
|
395
422
|
}
|
|
@@ -429,29 +456,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
429
456
|
class RdxPopoverBackdrop {
|
|
430
457
|
constructor() {
|
|
431
458
|
this.rootContext = injectRdxPopoverRootContext();
|
|
459
|
+
const host = inject(ElementRef).nativeElement;
|
|
460
|
+
host.style.setProperty('-webkit-user-select', 'none');
|
|
432
461
|
// Register the backdrop as owned DOM footprint for primitive-specific checks. The focus manager's
|
|
433
462
|
// marker keep-set stays narrow and does not keep sibling backdrop roots.
|
|
434
463
|
const floatingContext = inject(RDX_FLOATING_ROOT_CONTEXT, { optional: true });
|
|
435
464
|
if (floatingContext) {
|
|
436
|
-
const host = inject(ElementRef).nativeElement;
|
|
437
465
|
floatingContext.addFloatingElement(host);
|
|
438
466
|
inject(DestroyRef).onDestroy(() => floatingContext.removeFloatingElement(host));
|
|
439
467
|
}
|
|
440
468
|
}
|
|
441
469
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
442
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverBackdrop, isStandalone: true, selector: "[rdxPopoverBackdrop]", host: { properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"" } }, ngImport: i0 }); }
|
|
470
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxPopoverBackdrop, isStandalone: true, selector: "[rdxPopoverBackdrop]", host: { attributes: { "role": "presentation" }, properties: { "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-instant": "rootContext.instant() ? \"\" : undefined", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "style.pointer-events": "rootContext.openChangeReason() === \"trigger-hover\" ? \"none\" : null", "style.user-select": "\"none\"" } }, ngImport: i0 }); }
|
|
443
471
|
}
|
|
444
472
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverBackdrop, decorators: [{
|
|
445
473
|
type: Directive,
|
|
446
474
|
args: [{
|
|
447
475
|
selector: '[rdxPopoverBackdrop]',
|
|
448
476
|
host: {
|
|
477
|
+
role: 'presentation',
|
|
449
478
|
'[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
|
|
450
479
|
'[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
|
|
451
480
|
'[attr.data-instant]': 'rootContext.instant() ? "" : undefined',
|
|
452
481
|
'[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
453
482
|
'[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
|
|
454
|
-
'[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"'
|
|
483
|
+
'[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
|
|
484
|
+
'[style.pointer-events]': 'rootContext.openChangeReason() === "trigger-hover" ? "none" : null',
|
|
485
|
+
'[style.user-select]': '"none"'
|
|
455
486
|
}
|
|
456
487
|
}]
|
|
457
488
|
}], ctorParameters: () => [] });
|
|
@@ -469,8 +500,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
469
500
|
* - No `disablePointerDismissal` — outside-press + focus-out always close.
|
|
470
501
|
*
|
|
471
502
|
* Note: a positioned popover does **not** auto-focus into the popup on open (pre-existing — the legacy
|
|
472
|
-
* behaved the same; verified). The trap holds focus once it is inside
|
|
473
|
-
*
|
|
503
|
+
* behaved the same; verified). The trap holds focus once it is inside; portal tab-order handoff is owned
|
|
504
|
+
* by `RdxFloatingFocusManager` and anchored to the active trigger below.
|
|
474
505
|
*/
|
|
475
506
|
class RdxPopoverPopup {
|
|
476
507
|
constructor() {
|
|
@@ -547,20 +578,29 @@ class RdxPopoverPopup {
|
|
|
547
578
|
(rootContext.modal() === true && rootContext.hasPopupClose()),
|
|
548
579
|
// Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
|
|
549
580
|
inert: () => rootContext.modal() === true && rootContext.hasPopupClose(),
|
|
581
|
+
restoreFocus: () => 'popup',
|
|
582
|
+
previousFocusableElement: () => rootContext.trigger() ?? null,
|
|
583
|
+
beforeContentFocusGuardRef: () => (element) => rootContext.setBeforeContentFocusGuard(element),
|
|
550
584
|
// Active for the whole MOUNTED lifetime (Base UI `disabled={!mounted}`, not `open`) for
|
|
551
585
|
// trap/return-focus — including an explicit `preventUnmountOnClose()` cycle after the
|
|
552
586
|
// exit transition. Marker + isolation are additionally gated on `open` inside the
|
|
553
587
|
// manager. Still suppressed while hover-opened.
|
|
554
|
-
enabled: () => rootContext.present() && !rootContext.isHoverActive()
|
|
588
|
+
enabled: () => rootContext.present() && !rootContext.isHoverActive(),
|
|
589
|
+
openInteractionType: () => rootContext.openInteractionType(),
|
|
590
|
+
closeInteractionType: () => rootContext.closeInteractionType()
|
|
555
591
|
};
|
|
556
592
|
})
|
|
557
|
-
], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFloatingNodeRegistration }, { directive: i3.RdxFloatingFocusManager }], ngImport: i0 }); }
|
|
593
|
+
], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFloatingNodeRegistration }, { directive: i3.RdxFloatingFocusManager, inputs: ["initialFocus", "initialFocus", "returnFocus", "finalFocus"] }], ngImport: i0 }); }
|
|
558
594
|
}
|
|
559
595
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverPopup, decorators: [{
|
|
560
596
|
type: Directive,
|
|
561
597
|
args: [{
|
|
562
598
|
selector: '[rdxPopoverPopup]',
|
|
563
|
-
hostDirectives: [
|
|
599
|
+
hostDirectives: [
|
|
600
|
+
RdxPopperContent,
|
|
601
|
+
RdxFloatingNodeRegistration,
|
|
602
|
+
{ directive: RdxFloatingFocusManager, inputs: ['initialFocus', 'returnFocus: finalFocus'] }
|
|
603
|
+
],
|
|
564
604
|
providers: [
|
|
565
605
|
provideFloatingFocusManagerConfig(() => {
|
|
566
606
|
const rootContext = injectRdxPopoverRootContext();
|
|
@@ -569,11 +609,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
569
609
|
(rootContext.modal() === true && rootContext.hasPopupClose()),
|
|
570
610
|
// Full modal blocks outside pointer interaction; `trap-focus` only traps focus.
|
|
571
611
|
inert: () => rootContext.modal() === true && rootContext.hasPopupClose(),
|
|
612
|
+
restoreFocus: () => 'popup',
|
|
613
|
+
previousFocusableElement: () => rootContext.trigger() ?? null,
|
|
614
|
+
beforeContentFocusGuardRef: () => (element) => rootContext.setBeforeContentFocusGuard(element),
|
|
572
615
|
// Active for the whole MOUNTED lifetime (Base UI `disabled={!mounted}`, not `open`) for
|
|
573
616
|
// trap/return-focus — including an explicit `preventUnmountOnClose()` cycle after the
|
|
574
617
|
// exit transition. Marker + isolation are additionally gated on `open` inside the
|
|
575
618
|
// manager. Still suppressed while hover-opened.
|
|
576
|
-
enabled: () => rootContext.present() && !rootContext.isHoverActive()
|
|
619
|
+
enabled: () => rootContext.present() && !rootContext.isHoverActive(),
|
|
620
|
+
openInteractionType: () => rootContext.openInteractionType(),
|
|
621
|
+
closeInteractionType: () => rootContext.closeInteractionType()
|
|
577
622
|
};
|
|
578
623
|
})
|
|
579
624
|
],
|
|
@@ -626,22 +671,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
626
671
|
class RdxPopoverDescription {
|
|
627
672
|
constructor() {
|
|
628
673
|
this.rootContext = injectRdxPopoverRootContext();
|
|
629
|
-
this.
|
|
630
|
-
this.
|
|
674
|
+
this.generatedId = injectId('rdx-popover-description-');
|
|
675
|
+
this.idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
|
|
676
|
+
this.id = computed(() => this.idInput() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
677
|
+
effect((onCleanup) => {
|
|
678
|
+
const id = this.id();
|
|
679
|
+
this.rootContext.setDescriptionId(id);
|
|
680
|
+
onCleanup(() => this.rootContext.setDescriptionId(undefined));
|
|
681
|
+
});
|
|
631
682
|
inject(DestroyRef).onDestroy(() => this.rootContext.setDescriptionId(undefined));
|
|
632
683
|
}
|
|
633
684
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
634
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
685
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverDescription, isStandalone: true, selector: "[rdxPopoverDescription]", inputs: { idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "id()" } }, ngImport: i0 }); }
|
|
635
686
|
}
|
|
636
687
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverDescription, decorators: [{
|
|
637
688
|
type: Directive,
|
|
638
689
|
args: [{
|
|
639
690
|
selector: '[rdxPopoverDescription]',
|
|
640
691
|
host: {
|
|
641
|
-
'[id]': 'id'
|
|
692
|
+
'[id]': 'id()'
|
|
642
693
|
}
|
|
643
694
|
}]
|
|
644
|
-
}], ctorParameters: () => [] });
|
|
695
|
+
}], ctorParameters: () => [], propDecorators: { idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
|
|
645
696
|
|
|
646
697
|
/**
|
|
647
698
|
* Structural directive that teleports the popover content into a container (default `document.body`)
|
|
@@ -741,22 +792,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
741
792
|
class RdxPopoverTitle {
|
|
742
793
|
constructor() {
|
|
743
794
|
this.rootContext = injectRdxPopoverRootContext();
|
|
744
|
-
this.
|
|
745
|
-
this.
|
|
795
|
+
this.generatedId = injectId('rdx-popover-title-');
|
|
796
|
+
this.idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
|
|
797
|
+
this.id = computed(() => this.idInput() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
798
|
+
effect((onCleanup) => {
|
|
799
|
+
const id = this.id();
|
|
800
|
+
this.rootContext.setTitleId(id);
|
|
801
|
+
onCleanup(() => this.rootContext.setTitleId(undefined));
|
|
802
|
+
});
|
|
746
803
|
inject(DestroyRef).onDestroy(() => this.rootContext.setTitleId(undefined));
|
|
747
804
|
}
|
|
748
805
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
749
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
806
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverTitle, isStandalone: true, selector: "[rdxPopoverTitle]", inputs: { idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "id()" } }, ngImport: i0 }); }
|
|
750
807
|
}
|
|
751
808
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTitle, decorators: [{
|
|
752
809
|
type: Directive,
|
|
753
810
|
args: [{
|
|
754
811
|
selector: '[rdxPopoverTitle]',
|
|
755
812
|
host: {
|
|
756
|
-
'[id]': 'id'
|
|
813
|
+
'[id]': 'id()'
|
|
757
814
|
}
|
|
758
815
|
}]
|
|
759
|
-
}], ctorParameters: () => [] });
|
|
816
|
+
}], ctorParameters: () => [], propDecorators: { idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
|
|
760
817
|
|
|
761
818
|
/**
|
|
762
819
|
* A button that opens the popover.
|
|
@@ -765,8 +822,6 @@ class RdxPopoverTrigger {
|
|
|
765
822
|
constructor() {
|
|
766
823
|
this.parentRootContext = injectRdxPopoverRootContext(true);
|
|
767
824
|
this.elementRef = inject(ElementRef);
|
|
768
|
-
/** Pointer type of the most recent `pointerdown`, used to detect a touch open (ADR 0016 §3). */
|
|
769
|
-
this.lastPointerType = '';
|
|
770
825
|
/**
|
|
771
826
|
* Associates this trigger with a detached popover root.
|
|
772
827
|
*/
|
|
@@ -798,8 +853,20 @@ class RdxPopoverTrigger {
|
|
|
798
853
|
this.triggerId = computed(() => this.id() ?? this.generatedId, ...(ngDevMode ? [{ debugName: "triggerId" }] : /* istanbul ignore next */ []));
|
|
799
854
|
this.rootContext = computed(() => this.handle()?.context() ?? this.parentRootContext, ...(ngDevMode ? [{ debugName: "rootContext" }] : /* istanbul ignore next */ []));
|
|
800
855
|
this.isOpen = computed(() => this.rootContext()?.isOpen() === true && this.rootContext()?.trigger() === this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
801
|
-
this.
|
|
856
|
+
this.triggerInteraction = createRdxTriggerInteraction({
|
|
857
|
+
trigger: () => this.elementRef.nativeElement,
|
|
858
|
+
activeTrigger: () => this.rootContext()?.trigger(),
|
|
859
|
+
open: () => this.rootContext()?.isOpen() ?? false,
|
|
860
|
+
disabled: () => this.disabled(),
|
|
861
|
+
contentId: () => this.rootContext()?.contentId
|
|
862
|
+
});
|
|
863
|
+
this.isPressed = computed(() => this.triggerInteraction.isActive() && this.rootContext()?.openChangeReason() === 'trigger-press', ...(ngDevMode ? [{ debugName: "isPressed" }] : /* istanbul ignore next */ []));
|
|
802
864
|
this.generatedId = injectId('rdx-popover-trigger-');
|
|
865
|
+
effect(() => {
|
|
866
|
+
if (!this.handle() && !this.parentRootContext) {
|
|
867
|
+
rdxDevError('popover/trigger-missing-root', '`rdxPopoverTrigger` must be used inside `rdxPopoverRoot` or receive a `handle` connected to a root.', 'components/popover');
|
|
868
|
+
}
|
|
869
|
+
});
|
|
803
870
|
effect((onCleanup) => {
|
|
804
871
|
const handle = this.handle();
|
|
805
872
|
if (handle) {
|
|
@@ -809,6 +876,19 @@ class RdxPopoverTrigger {
|
|
|
809
876
|
onCleanup(untracked(() => this.parentRootContext.registerTrigger(this.triggerId(), this.elementRef.nativeElement, () => this.payload())));
|
|
810
877
|
}
|
|
811
878
|
});
|
|
879
|
+
useTriggerFocusGuards({
|
|
880
|
+
trigger: () => this.elementRef.nativeElement,
|
|
881
|
+
close: (event) => this.rootContext()?.close('focus-out', event),
|
|
882
|
+
beforeContentFocusGuard: () => this.rootContext()?.beforeContentFocusGuard(),
|
|
883
|
+
contentId: () => this.rootContext()?.contentId,
|
|
884
|
+
enabled: () => this.triggerInteraction.isActive(),
|
|
885
|
+
popupElement: () => {
|
|
886
|
+
const contentId = this.rootContext()?.contentId;
|
|
887
|
+
return contentId
|
|
888
|
+
? this.elementRef.nativeElement.ownerDocument.getElementById(contentId)
|
|
889
|
+
: null;
|
|
890
|
+
}
|
|
891
|
+
});
|
|
812
892
|
}
|
|
813
893
|
handleClick(event) {
|
|
814
894
|
if (this.disabled()) {
|
|
@@ -816,7 +896,9 @@ class RdxPopoverTrigger {
|
|
|
816
896
|
}
|
|
817
897
|
// Record whether this open is a touch tap (ADR 0016 §3). `detail === 0` is a keyboard-activated
|
|
818
898
|
// click (no preceding pointerdown), which must read non-touch regardless of the last pointer type.
|
|
819
|
-
|
|
899
|
+
const interactionType = this.triggerInteraction.clickInteractionType(event);
|
|
900
|
+
this.rootContext()?.setOpenedByTouch(interactionType === 'touch');
|
|
901
|
+
this.rootContext()?.setTriggerOpenInteractionType(interactionType);
|
|
820
902
|
this.rootContext()?.setPointerDownOnTrigger(false);
|
|
821
903
|
if (this.handle()) {
|
|
822
904
|
this.handle().toggle(this.triggerId(), event);
|
|
@@ -840,14 +922,14 @@ class RdxPopoverTrigger {
|
|
|
840
922
|
this.rootContext()?.cancelHoverOpen();
|
|
841
923
|
}
|
|
842
924
|
handlePointerDown(event) {
|
|
843
|
-
this.
|
|
925
|
+
this.triggerInteraction.recordPointerDown(event);
|
|
844
926
|
this.rootContext()?.setPointerDownOnTrigger(true);
|
|
845
927
|
}
|
|
846
928
|
handlePointerUp() {
|
|
847
929
|
this.rootContext()?.setPointerDownOnTrigger(false);
|
|
848
930
|
}
|
|
849
931
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
850
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverTrigger, isStandalone: true, selector: "button[rdxPopoverTrigger]", inputs: { handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, openOnHover: { classPropertyName: "openOnHover", publicName: "openOnHover", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointerleave": "handlePointerLeave($event)", "pointerdown": "handlePointerDown($event)", "pointerup": "handlePointerUp()", "pointercancel": "handlePointerUp()" }, properties: { "attr.aria-controls": "rootContext()?.contentId", "attr.aria-expanded": "
|
|
932
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxPopoverTrigger, isStandalone: true, selector: "button[rdxPopoverTrigger]", inputs: { handle: { classPropertyName: "handle", publicName: "handle", isSignal: true, isRequired: false, transformFunction: null }, payload: { classPropertyName: "payload", publicName: "payload", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, openOnHover: { classPropertyName: "openOnHover", publicName: "openOnHover", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointerleave": "handlePointerLeave($event)", "pointerdown": "handlePointerDown($event)", "pointerup": "handlePointerUp()", "pointercancel": "handlePointerUp()" }, properties: { "attr.aria-controls": "rootContext()?.contentId", "attr.aria-expanded": "triggerInteraction.ariaExpanded()", "attr.aria-haspopup": "\"dialog\"", "attr.data-state": "triggerInteraction.dataState()", "attr.data-popup-open": "triggerInteraction.dataPopupOpen()", "attr.data-pressed": "isPressed() ? \"\" : undefined", "attr.disabled": "triggerInteraction.disabled() ? \"\" : undefined", "id": "triggerId()" } }, hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
|
|
851
933
|
}
|
|
852
934
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxPopoverTrigger, decorators: [{
|
|
853
935
|
type: Directive,
|
|
@@ -857,12 +939,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
857
939
|
host: {
|
|
858
940
|
type: 'button',
|
|
859
941
|
'[attr.aria-controls]': 'rootContext()?.contentId',
|
|
860
|
-
'[attr.aria-expanded]': '
|
|
942
|
+
'[attr.aria-expanded]': 'triggerInteraction.ariaExpanded()',
|
|
861
943
|
'[attr.aria-haspopup]': '"dialog"',
|
|
862
|
-
'[attr.data-state]': '
|
|
863
|
-
'[attr.data-popup-open]': '
|
|
944
|
+
'[attr.data-state]': 'triggerInteraction.dataState()',
|
|
945
|
+
'[attr.data-popup-open]': 'triggerInteraction.dataPopupOpen()',
|
|
864
946
|
'[attr.data-pressed]': 'isPressed() ? "" : undefined',
|
|
865
|
-
'[attr.disabled]': 'disabled() ? "" : undefined',
|
|
947
|
+
'[attr.disabled]': 'triggerInteraction.disabled() ? "" : undefined',
|
|
866
948
|
'[id]': 'triggerId()',
|
|
867
949
|
'(click)': 'handleClick($event)',
|
|
868
950
|
'(pointerenter)': 'handlePointerEnter($event)',
|