@radix-ng/primitives 1.0.0-beta.5 → 1.0.2
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 +20 -44
- package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-checkbox.mjs +134 -58
- package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-composite.mjs +599 -0
- package/fesm2022/radix-ng-primitives-composite.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-drawer.mjs +442 -2
- package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menu.mjs +315 -68
- package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menubar.mjs +91 -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-popover.mjs +40 -15
- 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 +63 -27
- package/fesm2022/radix-ng-primitives-radio.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 +59 -29
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +57 -13
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tabs.mjs +335 -73
- package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +66 -21
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle.mjs +29 -11
- package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toolbar.mjs +68 -36
- package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
- package/navigation-menu/README.md +5 -2
- package/package.json +6 -10
- package/types/radix-ng-primitives-accordion.d.ts +12 -16
- package/types/radix-ng-primitives-checkbox.d.ts +98 -70
- package/types/radix-ng-primitives-composite.d.ts +195 -0
- package/types/radix-ng-primitives-drawer.d.ts +40 -2
- package/types/radix-ng-primitives-menu.d.ts +46 -16
- package/types/radix-ng-primitives-menubar.d.ts +12 -5
- package/types/radix-ng-primitives-navigation-menu.d.ts +65 -33
- package/types/radix-ng-primitives-popover.d.ts +9 -5
- package/types/radix-ng-primitives-popper.d.ts +1 -0
- package/types/radix-ng-primitives-radio.d.ts +11 -9
- package/types/radix-ng-primitives-scroll-area.d.ts +4 -1
- package/types/radix-ng-primitives-select.d.ts +46 -32
- package/types/radix-ng-primitives-slider.d.ts +19 -4
- package/types/radix-ng-primitives-tabs.d.ts +69 -14
- package/types/radix-ng-primitives-toggle-group.d.ts +27 -16
- package/types/radix-ng-primitives-toggle.d.ts +5 -5
- package/types/radix-ng-primitives-toolbar.d.ts +84 -69
- package/collection/README.md +0 -1
- package/fesm2022/radix-ng-primitives-collection.mjs +0 -72
- package/fesm2022/radix-ng-primitives-collection.mjs.map +0 -1
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +0 -388
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +0 -1
- package/roving-focus/README.md +0 -3
- package/types/radix-ng-primitives-collection.d.ts +0 -44
- package/types/radix-ng-primitives-roving-focus.d.ts +0 -187
|
@@ -7,19 +7,83 @@ import { createContext, createFloatingRootContext, useTransitionStatus, createCa
|
|
|
7
7
|
import { injectDirection } from '@radix-ng/primitives/direction-provider';
|
|
8
8
|
import * as i3 from '@radix-ng/primitives/floating-focus-manager';
|
|
9
9
|
import { getInteractionTypeFromEvent, RdxFloatingFocusManager, provideFloatingFocusManagerConfig, createRdxTriggerInteraction, useTriggerFocusGuards } from '@radix-ng/primitives/floating-focus-manager';
|
|
10
|
+
import * as i1$1 from '@radix-ng/primitives/composite';
|
|
11
|
+
import { isElementVisible, RdxCompositeListItem, RdxCompositeList } from '@radix-ng/primitives/composite';
|
|
10
12
|
import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
|
|
11
13
|
import { RdxDismiss } from '@radix-ng/primitives/dismissable-layer';
|
|
12
14
|
import { RdxFocusScope } from '@radix-ng/primitives/focus-scope';
|
|
13
|
-
import * as i1$
|
|
15
|
+
import * as i1$2 from '@radix-ng/primitives/portal';
|
|
14
16
|
import { RdxPortalPresence } from '@radix-ng/primitives/portal';
|
|
15
17
|
import { provideRdxPresenceContext } from '@radix-ng/primitives/presence';
|
|
16
18
|
import { isPlatformBrowser } from '@angular/common';
|
|
17
19
|
|
|
20
|
+
/** Selector for menu items within a popup. Disabled items stay focusable to match Base UI. */
|
|
21
|
+
const RDX_MENU_ITEM_SELECTOR = [
|
|
22
|
+
'[rdxMenuItem]',
|
|
23
|
+
'[rdxMenuCheckboxItem]',
|
|
24
|
+
'[rdxMenuRadioItem]',
|
|
25
|
+
'[rdxMenuLinkItem]',
|
|
26
|
+
'[rdxMenuSubTrigger]'
|
|
27
|
+
].join(',');
|
|
28
|
+
function getFocusableMenuItems(popup) {
|
|
29
|
+
return Array.from(popup.querySelectorAll(RDX_MENU_ITEM_SELECTOR)).filter((item) => item.closest('[rdxMenuPopup]') === popup);
|
|
30
|
+
}
|
|
31
|
+
function getCompositeMenuItems(list) {
|
|
32
|
+
const map = list.itemMap();
|
|
33
|
+
return list
|
|
34
|
+
.items()
|
|
35
|
+
.map(({ element }) => {
|
|
36
|
+
const metadata = map.get(element);
|
|
37
|
+
if (!metadata || !isElementVisible(element)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
element,
|
|
42
|
+
index: metadata.index,
|
|
43
|
+
label: getMenuItemLabel(element, metadata),
|
|
44
|
+
metadata
|
|
45
|
+
};
|
|
46
|
+
})
|
|
47
|
+
.filter((item) => item !== null);
|
|
48
|
+
}
|
|
49
|
+
function getDomMenuItems(popup) {
|
|
50
|
+
return getFocusableMenuItems(popup).map((element, index) => ({
|
|
51
|
+
element,
|
|
52
|
+
index,
|
|
53
|
+
label: getMenuItemLabel(element),
|
|
54
|
+
metadata: {
|
|
55
|
+
index,
|
|
56
|
+
type: getMenuItemType(element),
|
|
57
|
+
disabled: element.hasAttribute('data-disabled'),
|
|
58
|
+
label: element.dataset['label']
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
function getMenuItemLabel(element, metadata) {
|
|
63
|
+
return (metadata?.label ?? element.dataset['label'] ?? element.textContent?.trim() ?? '').toLowerCase();
|
|
64
|
+
}
|
|
65
|
+
function getMenuItemType(element) {
|
|
66
|
+
if (element.hasAttribute('rdxMenuCheckboxItem')) {
|
|
67
|
+
return 'checkbox-item';
|
|
68
|
+
}
|
|
69
|
+
if (element.hasAttribute('rdxMenuRadioItem')) {
|
|
70
|
+
return 'radio-item';
|
|
71
|
+
}
|
|
72
|
+
if (element.hasAttribute('rdxMenuLinkItem')) {
|
|
73
|
+
return 'link-item';
|
|
74
|
+
}
|
|
75
|
+
if (element.hasAttribute('rdxMenuSubTrigger')) {
|
|
76
|
+
return 'submenu-trigger';
|
|
77
|
+
}
|
|
78
|
+
return 'regular-item';
|
|
79
|
+
}
|
|
80
|
+
|
|
18
81
|
const [injectRdxMenuRootContext, provideRdxMenuRootContext] = createContext('RdxMenuRootContext', 'components/menu');
|
|
19
82
|
function buildContext(instance) {
|
|
20
83
|
return {
|
|
21
84
|
isOpen: instance.open,
|
|
22
85
|
present: instance.present,
|
|
86
|
+
activeIndex: instance.activeIndex.asReadonly(),
|
|
23
87
|
disabled: instance.effectiveDisabled,
|
|
24
88
|
modal: instance.effectiveModal,
|
|
25
89
|
loopFocus: instance.loopFocus,
|
|
@@ -41,6 +105,7 @@ function buildContext(instance) {
|
|
|
41
105
|
beforeContentFocusGuard: instance.beforeContentFocusGuard.asReadonly(),
|
|
42
106
|
transitionStatus: instance.transitionStatus,
|
|
43
107
|
close: (reason, event) => instance.close(reason, event),
|
|
108
|
+
setActiveIndex: (index) => instance.setActiveIndex(index),
|
|
44
109
|
closeEntireMenu: (reason, event) => instance.closeEntireMenu(reason, event),
|
|
45
110
|
toggle: (reason, event) => instance.toggle(reason, event),
|
|
46
111
|
show: (autoFocus, reason, event) => instance.show(autoFocus, reason, event),
|
|
@@ -109,6 +174,7 @@ class RdxMenuRoot {
|
|
|
109
174
|
this.popupElement = signal(undefined, ...(ngDevMode ? [{ debugName: "popupElement" }] : /* istanbul ignore next */ []));
|
|
110
175
|
this.beforeContentFocusGuard = signal(null, ...(ngDevMode ? [{ debugName: "beforeContentFocusGuard" }] : /* istanbul ignore next */ []));
|
|
111
176
|
this.transitionStatus = this.transition.status;
|
|
177
|
+
this.activeIndex = signal(null, ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
112
178
|
/** Whether the popup grabs focus when it opens. Set false for menubar hover-switching. */
|
|
113
179
|
this.autoFocus = signal('first', ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
|
|
114
180
|
this.isSubmenu = signal(false, ...(ngDevMode ? [{ debugName: "isSubmenu" }] : /* istanbul ignore next */ []));
|
|
@@ -164,6 +230,11 @@ class RdxMenuRoot {
|
|
|
164
230
|
this.preventUnmountOnClose.set(false);
|
|
165
231
|
}
|
|
166
232
|
});
|
|
233
|
+
effect(() => {
|
|
234
|
+
if (!this.open()) {
|
|
235
|
+
this.activeIndex.set(null);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
167
238
|
let previousOpen = this.open();
|
|
168
239
|
effect(() => {
|
|
169
240
|
const open = this.open();
|
|
@@ -177,7 +248,12 @@ class RdxMenuRoot {
|
|
|
177
248
|
if (this.effectiveDisabled()) {
|
|
178
249
|
return;
|
|
179
250
|
}
|
|
180
|
-
|
|
251
|
+
const nextAutoFocus = autoFocus === true ? 'first' : autoFocus;
|
|
252
|
+
this.autoFocus.set(nextAutoFocus);
|
|
253
|
+
if (this.open()) {
|
|
254
|
+
this.focusOpenPopup(nextAutoFocus);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
181
257
|
if (!this.open()) {
|
|
182
258
|
const change = this.createOpenChangeEvent(true, reason, event);
|
|
183
259
|
this.onOpenChange.emit(change.payload);
|
|
@@ -225,6 +301,14 @@ class RdxMenuRoot {
|
|
|
225
301
|
markAsContextMenu() {
|
|
226
302
|
this.isContextMenu.set(true);
|
|
227
303
|
}
|
|
304
|
+
setActiveIndex(index) {
|
|
305
|
+
if (this.effectiveDisabled() && index !== null) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (this.activeIndex() !== index) {
|
|
309
|
+
this.activeIndex.set(index);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
228
312
|
setAllowMouseUpTrigger(value) {
|
|
229
313
|
if (this.parentRoot) {
|
|
230
314
|
this.parentRoot.setAllowMouseUpTrigger(value);
|
|
@@ -310,6 +394,23 @@ class RdxMenuRoot {
|
|
|
310
394
|
}
|
|
311
395
|
};
|
|
312
396
|
}
|
|
397
|
+
focusOpenPopup(autoFocus) {
|
|
398
|
+
if (autoFocus === false) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const popup = this.popupElement();
|
|
402
|
+
if (!popup) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (autoFocus === 'popup') {
|
|
406
|
+
this.setActiveIndex(null);
|
|
407
|
+
popup.focus({ preventScroll: true });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const items = getFocusableMenuItems(popup);
|
|
411
|
+
const item = autoFocus === 'last' ? items.at(-1) : items[0];
|
|
412
|
+
(item ?? popup).focus({ preventScroll: true });
|
|
413
|
+
}
|
|
313
414
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
314
415
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuRoot, isStandalone: true, selector: "[rdxMenuRoot],[rdxMenuSubmenuRoot]", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, defaultOpen: { classPropertyName: "defaultOpen", publicName: "defaultOpen", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, loopFocus: { classPropertyName: "loopFocus", publicName: "loopFocus", isSignal: true, isRequired: false, transformFunction: null }, highlightItemOnHover: { classPropertyName: "highlightItemOnHover", publicName: "highlightItemOnHover", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, dirInput: { classPropertyName: "dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, closeParentOnEsc: { classPropertyName: "closeParentOnEsc", publicName: "closeParentOnEsc", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [
|
|
315
416
|
provideRdxMenuRootContext(contextFactory),
|
|
@@ -413,6 +514,7 @@ const checkboxItemContextFactory = () => {
|
|
|
413
514
|
class RdxMenuCheckboxItem {
|
|
414
515
|
constructor() {
|
|
415
516
|
this.rootContext = injectRdxMenuRootContext(true);
|
|
517
|
+
this.listItem = inject(RdxCompositeListItem, { self: true });
|
|
416
518
|
this.elementRef = inject(ElementRef);
|
|
417
519
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
418
520
|
/** Whether this item is disabled. */
|
|
@@ -425,19 +527,28 @@ class RdxMenuCheckboxItem {
|
|
|
425
527
|
this.checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
426
528
|
/** Emits when the checked state changes. */
|
|
427
529
|
this.onCheckedChange = output();
|
|
428
|
-
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
530
|
+
this.highlighted = computed(() => this.rootContext?.activeIndex() === this.listItem.index() || this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
429
531
|
this.effectiveDisabled = computed(() => this.disabled() || (this.rootContext?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
|
|
430
532
|
// Expose helpers for host bindings
|
|
431
533
|
this.isIndeterminate = isIndeterminate;
|
|
432
534
|
this.getCheckedState = getCheckedState;
|
|
535
|
+
effect(() => {
|
|
536
|
+
this.listItem.setMetadata({
|
|
537
|
+
type: 'checkbox-item',
|
|
538
|
+
disabled: this.effectiveDisabled(),
|
|
539
|
+
label: this.label()
|
|
540
|
+
});
|
|
541
|
+
});
|
|
433
542
|
}
|
|
434
543
|
onFocus() {
|
|
435
|
-
if (!this.
|
|
544
|
+
if (!this.rootContext?.disabled()) {
|
|
436
545
|
this.isFocused.set(true);
|
|
437
546
|
}
|
|
547
|
+
this.setActiveIndex();
|
|
438
548
|
}
|
|
439
549
|
onBlur() {
|
|
440
550
|
this.isFocused.set(false);
|
|
551
|
+
this.clearActiveIndex();
|
|
441
552
|
}
|
|
442
553
|
onPointerMove(event) {
|
|
443
554
|
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.effectiveDisabled()) {
|
|
@@ -446,6 +557,7 @@ class RdxMenuCheckboxItem {
|
|
|
446
557
|
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
447
558
|
return;
|
|
448
559
|
}
|
|
560
|
+
this.setActiveIndex();
|
|
449
561
|
if (this.elementRef.nativeElement.ownerDocument.activeElement !== this.elementRef.nativeElement) {
|
|
450
562
|
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
451
563
|
}
|
|
@@ -455,6 +567,8 @@ class RdxMenuCheckboxItem {
|
|
|
455
567
|
return;
|
|
456
568
|
}
|
|
457
569
|
if (this.elementRef.nativeElement.ownerDocument.activeElement === this.elementRef.nativeElement) {
|
|
570
|
+
this.isFocused.set(false);
|
|
571
|
+
this.clearActiveIndex();
|
|
458
572
|
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
459
573
|
}
|
|
460
574
|
}
|
|
@@ -485,8 +599,22 @@ class RdxMenuCheckboxItem {
|
|
|
485
599
|
this.checked.set(next);
|
|
486
600
|
this.onCheckedChange.emit(next);
|
|
487
601
|
}
|
|
602
|
+
setActiveIndex() {
|
|
603
|
+
if (!this.rootContext || this.rootContext.disabled()) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const index = this.listItem.index();
|
|
607
|
+
if (index !== -1) {
|
|
608
|
+
this.rootContext.setActiveIndex(index);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
clearActiveIndex() {
|
|
612
|
+
if (this.rootContext?.activeIndex() === this.listItem.index()) {
|
|
613
|
+
this.rootContext.setActiveIndex(null);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
488
616
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
489
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuCheckboxItem, isStandalone: true, selector: "[rdxMenuCheckboxItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", onCheckedChange: "onCheckedChange" }, host: { attributes: { "role": "menuitemcheckbox"
|
|
617
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuCheckboxItem, isStandalone: true, selector: "[rdxMenuCheckboxItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", onCheckedChange: "onCheckedChange" }, host: { attributes: { "role": "menuitemcheckbox" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "mouseup": "onMouseUp($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.tabindex": "rootContext?.isOpen() && highlighted() ? 0 : -1", "attr.aria-checked": "isIndeterminate(checked()) ? \"mixed\" : checked()", "attr.data-state": "getCheckedState(checked())", "attr.data-disabled": "effectiveDisabled() ? \"\" : undefined", "attr.aria-disabled": "effectiveDisabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, providers: [provideRdxMenuCheckboxItemContext(checkboxItemContextFactory)], exportAs: ["rdxMenuCheckboxItem"], hostDirectives: [{ directive: i1$1.RdxCompositeListItem }], ngImport: i0 }); }
|
|
490
618
|
}
|
|
491
619
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItem, decorators: [{
|
|
492
620
|
type: Directive,
|
|
@@ -494,9 +622,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
494
622
|
selector: '[rdxMenuCheckboxItem]',
|
|
495
623
|
exportAs: 'rdxMenuCheckboxItem',
|
|
496
624
|
providers: [provideRdxMenuCheckboxItemContext(checkboxItemContextFactory)],
|
|
625
|
+
hostDirectives: [RdxCompositeListItem],
|
|
497
626
|
host: {
|
|
498
627
|
role: 'menuitemcheckbox',
|
|
499
|
-
tabindex: '-1',
|
|
628
|
+
'[attr.tabindex]': 'rootContext?.isOpen() && highlighted() ? 0 : -1',
|
|
500
629
|
'[attr.aria-checked]': 'isIndeterminate(checked()) ? "mixed" : checked()',
|
|
501
630
|
'[attr.data-state]': 'getCheckedState(checked())',
|
|
502
631
|
'[attr.data-disabled]': 'effectiveDisabled() ? "" : undefined',
|
|
@@ -513,7 +642,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
513
642
|
'(keydown.space)': 'onActivate($event)'
|
|
514
643
|
}
|
|
515
644
|
}]
|
|
516
|
-
}], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], onCheckedChange: [{ type: i0.Output, args: ["onCheckedChange"] }] } });
|
|
645
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], onCheckedChange: [{ type: i0.Output, args: ["onCheckedChange"] }] } });
|
|
517
646
|
|
|
518
647
|
/**
|
|
519
648
|
* Renders when the parent checkbox item is checked or indeterminate.
|
|
@@ -607,6 +736,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
607
736
|
class RdxMenuItem {
|
|
608
737
|
constructor() {
|
|
609
738
|
this.rootContext = injectRdxMenuRootContext(true);
|
|
739
|
+
this.listItem = inject(RdxCompositeListItem, { self: true });
|
|
610
740
|
this.elementRef = inject(ElementRef);
|
|
611
741
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
612
742
|
/** Whether this item is disabled. */
|
|
@@ -617,16 +747,25 @@ class RdxMenuItem {
|
|
|
617
747
|
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
618
748
|
/** Emits when the item is selected. */
|
|
619
749
|
this.onSelect = output();
|
|
620
|
-
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
750
|
+
this.highlighted = computed(() => this.rootContext?.activeIndex() === this.listItem.index() || this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
621
751
|
this.effectiveDisabled = computed(() => this.disabled() || (this.rootContext?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
|
|
752
|
+
effect(() => {
|
|
753
|
+
this.listItem.setMetadata({
|
|
754
|
+
type: 'regular-item',
|
|
755
|
+
disabled: this.effectiveDisabled(),
|
|
756
|
+
label: this.label()
|
|
757
|
+
});
|
|
758
|
+
});
|
|
622
759
|
}
|
|
623
760
|
onFocus() {
|
|
624
|
-
if (!this.
|
|
761
|
+
if (!this.rootContext?.disabled()) {
|
|
625
762
|
this.isFocused.set(true);
|
|
626
763
|
}
|
|
764
|
+
this.setActiveIndex();
|
|
627
765
|
}
|
|
628
766
|
onBlur() {
|
|
629
767
|
this.isFocused.set(false);
|
|
768
|
+
this.clearActiveIndex();
|
|
630
769
|
}
|
|
631
770
|
onPointerMove(event) {
|
|
632
771
|
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.effectiveDisabled()) {
|
|
@@ -635,6 +774,7 @@ class RdxMenuItem {
|
|
|
635
774
|
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
636
775
|
return;
|
|
637
776
|
}
|
|
777
|
+
this.setActiveIndex();
|
|
638
778
|
if (this.elementRef.nativeElement.ownerDocument.activeElement !== this.elementRef.nativeElement) {
|
|
639
779
|
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
640
780
|
}
|
|
@@ -646,6 +786,8 @@ class RdxMenuItem {
|
|
|
646
786
|
// Clear highlight when the pointer leaves: move focus back to the popup. A subsequent
|
|
647
787
|
// pointermove on a sibling item re-focuses it, so moving between items still works.
|
|
648
788
|
if (this.elementRef.nativeElement.ownerDocument.activeElement === this.elementRef.nativeElement) {
|
|
789
|
+
this.isFocused.set(false);
|
|
790
|
+
this.clearActiveIndex();
|
|
649
791
|
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
650
792
|
}
|
|
651
793
|
}
|
|
@@ -671,17 +813,32 @@ class RdxMenuItem {
|
|
|
671
813
|
if (this.closeOnClick())
|
|
672
814
|
this.rootContext?.closeEntireMenu();
|
|
673
815
|
}
|
|
816
|
+
setActiveIndex() {
|
|
817
|
+
if (!this.rootContext || this.rootContext.disabled()) {
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
const index = this.listItem.index();
|
|
821
|
+
if (index !== -1) {
|
|
822
|
+
this.rootContext.setActiveIndex(index);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
clearActiveIndex() {
|
|
826
|
+
if (this.rootContext?.activeIndex() === this.listItem.index()) {
|
|
827
|
+
this.rootContext.setActiveIndex(null);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
674
830
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
675
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuItem, isStandalone: true, selector: "[rdxMenuItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitem"
|
|
831
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuItem, isStandalone: true, selector: "[rdxMenuItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitem" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "mouseup": "onMouseUp($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.tabindex": "rootContext?.isOpen() && highlighted() ? 0 : -1", "attr.data-disabled": "effectiveDisabled() ? \"\" : undefined", "attr.aria-disabled": "effectiveDisabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuItem"], hostDirectives: [{ directive: i1$1.RdxCompositeListItem }], ngImport: i0 }); }
|
|
676
832
|
}
|
|
677
833
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuItem, decorators: [{
|
|
678
834
|
type: Directive,
|
|
679
835
|
args: [{
|
|
680
836
|
selector: '[rdxMenuItem]',
|
|
681
837
|
exportAs: 'rdxMenuItem',
|
|
838
|
+
hostDirectives: [RdxCompositeListItem],
|
|
682
839
|
host: {
|
|
683
840
|
role: 'menuitem',
|
|
684
|
-
tabindex: '-1',
|
|
841
|
+
'[attr.tabindex]': 'rootContext?.isOpen() && highlighted() ? 0 : -1',
|
|
685
842
|
'[attr.data-disabled]': 'effectiveDisabled() ? "" : undefined',
|
|
686
843
|
'[attr.aria-disabled]': 'effectiveDisabled() ? true : undefined',
|
|
687
844
|
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
@@ -696,7 +853,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
696
853
|
'(keydown.space)': 'onActivate($event)'
|
|
697
854
|
}
|
|
698
855
|
}]
|
|
699
|
-
}], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
856
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
700
857
|
|
|
701
858
|
/**
|
|
702
859
|
* A menu item that renders as a link.
|
|
@@ -704,6 +861,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
704
861
|
class RdxMenuLinkItem {
|
|
705
862
|
constructor() {
|
|
706
863
|
this.rootContext = injectRdxMenuRootContext(true);
|
|
864
|
+
this.listItem = inject(RdxCompositeListItem, { self: true });
|
|
707
865
|
this.elementRef = inject(ElementRef);
|
|
708
866
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
709
867
|
/** Whether this item is disabled. */
|
|
@@ -714,16 +872,25 @@ class RdxMenuLinkItem {
|
|
|
714
872
|
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
715
873
|
/** Emits when the item is selected. */
|
|
716
874
|
this.onSelect = output();
|
|
717
|
-
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
875
|
+
this.highlighted = computed(() => this.rootContext?.activeIndex() === this.listItem.index() || this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
718
876
|
this.effectiveDisabled = computed(() => this.disabled() || (this.rootContext?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
|
|
877
|
+
effect(() => {
|
|
878
|
+
this.listItem.setMetadata({
|
|
879
|
+
type: 'link-item',
|
|
880
|
+
disabled: this.effectiveDisabled(),
|
|
881
|
+
label: this.label()
|
|
882
|
+
});
|
|
883
|
+
});
|
|
719
884
|
}
|
|
720
885
|
onFocus() {
|
|
721
|
-
if (!this.
|
|
886
|
+
if (!this.rootContext?.disabled()) {
|
|
722
887
|
this.isFocused.set(true);
|
|
723
888
|
}
|
|
889
|
+
this.setActiveIndex();
|
|
724
890
|
}
|
|
725
891
|
onBlur() {
|
|
726
892
|
this.isFocused.set(false);
|
|
893
|
+
this.clearActiveIndex();
|
|
727
894
|
}
|
|
728
895
|
onPointerMove(event) {
|
|
729
896
|
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.effectiveDisabled()) {
|
|
@@ -732,6 +899,7 @@ class RdxMenuLinkItem {
|
|
|
732
899
|
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
733
900
|
return;
|
|
734
901
|
}
|
|
902
|
+
this.setActiveIndex();
|
|
735
903
|
if (this.elementRef.nativeElement.ownerDocument.activeElement !== this.elementRef.nativeElement) {
|
|
736
904
|
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
737
905
|
}
|
|
@@ -741,6 +909,8 @@ class RdxMenuLinkItem {
|
|
|
741
909
|
return;
|
|
742
910
|
}
|
|
743
911
|
if (this.elementRef.nativeElement.ownerDocument.activeElement === this.elementRef.nativeElement) {
|
|
912
|
+
this.isFocused.set(false);
|
|
913
|
+
this.clearActiveIndex();
|
|
744
914
|
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
745
915
|
}
|
|
746
916
|
}
|
|
@@ -761,25 +931,38 @@ class RdxMenuLinkItem {
|
|
|
761
931
|
this.elementRef.nativeElement.click();
|
|
762
932
|
}
|
|
763
933
|
onActivate(event) {
|
|
934
|
+
event.preventDefault();
|
|
764
935
|
if (this.effectiveDisabled()) {
|
|
765
|
-
event.preventDefault();
|
|
766
936
|
return;
|
|
767
937
|
}
|
|
768
|
-
this.
|
|
769
|
-
|
|
770
|
-
|
|
938
|
+
this.elementRef.nativeElement.click();
|
|
939
|
+
}
|
|
940
|
+
setActiveIndex() {
|
|
941
|
+
if (!this.rootContext || this.rootContext.disabled()) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
const index = this.listItem.index();
|
|
945
|
+
if (index !== -1) {
|
|
946
|
+
this.rootContext.setActiveIndex(index);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
clearActiveIndex() {
|
|
950
|
+
if (this.rootContext?.activeIndex() === this.listItem.index()) {
|
|
951
|
+
this.rootContext.setActiveIndex(null);
|
|
952
|
+
}
|
|
771
953
|
}
|
|
772
954
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLinkItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
773
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuLinkItem, isStandalone: true, selector: "a[rdxMenuLinkItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitem"
|
|
955
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuLinkItem, isStandalone: true, selector: "a[rdxMenuLinkItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitem" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "mouseup": "onMouseUp($event)", "click": "onItemClick($event)", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.tabindex": "rootContext?.isOpen() && highlighted() ? 0 : -1", "attr.data-disabled": "effectiveDisabled() ? \"\" : undefined", "attr.aria-disabled": "effectiveDisabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuLinkItem"], hostDirectives: [{ directive: i1$1.RdxCompositeListItem }], ngImport: i0 }); }
|
|
774
956
|
}
|
|
775
957
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLinkItem, decorators: [{
|
|
776
958
|
type: Directive,
|
|
777
959
|
args: [{
|
|
778
960
|
selector: 'a[rdxMenuLinkItem]',
|
|
779
961
|
exportAs: 'rdxMenuLinkItem',
|
|
962
|
+
hostDirectives: [RdxCompositeListItem],
|
|
780
963
|
host: {
|
|
781
964
|
role: 'menuitem',
|
|
782
|
-
tabindex: '-1',
|
|
965
|
+
'[attr.tabindex]': 'rootContext?.isOpen() && highlighted() ? 0 : -1',
|
|
783
966
|
'[attr.data-disabled]': 'effectiveDisabled() ? "" : undefined',
|
|
784
967
|
'[attr.aria-disabled]': 'effectiveDisabled() ? true : undefined',
|
|
785
968
|
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
@@ -790,22 +973,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
790
973
|
'(pointerleave)': 'onPointerLeave($event)',
|
|
791
974
|
'(mouseup)': 'onMouseUp($event)',
|
|
792
975
|
'(click)': 'onItemClick($event)',
|
|
793
|
-
'(keydown.enter)': 'onActivate($event)'
|
|
976
|
+
'(keydown.enter)': 'onActivate($event)',
|
|
977
|
+
'(keydown.space)': 'onActivate($event)'
|
|
794
978
|
}
|
|
795
979
|
}]
|
|
796
|
-
}], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
797
|
-
|
|
798
|
-
/** Selector for focusable menu items within a popup. */
|
|
799
|
-
const RDX_MENU_ITEM_SELECTOR = [
|
|
800
|
-
'[rdxMenuItem]:not([data-disabled])',
|
|
801
|
-
'[rdxMenuCheckboxItem]:not([data-disabled])',
|
|
802
|
-
'[rdxMenuRadioItem]:not([data-disabled])',
|
|
803
|
-
'[rdxMenuLinkItem]:not([data-disabled])',
|
|
804
|
-
'[rdxMenuSubTrigger]:not([data-disabled])'
|
|
805
|
-
].join(',');
|
|
806
|
-
function getFocusableMenuItems(popup) {
|
|
807
|
-
return Array.from(popup.querySelectorAll(RDX_MENU_ITEM_SELECTOR)).filter((item) => item.closest('[rdxMenuPopup]') === popup);
|
|
808
|
-
}
|
|
980
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
809
981
|
|
|
810
982
|
/**
|
|
811
983
|
* A container for the menu contents.
|
|
@@ -817,6 +989,7 @@ class RdxMenuPopup {
|
|
|
817
989
|
this.registration = inject(RDX_FLOATING_REGISTRATION, { optional: true });
|
|
818
990
|
this.focusManager = inject(RdxFloatingFocusManager);
|
|
819
991
|
this.focusScope = inject(RdxFocusScope);
|
|
992
|
+
this.compositeList = inject(RdxCompositeList, { self: true });
|
|
820
993
|
this.wrapper = inject(RdxPopperContentWrapper, { optional: true });
|
|
821
994
|
this.elementRef = inject(ElementRef);
|
|
822
995
|
this.search = '';
|
|
@@ -931,10 +1104,11 @@ class RdxMenuPopup {
|
|
|
931
1104
|
}
|
|
932
1105
|
}
|
|
933
1106
|
handleKeydown(event) {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const
|
|
1107
|
+
if (this.rootContext.disabled()) {
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
const items = this.menuItems();
|
|
1111
|
+
const currentIndex = this.currentItemIndex(items);
|
|
938
1112
|
switch (event.key) {
|
|
939
1113
|
case 'ArrowDown': {
|
|
940
1114
|
event.preventDefault();
|
|
@@ -945,7 +1119,7 @@ class RdxMenuPopup {
|
|
|
945
1119
|
? items[0]
|
|
946
1120
|
: items[items.length - 1]
|
|
947
1121
|
: items[currentIndex + 1];
|
|
948
|
-
next
|
|
1122
|
+
this.focusMenuItem(next);
|
|
949
1123
|
break;
|
|
950
1124
|
}
|
|
951
1125
|
case 'ArrowUp': {
|
|
@@ -957,19 +1131,19 @@ class RdxMenuPopup {
|
|
|
957
1131
|
? items[items.length - 1]
|
|
958
1132
|
: items[0]
|
|
959
1133
|
: items[currentIndex - 1];
|
|
960
|
-
prev
|
|
1134
|
+
this.focusMenuItem(prev);
|
|
961
1135
|
break;
|
|
962
1136
|
}
|
|
963
1137
|
case 'Home': {
|
|
964
1138
|
event.preventDefault();
|
|
965
1139
|
event.stopPropagation();
|
|
966
|
-
items[0]
|
|
1140
|
+
this.focusMenuItem(items[0]);
|
|
967
1141
|
break;
|
|
968
1142
|
}
|
|
969
1143
|
case 'End': {
|
|
970
1144
|
event.preventDefault();
|
|
971
1145
|
event.stopPropagation();
|
|
972
|
-
items[items.length - 1]
|
|
1146
|
+
this.focusMenuItem(items[items.length - 1]);
|
|
973
1147
|
break;
|
|
974
1148
|
}
|
|
975
1149
|
case 'ArrowLeft': {
|
|
@@ -1032,11 +1206,8 @@ class RdxMenuPopup {
|
|
|
1032
1206
|
const query = this.search.length > 1 && [...this.search].every((c) => c === char) ? char : this.search;
|
|
1033
1207
|
const startIndex = currentIndex >= 0 ? currentIndex + 1 : 0;
|
|
1034
1208
|
const rotated = [...items.slice(startIndex), ...items.slice(0, startIndex)];
|
|
1035
|
-
const match = rotated.find((item) =>
|
|
1036
|
-
|
|
1037
|
-
return text.startsWith(query);
|
|
1038
|
-
});
|
|
1039
|
-
match?.focus({ preventScroll: true });
|
|
1209
|
+
const match = rotated.find((item) => item.label.startsWith(query));
|
|
1210
|
+
this.focusMenuItem(match);
|
|
1040
1211
|
}
|
|
1041
1212
|
break;
|
|
1042
1213
|
}
|
|
@@ -1056,14 +1227,34 @@ class RdxMenuPopup {
|
|
|
1056
1227
|
if (activeElement && popup.contains(activeElement)) {
|
|
1057
1228
|
return;
|
|
1058
1229
|
}
|
|
1059
|
-
const items =
|
|
1230
|
+
const items = this.menuItems();
|
|
1060
1231
|
if (items.length === 0) {
|
|
1061
1232
|
if (attempt < maxAttempts) {
|
|
1062
1233
|
this.scheduleSubmenuKeyboardFocus(attempt + 1);
|
|
1063
1234
|
}
|
|
1064
1235
|
return;
|
|
1065
1236
|
}
|
|
1066
|
-
items[0]
|
|
1237
|
+
this.focusMenuItem(items[0]);
|
|
1238
|
+
}
|
|
1239
|
+
menuItems() {
|
|
1240
|
+
const compositeItems = getCompositeMenuItems(this.compositeList);
|
|
1241
|
+
return compositeItems.length > 0 ? compositeItems : getDomMenuItems(this.elementRef.nativeElement);
|
|
1242
|
+
}
|
|
1243
|
+
currentItemIndex(items) {
|
|
1244
|
+
const current = this.elementRef.nativeElement.ownerDocument.activeElement;
|
|
1245
|
+
const focusedIndex = items.findIndex((item) => item.element === current);
|
|
1246
|
+
if (focusedIndex !== -1) {
|
|
1247
|
+
return focusedIndex;
|
|
1248
|
+
}
|
|
1249
|
+
const activeIndex = this.rootContext.activeIndex();
|
|
1250
|
+
return items.findIndex((item) => item.index === activeIndex);
|
|
1251
|
+
}
|
|
1252
|
+
focusMenuItem(item) {
|
|
1253
|
+
if (!item) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
this.rootContext.setActiveIndex(item.index);
|
|
1257
|
+
item.element.focus({ preventScroll: true });
|
|
1067
1258
|
}
|
|
1068
1259
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1069
1260
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuPopup, isStandalone: true, selector: "[rdxMenuPopup]", outputs: { escapeKeyDown: "escapeKeyDown", pointerDownOutside: "pointerDownOutside", focusOutside: "focusOutside", interactOutside: "interactOutside", openAutoFocus: "openAutoFocus", closeAutoFocus: "closeAutoFocus" }, host: { attributes: { "role": "menu", "tabindex": "-1" }, listeners: { "keydown": "handleKeydown($event)", "rdx-menu-close-parent": "handleCloseParent($event)" }, properties: { "attr.aria-orientation": "rootContext.orientation()", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-starting-style": "rootContext.transitionStatus() === \"starting\" ? \"\" : undefined", "attr.data-ending-style": "rootContext.transitionStatus() === \"ending\" ? \"\" : undefined", "attr.data-align": "align()", "attr.data-side": "side()" } }, providers: [
|
|
@@ -1115,14 +1306,14 @@ class RdxMenuPopup {
|
|
|
1115
1306
|
closeInteractionType: () => rootContext.closeInteractionType()
|
|
1116
1307
|
};
|
|
1117
1308
|
})
|
|
1118
|
-
], exportAs: ["rdxMenuPopup"], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFloatingNodeRegistration }, { directive: i3.RdxFloatingFocusManager }], ngImport: i0 }); }
|
|
1309
|
+
], exportAs: ["rdxMenuPopup"], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxFloatingNodeRegistration }, { directive: i3.RdxFloatingFocusManager }, { directive: i1$1.RdxCompositeList }], ngImport: i0 }); }
|
|
1119
1310
|
}
|
|
1120
1311
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPopup, decorators: [{
|
|
1121
1312
|
type: Directive,
|
|
1122
1313
|
args: [{
|
|
1123
1314
|
selector: '[rdxMenuPopup]',
|
|
1124
1315
|
exportAs: 'rdxMenuPopup',
|
|
1125
|
-
hostDirectives: [RdxPopperContent, RdxFloatingNodeRegistration, RdxFloatingFocusManager],
|
|
1316
|
+
hostDirectives: [RdxPopperContent, RdxFloatingNodeRegistration, RdxFloatingFocusManager, RdxCompositeList],
|
|
1126
1317
|
providers: [
|
|
1127
1318
|
provideFloatingFocusManagerConfig(() => {
|
|
1128
1319
|
const rootContext = injectRdxMenuRootContext();
|
|
@@ -1201,7 +1392,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1201
1392
|
*/
|
|
1202
1393
|
class RdxMenuPortal {
|
|
1203
1394
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1204
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuPortal, isStandalone: true, selector: "ng-template[rdxMenuPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxMenuRootContext().present }))], exportAs: ["rdxMenuPortal"], hostDirectives: [{ directive: i1$
|
|
1395
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuPortal, isStandalone: true, selector: "ng-template[rdxMenuPortal]", providers: [provideRdxPresenceContext(() => ({ present: injectRdxMenuRootContext().present }))], exportAs: ["rdxMenuPortal"], hostDirectives: [{ directive: i1$2.RdxPortalPresence, inputs: ["container", "container"] }], ngImport: i0 }); }
|
|
1205
1396
|
}
|
|
1206
1397
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPortal, decorators: [{
|
|
1207
1398
|
type: Directive,
|
|
@@ -1399,6 +1590,7 @@ class RdxMenuRadioItem {
|
|
|
1399
1590
|
constructor() {
|
|
1400
1591
|
this.rootContext = injectRdxMenuRootContext(true);
|
|
1401
1592
|
this.radioGroupContext = injectRdxMenuRadioGroupContext();
|
|
1593
|
+
this.listItem = inject(RdxCompositeListItem, { self: true });
|
|
1402
1594
|
this.elementRef = inject(ElementRef);
|
|
1403
1595
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
1404
1596
|
/** The value of this radio item. */
|
|
@@ -1412,17 +1604,26 @@ class RdxMenuRadioItem {
|
|
|
1412
1604
|
/** Emits when this item is selected. */
|
|
1413
1605
|
this.onSelect = output();
|
|
1414
1606
|
this.checked = computed(() => this.radioGroupContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
1415
|
-
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
1607
|
+
this.highlighted = computed(() => this.rootContext?.activeIndex() === this.listItem.index() || this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
1416
1608
|
this.effectiveDisabled = computed(() => this.disabled() || this.radioGroupContext.disabled() || (this.rootContext?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
|
|
1417
1609
|
this.getCheckedState = getCheckedState;
|
|
1610
|
+
effect(() => {
|
|
1611
|
+
this.listItem.setMetadata({
|
|
1612
|
+
type: 'radio-item',
|
|
1613
|
+
disabled: this.effectiveDisabled(),
|
|
1614
|
+
label: this.label()
|
|
1615
|
+
});
|
|
1616
|
+
});
|
|
1418
1617
|
}
|
|
1419
1618
|
onFocus() {
|
|
1420
|
-
if (!this.
|
|
1619
|
+
if (!this.rootContext?.disabled()) {
|
|
1421
1620
|
this.isFocused.set(true);
|
|
1422
1621
|
}
|
|
1622
|
+
this.setActiveIndex();
|
|
1423
1623
|
}
|
|
1424
1624
|
onBlur() {
|
|
1425
1625
|
this.isFocused.set(false);
|
|
1626
|
+
this.clearActiveIndex();
|
|
1426
1627
|
}
|
|
1427
1628
|
onPointerMove(event) {
|
|
1428
1629
|
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.effectiveDisabled()) {
|
|
@@ -1431,6 +1632,7 @@ class RdxMenuRadioItem {
|
|
|
1431
1632
|
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
1432
1633
|
return;
|
|
1433
1634
|
}
|
|
1635
|
+
this.setActiveIndex();
|
|
1434
1636
|
if (this.elementRef.nativeElement.ownerDocument.activeElement !== this.elementRef.nativeElement) {
|
|
1435
1637
|
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
1436
1638
|
}
|
|
@@ -1440,6 +1642,8 @@ class RdxMenuRadioItem {
|
|
|
1440
1642
|
return;
|
|
1441
1643
|
}
|
|
1442
1644
|
if (this.elementRef.nativeElement.ownerDocument.activeElement === this.elementRef.nativeElement) {
|
|
1645
|
+
this.isFocused.set(false);
|
|
1646
|
+
this.clearActiveIndex();
|
|
1443
1647
|
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
1444
1648
|
}
|
|
1445
1649
|
}
|
|
@@ -1470,8 +1674,22 @@ class RdxMenuRadioItem {
|
|
|
1470
1674
|
if (this.closeOnClick())
|
|
1471
1675
|
this.rootContext?.closeEntireMenu();
|
|
1472
1676
|
}
|
|
1677
|
+
setActiveIndex() {
|
|
1678
|
+
if (!this.rootContext || this.rootContext.disabled()) {
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
const index = this.listItem.index();
|
|
1682
|
+
if (index !== -1) {
|
|
1683
|
+
this.rootContext.setActiveIndex(index);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
clearActiveIndex() {
|
|
1687
|
+
if (this.rootContext?.activeIndex() === this.listItem.index()) {
|
|
1688
|
+
this.rootContext.setActiveIndex(null);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1473
1691
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1474
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuRadioItem, isStandalone: true, selector: "[rdxMenuRadioItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitemradio"
|
|
1692
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuRadioItem, isStandalone: true, selector: "[rdxMenuRadioItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { attributes: { "role": "menuitemradio" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "mouseup": "onMouseUp($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.tabindex": "rootContext?.isOpen() && highlighted() ? 0 : -1", "attr.aria-checked": "checked()", "attr.data-state": "getCheckedState(checked())", "attr.data-disabled": "effectiveDisabled() ? \"\" : undefined", "attr.aria-disabled": "effectiveDisabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, providers: [provideRdxMenuRadioItemContext(radioItemContextFactory)], exportAs: ["rdxMenuRadioItem"], hostDirectives: [{ directive: i1$1.RdxCompositeListItem }], ngImport: i0 }); }
|
|
1475
1693
|
}
|
|
1476
1694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItem, decorators: [{
|
|
1477
1695
|
type: Directive,
|
|
@@ -1479,9 +1697,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1479
1697
|
selector: '[rdxMenuRadioItem]',
|
|
1480
1698
|
exportAs: 'rdxMenuRadioItem',
|
|
1481
1699
|
providers: [provideRdxMenuRadioItemContext(radioItemContextFactory)],
|
|
1700
|
+
hostDirectives: [RdxCompositeListItem],
|
|
1482
1701
|
host: {
|
|
1483
1702
|
role: 'menuitemradio',
|
|
1484
|
-
tabindex: '-1',
|
|
1703
|
+
'[attr.tabindex]': 'rootContext?.isOpen() && highlighted() ? 0 : -1',
|
|
1485
1704
|
'[attr.aria-checked]': 'checked()',
|
|
1486
1705
|
'[attr.data-state]': 'getCheckedState(checked())',
|
|
1487
1706
|
'[attr.data-disabled]': 'effectiveDisabled() ? "" : undefined',
|
|
@@ -1498,7 +1717,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1498
1717
|
'(keydown.space)': 'onActivate($event)'
|
|
1499
1718
|
}
|
|
1500
1719
|
}]
|
|
1501
|
-
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
1720
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
|
|
1502
1721
|
|
|
1503
1722
|
/**
|
|
1504
1723
|
* Renders when the parent radio item is selected.
|
|
@@ -1892,6 +2111,8 @@ class RdxMenuSubTrigger {
|
|
|
1892
2111
|
constructor() {
|
|
1893
2112
|
this.submenuContext = injectRdxMenuRootContext();
|
|
1894
2113
|
this.submenuRoot = inject(RdxMenuRoot);
|
|
2114
|
+
this.parentMenuRoot = this.submenuRoot.parentRoot;
|
|
2115
|
+
this.listItem = inject(RdxCompositeListItem, { self: true });
|
|
1895
2116
|
this.elementRef = inject(ElementRef);
|
|
1896
2117
|
this.destroyRef = inject(DestroyRef);
|
|
1897
2118
|
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
@@ -1913,8 +2134,10 @@ class RdxMenuSubTrigger {
|
|
|
1913
2134
|
this.closeDelay = input(0, { ...(ngDevMode ? { debugName: "closeDelay" } : /* istanbul ignore next */ {}), transform: numberOrUndefined$1 });
|
|
1914
2135
|
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
1915
2136
|
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1916
|
-
/** Highlighted when
|
|
1917
|
-
this.highlighted = computed(() => this.
|
|
2137
|
+
/** Highlighted when active in the parent menu or while the submenu is open. */
|
|
2138
|
+
this.highlighted = computed(() => this.parentMenuRoot?.activeIndex() === this.listItem.index() ||
|
|
2139
|
+
this.isFocused() ||
|
|
2140
|
+
this.submenuContext.isOpen(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
1918
2141
|
this.effectiveDisabled = computed(() => this.disabled() || this.submenuContext.disabled(), ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
|
|
1919
2142
|
this.nativeButtonState = computed(() => this.nativeButton() || this.elementRef.nativeElement.tagName === 'BUTTON', ...(ngDevMode ? [{ debugName: "nativeButtonState" }] : /* istanbul ignore next */ []));
|
|
1920
2143
|
this.submenuContext.markAsSubmenu();
|
|
@@ -1927,6 +2150,13 @@ class RdxMenuSubTrigger {
|
|
|
1927
2150
|
submenuRootsByTrigger.delete(el);
|
|
1928
2151
|
});
|
|
1929
2152
|
});
|
|
2153
|
+
effect(() => {
|
|
2154
|
+
this.listItem.setMetadata({
|
|
2155
|
+
type: 'submenu-trigger',
|
|
2156
|
+
disabled: this.effectiveDisabled(),
|
|
2157
|
+
label: this.label()
|
|
2158
|
+
});
|
|
2159
|
+
});
|
|
1930
2160
|
// While this submenu is open by hover, it owns the decision to close itself: a document
|
|
1931
2161
|
// `mousemove` handler keeps it open while the cursor traverses the safe polygon toward the
|
|
1932
2162
|
// popup, and a pointer-events tunnel stops siblings from stealing it mid-traversal.
|
|
@@ -1988,13 +2218,16 @@ class RdxMenuSubTrigger {
|
|
|
1988
2218
|
}
|
|
1989
2219
|
}
|
|
1990
2220
|
onFocus() {
|
|
1991
|
-
if (
|
|
1992
|
-
|
|
1993
|
-
this.isFocused.set(true);
|
|
2221
|
+
if (this.submenuContext.disabled()) {
|
|
2222
|
+
return;
|
|
1994
2223
|
}
|
|
2224
|
+
this.clearSiblingHighlights();
|
|
2225
|
+
this.isFocused.set(true);
|
|
2226
|
+
this.setParentActiveIndex();
|
|
1995
2227
|
}
|
|
1996
2228
|
onBlur() {
|
|
1997
2229
|
this.isFocused.set(false);
|
|
2230
|
+
this.clearParentActiveIndex();
|
|
1998
2231
|
}
|
|
1999
2232
|
onClick(event) {
|
|
2000
2233
|
if (this.effectiveDisabled())
|
|
@@ -2077,6 +2310,7 @@ class RdxMenuSubTrigger {
|
|
|
2077
2310
|
return;
|
|
2078
2311
|
this.lastPointer = { x: event.clientX, y: event.clientY };
|
|
2079
2312
|
this.clearSiblingHighlights();
|
|
2313
|
+
this.setParentActiveIndex();
|
|
2080
2314
|
const el = this.elementRef.nativeElement;
|
|
2081
2315
|
if (this.submenuContext.highlightItemOnHover() && el.ownerDocument.activeElement !== el) {
|
|
2082
2316
|
el.focus({ preventScroll: true });
|
|
@@ -2095,6 +2329,7 @@ class RdxMenuSubTrigger {
|
|
|
2095
2329
|
}
|
|
2096
2330
|
clearHighlight() {
|
|
2097
2331
|
this.isFocused.set(false);
|
|
2332
|
+
this.clearParentActiveIndex();
|
|
2098
2333
|
}
|
|
2099
2334
|
closeSiblingSubmenus() {
|
|
2100
2335
|
const currentTrigger = this.elementRef.nativeElement;
|
|
@@ -2154,23 +2389,34 @@ class RdxMenuSubTrigger {
|
|
|
2154
2389
|
setTimeout(run);
|
|
2155
2390
|
}
|
|
2156
2391
|
}
|
|
2392
|
+
setParentActiveIndex() {
|
|
2393
|
+
const index = this.listItem.index();
|
|
2394
|
+
if (index === -1 || !this.parentMenuRoot || this.parentMenuRoot.effectiveDisabled()) {
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2397
|
+
this.parentMenuRoot.setActiveIndex(index);
|
|
2398
|
+
}
|
|
2399
|
+
clearParentActiveIndex() {
|
|
2400
|
+
if (this.parentMenuRoot?.activeIndex() === this.listItem.index()) {
|
|
2401
|
+
this.parentMenuRoot.setActiveIndex(null);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2157
2404
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSubTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2158
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuSubTrigger, isStandalone: true, selector: "[rdxMenuSubTrigger]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, nativeButton: { classPropertyName: "nativeButton", publicName: "nativeButton", 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 }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem"
|
|
2405
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuSubTrigger, isStandalone: true, selector: "[rdxMenuSubTrigger]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, nativeButton: { classPropertyName: "nativeButton", publicName: "nativeButton", 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 }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "click": "onClick($event)", "keydown.enter": "onEnter($event)", "keydown.space": "onEnter($event)", "keydown.arrowleft": "onArrowLeft($event)", "keydown.arrowright": "onArrowRight($event)", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave()", "rdx-menu-subtrigger-clear-highlight": "clearHighlight()" }, properties: { "attr.type": "nativeButtonState() ? \"button\" : undefined", "attr.tabindex": "parentMenuRoot?.open() && highlighted() ? 0 : -1", "attr.aria-haspopup": "\"menu\"", "attr.aria-expanded": "submenuContext.isOpen()", "attr.aria-disabled": "effectiveDisabled() ? true : undefined", "attr.data-state": "submenuContext.isOpen() ? \"open\" : \"closed\"", "attr.data-popup-open": "submenuContext.isOpen() ? \"\" : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-disabled": "effectiveDisabled() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuSubTrigger"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i1$1.RdxCompositeListItem }], ngImport: i0 }); }
|
|
2159
2406
|
}
|
|
2160
2407
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSubTrigger, decorators: [{
|
|
2161
2408
|
type: Directive,
|
|
2162
2409
|
args: [{
|
|
2163
2410
|
selector: '[rdxMenuSubTrigger]',
|
|
2164
2411
|
exportAs: 'rdxMenuSubTrigger',
|
|
2165
|
-
hostDirectives: [RdxPopperAnchor],
|
|
2412
|
+
hostDirectives: [RdxPopperAnchor, RdxCompositeListItem],
|
|
2166
2413
|
host: {
|
|
2167
2414
|
'[attr.type]': 'nativeButtonState() ? "button" : undefined',
|
|
2168
2415
|
role: 'menuitem',
|
|
2169
|
-
tabindex: '-1',
|
|
2416
|
+
'[attr.tabindex]': 'parentMenuRoot?.open() && highlighted() ? 0 : -1',
|
|
2170
2417
|
'[attr.aria-haspopup]': '"menu"',
|
|
2171
2418
|
'[attr.aria-expanded]': 'submenuContext.isOpen()',
|
|
2172
2419
|
'[attr.aria-disabled]': 'effectiveDisabled() ? true : undefined',
|
|
2173
|
-
'[attr.disabled]': 'nativeButtonState() && effectiveDisabled() ? "" : undefined',
|
|
2174
2420
|
'[attr.data-state]': 'submenuContext.isOpen() ? "open" : "closed"',
|
|
2175
2421
|
'[attr.data-popup-open]': 'submenuContext.isOpen() ? "" : undefined',
|
|
2176
2422
|
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
@@ -2180,6 +2426,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2180
2426
|
'(blur)': 'onBlur()',
|
|
2181
2427
|
'(click)': 'onClick($event)',
|
|
2182
2428
|
'(keydown.enter)': 'onEnter($event)',
|
|
2429
|
+
'(keydown.space)': 'onEnter($event)',
|
|
2183
2430
|
'(keydown.arrowleft)': 'onArrowLeft($event)',
|
|
2184
2431
|
'(keydown.arrowright)': 'onArrowRight($event)',
|
|
2185
2432
|
'(pointermove)': 'onPointerMove($event)',
|
|
@@ -2203,6 +2450,7 @@ class RdxMenuTrigger {
|
|
|
2203
2450
|
this.openedByHover = false;
|
|
2204
2451
|
this.ignoreNextClick = null;
|
|
2205
2452
|
this.handleDocumentMouseUp = (event) => {
|
|
2453
|
+
clearTimeout(this.allowMouseUpTriggerTimer);
|
|
2206
2454
|
this.allowMouseUpTriggerTimer = undefined;
|
|
2207
2455
|
this.rootContext.setAllowMouseUpTrigger(false);
|
|
2208
2456
|
const trigger = this.elementRef.nativeElement;
|
|
@@ -2492,7 +2740,7 @@ class RdxMenuTrigger {
|
|
|
2492
2740
|
}
|
|
2493
2741
|
}
|
|
2494
2742
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2495
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuTrigger, isStandalone: true, selector: "[rdxMenuTrigger]", inputs: { nativeButton: { classPropertyName: "nativeButton", publicName: "nativeButton", 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: { listeners: { "pointerdown": "handlePointerDown($event)", "mousedown": "handleMouseDown($event)", "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointermove": "handlePointerMove($event)", "pointerleave": "handlePointerLeave($event)", "keydown.arrowdown": "handleArrowDown($event)", "keydown.arrowup": "handleArrowUp($event)", "keydown.arrowleft": "handleArrowLeft($event)", "keydown.arrowright": "handleArrowRight($event)", "keydown.home": "handleHome($event)", "keydown.end": "handleEnd($event)", "keydown.escape": "handleEscape($event)", "keydown.enter": "handleKeyboardToggle($event)", "keydown.space": "handleKeyboardToggle($event)" }, properties: { "attr.type": "nativeButtonState() ? \"button\" : undefined", "attr.role": "rootContext.hasTriggerInteractionHandler() ? \"menuitem\" : nativeButtonState() ? undefined : \"button\"", "attr.
|
|
2743
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuTrigger, isStandalone: true, selector: "[rdxMenuTrigger]", inputs: { nativeButton: { classPropertyName: "nativeButton", publicName: "nativeButton", 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: { listeners: { "pointerdown": "handlePointerDown($event)", "mousedown": "handleMouseDown($event)", "click": "handleClick($event)", "pointerenter": "handlePointerEnter($event)", "pointermove": "handlePointerMove($event)", "pointerleave": "handlePointerLeave($event)", "keydown.arrowdown": "handleArrowDown($event)", "keydown.arrowup": "handleArrowUp($event)", "keydown.arrowleft": "handleArrowLeft($event)", "keydown.arrowright": "handleArrowRight($event)", "keydown.home": "handleHome($event)", "keydown.end": "handleEnd($event)", "keydown.escape": "handleEscape($event)", "keydown.enter": "handleKeyboardToggle($event)", "keydown.space": "handleKeyboardToggle($event)" }, properties: { "attr.type": "nativeButtonState() ? \"button\" : undefined", "attr.role": "rootContext.hasTriggerInteractionHandler() ? \"menuitem\" : nativeButtonState() ? undefined : \"button\"", "attr.aria-haspopup": "\"menu\"", "attr.aria-expanded": "triggerInteraction.ariaExpanded()", "attr.aria-disabled": "isDisabled() ? true : undefined", "attr.disabled": "nativeButtonState() && isDisabled() ? \"\" : undefined", "attr.data-state": "triggerInteraction.dataState()", "attr.data-disabled": "isDisabled() ? \"\" : undefined", "attr.data-popup-open": "triggerInteraction.dataPopupOpen()", "style.pointer-events": "rootContext.isOpen() && rootContext.modal() ? \"auto\" : undefined" } }, exportAs: ["rdxMenuTrigger"], hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
|
|
2496
2744
|
}
|
|
2497
2745
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuTrigger, decorators: [{
|
|
2498
2746
|
type: Directive,
|
|
@@ -2503,7 +2751,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2503
2751
|
host: {
|
|
2504
2752
|
'[attr.type]': 'nativeButtonState() ? "button" : undefined',
|
|
2505
2753
|
'[attr.role]': 'rootContext.hasTriggerInteractionHandler() ? "menuitem" : nativeButtonState() ? undefined : "button"',
|
|
2506
|
-
'[attr.tabindex]': 'rootContext.hasTriggerInteractionHandler() ? "-1" : undefined',
|
|
2507
2754
|
'[attr.aria-haspopup]': '"menu"',
|
|
2508
2755
|
'[attr.aria-expanded]': 'triggerInteraction.ariaExpanded()',
|
|
2509
2756
|
'[attr.aria-disabled]': 'isDisabled() ? true : undefined',
|