@radix-ng/primitives 0.51.0 → 1.0.0-beta.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/fesm2022/radix-ng-primitives-accordion.mjs +105 -38
- package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs +221 -129
- package/fesm2022/radix-ng-primitives-alert-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-arrow.mjs +20 -4
- package/fesm2022/radix-ng-primitives-arrow.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-aspect-ratio.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-avatar.mjs +54 -61
- package/fesm2022/radix-ng-primitives-avatar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-button.mjs +123 -0
- package/fesm2022/radix-ng-primitives-button.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-calendar.mjs +95 -83
- package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-checkbox.mjs +378 -54
- package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-collapsible.mjs +182 -81
- package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-collection.mjs +40 -57
- package/fesm2022/radix-ng-primitives-collection.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-config.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-context-menu.mjs +140 -424
- package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-core.mjs +845 -744
- package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-cropper.mjs +288 -308
- package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-date-field.mjs +104 -58
- package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-dialog.mjs +655 -327
- package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs +70 -46
- package/fesm2022/radix-ng-primitives-dismissable-layer.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-drawer.mjs +960 -0
- package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-editable.mjs +304 -23
- package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-field.mjs +363 -0
- package/fesm2022/radix-ng-primitives-field.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-fieldset.mjs +79 -0
- package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-focus-scope.mjs +23 -8
- package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-input.mjs +172 -0
- package/fesm2022/radix-ng-primitives-input.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-label.mjs +6 -6
- package/fesm2022/radix-ng-primitives-label.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menu.mjs +1907 -363
- package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-menubar.mjs +290 -162
- package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-meter.mjs +271 -0
- package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1052 -1553
- package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-number-field.mjs +1102 -367
- package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-pagination.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popover.mjs +978 -989
- package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-popper.mjs +111 -44
- package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-portal.mjs +34 -10
- package/fesm2022/radix-ng-primitives-portal.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-presence.mjs +134 -246
- package/fesm2022/radix-ng-primitives-presence.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-preview-card.mjs +997 -0
- package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-progress.mjs +223 -84
- package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-radio.mjs +191 -51
- package/fesm2022/radix-ng-primitives-radio.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-roving-focus.mjs +96 -50
- package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-scroll-area.mjs +923 -0
- package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-select.mjs +791 -509
- package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-separator.mjs +12 -35
- package/fesm2022/radix-ng-primitives-separator.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-slider.mjs +969 -717
- package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-stepper.mjs +15 -19
- package/fesm2022/radix-ng-primitives-stepper.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-switch.mjs +125 -113
- package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tabs.mjs +390 -108
- package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-time-field.mjs +55 -46
- package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toast.mjs +839 -0
- package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -0
- package/fesm2022/radix-ng-primitives-toggle-group.mjs +121 -247
- package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toggle.mjs +98 -61
- package/fesm2022/radix-ng-primitives-toggle.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-toolbar.mjs +303 -92
- package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-tooltip.mjs +699 -1072
- package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
- package/fesm2022/radix-ng-primitives-visually-hidden.mjs +25 -66
- package/fesm2022/radix-ng-primitives-visually-hidden.mjs.map +1 -1
- package/meter/README.md +3 -0
- package/navigation-menu/README.md +2 -1
- package/package.json +39 -18
- package/portal/README.md +2 -0
- package/preview-card/README.md +3 -0
- package/schematics/collection.json +1 -0
- package/schematics/ng-add/index.d.ts +3 -2
- package/schematics/ng-add/index.js +62 -31
- package/schematics/ng-add/index.js.map +1 -1
- package/schematics/ng-add/package-config.d.ts +4 -2
- package/schematics/ng-add/package-config.js +10 -2
- package/schematics/ng-add/package-config.js.map +1 -1
- package/schematics/ng-add/schema.d.ts +3 -0
- package/schematics/ng-add/schema.js +3 -0
- package/schematics/ng-add/schema.js.map +1 -0
- package/schematics/ng-add/schema.json +14 -0
- package/select/README.md +2 -0
- package/types/radix-ng-primitives-accordion.d.ts +51 -16
- package/types/radix-ng-primitives-alert-dialog.d.ts +95 -38
- package/types/radix-ng-primitives-arrow.d.ts +1 -1
- package/types/radix-ng-primitives-aspect-ratio.d.ts +1 -1
- package/types/radix-ng-primitives-avatar.d.ts +7 -11
- package/types/radix-ng-primitives-button.d.ts +73 -0
- package/types/radix-ng-primitives-calendar.d.ts +39 -20
- package/types/radix-ng-primitives-checkbox.d.ts +204 -35
- package/types/radix-ng-primitives-collapsible.d.ts +114 -40
- package/types/radix-ng-primitives-collection.d.ts +38 -34
- package/types/radix-ng-primitives-config.d.ts +1 -1
- package/types/radix-ng-primitives-context-menu.d.ts +61 -116
- package/types/radix-ng-primitives-core.d.ts +345 -235
- package/types/radix-ng-primitives-cropper.d.ts +89 -56
- package/types/radix-ng-primitives-date-field.d.ts +49 -28
- package/types/radix-ng-primitives-dialog.d.ts +283 -165
- package/types/radix-ng-primitives-dismissable-layer.d.ts +15 -7
- package/types/radix-ng-primitives-drawer.d.ts +426 -0
- package/types/radix-ng-primitives-editable.d.ts +91 -14
- package/types/radix-ng-primitives-field.d.ts +374 -0
- package/types/radix-ng-primitives-fieldset.d.ts +49 -0
- package/types/radix-ng-primitives-focus-scope.d.ts +15 -6
- package/types/radix-ng-primitives-input.d.ts +87 -0
- package/types/radix-ng-primitives-label.d.ts +0 -1
- package/types/radix-ng-primitives-menu.d.ts +584 -99
- package/types/radix-ng-primitives-menubar.d.ts +61 -50
- package/types/radix-ng-primitives-meter.d.ts +194 -0
- package/types/radix-ng-primitives-navigation-menu.d.ts +422 -340
- package/types/radix-ng-primitives-number-field.d.ts +405 -145
- package/types/radix-ng-primitives-pagination.d.ts +2 -2
- package/types/radix-ng-primitives-popover.d.ts +366 -351
- package/types/radix-ng-primitives-popper.d.ts +68 -11
- package/types/radix-ng-primitives-portal.d.ts +14 -6
- package/types/radix-ng-primitives-presence.d.ts +28 -76
- package/types/radix-ng-primitives-preview-card.d.ts +359 -0
- package/types/radix-ng-primitives-progress.d.ts +175 -48
- package/types/radix-ng-primitives-radio.d.ts +55 -25
- package/types/radix-ng-primitives-roving-focus.d.ts +33 -23
- package/types/radix-ng-primitives-scroll-area.d.ts +253 -0
- package/types/radix-ng-primitives-select.d.ts +475 -177
- package/types/radix-ng-primitives-separator.d.ts +7 -32
- package/types/radix-ng-primitives-slider.d.ts +315 -201
- package/types/radix-ng-primitives-stepper.d.ts +5 -7
- package/types/radix-ng-primitives-switch.d.ts +86 -71
- package/types/radix-ng-primitives-tabs.d.ts +213 -79
- package/types/radix-ng-primitives-time-field.d.ts +42 -27
- package/types/radix-ng-primitives-toast.d.ts +378 -0
- package/types/radix-ng-primitives-toggle-group.d.ts +86 -164
- package/types/radix-ng-primitives-toggle.d.ts +43 -53
- package/types/radix-ng-primitives-toolbar.d.ts +164 -38
- package/types/radix-ng-primitives-tooltip.d.ts +348 -384
- package/types/radix-ng-primitives-visually-hidden.d.ts +19 -19
- package/dropdown-menu/README.md +0 -1
- package/fesm2022/radix-ng-primitives-dropdown-menu.mjs +0 -581
- package/fesm2022/radix-ng-primitives-dropdown-menu.mjs.map +0 -1
- package/fesm2022/radix-ng-primitives-hover-card.mjs +0 -1238
- package/fesm2022/radix-ng-primitives-hover-card.mjs.map +0 -1
- package/fesm2022/radix-ng-primitives-select2.mjs +0 -897
- package/fesm2022/radix-ng-primitives-select2.mjs.map +0 -1
- package/fesm2022/radix-ng-primitives-tooltip2.mjs +0 -735
- package/fesm2022/radix-ng-primitives-tooltip2.mjs.map +0 -1
- package/hover-card/README.md +0 -3
- package/select2/README.md +0 -3
- package/tooltip2/README.md +0 -3
- package/types/radix-ng-primitives-dropdown-menu.d.ts +0 -171
- package/types/radix-ng-primitives-hover-card.d.ts +0 -471
- package/types/radix-ng-primitives-select2.d.ts +0 -511
- package/types/radix-ng-primitives-tooltip2.d.ts +0 -325
|
@@ -1,48 +1,248 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
import * as i1 from '@
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { inject, model, input, booleanAttribute, output, signal, computed, effect, untracked, Directive, ElementRef, DestroyRef, numberAttribute, PLATFORM_ID, afterNextRender, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1 from '@radix-ng/primitives/popper';
|
|
4
|
+
import { RdxPopper, RdxPopperContentWrapper, RdxPopperArrow, RdxPopperContent, provideRdxPopperContentConfig, RdxPopperAnchor } from '@radix-ng/primitives/popper';
|
|
5
|
+
import { createContext, useTransitionStatus, getMaxTransitionDuration } from '@radix-ng/primitives/core';
|
|
6
|
+
import { outputFromObservable, outputToObservable } from '@angular/core/rxjs-interop';
|
|
7
|
+
import * as i2 from '@radix-ng/primitives/dismissable-layer';
|
|
8
|
+
import { RdxDismissableLayer, RdxDismissableLayersContextToken, provideRdxDismissableLayerConfig, RdxDismissableLayerBranch } from '@radix-ng/primitives/dismissable-layer';
|
|
9
|
+
import * as i3 from '@radix-ng/primitives/focus-scope';
|
|
10
|
+
import { RdxFocusScope, provideRdxFocusScopeConfig } from '@radix-ng/primitives/focus-scope';
|
|
11
|
+
import * as i1$1 from '@radix-ng/primitives/portal';
|
|
12
|
+
import { RdxPortal } from '@radix-ng/primitives/portal';
|
|
13
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
const [injectRdxMenuRootContext, provideRdxMenuRootContext] = createContext('RdxMenuRootContext');
|
|
16
|
+
function buildContext(instance) {
|
|
17
|
+
return {
|
|
18
|
+
isOpen: instance.open,
|
|
19
|
+
disabled: instance.disabled,
|
|
20
|
+
modal: instance.modal,
|
|
21
|
+
loopFocus: instance.loopFocus,
|
|
22
|
+
highlightItemOnHover: instance.highlightItemOnHover,
|
|
23
|
+
orientation: instance.orientation,
|
|
24
|
+
closeParentOnEsc: instance.closeParentOnEsc,
|
|
25
|
+
autoFocus: instance.autoFocus.asReadonly(),
|
|
26
|
+
isSubmenu: instance.isSubmenu.asReadonly(),
|
|
27
|
+
hasTriggerInteractionHandler: instance.hasTriggerInteractionHandler.asReadonly(),
|
|
28
|
+
trigger: instance.trigger.asReadonly(),
|
|
29
|
+
popupElement: instance.popupElement.asReadonly(),
|
|
30
|
+
transitionStatus: instance.transitionStatus,
|
|
31
|
+
close: () => instance.close(),
|
|
32
|
+
toggle: () => instance.toggle(),
|
|
33
|
+
show: (autoFocus) => instance.show(autoFocus),
|
|
34
|
+
showWithoutAutoFocus: () => instance.show(false),
|
|
35
|
+
registerTrigger: (el) => instance.registerTrigger(el),
|
|
36
|
+
registerPopup: (el) => instance.registerPopup(el),
|
|
37
|
+
registerTransitionElement: (el) => instance.registerTransitionElement(el),
|
|
38
|
+
registerPopupArrowNavigationHandler: (handler) => instance.registerPopupArrowNavigationHandler(handler),
|
|
39
|
+
registerTriggerInteractionHandler: (handler) => instance.registerTriggerInteractionHandler(handler),
|
|
40
|
+
markAsSubmenu: () => instance.markAsSubmenu(),
|
|
41
|
+
closeParent: () => instance.closeParent(),
|
|
42
|
+
handlePopupArrowNavigation: (offset) => instance.handlePopupArrowNavigation(offset),
|
|
43
|
+
handleTriggerInteraction: (interaction) => instance.handleTriggerInteraction(interaction)
|
|
44
|
+
};
|
|
10
45
|
}
|
|
11
|
-
|
|
46
|
+
const contextFactory = () => buildContext(inject(RdxMenuRoot));
|
|
47
|
+
/**
|
|
48
|
+
* Groups all parts of a menu.
|
|
49
|
+
*/
|
|
50
|
+
class RdxMenuRoot {
|
|
51
|
+
constructor() {
|
|
52
|
+
this.popper = inject(RdxPopper);
|
|
53
|
+
/** Shared open/close transition state machine (completes on the real animationend). */
|
|
54
|
+
this.transition = useTransitionStatus((open) => this.onOpenChangeComplete.emit(open));
|
|
55
|
+
this.hasAppliedDefaultOpen = false;
|
|
56
|
+
/** Whether the menu is currently open. */
|
|
57
|
+
this.open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
58
|
+
/** Whether the menu is initially open. */
|
|
59
|
+
this.defaultOpen = input(false, { ...(ngDevMode ? { debugName: "defaultOpen" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
60
|
+
/** Whether interactions with the menu are disabled. */
|
|
61
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
62
|
+
/** Whether the menu should block outside interactions. */
|
|
63
|
+
this.modal = input(false, { ...(ngDevMode ? { debugName: "modal" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
64
|
+
/** Whether keyboard navigation wraps at list boundaries. */
|
|
65
|
+
this.loopFocus = input(true, { ...(ngDevMode ? { debugName: "loopFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
66
|
+
/** Whether moving the pointer over items should highlight them. */
|
|
67
|
+
this.highlightItemOnHover = input(true, { ...(ngDevMode ? { debugName: "highlightItemOnHover" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
68
|
+
/** The menu orientation. */
|
|
69
|
+
this.orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
70
|
+
/** Whether pressing Escape inside a submenu closes the whole menu chain. */
|
|
71
|
+
this.closeParentOnEsc = input(false, { ...(ngDevMode ? { debugName: "closeParentOnEsc" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
72
|
+
/** Emits when the open state changes. */
|
|
73
|
+
this.onOpenChange = output();
|
|
74
|
+
/** Emits when the open/close CSS transition or animation finishes. */
|
|
75
|
+
this.onOpenChangeComplete = output();
|
|
76
|
+
this.trigger = signal(undefined, ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
|
|
77
|
+
this.popupElement = signal(undefined, ...(ngDevMode ? [{ debugName: "popupElement" }] : /* istanbul ignore next */ []));
|
|
78
|
+
this.transitionStatus = this.transition.status;
|
|
79
|
+
/** Whether the popup grabs focus when it opens. Set false for menubar hover-switching. */
|
|
80
|
+
this.autoFocus = signal('first', ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
|
|
81
|
+
this.isSubmenu = signal(false, ...(ngDevMode ? [{ debugName: "isSubmenu" }] : /* istanbul ignore next */ []));
|
|
82
|
+
this.hasTriggerInteractionHandler = signal(false, ...(ngDevMode ? [{ debugName: "hasTriggerInteractionHandler" }] : /* istanbul ignore next */ []));
|
|
83
|
+
this.state = computed(() => (this.open() ? 'open' : 'closed'), ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
84
|
+
effect(() => {
|
|
85
|
+
const defaultOpen = this.defaultOpen();
|
|
86
|
+
if (!this.hasAppliedDefaultOpen && defaultOpen) {
|
|
87
|
+
this.hasAppliedDefaultOpen = true;
|
|
88
|
+
this.open.set(defaultOpen);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
effect(() => this.popper.anchorOverride.set(this.trigger()));
|
|
92
|
+
let previousOpen = this.open();
|
|
93
|
+
effect(() => {
|
|
94
|
+
const open = this.open();
|
|
95
|
+
if (open !== previousOpen) {
|
|
96
|
+
previousOpen = open;
|
|
97
|
+
untracked(() => this.transition.start(open));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
show(autoFocus = 'first') {
|
|
102
|
+
if (this.disabled()) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.autoFocus.set(autoFocus === true ? 'first' : autoFocus);
|
|
106
|
+
if (!this.open()) {
|
|
107
|
+
this.open.set(true);
|
|
108
|
+
this.onOpenChange.emit(true);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
close() {
|
|
112
|
+
if (this.open()) {
|
|
113
|
+
this.open.set(false);
|
|
114
|
+
this.onOpenChange.emit(false);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
toggle() {
|
|
118
|
+
if (this.disabled()) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (this.open()) {
|
|
122
|
+
this.close();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.show();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
registerTrigger(el) {
|
|
129
|
+
this.registeredTrigger = el;
|
|
130
|
+
this.trigger.set(el);
|
|
131
|
+
return () => {
|
|
132
|
+
if (this.registeredTrigger === el) {
|
|
133
|
+
this.registeredTrigger = undefined;
|
|
134
|
+
this.trigger.set(undefined);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
registerPopup(el) {
|
|
139
|
+
this.popupElement.set(el);
|
|
140
|
+
return () => {
|
|
141
|
+
if (this.popupElement() === el) {
|
|
142
|
+
this.popupElement.set(undefined);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
registerTransitionElement(element) {
|
|
147
|
+
return this.transition.registerElement(element);
|
|
148
|
+
}
|
|
149
|
+
registerPopupArrowNavigationHandler(handler) {
|
|
150
|
+
this.popupArrowNavigationHandler = handler;
|
|
151
|
+
return () => {
|
|
152
|
+
if (this.popupArrowNavigationHandler === handler) {
|
|
153
|
+
this.popupArrowNavigationHandler = undefined;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
handlePopupArrowNavigation(offset) {
|
|
158
|
+
return this.popupArrowNavigationHandler?.(offset) ?? false;
|
|
159
|
+
}
|
|
160
|
+
registerTriggerInteractionHandler(handler) {
|
|
161
|
+
this.triggerInteractionHandler = handler;
|
|
162
|
+
this.hasTriggerInteractionHandler.set(true);
|
|
163
|
+
return () => {
|
|
164
|
+
if (this.triggerInteractionHandler === handler) {
|
|
165
|
+
this.triggerInteractionHandler = undefined;
|
|
166
|
+
this.hasTriggerInteractionHandler.set(false);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
handleTriggerInteraction(interaction) {
|
|
171
|
+
return this.triggerInteractionHandler?.(interaction) ?? false;
|
|
172
|
+
}
|
|
173
|
+
markAsSubmenu() {
|
|
174
|
+
this.isSubmenu.set(true);
|
|
175
|
+
}
|
|
176
|
+
closeParent() {
|
|
177
|
+
this.trigger()?.dispatchEvent(new CustomEvent('rdx-menu-close-parent', { bubbles: true }));
|
|
178
|
+
}
|
|
179
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
180
|
+
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 }, closeParentOnEsc: { classPropertyName: "closeParentOnEsc", publicName: "closeParentOnEsc", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", onOpenChange: "onOpenChange", onOpenChangeComplete: "onOpenChangeComplete" }, providers: [provideRdxMenuRootContext(contextFactory)], exportAs: ["rdxMenuRoot"], hostDirectives: [{ directive: i1.RdxPopper }], ngImport: i0 }); }
|
|
181
|
+
}
|
|
182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRoot, decorators: [{
|
|
12
183
|
type: Directive,
|
|
13
184
|
args: [{
|
|
14
|
-
selector: '[
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'[attr.aria-orientation]': '"vertical"'
|
|
19
|
-
}
|
|
185
|
+
selector: '[rdxMenuRoot],[rdxMenuSubmenuRoot]',
|
|
186
|
+
exportAs: 'rdxMenuRoot',
|
|
187
|
+
providers: [provideRdxMenuRootContext(contextFactory)],
|
|
188
|
+
hostDirectives: [RdxPopper]
|
|
20
189
|
}]
|
|
21
|
-
}] });
|
|
190
|
+
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], defaultOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultOpen", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], loopFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "loopFocus", required: false }] }], highlightItemOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightItemOnHover", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], closeParentOnEsc: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeParentOnEsc", required: false }] }], onOpenChange: [{ type: i0.Output, args: ["onOpenChange"] }], onOpenChangeComplete: [{ type: i0.Output, args: ["onOpenChangeComplete"] }] } });
|
|
22
191
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
192
|
+
/**
|
|
193
|
+
* An optional visual arrow connecting the popup to its trigger.
|
|
194
|
+
* Place it inside `rdxMenuPopup`. Positioning is handled by the shared Popper Arrow primitive.
|
|
195
|
+
*/
|
|
196
|
+
class RdxMenuArrow {
|
|
197
|
+
constructor() {
|
|
198
|
+
this.rootContext = injectRdxMenuRootContext();
|
|
199
|
+
this.wrapper = inject(RdxPopperContentWrapper, { optional: true });
|
|
200
|
+
this.side = computed(() => this.wrapper?.placedSide(), ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
201
|
+
this.align = computed(() => this.wrapper?.placedAlign(), ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
202
|
+
this.uncentered = computed(() => this.wrapper?.arrowUncentered() ?? false, ...(ngDevMode ? [{ debugName: "uncentered" }] : /* istanbul ignore next */ []));
|
|
203
|
+
}
|
|
204
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuArrow, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
205
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuArrow, isStandalone: true, selector: "[rdxMenuArrow]", host: { properties: { "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-side": "side()", "attr.data-align": "align()", "attr.data-uncentered": "uncentered() ? \"\" : undefined" } }, exportAs: ["rdxMenuArrow"], hostDirectives: [{ directive: i1.RdxPopperArrow }], ngImport: i0 }); }
|
|
26
206
|
}
|
|
27
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuArrow, decorators: [{
|
|
28
208
|
type: Directive,
|
|
29
209
|
args: [{
|
|
30
|
-
selector: '[
|
|
31
|
-
|
|
210
|
+
selector: '[rdxMenuArrow]',
|
|
211
|
+
exportAs: 'rdxMenuArrow',
|
|
212
|
+
hostDirectives: [RdxPopperArrow],
|
|
213
|
+
host: {
|
|
214
|
+
'[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
215
|
+
'[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
|
|
216
|
+
'[attr.data-side]': 'side()',
|
|
217
|
+
'[attr.data-align]': 'align()',
|
|
218
|
+
'[attr.data-uncentered]': 'uncentered() ? "" : undefined'
|
|
219
|
+
}
|
|
32
220
|
}]
|
|
33
221
|
}] });
|
|
34
222
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
223
|
+
/**
|
|
224
|
+
* An optional overlay rendered behind the menu popup.
|
|
225
|
+
* Style it with `position: fixed; inset: 0` and use `data-open` / `data-closed`
|
|
226
|
+
* for CSS animations.
|
|
227
|
+
*/
|
|
228
|
+
class RdxMenuBackdrop {
|
|
229
|
+
constructor() {
|
|
230
|
+
this.rootContext = injectRdxMenuRootContext();
|
|
231
|
+
}
|
|
232
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
233
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuBackdrop, isStandalone: true, selector: "[rdxMenuBackdrop]", host: { properties: { "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-closed": "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" } }, exportAs: ["rdxMenuBackdrop"], ngImport: i0 }); }
|
|
38
234
|
}
|
|
39
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
235
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuBackdrop, decorators: [{
|
|
40
236
|
type: Directive,
|
|
41
237
|
args: [{
|
|
42
|
-
selector: '[
|
|
43
|
-
|
|
238
|
+
selector: '[rdxMenuBackdrop]',
|
|
239
|
+
exportAs: 'rdxMenuBackdrop',
|
|
44
240
|
host: {
|
|
45
|
-
|
|
241
|
+
'[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
242
|
+
'[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
|
|
243
|
+
'[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
|
|
244
|
+
'[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
|
|
245
|
+
'[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined'
|
|
46
246
|
}
|
|
47
247
|
}]
|
|
48
248
|
}] });
|
|
@@ -54,26 +254,35 @@ function getCheckedState(checked) {
|
|
|
54
254
|
return isIndeterminate(checked) ? 'indeterminate' : checked ? 'checked' : 'unchecked';
|
|
55
255
|
}
|
|
56
256
|
|
|
57
|
-
|
|
257
|
+
const [injectRdxMenuCheckboxItemContext, provideRdxMenuCheckboxItemContext] = createContext('RdxMenuCheckboxItemContext');
|
|
258
|
+
const checkboxItemContextFactory = () => {
|
|
259
|
+
const instance = inject(RdxMenuCheckboxItem);
|
|
260
|
+
return {
|
|
261
|
+
checked: instance.checked
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* A menu item that can be checked or unchecked.
|
|
266
|
+
*/
|
|
267
|
+
class RdxMenuCheckboxItem {
|
|
58
268
|
constructor() {
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.checked = input(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
62
|
-
this.onCheckedChange = outputFromObservable(this.cdkMenuItemCheckbox.triggered);
|
|
63
|
-
this.disabledState = computed(() => this.disabled, ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
|
|
64
|
-
this.highlightedState = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlightedState" }] : /* istanbul ignore next */ []));
|
|
269
|
+
this.rootContext = injectRdxMenuRootContext(true);
|
|
270
|
+
this.elementRef = inject(ElementRef);
|
|
65
271
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
272
|
+
/** Whether this item is disabled. */
|
|
273
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
274
|
+
/** Whether toggling closes the menu. Defaults to false — checkbox items stay open. */
|
|
275
|
+
this.closeOnClick = input(false, { ...(ngDevMode ? { debugName: "closeOnClick" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
276
|
+
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
277
|
+
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
278
|
+
/** The checked state of the item. */
|
|
279
|
+
this.checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
280
|
+
/** Emits when the checked state changes. */
|
|
281
|
+
this.onCheckedChange = output();
|
|
282
|
+
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
283
|
+
// Expose helpers for host bindings
|
|
66
284
|
this.isIndeterminate = isIndeterminate;
|
|
67
285
|
this.getCheckedState = getCheckedState;
|
|
68
|
-
effect(() => {
|
|
69
|
-
if (isIndeterminate(this.checked())) {
|
|
70
|
-
this.cdkMenuItemCheckbox.checked = true;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
this.cdkMenuItemCheckbox.checked = !this.checked();
|
|
74
|
-
}
|
|
75
|
-
this.cdkMenuItemCheckbox.disabled = this.disabled();
|
|
76
|
-
});
|
|
77
286
|
}
|
|
78
287
|
onFocus() {
|
|
79
288
|
if (!this.disabled()) {
|
|
@@ -84,54 +293,152 @@ class RdxMenuItemCheckboxDirective {
|
|
|
84
293
|
this.isFocused.set(false);
|
|
85
294
|
}
|
|
86
295
|
onPointerMove(event) {
|
|
87
|
-
if (event.defaultPrevented)
|
|
296
|
+
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.disabled()) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
88
300
|
return;
|
|
89
|
-
|
|
301
|
+
}
|
|
302
|
+
if (document.activeElement !== this.elementRef.nativeElement) {
|
|
303
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
onPointerLeave(event) {
|
|
307
|
+
if (event.pointerType !== 'mouse') {
|
|
90
308
|
return;
|
|
91
|
-
if (!this.disabled()) {
|
|
92
|
-
const item = event.currentTarget;
|
|
93
|
-
item?.focus({ preventScroll: true });
|
|
94
309
|
}
|
|
310
|
+
if (document.activeElement === this.elementRef.nativeElement) {
|
|
311
|
+
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
onItemClick() {
|
|
315
|
+
if (this.disabled())
|
|
316
|
+
return;
|
|
317
|
+
this.toggleChecked();
|
|
318
|
+
if (this.closeOnClick())
|
|
319
|
+
this.rootContext?.close();
|
|
95
320
|
}
|
|
96
|
-
|
|
97
|
-
|
|
321
|
+
onActivate(event) {
|
|
322
|
+
if (this.disabled())
|
|
323
|
+
return;
|
|
324
|
+
event.preventDefault();
|
|
325
|
+
this.toggleChecked();
|
|
326
|
+
if (this.closeOnClick())
|
|
327
|
+
this.rootContext?.close();
|
|
328
|
+
}
|
|
329
|
+
toggleChecked() {
|
|
330
|
+
const next = isIndeterminate(this.checked()) ? true : !this.checked();
|
|
331
|
+
this.checked.set(next);
|
|
332
|
+
this.onCheckedChange.emit(next);
|
|
333
|
+
}
|
|
334
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
335
|
+
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", "tabindex": "-1" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.aria-checked": "isIndeterminate(checked()) ? \"mixed\" : checked()", "attr.data-state": "getCheckedState(checked())", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.aria-disabled": "disabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, providers: [provideRdxMenuCheckboxItemContext(checkboxItemContextFactory)], exportAs: ["rdxMenuCheckboxItem"], ngImport: i0 }); }
|
|
98
336
|
}
|
|
99
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
337
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItem, decorators: [{
|
|
100
338
|
type: Directive,
|
|
101
339
|
args: [{
|
|
102
|
-
selector: '[
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
directive: CdkMenuItemCheckbox,
|
|
106
|
-
outputs: ['cdkMenuItemTriggered: menuItemTriggered']
|
|
107
|
-
}
|
|
108
|
-
],
|
|
340
|
+
selector: '[rdxMenuCheckboxItem]',
|
|
341
|
+
exportAs: 'rdxMenuCheckboxItem',
|
|
342
|
+
providers: [provideRdxMenuCheckboxItemContext(checkboxItemContextFactory)],
|
|
109
343
|
host: {
|
|
110
344
|
role: 'menuitemcheckbox',
|
|
345
|
+
tabindex: '-1',
|
|
111
346
|
'[attr.aria-checked]': 'isIndeterminate(checked()) ? "mixed" : checked()',
|
|
112
347
|
'[attr.data-state]': 'getCheckedState(checked())',
|
|
113
|
-
'[attr.data-
|
|
348
|
+
'[attr.data-disabled]': 'disabled() ? "" : undefined',
|
|
349
|
+
'[attr.aria-disabled]': 'disabled() ? true : undefined',
|
|
350
|
+
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
351
|
+
'[attr.data-label]': 'label() ?? undefined',
|
|
114
352
|
'(focus)': 'onFocus()',
|
|
115
353
|
'(blur)': 'onBlur()',
|
|
116
|
-
'(pointermove)': 'onPointerMove($event)'
|
|
354
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
355
|
+
'(pointerleave)': 'onPointerLeave($event)',
|
|
356
|
+
'(click)': 'onItemClick()',
|
|
357
|
+
'(keydown.enter)': 'onActivate($event)',
|
|
358
|
+
'(keydown.space)': 'onActivate($event)'
|
|
117
359
|
}
|
|
118
360
|
}]
|
|
119
|
-
}],
|
|
361
|
+
}], 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"] }] } });
|
|
120
362
|
|
|
121
|
-
|
|
363
|
+
/**
|
|
364
|
+
* Renders when the parent checkbox item is checked or indeterminate.
|
|
365
|
+
* Set `keepMounted` to keep the element in the DOM when unchecked (enables CSS animations).
|
|
366
|
+
*/
|
|
367
|
+
class RdxMenuCheckboxItemIndicator {
|
|
122
368
|
constructor() {
|
|
123
|
-
this.
|
|
124
|
-
|
|
125
|
-
this.
|
|
126
|
-
this.
|
|
127
|
-
this.
|
|
128
|
-
|
|
369
|
+
this.itemContext = injectRdxMenuCheckboxItemContext();
|
|
370
|
+
/** Keep the indicator in the DOM when unchecked so CSS exit animations can play. */
|
|
371
|
+
this.keepMounted = input(false, { ...(ngDevMode ? { debugName: "keepMounted" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
372
|
+
this.dataState = computed(() => getCheckedState(this.itemContext.checked()), ...(ngDevMode ? [{ debugName: "dataState" }] : /* istanbul ignore next */ []));
|
|
373
|
+
this.isVisible = computed(() => isIndeterminate(this.itemContext.checked()) || this.itemContext.checked() === true, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
|
|
374
|
+
}
|
|
375
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItemIndicator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
376
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuCheckboxItemIndicator, isStandalone: true, selector: "[rdxMenuCheckboxItemIndicator]", inputs: { keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-state": "dataState()", "attr.data-starting-style": "isVisible() ? \"\" : undefined", "attr.data-ending-style": "!isVisible() ? \"\" : undefined", "style.display": "!keepMounted() && !isVisible() ? \"none\" : null" } }, exportAs: ["rdxMenuCheckboxItemIndicator"], ngImport: i0 }); }
|
|
377
|
+
}
|
|
378
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuCheckboxItemIndicator, decorators: [{
|
|
379
|
+
type: Directive,
|
|
380
|
+
args: [{
|
|
381
|
+
selector: '[rdxMenuCheckboxItemIndicator]',
|
|
382
|
+
exportAs: 'rdxMenuCheckboxItemIndicator',
|
|
383
|
+
host: {
|
|
384
|
+
'[attr.data-state]': 'dataState()',
|
|
385
|
+
'[attr.data-starting-style]': 'isVisible() ? "" : undefined',
|
|
386
|
+
'[attr.data-ending-style]': '!isVisible() ? "" : undefined',
|
|
387
|
+
'[style.display]': '!keepMounted() && !isVisible() ? "none" : null'
|
|
388
|
+
}
|
|
389
|
+
}]
|
|
390
|
+
}], propDecorators: { keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }] } });
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Groups related menu items together.
|
|
394
|
+
*/
|
|
395
|
+
class RdxMenuGroup {
|
|
396
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
397
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuGroup, isStandalone: true, selector: "[rdxMenuGroup]", host: { attributes: { "role": "group" } }, exportAs: ["rdxMenuGroup"], ngImport: i0 }); }
|
|
398
|
+
}
|
|
399
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuGroup, decorators: [{
|
|
400
|
+
type: Directive,
|
|
401
|
+
args: [{
|
|
402
|
+
selector: '[rdxMenuGroup]',
|
|
403
|
+
exportAs: 'rdxMenuGroup',
|
|
404
|
+
host: {
|
|
405
|
+
role: 'group'
|
|
406
|
+
}
|
|
407
|
+
}]
|
|
408
|
+
}] });
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* A label for a menu group.
|
|
412
|
+
*/
|
|
413
|
+
class RdxMenuGroupLabel {
|
|
414
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuGroupLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
415
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuGroupLabel, isStandalone: true, selector: "[rdxMenuGroupLabel]", exportAs: ["rdxMenuGroupLabel"], ngImport: i0 }); }
|
|
416
|
+
}
|
|
417
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuGroupLabel, decorators: [{
|
|
418
|
+
type: Directive,
|
|
419
|
+
args: [{
|
|
420
|
+
selector: '[rdxMenuGroupLabel]',
|
|
421
|
+
exportAs: 'rdxMenuGroupLabel'
|
|
422
|
+
}]
|
|
423
|
+
}] });
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* An individual menu item.
|
|
427
|
+
*/
|
|
428
|
+
class RdxMenuItem {
|
|
429
|
+
constructor() {
|
|
430
|
+
this.rootContext = injectRdxMenuRootContext(true);
|
|
431
|
+
this.elementRef = inject(ElementRef);
|
|
129
432
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
130
|
-
this.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
433
|
+
/** Whether this item is disabled. */
|
|
434
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
435
|
+
/** Whether selecting this item closes the menu. */
|
|
436
|
+
this.closeOnClick = input(true, { ...(ngDevMode ? { debugName: "closeOnClick" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
437
|
+
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
438
|
+
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
439
|
+
/** Emits when the item is selected. */
|
|
440
|
+
this.onSelect = output();
|
|
441
|
+
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
135
442
|
}
|
|
136
443
|
onFocus() {
|
|
137
444
|
if (!this.disabled()) {
|
|
@@ -142,82 +449,84 @@ class RdxMenuItemRadioDirective {
|
|
|
142
449
|
this.isFocused.set(false);
|
|
143
450
|
}
|
|
144
451
|
onPointerMove(event) {
|
|
145
|
-
if (event.defaultPrevented)
|
|
452
|
+
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.disabled()) {
|
|
146
453
|
return;
|
|
147
|
-
|
|
454
|
+
}
|
|
455
|
+
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
148
456
|
return;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
457
|
+
}
|
|
458
|
+
if (document.activeElement !== this.elementRef.nativeElement) {
|
|
459
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
152
460
|
}
|
|
153
461
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuItemRadioDirective, decorators: [{
|
|
158
|
-
type: Directive,
|
|
159
|
-
args: [{
|
|
160
|
-
selector: '[RdxMenuItemRadio]',
|
|
161
|
-
hostDirectives: [
|
|
162
|
-
{
|
|
163
|
-
directive: CdkMenuItemRadio,
|
|
164
|
-
outputs: ['cdkMenuItemTriggered: menuItemTriggered']
|
|
165
|
-
}
|
|
166
|
-
],
|
|
167
|
-
host: {
|
|
168
|
-
role: 'menuitemradio',
|
|
169
|
-
'[attr.aria-checked]': 'checked()',
|
|
170
|
-
'[attr.data-state]': 'getCheckedState(checked())',
|
|
171
|
-
'[attr.data-highlighted]': "highlightedState() ? '' : undefined",
|
|
172
|
-
'(focus)': 'onFocus()',
|
|
173
|
-
'(blur)': 'onBlur()',
|
|
174
|
-
'(pointermove)': 'onPointerMove($event)'
|
|
175
|
-
}
|
|
176
|
-
}]
|
|
177
|
-
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
|
|
178
|
-
|
|
179
|
-
class RdxMenuItemIndicatorDirective {
|
|
180
|
-
constructor() {
|
|
181
|
-
this.menuItemRadio = inject(RdxMenuItemRadioDirective, { host: true, optional: true });
|
|
182
|
-
this.menuCheckboxItem = inject(RdxMenuItemCheckboxDirective, { host: true, optional: true });
|
|
183
|
-
this.getCheckedState = getCheckedState;
|
|
184
|
-
}
|
|
185
|
-
get isChecked() {
|
|
186
|
-
if (this.menuItemRadio) {
|
|
187
|
-
return this.menuItemRadio.checked();
|
|
462
|
+
onPointerLeave(event) {
|
|
463
|
+
if (event.pointerType !== 'mouse') {
|
|
464
|
+
return;
|
|
188
465
|
}
|
|
189
|
-
|
|
190
|
-
|
|
466
|
+
// Clear highlight when the pointer leaves: move focus back to the popup. A subsequent
|
|
467
|
+
// pointermove on a sibling item re-focuses it, so moving between items still works.
|
|
468
|
+
if (document.activeElement === this.elementRef.nativeElement) {
|
|
469
|
+
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
191
470
|
}
|
|
192
|
-
return false;
|
|
193
471
|
}
|
|
194
|
-
|
|
195
|
-
|
|
472
|
+
onItemClick() {
|
|
473
|
+
if (this.disabled())
|
|
474
|
+
return;
|
|
475
|
+
this.onSelect.emit();
|
|
476
|
+
if (this.closeOnClick())
|
|
477
|
+
this.rootContext?.close();
|
|
478
|
+
}
|
|
479
|
+
onActivate(event) {
|
|
480
|
+
if (this.disabled())
|
|
481
|
+
return;
|
|
482
|
+
event.preventDefault();
|
|
483
|
+
this.onSelect.emit();
|
|
484
|
+
if (this.closeOnClick())
|
|
485
|
+
this.rootContext?.close();
|
|
486
|
+
}
|
|
487
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
488
|
+
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", "tabindex": "-1" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.aria-disabled": "disabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuItem"], ngImport: i0 }); }
|
|
196
489
|
}
|
|
197
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
490
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuItem, decorators: [{
|
|
198
491
|
type: Directive,
|
|
199
492
|
args: [{
|
|
200
|
-
selector: '[
|
|
493
|
+
selector: '[rdxMenuItem]',
|
|
494
|
+
exportAs: 'rdxMenuItem',
|
|
201
495
|
host: {
|
|
202
|
-
|
|
203
|
-
|
|
496
|
+
role: 'menuitem',
|
|
497
|
+
tabindex: '-1',
|
|
498
|
+
'[attr.data-disabled]': 'disabled() ? "" : undefined',
|
|
499
|
+
'[attr.aria-disabled]': 'disabled() ? true : undefined',
|
|
500
|
+
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
501
|
+
'[attr.data-label]': 'label() ?? undefined',
|
|
502
|
+
'(focus)': 'onFocus()',
|
|
503
|
+
'(blur)': 'onBlur()',
|
|
504
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
505
|
+
'(pointerleave)': 'onPointerLeave($event)',
|
|
506
|
+
'(click)': 'onItemClick()',
|
|
507
|
+
'(keydown.enter)': 'onActivate($event)',
|
|
508
|
+
'(keydown.space)': 'onActivate($event)'
|
|
204
509
|
}
|
|
205
510
|
}]
|
|
206
|
-
}] });
|
|
511
|
+
}], 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"] }] } });
|
|
207
512
|
|
|
208
|
-
|
|
513
|
+
/**
|
|
514
|
+
* A menu item that renders as a link.
|
|
515
|
+
*/
|
|
516
|
+
class RdxMenuLinkItem {
|
|
209
517
|
constructor() {
|
|
210
|
-
this.
|
|
211
|
-
this.
|
|
212
|
-
this.onSelect = outputFromObservable(this.cdkMenuItem.triggered);
|
|
518
|
+
this.rootContext = injectRdxMenuRootContext(true);
|
|
519
|
+
this.elementRef = inject(ElementRef);
|
|
213
520
|
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
214
|
-
|
|
215
|
-
this.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
521
|
+
/** Whether this item is disabled. */
|
|
522
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
523
|
+
/** Whether selecting this item closes the menu. Defaults to false — links navigate by default. */
|
|
524
|
+
this.closeOnClick = input(false, { ...(ngDevMode ? { debugName: "closeOnClick" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
525
|
+
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
526
|
+
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
527
|
+
/** Emits when the item is selected. */
|
|
528
|
+
this.onSelect = output();
|
|
529
|
+
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
221
530
|
}
|
|
222
531
|
onFocus() {
|
|
223
532
|
if (!this.disabled()) {
|
|
@@ -228,280 +537,1515 @@ class RdxMenuItemDirective {
|
|
|
228
537
|
this.isFocused.set(false);
|
|
229
538
|
}
|
|
230
539
|
onPointerMove(event) {
|
|
231
|
-
if (event.defaultPrevented)
|
|
540
|
+
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.disabled()) {
|
|
232
541
|
return;
|
|
233
|
-
|
|
542
|
+
}
|
|
543
|
+
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
if (document.activeElement !== this.elementRef.nativeElement) {
|
|
547
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
onPointerLeave(event) {
|
|
551
|
+
if (event.pointerType !== 'mouse') {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (document.activeElement === this.elementRef.nativeElement) {
|
|
555
|
+
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
onItemClick(event) {
|
|
559
|
+
if (this.disabled()) {
|
|
560
|
+
event.preventDefault();
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
this.onSelect.emit();
|
|
564
|
+
if (this.closeOnClick())
|
|
565
|
+
this.rootContext?.close();
|
|
566
|
+
}
|
|
567
|
+
onActivate(event) {
|
|
568
|
+
if (this.disabled()) {
|
|
569
|
+
event.preventDefault();
|
|
234
570
|
return;
|
|
235
|
-
if (!this.disabled()) {
|
|
236
|
-
const item = event.currentTarget;
|
|
237
|
-
item?.focus({ preventScroll: true });
|
|
238
571
|
}
|
|
572
|
+
this.onSelect.emit();
|
|
573
|
+
if (this.closeOnClick())
|
|
574
|
+
this.rootContext?.close();
|
|
239
575
|
}
|
|
240
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
241
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type:
|
|
576
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLinkItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
577
|
+
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", "tabindex": "-1" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "click": "onItemClick($event)", "keydown.enter": "onActivate($event)" }, properties: { "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.aria-disabled": "disabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuLinkItem"], ngImport: i0 }); }
|
|
242
578
|
}
|
|
243
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
579
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLinkItem, decorators: [{
|
|
244
580
|
type: Directive,
|
|
245
581
|
args: [{
|
|
246
|
-
selector: '[
|
|
247
|
-
|
|
248
|
-
{
|
|
249
|
-
directive: CdkMenuItem,
|
|
250
|
-
outputs: ['cdkMenuItemTriggered: menuItemTriggered']
|
|
251
|
-
}
|
|
252
|
-
],
|
|
582
|
+
selector: 'a[rdxMenuLinkItem]',
|
|
583
|
+
exportAs: 'rdxMenuLinkItem',
|
|
253
584
|
host: {
|
|
254
585
|
role: 'menuitem',
|
|
255
586
|
tabindex: '-1',
|
|
256
|
-
'[attr.data-
|
|
257
|
-
'[attr.
|
|
258
|
-
'[attr.
|
|
259
|
-
'[attr.data-
|
|
260
|
-
'[attr.data-highlighted]': "highlightedState() ? '' : undefined",
|
|
587
|
+
'[attr.data-disabled]': 'disabled() ? "" : undefined',
|
|
588
|
+
'[attr.aria-disabled]': 'disabled() ? true : undefined',
|
|
589
|
+
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
590
|
+
'[attr.data-label]': 'label() ?? undefined',
|
|
261
591
|
'(focus)': 'onFocus()',
|
|
262
592
|
'(blur)': 'onBlur()',
|
|
263
|
-
'(pointermove)': 'onPointerMove($event)'
|
|
593
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
594
|
+
'(pointerleave)': 'onPointerLeave($event)',
|
|
595
|
+
'(click)': 'onItemClick($event)',
|
|
596
|
+
'(keydown.enter)': 'onActivate($event)'
|
|
264
597
|
}
|
|
265
598
|
}]
|
|
266
|
-
}],
|
|
267
|
-
|
|
268
|
-
class RdxMenuLabelDirective {
|
|
269
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLabelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
270
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuLabelDirective, isStandalone: true, selector: "[RdxMenuLabel]", ngImport: i0 }); }
|
|
271
|
-
}
|
|
272
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuLabelDirective, decorators: [{
|
|
273
|
-
type: Directive,
|
|
274
|
-
args: [{
|
|
275
|
-
selector: '[RdxMenuLabel]'
|
|
276
|
-
}]
|
|
277
|
-
}] });
|
|
278
|
-
|
|
279
|
-
class RdxMenuRadioGroupDirective {
|
|
280
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
281
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuRadioGroupDirective, isStandalone: true, selector: "[RdxMenuRadioGroup]", hostDirectives: [{ directive: i1.CdkMenuGroup }], ngImport: i0 }); }
|
|
282
|
-
}
|
|
283
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioGroupDirective, decorators: [{
|
|
284
|
-
type: Directive,
|
|
285
|
-
args: [{
|
|
286
|
-
selector: '[RdxMenuRadioGroup]',
|
|
287
|
-
hostDirectives: [CdkMenuGroup]
|
|
288
|
-
}]
|
|
289
|
-
}] });
|
|
599
|
+
}], 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"] }] } });
|
|
290
600
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
601
|
+
/** Selector for focusable menu items within the popup. */
|
|
602
|
+
const ITEM_SELECTOR = [
|
|
603
|
+
'[rdxMenuItem]:not([data-disabled])',
|
|
604
|
+
'[rdxMenuCheckboxItem]:not([data-disabled])',
|
|
605
|
+
'[rdxMenuRadioItem]:not([data-disabled])',
|
|
606
|
+
'[rdxMenuLinkItem]:not([data-disabled])',
|
|
607
|
+
'[rdxMenuSubTrigger]:not([data-disabled])'
|
|
608
|
+
].join(',');
|
|
609
|
+
function getFocusableItems(popup) {
|
|
610
|
+
// Exclude items that belong to a nested child popup (submenu).
|
|
611
|
+
return Array.from(popup.querySelectorAll(ITEM_SELECTOR)).filter((item) => item.closest('[rdxMenuPopup]') === popup);
|
|
294
612
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
613
|
+
/**
|
|
614
|
+
* A container for the menu contents.
|
|
615
|
+
*/
|
|
616
|
+
class RdxMenuPopup {
|
|
617
|
+
constructor() {
|
|
618
|
+
this.rootContext = injectRdxMenuRootContext();
|
|
619
|
+
this.dismissableLayer = inject(RdxDismissableLayer);
|
|
620
|
+
this.focusScope = inject(RdxFocusScope);
|
|
621
|
+
this.wrapper = inject(RdxPopperContentWrapper, { optional: true });
|
|
622
|
+
this.elementRef = inject(ElementRef);
|
|
623
|
+
this.dismissableLayersContext = inject(RdxDismissableLayersContextToken);
|
|
624
|
+
this.search = '';
|
|
625
|
+
this.align = computed(() => this.wrapper?.placedAlign(), ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
626
|
+
this.side = computed(() => this.wrapper?.placedSide(), ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
627
|
+
/**
|
|
628
|
+
* Event handler called when the escape key is pressed. Can be prevented.
|
|
629
|
+
*/
|
|
630
|
+
this.escapeKeyDown = outputFromObservable(outputToObservable(this.dismissableLayer.escapeKeyDown));
|
|
631
|
+
/**
|
|
632
|
+
* Event handler called when a pointerdown event happens outside of the popup. Can be prevented.
|
|
633
|
+
*/
|
|
634
|
+
this.pointerDownOutside = outputFromObservable(outputToObservable(this.dismissableLayer.pointerDownOutside));
|
|
635
|
+
/**
|
|
636
|
+
* Event handler called when focus moves outside of the popup. Can be prevented.
|
|
637
|
+
*/
|
|
638
|
+
this.focusOutside = outputFromObservable(outputToObservable(this.dismissableLayer.focusOutside));
|
|
639
|
+
/**
|
|
640
|
+
* Event handler called when an interaction happens outside of the popup. Can be prevented.
|
|
641
|
+
*/
|
|
642
|
+
this.interactOutside = outputFromObservable(outputToObservable(this.dismissableLayer.interactOutside));
|
|
643
|
+
/**
|
|
644
|
+
* Event handler called before focus moves into the popup. Can be prevented.
|
|
645
|
+
*/
|
|
646
|
+
this.openAutoFocus = outputFromObservable(outputToObservable(this.focusScope.mountAutoFocus));
|
|
647
|
+
/**
|
|
648
|
+
* Event handler called before focus returns after the popup is removed. Can be prevented.
|
|
649
|
+
*/
|
|
650
|
+
this.closeAutoFocus = outputFromObservable(outputToObservable(this.focusScope.unmountAutoFocus));
|
|
651
|
+
const unregister = this.rootContext.registerTransitionElement(this.elementRef.nativeElement);
|
|
652
|
+
const unregisterPopup = this.rootContext.registerPopup(this.elementRef.nativeElement);
|
|
653
|
+
inject(DestroyRef).onDestroy(() => {
|
|
654
|
+
unregister();
|
|
655
|
+
unregisterPopup();
|
|
656
|
+
clearTimeout(this.searchTimer);
|
|
657
|
+
});
|
|
658
|
+
effect((onCleanup) => {
|
|
659
|
+
if (!this.rootContext.isSubmenu()) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
const element = this.elementRef.nativeElement;
|
|
663
|
+
this.dismissableLayersContext.branches.update((branches) => [...branches, element]);
|
|
664
|
+
onCleanup(() => {
|
|
665
|
+
this.dismissableLayersContext.branches.update((branches) => branches.filter((branch) => branch !== element));
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
this.dismissableLayer.dismiss.subscribe(() => {
|
|
669
|
+
this.rootContext.close();
|
|
670
|
+
});
|
|
671
|
+
// Move focus into the popup when the menu opens — unless the opener suppressed it
|
|
672
|
+
// (e.g. menubar hover-switching, where focus stays on the trigger).
|
|
673
|
+
effect(() => {
|
|
674
|
+
const autoFocus = this.rootContext.autoFocus();
|
|
675
|
+
if (this.rootContext.isOpen() && autoFocus) {
|
|
676
|
+
requestAnimationFrame(() => {
|
|
677
|
+
// `'popup'` focuses the container without highlighting an item (pointer opening).
|
|
678
|
+
if (autoFocus === 'popup') {
|
|
679
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
680
|
+
return;
|
|
302
681
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
682
|
+
const items = getFocusableItems(this.elementRef.nativeElement);
|
|
683
|
+
const item = autoFocus === 'last' ? items[items.length - 1] : items[0];
|
|
684
|
+
item?.focus({ preventScroll: true });
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
handleCloseParent(event) {
|
|
690
|
+
event.stopPropagation();
|
|
691
|
+
this.rootContext.close();
|
|
692
|
+
if (this.rootContext.isSubmenu() && this.rootContext.closeParentOnEsc()) {
|
|
693
|
+
this.rootContext.closeParent();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
handleKeydown(event) {
|
|
697
|
+
const el = this.elementRef.nativeElement;
|
|
698
|
+
const items = getFocusableItems(el);
|
|
699
|
+
const current = document.activeElement;
|
|
700
|
+
const currentIndex = items.indexOf(current);
|
|
701
|
+
switch (event.key) {
|
|
702
|
+
case 'ArrowDown': {
|
|
703
|
+
event.preventDefault();
|
|
704
|
+
event.stopPropagation();
|
|
705
|
+
const atEnd = currentIndex >= items.length - 1;
|
|
706
|
+
const next = atEnd
|
|
707
|
+
? this.rootContext.loopFocus()
|
|
708
|
+
? items[0]
|
|
709
|
+
: items[items.length - 1]
|
|
710
|
+
: items[currentIndex + 1];
|
|
711
|
+
next?.focus({ preventScroll: true });
|
|
326
712
|
break;
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
713
|
+
}
|
|
714
|
+
case 'ArrowUp': {
|
|
715
|
+
event.preventDefault();
|
|
716
|
+
event.stopPropagation();
|
|
717
|
+
const atStart = currentIndex <= 0;
|
|
718
|
+
const prev = atStart
|
|
719
|
+
? this.rootContext.loopFocus()
|
|
720
|
+
? items[items.length - 1]
|
|
721
|
+
: items[0]
|
|
722
|
+
: items[currentIndex - 1];
|
|
723
|
+
prev?.focus({ preventScroll: true });
|
|
331
724
|
break;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
725
|
+
}
|
|
726
|
+
case 'Home': {
|
|
727
|
+
event.preventDefault();
|
|
728
|
+
event.stopPropagation();
|
|
729
|
+
items[0]?.focus({ preventScroll: true });
|
|
336
730
|
break;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
731
|
+
}
|
|
732
|
+
case 'End': {
|
|
733
|
+
event.preventDefault();
|
|
734
|
+
event.stopPropagation();
|
|
735
|
+
items[items.length - 1]?.focus({ preventScroll: true });
|
|
341
736
|
break;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
originY = 'top';
|
|
352
|
-
overlayY = 'top';
|
|
353
|
-
offsetY = alignOffset;
|
|
737
|
+
}
|
|
738
|
+
case 'ArrowLeft': {
|
|
739
|
+
const trigger = this.rootContext.trigger();
|
|
740
|
+
if (!trigger?.hasAttribute('rdxMenuSubTrigger')) {
|
|
741
|
+
if (this.rootContext.handlePopupArrowNavigation(-1)) {
|
|
742
|
+
event.preventDefault();
|
|
743
|
+
event.stopPropagation();
|
|
744
|
+
}
|
|
745
|
+
break;
|
|
354
746
|
}
|
|
747
|
+
// Close this popup and return focus to the trigger (used by submenus).
|
|
748
|
+
event.preventDefault();
|
|
749
|
+
event.stopPropagation();
|
|
750
|
+
this.rootContext.close();
|
|
751
|
+
trigger.focus({ preventScroll: true });
|
|
355
752
|
break;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
originY = 'bottom';
|
|
364
|
-
overlayY = 'bottom';
|
|
365
|
-
offsetY = -alignOffset;
|
|
753
|
+
}
|
|
754
|
+
case 'ArrowRight': {
|
|
755
|
+
if (this.rootContext.handlePopupArrowNavigation(1)) {
|
|
756
|
+
event.preventDefault();
|
|
757
|
+
event.stopPropagation();
|
|
366
758
|
}
|
|
367
759
|
break;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
760
|
+
}
|
|
761
|
+
case 'Escape': {
|
|
762
|
+
event.preventDefault();
|
|
763
|
+
event.stopPropagation();
|
|
764
|
+
this.rootContext.close();
|
|
765
|
+
if (this.rootContext.isSubmenu() && this.rootContext.closeParentOnEsc()) {
|
|
766
|
+
this.rootContext.closeParent();
|
|
373
767
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
768
|
+
this.rootContext.trigger()?.focus({ preventScroll: true });
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
case 'Tab': {
|
|
772
|
+
// Close on tab to allow natural tab navigation
|
|
773
|
+
this.rootContext.close();
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
default: {
|
|
777
|
+
// Typeahead
|
|
778
|
+
if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
779
|
+
event.preventDefault();
|
|
780
|
+
const char = event.key.toLowerCase();
|
|
781
|
+
this.search += char;
|
|
782
|
+
clearTimeout(this.searchTimer);
|
|
783
|
+
this.searchTimer = setTimeout(() => {
|
|
784
|
+
this.search = '';
|
|
785
|
+
this.searchTimer = undefined;
|
|
786
|
+
}, 1000);
|
|
787
|
+
const query = this.search.length > 1 && [...this.search].every((c) => c === char) ? char : this.search;
|
|
788
|
+
const startIndex = currentIndex >= 0 ? currentIndex + 1 : 0;
|
|
789
|
+
const rotated = [...items.slice(startIndex), ...items.slice(0, startIndex)];
|
|
790
|
+
const match = rotated.find((item) => {
|
|
791
|
+
const text = (item.dataset['label'] ?? item.textContent?.trim() ?? '').toLowerCase();
|
|
792
|
+
return text.startsWith(query);
|
|
793
|
+
});
|
|
794
|
+
match?.focus({ preventScroll: true });
|
|
377
795
|
}
|
|
378
796
|
break;
|
|
379
|
-
}
|
|
380
|
-
return {
|
|
381
|
-
originX,
|
|
382
|
-
originY,
|
|
383
|
-
overlayX,
|
|
384
|
-
overlayY,
|
|
385
|
-
offsetX,
|
|
386
|
-
offsetY
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
constructor() {
|
|
390
|
-
this.cdkTrigger = inject(CdkMenuTrigger, { host: true });
|
|
391
|
-
this.menuTriggerFor = input.required(...(ngDevMode ? [{ debugName: "menuTriggerFor" }] : /* istanbul ignore next */ []));
|
|
392
|
-
/**
|
|
393
|
-
* @description The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
|
|
394
|
-
*/
|
|
395
|
-
this.side = input(...(ngDevMode ? [undefined, { debugName: "side" }] : /* istanbul ignore next */ []));
|
|
396
|
-
this.align = input(...(ngDevMode ? [undefined, { debugName: "align" }] : /* istanbul ignore next */ []));
|
|
397
|
-
/**
|
|
398
|
-
* @description The distance in pixels from the trigger.
|
|
399
|
-
*/
|
|
400
|
-
this.sideOffset = input(NaN, { ...(ngDevMode ? { debugName: "sideOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
401
|
-
/**
|
|
402
|
-
* @description An offset in pixels from the "start" or "end" alignment options.
|
|
403
|
-
*/
|
|
404
|
-
this.alignOffset = input(NaN, { ...(ngDevMode ? { debugName: "alignOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
405
|
-
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
406
|
-
this.enablePositions = false;
|
|
407
|
-
// TODO
|
|
408
|
-
this.positions = computed(() => this.computePositions(), ...(ngDevMode ? [{ debugName: "positions" }] : /* istanbul ignore next */ []));
|
|
409
|
-
this.onMenuPositionEffect();
|
|
410
|
-
}
|
|
411
|
-
/** @ignore */
|
|
412
|
-
onPointerDown($event) {
|
|
413
|
-
const mouseEvent = $event;
|
|
414
|
-
// only call handler if it's the left button (mousedown gets triggered by all mouse buttons)
|
|
415
|
-
// but not when the control key is pressed (avoiding MacOS right click)
|
|
416
|
-
if (!this.disabled() && mouseEvent.button === 0 && !mouseEvent.ctrlKey) {
|
|
417
|
-
/* empty */
|
|
418
|
-
if (!this.cdkTrigger.isOpen()) {
|
|
419
|
-
// prevent trigger focusing when opening
|
|
420
|
-
// this allows the content to be given focus without competition
|
|
421
|
-
$event.preventDefault();
|
|
422
797
|
}
|
|
423
798
|
}
|
|
424
799
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
})
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
this.cdkTrigger.menuPosition = positions;
|
|
438
|
-
this.fireNgOnChanges('menuPosition', this.cdkTrigger.menuPosition, prevMenuPosition);
|
|
439
|
-
}
|
|
440
|
-
fireNgOnChanges(input, currentValue, previousValue, firstChange = false) {
|
|
441
|
-
this.cdkTrigger.ngOnChanges({
|
|
442
|
-
[input]: new SimpleChange(previousValue, currentValue, firstChange)
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
446
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuTriggerDirective, isStandalone: true, selector: "[RdxMenuTrigger]", inputs: { menuTriggerFor: { classPropertyName: "menuTriggerFor", publicName: "menuTriggerFor", isSignal: true, isRequired: true, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem" }, listeners: { "pointerdown": "onPointerDown($event)" }, properties: { "attr.aria-haspopup": "'menu'", "attr.aria-expanded": "cdkTrigger.isOpen()", "attr.data-state": "cdkTrigger.isOpen() ? 'open': 'closed'", "attr.data-disabled": "disabled() ? '' : undefined" } }, hostDirectives: [{ directive: i1.CdkMenuTrigger, inputs: ["cdkMenuTriggerFor", "menuTriggerFor", "cdkMenuPosition", "menuPosition"] }], ngImport: i0 }); }
|
|
800
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPopup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
801
|
+
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: [
|
|
802
|
+
provideRdxDismissableLayerConfig(() => {
|
|
803
|
+
const rootContext = injectRdxMenuRootContext();
|
|
804
|
+
return {
|
|
805
|
+
disableOutsidePointerEvents: computed(() => rootContext.modal())
|
|
806
|
+
};
|
|
807
|
+
}),
|
|
808
|
+
provideRdxFocusScopeConfig(() => ({
|
|
809
|
+
trapped: signal(false)
|
|
810
|
+
}))
|
|
811
|
+
], exportAs: ["rdxMenuPopup"], hostDirectives: [{ directive: i1.RdxPopperContent }, { directive: i2.RdxDismissableLayer }, { directive: i3.RdxFocusScope }], ngImport: i0 }); }
|
|
447
812
|
}
|
|
448
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type:
|
|
813
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPopup, decorators: [{
|
|
449
814
|
type: Directive,
|
|
450
815
|
args: [{
|
|
451
|
-
selector: '[
|
|
452
|
-
|
|
816
|
+
selector: '[rdxMenuPopup]',
|
|
817
|
+
exportAs: 'rdxMenuPopup',
|
|
818
|
+
hostDirectives: [RdxPopperContent, RdxDismissableLayer, RdxFocusScope],
|
|
819
|
+
providers: [
|
|
820
|
+
provideRdxDismissableLayerConfig(() => {
|
|
821
|
+
const rootContext = injectRdxMenuRootContext();
|
|
822
|
+
return {
|
|
823
|
+
disableOutsidePointerEvents: computed(() => rootContext.modal())
|
|
824
|
+
};
|
|
825
|
+
}),
|
|
826
|
+
provideRdxFocusScopeConfig(() => ({
|
|
827
|
+
trapped: signal(false)
|
|
828
|
+
}))
|
|
829
|
+
],
|
|
830
|
+
host: {
|
|
831
|
+
role: 'menu',
|
|
832
|
+
tabindex: '-1',
|
|
833
|
+
'[attr.aria-orientation]': 'rootContext.orientation()',
|
|
834
|
+
'[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
|
|
835
|
+
'[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
836
|
+
'[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
|
|
837
|
+
'[attr.data-starting-style]': 'rootContext.transitionStatus() === "starting" ? "" : undefined',
|
|
838
|
+
'[attr.data-ending-style]': 'rootContext.transitionStatus() === "ending" ? "" : undefined',
|
|
839
|
+
'[attr.data-align]': 'align()',
|
|
840
|
+
'[attr.data-side]': 'side()',
|
|
841
|
+
'(keydown)': 'handleKeydown($event)',
|
|
842
|
+
'(rdx-menu-close-parent)': 'handleCloseParent($event)'
|
|
843
|
+
}
|
|
844
|
+
}]
|
|
845
|
+
}], ctorParameters: () => [], propDecorators: { escapeKeyDown: [{ type: i0.Output, args: ["escapeKeyDown"] }], pointerDownOutside: [{ type: i0.Output, args: ["pointerDownOutside"] }], focusOutside: [{ type: i0.Output, args: ["focusOutside"] }], interactOutside: [{ type: i0.Output, args: ["interactOutside"] }], openAutoFocus: [{ type: i0.Output, args: ["openAutoFocus"] }], closeAutoFocus: [{ type: i0.Output, args: ["closeAutoFocus"] }] } });
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Moves the menu to a different part of the DOM.
|
|
849
|
+
* Applied on ng-template — no host bindings (ng-template is not a real DOM node).
|
|
850
|
+
*/
|
|
851
|
+
class RdxMenuPortal {
|
|
852
|
+
constructor() {
|
|
853
|
+
/**
|
|
854
|
+
* Optional container to portal the content into. Defaults to `document.body`.
|
|
855
|
+
*/
|
|
856
|
+
this.container = input(...(ngDevMode ? [undefined, { debugName: "container" }] : /* istanbul ignore next */ []));
|
|
857
|
+
}
|
|
858
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
859
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuPortal, isStandalone: true, selector: "[rdxMenuPortal]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["rdxMenuPortal"], hostDirectives: [{ directive: i1$1.RdxPortal, inputs: ["container", "container"] }], ngImport: i0 }); }
|
|
860
|
+
}
|
|
861
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPortal, decorators: [{
|
|
862
|
+
type: Directive,
|
|
863
|
+
args: [{
|
|
864
|
+
selector: '[rdxMenuPortal]',
|
|
865
|
+
exportAs: 'rdxMenuPortal',
|
|
866
|
+
hostDirectives: [
|
|
867
|
+
{
|
|
868
|
+
directive: RdxPortal,
|
|
869
|
+
inputs: ['container']
|
|
870
|
+
}
|
|
871
|
+
]
|
|
872
|
+
}]
|
|
873
|
+
}], propDecorators: { container: [{ type: i0.Input, args: [{ isSignal: true, alias: "container", required: false }] }] } });
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Positions the menu against its trigger.
|
|
877
|
+
*/
|
|
878
|
+
class RdxMenuPositioner {
|
|
879
|
+
constructor() {
|
|
880
|
+
this.rootContext = injectRdxMenuRootContext();
|
|
881
|
+
this.wrapper = inject(RdxPopperContentWrapper);
|
|
882
|
+
/**
|
|
883
|
+
* An element to position the popup against. Defaults to the trigger.
|
|
884
|
+
*/
|
|
885
|
+
this.anchor = input(...(ngDevMode ? [undefined, { debugName: "anchor" }] : /* istanbul ignore next */ []));
|
|
886
|
+
/**
|
|
887
|
+
* The preferred side of the trigger to render against when open.
|
|
888
|
+
*/
|
|
889
|
+
this.side = input('bottom', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
890
|
+
/**
|
|
891
|
+
* Distance between the trigger and the popup in pixels.
|
|
892
|
+
*/
|
|
893
|
+
this.sideOffset = input(0, { ...(ngDevMode ? { debugName: "sideOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
894
|
+
/**
|
|
895
|
+
* How to align the popup relative to the specified side.
|
|
896
|
+
*/
|
|
897
|
+
this.align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
898
|
+
/**
|
|
899
|
+
* An offset in pixels from the `start` or `end` alignment options.
|
|
900
|
+
*/
|
|
901
|
+
this.alignOffset = input(0, { ...(ngDevMode ? { debugName: "alignOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
902
|
+
/**
|
|
903
|
+
* Minimum distance to maintain between the arrow and the edges of the popup.
|
|
904
|
+
*/
|
|
905
|
+
this.arrowPadding = input(5, { ...(ngDevMode ? { debugName: "arrowPadding" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
906
|
+
/**
|
|
907
|
+
* Whether to override side and alignment preferences to prevent collisions.
|
|
908
|
+
*/
|
|
909
|
+
this.avoidCollisions = input(true, { ...(ngDevMode ? { debugName: "avoidCollisions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
910
|
+
/**
|
|
911
|
+
* The element used as the collision boundary.
|
|
912
|
+
*/
|
|
913
|
+
this.collisionBoundary = input(...(ngDevMode ? [undefined, { debugName: "collisionBoundary" }] : /* istanbul ignore next */ []));
|
|
914
|
+
/**
|
|
915
|
+
* Distance in pixels from the boundary edges where collision detection should occur.
|
|
916
|
+
*/
|
|
917
|
+
this.collisionPadding = input(5, ...(ngDevMode ? [{ debugName: "collisionPadding" }] : /* istanbul ignore next */ []));
|
|
918
|
+
/**
|
|
919
|
+
* The sticky behavior on the alignment axis.
|
|
920
|
+
*/
|
|
921
|
+
this.sticky = input('partial', ...(ngDevMode ? [{ debugName: "sticky" }] : /* istanbul ignore next */ []));
|
|
922
|
+
/**
|
|
923
|
+
* Whether to hide the popup when the trigger becomes fully occluded.
|
|
924
|
+
*/
|
|
925
|
+
this.hideWhenDetached = input(false, { ...(ngDevMode ? { debugName: "hideWhenDetached" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
926
|
+
/**
|
|
927
|
+
* The CSS position strategy used by Floating UI.
|
|
928
|
+
*/
|
|
929
|
+
this.positionStrategy = input('fixed', ...(ngDevMode ? [{ debugName: "positionStrategy" }] : /* istanbul ignore next */ []));
|
|
930
|
+
/**
|
|
931
|
+
* Whether to update position on every animation frame.
|
|
932
|
+
*/
|
|
933
|
+
this.updatePositionStrategy = input('always', ...(ngDevMode ? [{ debugName: "updatePositionStrategy" }] : /* istanbul ignore next */ []));
|
|
934
|
+
/**
|
|
935
|
+
* Emits when the popup has been placed.
|
|
936
|
+
*/
|
|
937
|
+
this.placed = outputFromObservable(outputToObservable(inject(RdxPopperContentWrapper).placed));
|
|
938
|
+
}
|
|
939
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPositioner, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
940
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuPositioner, isStandalone: true, selector: "[rdxMenuPositioner]", inputs: { anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, alignOffset: { classPropertyName: "alignOffset", publicName: "alignOffset", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, avoidCollisions: { classPropertyName: "avoidCollisions", publicName: "avoidCollisions", isSignal: true, isRequired: false, transformFunction: null }, collisionBoundary: { classPropertyName: "collisionBoundary", publicName: "collisionBoundary", isSignal: true, isRequired: false, transformFunction: null }, collisionPadding: { classPropertyName: "collisionPadding", publicName: "collisionPadding", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, hideWhenDetached: { classPropertyName: "hideWhenDetached", publicName: "hideWhenDetached", isSignal: true, isRequired: false, transformFunction: null }, positionStrategy: { classPropertyName: "positionStrategy", publicName: "positionStrategy", isSignal: true, isRequired: false, transformFunction: null }, updatePositionStrategy: { classPropertyName: "updatePositionStrategy", publicName: "updatePositionStrategy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { placed: "placed" }, host: { properties: { "attr.data-open": "rootContext.isOpen() ? \"\" : undefined", "attr.data-closed": "rootContext.isOpen() ? undefined : \"\"", "attr.data-anchor-hidden": "wrapper.anchorHidden() ? \"\" : undefined", "attr.data-align": "wrapper.placedAlign()", "attr.data-side": "wrapper.placedSide()", "style": "{\n '--anchor-width': 'var(--radix-popper-anchor-width)',\n '--anchor-height': 'var(--radix-popper-anchor-height)',\n '--available-width': 'var(--radix-popper-available-width)',\n '--available-height': 'var(--radix-popper-available-height)',\n '--positioner-width': 'var(--radix-popper-content-wrapper-width)',\n '--positioner-height': 'var(--radix-popper-content-wrapper-height)',\n '--transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-menu-content-transform-origin': 'var(--radix-popper-transform-origin)',\n '--radix-menu-content-available-width': 'var(--radix-popper-available-width)',\n '--radix-menu-content-available-height': 'var(--radix-popper-available-height)',\n '--radix-menu-trigger-width': 'var(--radix-popper-anchor-width)',\n '--radix-menu-trigger-height': 'var(--radix-popper-anchor-height)'\n }" } }, providers: [
|
|
941
|
+
provideRdxPopperContentConfig({ arrowPadding: 5, collisionPadding: 5, updatePositionStrategy: 'always' })
|
|
942
|
+
], exportAs: ["rdxMenuPositioner"], hostDirectives: [{ directive: i1.RdxPopperContentWrapper, inputs: ["anchor", "anchor", "side", "side", "sideOffset", "sideOffset", "align", "align", "alignOffset", "alignOffset", "arrowPadding", "arrowPadding", "avoidCollisions", "avoidCollisions", "collisionBoundary", "collisionBoundary", "collisionPadding", "collisionPadding", "sticky", "sticky", "hideWhenDetached", "hideWhenDetached", "positionStrategy", "positionStrategy", "updatePositionStrategy", "updatePositionStrategy"] }], ngImport: i0 }); }
|
|
943
|
+
}
|
|
944
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuPositioner, decorators: [{
|
|
945
|
+
type: Directive,
|
|
946
|
+
args: [{
|
|
947
|
+
selector: '[rdxMenuPositioner]',
|
|
948
|
+
exportAs: 'rdxMenuPositioner',
|
|
949
|
+
providers: [
|
|
950
|
+
provideRdxPopperContentConfig({ arrowPadding: 5, collisionPadding: 5, updatePositionStrategy: 'always' })
|
|
951
|
+
],
|
|
952
|
+
hostDirectives: [
|
|
453
953
|
{
|
|
454
|
-
directive:
|
|
455
|
-
inputs: [
|
|
954
|
+
directive: RdxPopperContentWrapper,
|
|
955
|
+
inputs: [
|
|
956
|
+
'anchor',
|
|
957
|
+
'side',
|
|
958
|
+
'sideOffset',
|
|
959
|
+
'align',
|
|
960
|
+
'alignOffset',
|
|
961
|
+
'arrowPadding',
|
|
962
|
+
'avoidCollisions',
|
|
963
|
+
'collisionBoundary',
|
|
964
|
+
'collisionPadding',
|
|
965
|
+
'sticky',
|
|
966
|
+
'hideWhenDetached',
|
|
967
|
+
'positionStrategy',
|
|
968
|
+
'updatePositionStrategy'
|
|
969
|
+
]
|
|
456
970
|
}
|
|
457
971
|
],
|
|
458
972
|
host: {
|
|
973
|
+
'[attr.data-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
974
|
+
'[attr.data-closed]': 'rootContext.isOpen() ? undefined : ""',
|
|
975
|
+
'[attr.data-anchor-hidden]': 'wrapper.anchorHidden() ? "" : undefined',
|
|
976
|
+
'[attr.data-align]': 'wrapper.placedAlign()',
|
|
977
|
+
'[attr.data-side]': 'wrapper.placedSide()',
|
|
978
|
+
'[style]': `{
|
|
979
|
+
'--anchor-width': 'var(--radix-popper-anchor-width)',
|
|
980
|
+
'--anchor-height': 'var(--radix-popper-anchor-height)',
|
|
981
|
+
'--available-width': 'var(--radix-popper-available-width)',
|
|
982
|
+
'--available-height': 'var(--radix-popper-available-height)',
|
|
983
|
+
'--positioner-width': 'var(--radix-popper-content-wrapper-width)',
|
|
984
|
+
'--positioner-height': 'var(--radix-popper-content-wrapper-height)',
|
|
985
|
+
'--transform-origin': 'var(--radix-popper-transform-origin)',
|
|
986
|
+
'--radix-menu-content-transform-origin': 'var(--radix-popper-transform-origin)',
|
|
987
|
+
'--radix-menu-content-available-width': 'var(--radix-popper-available-width)',
|
|
988
|
+
'--radix-menu-content-available-height': 'var(--radix-popper-available-height)',
|
|
989
|
+
'--radix-menu-trigger-width': 'var(--radix-popper-anchor-width)',
|
|
990
|
+
'--radix-menu-trigger-height': 'var(--radix-popper-anchor-height)'
|
|
991
|
+
}`
|
|
992
|
+
}
|
|
993
|
+
}]
|
|
994
|
+
}], propDecorators: { anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], alignOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignOffset", required: false }] }], arrowPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowPadding", required: false }] }], avoidCollisions: [{ type: i0.Input, args: [{ isSignal: true, alias: "avoidCollisions", required: false }] }], collisionBoundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionBoundary", required: false }] }], collisionPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionPadding", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], hideWhenDetached: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideWhenDetached", required: false }] }], positionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionStrategy", required: false }] }], updatePositionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "updatePositionStrategy", required: false }] }], placed: [{ type: i0.Output, args: ["placed"] }] } });
|
|
995
|
+
|
|
996
|
+
const [injectRdxMenuRadioGroupContext, provideRdxMenuRadioGroupContext] = createContext('RdxMenuRadioGroupContext');
|
|
997
|
+
const radioGroupContextFactory = () => {
|
|
998
|
+
const instance = inject(RdxMenuRadioGroup);
|
|
999
|
+
return {
|
|
1000
|
+
value: instance.value,
|
|
1001
|
+
selectValue: (v) => instance.selectValue(v)
|
|
1002
|
+
};
|
|
1003
|
+
};
|
|
1004
|
+
/**
|
|
1005
|
+
* Groups radio items in a menu.
|
|
1006
|
+
*/
|
|
1007
|
+
class RdxMenuRadioGroup {
|
|
1008
|
+
constructor() {
|
|
1009
|
+
/**
|
|
1010
|
+
* The currently selected value.
|
|
1011
|
+
*/
|
|
1012
|
+
this.value = model(undefined, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1013
|
+
/**
|
|
1014
|
+
* Emits when the selected value changes.
|
|
1015
|
+
*/
|
|
1016
|
+
this.onValueChange = output();
|
|
1017
|
+
}
|
|
1018
|
+
selectValue(newValue) {
|
|
1019
|
+
this.value.set(newValue);
|
|
1020
|
+
this.onValueChange.emit(newValue);
|
|
1021
|
+
}
|
|
1022
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1023
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuRadioGroup, isStandalone: true, selector: "[rdxMenuRadioGroup]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { attributes: { "role": "group" } }, providers: [provideRdxMenuRadioGroupContext(radioGroupContextFactory)], exportAs: ["rdxMenuRadioGroup"], ngImport: i0 }); }
|
|
1024
|
+
}
|
|
1025
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioGroup, decorators: [{
|
|
1026
|
+
type: Directive,
|
|
1027
|
+
args: [{
|
|
1028
|
+
selector: '[rdxMenuRadioGroup]',
|
|
1029
|
+
exportAs: 'rdxMenuRadioGroup',
|
|
1030
|
+
providers: [provideRdxMenuRadioGroupContext(radioGroupContextFactory)],
|
|
1031
|
+
host: {
|
|
1032
|
+
role: 'group'
|
|
1033
|
+
}
|
|
1034
|
+
}]
|
|
1035
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
|
|
1036
|
+
|
|
1037
|
+
const [injectRdxMenuRadioItemContext, provideRdxMenuRadioItemContext] = createContext('RdxMenuRadioItemContext');
|
|
1038
|
+
const radioItemContextFactory = () => {
|
|
1039
|
+
const instance = inject(RdxMenuRadioItem);
|
|
1040
|
+
return {
|
|
1041
|
+
checked: instance.checked
|
|
1042
|
+
};
|
|
1043
|
+
};
|
|
1044
|
+
/**
|
|
1045
|
+
* A radio item within a menu radio group.
|
|
1046
|
+
*/
|
|
1047
|
+
class RdxMenuRadioItem {
|
|
1048
|
+
constructor() {
|
|
1049
|
+
this.rootContext = injectRdxMenuRootContext(true);
|
|
1050
|
+
this.radioGroupContext = injectRdxMenuRadioGroupContext();
|
|
1051
|
+
this.elementRef = inject(ElementRef);
|
|
1052
|
+
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
1053
|
+
/** The value of this radio item. */
|
|
1054
|
+
this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1055
|
+
/** Whether this item is disabled. */
|
|
1056
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1057
|
+
/** Whether selecting closes the menu. Defaults to false — radio items stay open. */
|
|
1058
|
+
this.closeOnClick = input(false, { ...(ngDevMode ? { debugName: "closeOnClick" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1059
|
+
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
1060
|
+
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1061
|
+
/** Emits when this item is selected. */
|
|
1062
|
+
this.onSelect = output();
|
|
1063
|
+
this.checked = computed(() => this.radioGroupContext.value() === this.value(), ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
1064
|
+
this.highlighted = computed(() => this.isFocused(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
1065
|
+
this.getCheckedState = getCheckedState;
|
|
1066
|
+
}
|
|
1067
|
+
onFocus() {
|
|
1068
|
+
if (!this.disabled()) {
|
|
1069
|
+
this.isFocused.set(true);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
onBlur() {
|
|
1073
|
+
this.isFocused.set(false);
|
|
1074
|
+
}
|
|
1075
|
+
onPointerMove(event) {
|
|
1076
|
+
if (event.defaultPrevented || event.pointerType !== 'mouse' || this.disabled()) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (this.rootContext && !this.rootContext.highlightItemOnHover()) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
if (document.activeElement !== this.elementRef.nativeElement) {
|
|
1083
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
onPointerLeave(event) {
|
|
1087
|
+
if (event.pointerType !== 'mouse') {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
if (document.activeElement === this.elementRef.nativeElement) {
|
|
1091
|
+
this.elementRef.nativeElement.closest('[rdxMenuPopup]')?.focus({ preventScroll: true });
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
onItemClick() {
|
|
1095
|
+
if (this.disabled()) {
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
this.selectItem();
|
|
1099
|
+
}
|
|
1100
|
+
onActivate(event) {
|
|
1101
|
+
if (this.disabled()) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
event.preventDefault();
|
|
1105
|
+
this.selectItem();
|
|
1106
|
+
}
|
|
1107
|
+
selectItem() {
|
|
1108
|
+
const v = this.value();
|
|
1109
|
+
this.radioGroupContext.selectValue(v);
|
|
1110
|
+
this.onSelect.emit(v);
|
|
1111
|
+
if (this.closeOnClick())
|
|
1112
|
+
this.rootContext?.close();
|
|
1113
|
+
}
|
|
1114
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1115
|
+
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", "tabindex": "-1" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave($event)", "click": "onItemClick()", "keydown.enter": "onActivate($event)", "keydown.space": "onActivate($event)" }, properties: { "attr.aria-checked": "checked()", "attr.data-state": "getCheckedState(checked())", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.aria-disabled": "disabled() ? true : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, providers: [provideRdxMenuRadioItemContext(radioItemContextFactory)], exportAs: ["rdxMenuRadioItem"], ngImport: i0 }); }
|
|
1116
|
+
}
|
|
1117
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItem, decorators: [{
|
|
1118
|
+
type: Directive,
|
|
1119
|
+
args: [{
|
|
1120
|
+
selector: '[rdxMenuRadioItem]',
|
|
1121
|
+
exportAs: 'rdxMenuRadioItem',
|
|
1122
|
+
providers: [provideRdxMenuRadioItemContext(radioItemContextFactory)],
|
|
1123
|
+
host: {
|
|
1124
|
+
role: 'menuitemradio',
|
|
1125
|
+
tabindex: '-1',
|
|
1126
|
+
'[attr.aria-checked]': 'checked()',
|
|
1127
|
+
'[attr.data-state]': 'getCheckedState(checked())',
|
|
1128
|
+
'[attr.data-disabled]': 'disabled() ? "" : undefined',
|
|
1129
|
+
'[attr.aria-disabled]': 'disabled() ? true : undefined',
|
|
1130
|
+
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
1131
|
+
'[attr.data-label]': 'label() ?? undefined',
|
|
1132
|
+
'(focus)': 'onFocus()',
|
|
1133
|
+
'(blur)': 'onBlur()',
|
|
1134
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
1135
|
+
'(pointerleave)': 'onPointerLeave($event)',
|
|
1136
|
+
'(click)': 'onItemClick()',
|
|
1137
|
+
'(keydown.enter)': 'onActivate($event)',
|
|
1138
|
+
'(keydown.space)': 'onActivate($event)'
|
|
1139
|
+
}
|
|
1140
|
+
}]
|
|
1141
|
+
}], 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"] }] } });
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Renders when the parent radio item is selected.
|
|
1145
|
+
* Set `keepMounted` to keep the element in the DOM when unselected (enables CSS animations).
|
|
1146
|
+
*/
|
|
1147
|
+
class RdxMenuRadioItemIndicator {
|
|
1148
|
+
constructor() {
|
|
1149
|
+
this.itemContext = injectRdxMenuRadioItemContext();
|
|
1150
|
+
/** Keep the indicator in the DOM when unselected so CSS exit animations can play. */
|
|
1151
|
+
this.keepMounted = input(false, { ...(ngDevMode ? { debugName: "keepMounted" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1152
|
+
this.dataState = computed(() => getCheckedState(this.itemContext.checked()), ...(ngDevMode ? [{ debugName: "dataState" }] : /* istanbul ignore next */ []));
|
|
1153
|
+
this.isVisible = computed(() => this.itemContext.checked() === true, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
|
|
1154
|
+
}
|
|
1155
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItemIndicator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1156
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxMenuRadioItemIndicator, isStandalone: true, selector: "[rdxMenuRadioItemIndicator]", inputs: { keepMounted: { classPropertyName: "keepMounted", publicName: "keepMounted", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-state": "dataState()", "attr.data-starting-style": "isVisible() ? \"\" : undefined", "attr.data-ending-style": "!isVisible() ? \"\" : undefined", "style.display": "!keepMounted() && !isVisible() ? \"none\" : null" } }, exportAs: ["rdxMenuRadioItemIndicator"], ngImport: i0 }); }
|
|
1157
|
+
}
|
|
1158
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuRadioItemIndicator, decorators: [{
|
|
1159
|
+
type: Directive,
|
|
1160
|
+
args: [{
|
|
1161
|
+
selector: '[rdxMenuRadioItemIndicator]',
|
|
1162
|
+
exportAs: 'rdxMenuRadioItemIndicator',
|
|
1163
|
+
host: {
|
|
1164
|
+
'[attr.data-state]': 'dataState()',
|
|
1165
|
+
'[attr.data-starting-style]': 'isVisible() ? "" : undefined',
|
|
1166
|
+
'[attr.data-ending-style]': '!isVisible() ? "" : undefined',
|
|
1167
|
+
'[style.display]': '!keepMounted() && !isVisible() ? "none" : null'
|
|
1168
|
+
}
|
|
1169
|
+
}]
|
|
1170
|
+
}], propDecorators: { keepMounted: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepMounted", required: false }] }] } });
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* A visual separator between groups of menu items.
|
|
1174
|
+
*/
|
|
1175
|
+
class RdxMenuSeparator {
|
|
1176
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSeparator, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1177
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuSeparator, isStandalone: true, selector: "[rdxMenuSeparator]", host: { attributes: { "role": "separator" }, properties: { "attr.aria-orientation": "\"horizontal\"" } }, exportAs: ["rdxMenuSeparator"], ngImport: i0 }); }
|
|
1178
|
+
}
|
|
1179
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSeparator, decorators: [{
|
|
1180
|
+
type: Directive,
|
|
1181
|
+
args: [{
|
|
1182
|
+
selector: '[rdxMenuSeparator]',
|
|
1183
|
+
exportAs: 'rdxMenuSeparator',
|
|
1184
|
+
host: {
|
|
1185
|
+
role: 'separator',
|
|
1186
|
+
'[attr.aria-orientation]': '"horizontal"'
|
|
1187
|
+
}
|
|
1188
|
+
}]
|
|
1189
|
+
}] });
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Submenu "safe polygon" — a faithful port of Floating UI's `safePolygon` algorithm
|
|
1193
|
+
* (https://floating-ui.com/docs/useHover#safepolygon), adapted to this library.
|
|
1194
|
+
*
|
|
1195
|
+
* While a submenu is open by hover, the parent submenu owns the decision to close itself: a
|
|
1196
|
+
* document-level `mousemove` handler keeps it open as long as the cursor is heading toward the
|
|
1197
|
+
* popup inside a safe quadrilateral (built from the cursor's exit point and the popup rect), and
|
|
1198
|
+
* closes it once the cursor leaves that area. Combined with the pointer-events "tunnel" below
|
|
1199
|
+
* (`applyPointerTunnel`), siblings cannot steal the open submenu during a diagonal traversal.
|
|
1200
|
+
*
|
|
1201
|
+
* Differences from the upstream implementation:
|
|
1202
|
+
* - `elements.domReference` / `elements.floating` → `reference` / `floating` (plain elements).
|
|
1203
|
+
* - `placement.split('-')[0]` → the `side` option (read live from the popup's `data-side`).
|
|
1204
|
+
* - the Floating UI tree (`tree` / `nodeId`) → the `hasOpenChild` callback, backed by the
|
|
1205
|
+
* module-level open-submenu registry.
|
|
1206
|
+
*
|
|
1207
|
+
* This deliberately does NOT reuse the core `useGraceArea` composable (tooltip / navigation-menu /
|
|
1208
|
+
* popover): that one is a simpler convex-hull grace area with no velocity gating, trough handling, or
|
|
1209
|
+
* pointer-events tunnel — none of which it needs, but all of which the submenu does to match Base UI
|
|
1210
|
+
* and to stop sibling triggers from stealing the open submenu mid-traversal.
|
|
1211
|
+
*/
|
|
1212
|
+
const CURSOR_SPEED_THRESHOLD = 0.1;
|
|
1213
|
+
const CURSOR_SPEED_THRESHOLD_SQUARED = CURSOR_SPEED_THRESHOLD * CURSOR_SPEED_THRESHOLD;
|
|
1214
|
+
const POLYGON_BUFFER = 0.5;
|
|
1215
|
+
/** Re-check delay when the cursor is inside the polygon but has not landed on the popup yet. */
|
|
1216
|
+
const REST_CHECK_MS = 40;
|
|
1217
|
+
function hasIntersectingEdge(pointX, pointY, xi, yi, xj, yj) {
|
|
1218
|
+
return yi >= pointY !== yj >= pointY && pointX <= ((xj - xi) * (pointY - yi)) / (yj - yi) + xi;
|
|
1219
|
+
}
|
|
1220
|
+
function isPointInQuadrilateral(pointX, pointY, x1, y1, x2, y2, x3, y3, x4, y4) {
|
|
1221
|
+
let inside = false;
|
|
1222
|
+
if (hasIntersectingEdge(pointX, pointY, x1, y1, x2, y2))
|
|
1223
|
+
inside = !inside;
|
|
1224
|
+
if (hasIntersectingEdge(pointX, pointY, x2, y2, x3, y3))
|
|
1225
|
+
inside = !inside;
|
|
1226
|
+
if (hasIntersectingEdge(pointX, pointY, x3, y3, x4, y4))
|
|
1227
|
+
inside = !inside;
|
|
1228
|
+
if (hasIntersectingEdge(pointX, pointY, x4, y4, x1, y1))
|
|
1229
|
+
inside = !inside;
|
|
1230
|
+
return inside;
|
|
1231
|
+
}
|
|
1232
|
+
function isInsideRect(pointX, pointY, rect) {
|
|
1233
|
+
return pointX >= rect.left && pointX <= rect.right && pointY >= rect.top && pointY <= rect.bottom;
|
|
1234
|
+
}
|
|
1235
|
+
function isInsideAxisAlignedRect(pointX, pointY, x1, y1, x2, y2) {
|
|
1236
|
+
const minX = Math.min(x1, x2);
|
|
1237
|
+
const maxX = Math.max(x1, x2);
|
|
1238
|
+
const minY = Math.min(y1, y2);
|
|
1239
|
+
const maxY = Math.max(y1, y2);
|
|
1240
|
+
return pointX >= minX && pointX <= maxX && pointY >= minY && pointY <= maxY;
|
|
1241
|
+
}
|
|
1242
|
+
function getTarget(event) {
|
|
1243
|
+
const path = event.composedPath?.();
|
|
1244
|
+
return path?.[0] ?? event.target;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Builds the `mousemove` handler that decides whether the open submenu should stay open, plus a
|
|
1248
|
+
* `dispose()` that clears its internal rest-check timer (so a pending close can't fire after the
|
|
1249
|
+
* listener is removed).
|
|
1250
|
+
*/
|
|
1251
|
+
function createSafePolygonHandler(options) {
|
|
1252
|
+
const { reference, floating, side: sideOf, x, y, onClose, cancelClose, hasOpenChild, onLanded } = options;
|
|
1253
|
+
let hasLanded = false;
|
|
1254
|
+
let lastX = null;
|
|
1255
|
+
let lastY = null;
|
|
1256
|
+
let lastCursorTime = typeof performance !== 'undefined' ? performance.now() : 0;
|
|
1257
|
+
let restTimer;
|
|
1258
|
+
function isCursorMovingSlowly(nextX, nextY) {
|
|
1259
|
+
const currentTime = typeof performance !== 'undefined' ? performance.now() : 0;
|
|
1260
|
+
const elapsedTime = currentTime - lastCursorTime;
|
|
1261
|
+
if (lastX === null || lastY === null || elapsedTime === 0) {
|
|
1262
|
+
lastX = nextX;
|
|
1263
|
+
lastY = nextY;
|
|
1264
|
+
lastCursorTime = currentTime;
|
|
1265
|
+
return false;
|
|
1266
|
+
}
|
|
1267
|
+
const deltaX = nextX - lastX;
|
|
1268
|
+
const deltaY = nextY - lastY;
|
|
1269
|
+
const distanceSquared = deltaX * deltaX + deltaY * deltaY;
|
|
1270
|
+
const thresholdSquared = elapsedTime * elapsedTime * CURSOR_SPEED_THRESHOLD_SQUARED;
|
|
1271
|
+
lastX = nextX;
|
|
1272
|
+
lastY = nextY;
|
|
1273
|
+
lastCursorTime = currentTime;
|
|
1274
|
+
return distanceSquared < thresholdSquared;
|
|
1275
|
+
}
|
|
1276
|
+
function closeIfNoOpenChild() {
|
|
1277
|
+
if (!hasOpenChild()) {
|
|
1278
|
+
onClose();
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
function onMouseMove(event) {
|
|
1282
|
+
cancelClose();
|
|
1283
|
+
clearTimeout(restTimer);
|
|
1284
|
+
const { clientX, clientY } = event;
|
|
1285
|
+
const target = getTarget(event);
|
|
1286
|
+
const isOverFloatingEl = !!target && floating.contains(target);
|
|
1287
|
+
const isOverReferenceEl = !!target && reference.contains(target);
|
|
1288
|
+
// This handler is bound only to document `mousemove` (never `mouseleave`), so Floating UI's
|
|
1289
|
+
// leave-specific paths — the overlapping-element `relatedTarget` guard and the `!isLeave`
|
|
1290
|
+
// guards — are omitted: they could never run here.
|
|
1291
|
+
if (isOverFloatingEl) {
|
|
1292
|
+
// "Landed" tracks reaching the popup only — not the trigger. Setting it on the trigger
|
|
1293
|
+
// would close as soon as the cursor enters the gap (no leave event resets it).
|
|
1294
|
+
if (!hasLanded) {
|
|
1295
|
+
hasLanded = true;
|
|
1296
|
+
onLanded?.();
|
|
1297
|
+
}
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
if (isOverReferenceEl) {
|
|
1301
|
+
// Over the trigger — stay open; the polygon/trough logic resumes once in the gap.
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
// If any nested child submenu is open, never close the parent.
|
|
1305
|
+
if (hasOpenChild())
|
|
1306
|
+
return;
|
|
1307
|
+
// Read the placed side live — it may have been unresolved at open time, or flipped since.
|
|
1308
|
+
const side = sideOf();
|
|
1309
|
+
const refRect = reference.getBoundingClientRect();
|
|
1310
|
+
const rect = floating.getBoundingClientRect();
|
|
1311
|
+
const cursorLeaveFromRight = x > rect.right - rect.width / 2;
|
|
1312
|
+
const cursorLeaveFromBottom = y > rect.bottom - rect.height / 2;
|
|
1313
|
+
const isFloatingWider = rect.width > refRect.width;
|
|
1314
|
+
const isFloatingTaller = rect.height > refRect.height;
|
|
1315
|
+
const left = (isFloatingWider ? refRect : rect).left;
|
|
1316
|
+
const right = (isFloatingWider ? refRect : rect).right;
|
|
1317
|
+
const top = (isFloatingTaller ? refRect : rect).top;
|
|
1318
|
+
const bottom = (isFloatingTaller ? refRect : rect).bottom;
|
|
1319
|
+
// Leaving from the opposite side: the buffer logic would otherwise keep it open — close.
|
|
1320
|
+
if ((side === 'top' && y >= refRect.bottom - 1) ||
|
|
1321
|
+
(side === 'bottom' && y <= refRect.top + 1) ||
|
|
1322
|
+
(side === 'left' && x >= refRect.right - 1) ||
|
|
1323
|
+
(side === 'right' && x <= refRect.left + 1)) {
|
|
1324
|
+
closeIfNoOpenChild();
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
// Stay open while the cursor is within the rectangular trough between the two elements.
|
|
1328
|
+
let isInsideTroughRect = false;
|
|
1329
|
+
switch (side) {
|
|
1330
|
+
case 'top':
|
|
1331
|
+
isInsideTroughRect = isInsideAxisAlignedRect(clientX, clientY, left, refRect.top + 1, right, rect.bottom - 1);
|
|
1332
|
+
break;
|
|
1333
|
+
case 'bottom':
|
|
1334
|
+
isInsideTroughRect = isInsideAxisAlignedRect(clientX, clientY, left, rect.top + 1, right, refRect.bottom - 1);
|
|
1335
|
+
break;
|
|
1336
|
+
case 'left':
|
|
1337
|
+
isInsideTroughRect = isInsideAxisAlignedRect(clientX, clientY, rect.right - 1, bottom, refRect.left + 1, top);
|
|
1338
|
+
break;
|
|
1339
|
+
case 'right':
|
|
1340
|
+
isInsideTroughRect = isInsideAxisAlignedRect(clientX, clientY, refRect.right - 1, bottom, rect.left + 1, top);
|
|
1341
|
+
break;
|
|
1342
|
+
}
|
|
1343
|
+
if (isInsideTroughRect)
|
|
1344
|
+
return;
|
|
1345
|
+
if (hasLanded && !isInsideRect(clientX, clientY, refRect)) {
|
|
1346
|
+
closeIfNoOpenChild();
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
if (isCursorMovingSlowly(clientX, clientY)) {
|
|
1350
|
+
closeIfNoOpenChild();
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
let isInsidePolygon = false;
|
|
1354
|
+
switch (side) {
|
|
1355
|
+
case 'top': {
|
|
1356
|
+
const cursorXOffset = isFloatingWider ? POLYGON_BUFFER / 2 : POLYGON_BUFFER * 4;
|
|
1357
|
+
const cursorPointOneX = isFloatingWider
|
|
1358
|
+
? x + cursorXOffset
|
|
1359
|
+
: cursorLeaveFromRight
|
|
1360
|
+
? x + cursorXOffset
|
|
1361
|
+
: x - cursorXOffset;
|
|
1362
|
+
const cursorPointTwoX = isFloatingWider
|
|
1363
|
+
? x - cursorXOffset
|
|
1364
|
+
: cursorLeaveFromRight
|
|
1365
|
+
? x + cursorXOffset
|
|
1366
|
+
: x - cursorXOffset;
|
|
1367
|
+
const cursorPointY = y + POLYGON_BUFFER + 1;
|
|
1368
|
+
const commonYLeft = cursorLeaveFromRight
|
|
1369
|
+
? rect.bottom - POLYGON_BUFFER
|
|
1370
|
+
: isFloatingWider
|
|
1371
|
+
? rect.bottom - POLYGON_BUFFER
|
|
1372
|
+
: rect.top;
|
|
1373
|
+
const commonYRight = cursorLeaveFromRight
|
|
1374
|
+
? isFloatingWider
|
|
1375
|
+
? rect.bottom - POLYGON_BUFFER
|
|
1376
|
+
: rect.top
|
|
1377
|
+
: rect.bottom - POLYGON_BUFFER;
|
|
1378
|
+
isInsidePolygon = isPointInQuadrilateral(clientX, clientY, cursorPointOneX, cursorPointY, cursorPointTwoX, cursorPointY, rect.left, commonYLeft, rect.right, commonYRight);
|
|
1379
|
+
break;
|
|
1380
|
+
}
|
|
1381
|
+
case 'bottom': {
|
|
1382
|
+
const cursorXOffset = isFloatingWider ? POLYGON_BUFFER / 2 : POLYGON_BUFFER * 4;
|
|
1383
|
+
const cursorPointOneX = isFloatingWider
|
|
1384
|
+
? x + cursorXOffset
|
|
1385
|
+
: cursorLeaveFromRight
|
|
1386
|
+
? x + cursorXOffset
|
|
1387
|
+
: x - cursorXOffset;
|
|
1388
|
+
const cursorPointTwoX = isFloatingWider
|
|
1389
|
+
? x - cursorXOffset
|
|
1390
|
+
: cursorLeaveFromRight
|
|
1391
|
+
? x + cursorXOffset
|
|
1392
|
+
: x - cursorXOffset;
|
|
1393
|
+
const cursorPointY = y - POLYGON_BUFFER;
|
|
1394
|
+
const commonYLeft = cursorLeaveFromRight
|
|
1395
|
+
? rect.top + POLYGON_BUFFER
|
|
1396
|
+
: isFloatingWider
|
|
1397
|
+
? rect.top + POLYGON_BUFFER
|
|
1398
|
+
: rect.bottom;
|
|
1399
|
+
const commonYRight = cursorLeaveFromRight
|
|
1400
|
+
? isFloatingWider
|
|
1401
|
+
? rect.top + POLYGON_BUFFER
|
|
1402
|
+
: rect.bottom
|
|
1403
|
+
: rect.top + POLYGON_BUFFER;
|
|
1404
|
+
isInsidePolygon = isPointInQuadrilateral(clientX, clientY, cursorPointOneX, cursorPointY, cursorPointTwoX, cursorPointY, rect.left, commonYLeft, rect.right, commonYRight);
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
case 'left': {
|
|
1408
|
+
const cursorYOffset = isFloatingTaller ? POLYGON_BUFFER / 2 : POLYGON_BUFFER * 4;
|
|
1409
|
+
const cursorPointOneY = isFloatingTaller
|
|
1410
|
+
? y + cursorYOffset
|
|
1411
|
+
: cursorLeaveFromBottom
|
|
1412
|
+
? y + cursorYOffset
|
|
1413
|
+
: y - cursorYOffset;
|
|
1414
|
+
const cursorPointTwoY = isFloatingTaller
|
|
1415
|
+
? y - cursorYOffset
|
|
1416
|
+
: cursorLeaveFromBottom
|
|
1417
|
+
? y + cursorYOffset
|
|
1418
|
+
: y - cursorYOffset;
|
|
1419
|
+
const cursorPointX = x + POLYGON_BUFFER + 1;
|
|
1420
|
+
const commonXTop = cursorLeaveFromBottom
|
|
1421
|
+
? rect.right - POLYGON_BUFFER
|
|
1422
|
+
: isFloatingTaller
|
|
1423
|
+
? rect.right - POLYGON_BUFFER
|
|
1424
|
+
: rect.left;
|
|
1425
|
+
const commonXBottom = cursorLeaveFromBottom
|
|
1426
|
+
? isFloatingTaller
|
|
1427
|
+
? rect.right - POLYGON_BUFFER
|
|
1428
|
+
: rect.left
|
|
1429
|
+
: rect.right - POLYGON_BUFFER;
|
|
1430
|
+
isInsidePolygon = isPointInQuadrilateral(clientX, clientY, commonXTop, rect.top, commonXBottom, rect.bottom, cursorPointX, cursorPointOneY, cursorPointX, cursorPointTwoY);
|
|
1431
|
+
break;
|
|
1432
|
+
}
|
|
1433
|
+
case 'right': {
|
|
1434
|
+
const cursorYOffset = isFloatingTaller ? POLYGON_BUFFER / 2 : POLYGON_BUFFER * 4;
|
|
1435
|
+
const cursorPointOneY = isFloatingTaller
|
|
1436
|
+
? y + cursorYOffset
|
|
1437
|
+
: cursorLeaveFromBottom
|
|
1438
|
+
? y + cursorYOffset
|
|
1439
|
+
: y - cursorYOffset;
|
|
1440
|
+
const cursorPointTwoY = isFloatingTaller
|
|
1441
|
+
? y - cursorYOffset
|
|
1442
|
+
: cursorLeaveFromBottom
|
|
1443
|
+
? y + cursorYOffset
|
|
1444
|
+
: y - cursorYOffset;
|
|
1445
|
+
const cursorPointX = x - POLYGON_BUFFER;
|
|
1446
|
+
const commonXTop = cursorLeaveFromBottom
|
|
1447
|
+
? rect.left + POLYGON_BUFFER
|
|
1448
|
+
: isFloatingTaller
|
|
1449
|
+
? rect.left + POLYGON_BUFFER
|
|
1450
|
+
: rect.right;
|
|
1451
|
+
const commonXBottom = cursorLeaveFromBottom
|
|
1452
|
+
? isFloatingTaller
|
|
1453
|
+
? rect.left + POLYGON_BUFFER
|
|
1454
|
+
: rect.right
|
|
1455
|
+
: rect.left + POLYGON_BUFFER;
|
|
1456
|
+
isInsidePolygon = isPointInQuadrilateral(clientX, clientY, cursorPointX, cursorPointOneY, cursorPointX, cursorPointTwoY, commonXTop, rect.top, commonXBottom, rect.bottom);
|
|
1457
|
+
break;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
if (!isInsidePolygon) {
|
|
1461
|
+
closeIfNoOpenChild();
|
|
1462
|
+
}
|
|
1463
|
+
else if (!hasLanded) {
|
|
1464
|
+
// Inside the polygon but not landed: if the cursor halts here (no further moves),
|
|
1465
|
+
// close shortly after so a stationary cursor in the gap doesn't keep it open.
|
|
1466
|
+
restTimer = setTimeout(closeIfNoOpenChild, REST_CHECK_MS);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return { handler: onMouseMove, dispose: () => clearTimeout(restTimer) };
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Pointer-events "tunnel" used while a submenu opened by hover is being traversed. Disables pointer
|
|
1473
|
+
* events on `scope` (the parent popup or `document.body`) while keeping the `reference` and
|
|
1474
|
+
* `floating` interactive, so sibling items cannot react until the cursor lands or the submenu
|
|
1475
|
+
* closes. Returns a cleanup that restores the exact previous inline values.
|
|
1476
|
+
*/
|
|
1477
|
+
function applyPointerTunnel(scope, reference, floating) {
|
|
1478
|
+
const saved = [
|
|
1479
|
+
[scope, scope.style.pointerEvents],
|
|
1480
|
+
[reference, reference.style.pointerEvents],
|
|
1481
|
+
[floating, floating.style.pointerEvents]
|
|
1482
|
+
];
|
|
1483
|
+
scope.style.pointerEvents = 'none';
|
|
1484
|
+
reference.style.pointerEvents = 'auto';
|
|
1485
|
+
floating.style.pointerEvents = 'auto';
|
|
1486
|
+
let cleaned = false;
|
|
1487
|
+
return () => {
|
|
1488
|
+
if (cleaned)
|
|
1489
|
+
return;
|
|
1490
|
+
cleaned = true;
|
|
1491
|
+
saved.forEach(([el, prev]) => (el.style.pointerEvents = prev));
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
/** Registry of submenus currently open, keyed by their trigger element. */
|
|
1495
|
+
const openSubmenus = new Map();
|
|
1496
|
+
/** Marks `trigger`'s submenu (with popup `popup`) as open. Returns a cleanup to unmark it. */
|
|
1497
|
+
function registerOpenSubmenu(trigger, popup) {
|
|
1498
|
+
openSubmenus.set(trigger, popup);
|
|
1499
|
+
return () => {
|
|
1500
|
+
if (openSubmenus.get(trigger) === popup) {
|
|
1501
|
+
openSubmenus.delete(trigger);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Whether any *other* open submenu is a descendant of `floating` (a nested child is open).
|
|
1507
|
+
*
|
|
1508
|
+
* Portal-safe: `RdxMenuPortal` only teleports a submenu's positioner/popup template, never the
|
|
1509
|
+
* sub-trigger (which stays in its parent popup), and a portaled popup carries its descendant
|
|
1510
|
+
* triggers with it — so `floating.contains(childTrigger)` holds whether or not portals are used.
|
|
1511
|
+
*/
|
|
1512
|
+
function hasOpenChildSubmenu(reference, floating) {
|
|
1513
|
+
for (const trigger of openSubmenus.keys()) {
|
|
1514
|
+
if (trigger !== reference && floating.contains(trigger)) {
|
|
1515
|
+
return true;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
return false;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const numberOrUndefined$1 = (value) => (value == null ? undefined : numberAttribute(value));
|
|
1522
|
+
const submenuRootsByTrigger = new WeakMap();
|
|
1523
|
+
/**
|
|
1524
|
+
* An item inside a parent menu that opens a nested submenu.
|
|
1525
|
+
*
|
|
1526
|
+
* Place this inside `ng-container rdxMenuRoot` that wraps both the trigger
|
|
1527
|
+
* and the submenu positioner. The inner root provides the submenu context;
|
|
1528
|
+
* the outer popup discovers this element via `[rdxMenuSubTrigger]` in its
|
|
1529
|
+
* ITEM_SELECTOR and includes it in keyboard navigation.
|
|
1530
|
+
*/
|
|
1531
|
+
class RdxMenuSubTrigger {
|
|
1532
|
+
constructor() {
|
|
1533
|
+
this.submenuContext = injectRdxMenuRootContext();
|
|
1534
|
+
this.submenuRoot = inject(RdxMenuRoot);
|
|
1535
|
+
this.elementRef = inject(ElementRef);
|
|
1536
|
+
this.destroyRef = inject(DestroyRef);
|
|
1537
|
+
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
1538
|
+
this.isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
1539
|
+
/** Cursor position from the last pointer move over the trigger (safe-polygon apex). */
|
|
1540
|
+
this.lastPointer = null;
|
|
1541
|
+
/** Whether the current open was initiated by hover (vs keyboard / click). */
|
|
1542
|
+
this.openedByHover = false;
|
|
1543
|
+
/** Whether this trigger (and therefore the submenu) is disabled. */
|
|
1544
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1545
|
+
/** Whether this trigger should be treated as a native button. Auto-detected for `<button>`. */
|
|
1546
|
+
this.nativeButton = input(false, { ...(ngDevMode ? { debugName: "nativeButton" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1547
|
+
/** Whether hovering the trigger opens the submenu. */
|
|
1548
|
+
this.openOnHover = input(true, { ...(ngDevMode ? { debugName: "openOnHover" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1549
|
+
/** Delay before hover opens the submenu, in milliseconds. */
|
|
1550
|
+
this.delay = input(100, { ...(ngDevMode ? { debugName: "delay" } : /* istanbul ignore next */ {}), transform: numberOrUndefined$1 });
|
|
1551
|
+
/** Delay before a pending hover close runs, in milliseconds. */
|
|
1552
|
+
this.closeDelay = input(0, { ...(ngDevMode ? { debugName: "closeDelay" } : /* istanbul ignore next */ {}), transform: numberOrUndefined$1 });
|
|
1553
|
+
/** Explicit typeahead label. When set, overrides textContent for character search. */
|
|
1554
|
+
this.label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1555
|
+
/** Highlighted when focused OR while the submenu is open. */
|
|
1556
|
+
this.highlighted = computed(() => this.isFocused() || this.submenuContext.isOpen(), ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
|
|
1557
|
+
this.nativeButtonState = computed(() => this.nativeButton() || this.elementRef.nativeElement.tagName === 'BUTTON', ...(ngDevMode ? [{ debugName: "nativeButtonState" }] : /* istanbul ignore next */ []));
|
|
1558
|
+
this.submenuContext.markAsSubmenu();
|
|
1559
|
+
effect((onCleanup) => {
|
|
1560
|
+
const el = this.elementRef.nativeElement;
|
|
1561
|
+
const unregister = this.submenuContext.registerTrigger(el);
|
|
1562
|
+
submenuRootsByTrigger.set(el, this.submenuRoot);
|
|
1563
|
+
onCleanup(() => {
|
|
1564
|
+
unregister();
|
|
1565
|
+
submenuRootsByTrigger.delete(el);
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
// While this submenu is open by hover, it owns the decision to close itself: a document
|
|
1569
|
+
// `mousemove` handler keeps it open while the cursor traverses the safe polygon toward the
|
|
1570
|
+
// popup, and a pointer-events tunnel stops siblings from stealing it mid-traversal.
|
|
1571
|
+
effect((onCleanup) => {
|
|
1572
|
+
const open = this.submenuContext.isOpen();
|
|
1573
|
+
const popup = this.submenuContext.popupElement();
|
|
1574
|
+
// Once closed, forget how this open started so the next (possibly keyboard / programmatic)
|
|
1575
|
+
// open doesn't re-arm the hover tunnel from a stale flag.
|
|
1576
|
+
if (!open) {
|
|
1577
|
+
this.openedByHover = false;
|
|
1578
|
+
this.lastPointer = null;
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (!popup || !this.openedByHover || !this.lastPointer || !this.isBrowser) {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
const reference = this.elementRef.nativeElement;
|
|
1585
|
+
const scope = reference.closest('[rdxMenuPopup]') ?? document.body;
|
|
1586
|
+
const unregisterOpen = registerOpenSubmenu(reference, popup);
|
|
1587
|
+
let removeTunnel = applyPointerTunnel(scope, reference, popup);
|
|
1588
|
+
const { handler, dispose } = createSafePolygonHandler({
|
|
1589
|
+
reference,
|
|
1590
|
+
floating: popup,
|
|
1591
|
+
// Live getter: `data-side` may be unresolved at open time and can flip on collision.
|
|
1592
|
+
side: () => popup.getAttribute('data-side') ?? 'right',
|
|
1593
|
+
x: this.lastPointer.x,
|
|
1594
|
+
y: this.lastPointer.y,
|
|
1595
|
+
onClose: () => this.scheduleClose(),
|
|
1596
|
+
cancelClose: () => clearTimeout(this.closeTimer),
|
|
1597
|
+
hasOpenChild: () => hasOpenChildSubmenu(reference, popup),
|
|
1598
|
+
onLanded: () => {
|
|
1599
|
+
removeTunnel?.();
|
|
1600
|
+
removeTunnel = undefined;
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
document.addEventListener('mousemove', handler);
|
|
1604
|
+
onCleanup(() => {
|
|
1605
|
+
document.removeEventListener('mousemove', handler);
|
|
1606
|
+
dispose();
|
|
1607
|
+
removeTunnel?.();
|
|
1608
|
+
unregisterOpen();
|
|
1609
|
+
clearTimeout(this.closeTimer);
|
|
1610
|
+
});
|
|
1611
|
+
});
|
|
1612
|
+
this.destroyRef.onDestroy(() => {
|
|
1613
|
+
clearTimeout(this.openTimer);
|
|
1614
|
+
clearTimeout(this.closeTimer);
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
scheduleClose() {
|
|
1618
|
+
clearTimeout(this.closeTimer);
|
|
1619
|
+
const delay = this.closeDelay() ?? 0;
|
|
1620
|
+
if (delay <= 0) {
|
|
1621
|
+
this.submenuContext.close();
|
|
1622
|
+
}
|
|
1623
|
+
else {
|
|
1624
|
+
this.closeTimer = setTimeout(() => this.submenuContext.close(), delay);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
onFocus() {
|
|
1628
|
+
if (!this.disabled()) {
|
|
1629
|
+
this.clearSiblingHighlights();
|
|
1630
|
+
this.isFocused.set(true);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
onBlur() {
|
|
1634
|
+
this.isFocused.set(false);
|
|
1635
|
+
}
|
|
1636
|
+
onClick() {
|
|
1637
|
+
if (this.disabled())
|
|
1638
|
+
return;
|
|
1639
|
+
this.openedByHover = false;
|
|
1640
|
+
this.clearSiblingHighlights();
|
|
1641
|
+
if (!this.submenuContext.isOpen()) {
|
|
1642
|
+
this.closeSiblingSubmenus();
|
|
1643
|
+
}
|
|
1644
|
+
this.submenuContext.toggle();
|
|
1645
|
+
}
|
|
1646
|
+
onArrowRight(event) {
|
|
1647
|
+
if (this.disabled())
|
|
1648
|
+
return;
|
|
1649
|
+
event.preventDefault();
|
|
1650
|
+
event.stopPropagation();
|
|
1651
|
+
this.openedByHover = false;
|
|
1652
|
+
this.clearSiblingHighlights();
|
|
1653
|
+
if (!this.submenuContext.isOpen()) {
|
|
1654
|
+
this.closeSiblingSubmenus();
|
|
1655
|
+
this.submenuContext.show();
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
onPointerMove(event) {
|
|
1659
|
+
if (event.pointerType !== 'mouse' || this.disabled() || !this.openOnHover())
|
|
1660
|
+
return;
|
|
1661
|
+
this.lastPointer = { x: event.clientX, y: event.clientY };
|
|
1662
|
+
this.clearSiblingHighlights();
|
|
1663
|
+
if (this.submenuContext.highlightItemOnHover() && document.activeElement !== this.elementRef.nativeElement) {
|
|
1664
|
+
this.elementRef.nativeElement.focus({ preventScroll: true });
|
|
1665
|
+
}
|
|
1666
|
+
if (!this.submenuContext.isOpen()) {
|
|
1667
|
+
clearTimeout(this.openTimer);
|
|
1668
|
+
this.closeSiblingSubmenus();
|
|
1669
|
+
this.openTimer = setTimeout(() => {
|
|
1670
|
+
this.openedByHover = true;
|
|
1671
|
+
this.submenuContext.show(false);
|
|
1672
|
+
}, this.delay() ?? 100);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
onPointerLeave() {
|
|
1676
|
+
clearTimeout(this.openTimer);
|
|
1677
|
+
}
|
|
1678
|
+
clearHighlight() {
|
|
1679
|
+
this.isFocused.set(false);
|
|
1680
|
+
}
|
|
1681
|
+
closeSiblingSubmenus() {
|
|
1682
|
+
const currentTrigger = this.elementRef.nativeElement;
|
|
1683
|
+
const parentPopup = currentTrigger.closest('[rdxMenuPopup]');
|
|
1684
|
+
if (!parentPopup)
|
|
1685
|
+
return;
|
|
1686
|
+
parentPopup.querySelectorAll('[rdxMenuSubTrigger]').forEach((trigger) => {
|
|
1687
|
+
if (trigger === currentTrigger || trigger.closest('[rdxMenuPopup]') !== parentPopup) {
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
submenuRootsByTrigger.get(trigger)?.close();
|
|
1691
|
+
trigger.dispatchEvent(new CustomEvent('rdx-menu-subtrigger-clear-highlight'));
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
clearSiblingHighlights() {
|
|
1695
|
+
const currentTrigger = this.elementRef.nativeElement;
|
|
1696
|
+
const parentPopup = currentTrigger.closest('[rdxMenuPopup]');
|
|
1697
|
+
if (!parentPopup)
|
|
1698
|
+
return;
|
|
1699
|
+
parentPopup.querySelectorAll('[rdxMenuSubTrigger]').forEach((trigger) => {
|
|
1700
|
+
if (trigger === currentTrigger || trigger.closest('[rdxMenuPopup]') !== parentPopup) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
trigger.dispatchEvent(new CustomEvent('rdx-menu-subtrigger-clear-highlight'));
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSubTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1707
|
+
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", "tabindex": "-1" }, listeners: { "focus": "onFocus()", "blur": "onBlur()", "click": "onClick()", "keydown.arrowright": "onArrowRight($event)", "pointermove": "onPointerMove($event)", "pointerleave": "onPointerLeave()", "rdx-menu-subtrigger-clear-highlight": "clearHighlight()" }, properties: { "attr.type": "nativeButtonState() ? \"button\" : undefined", "attr.aria-haspopup": "\"menu\"", "attr.aria-expanded": "submenuContext.isOpen()", "attr.aria-disabled": "disabled() ? true : undefined", "attr.disabled": "nativeButtonState() && disabled() ? \"\" : undefined", "attr.data-state": "submenuContext.isOpen() ? \"open\" : \"closed\"", "attr.data-popup-open": "submenuContext.isOpen() ? \"\" : undefined", "attr.data-highlighted": "highlighted() ? \"\" : undefined", "attr.data-disabled": "disabled() ? \"\" : undefined", "attr.data-label": "label() ?? undefined" } }, exportAs: ["rdxMenuSubTrigger"], hostDirectives: [{ directive: i1.RdxPopperAnchor }, { directive: i2.RdxDismissableLayerBranch }], ngImport: i0 }); }
|
|
1708
|
+
}
|
|
1709
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuSubTrigger, decorators: [{
|
|
1710
|
+
type: Directive,
|
|
1711
|
+
args: [{
|
|
1712
|
+
selector: '[rdxMenuSubTrigger]',
|
|
1713
|
+
exportAs: 'rdxMenuSubTrigger',
|
|
1714
|
+
hostDirectives: [RdxPopperAnchor, RdxDismissableLayerBranch],
|
|
1715
|
+
host: {
|
|
1716
|
+
'[attr.type]': 'nativeButtonState() ? "button" : undefined',
|
|
459
1717
|
role: 'menuitem',
|
|
460
|
-
|
|
461
|
-
'[attr.aria-
|
|
462
|
-
'[attr.
|
|
463
|
-
'[attr.
|
|
464
|
-
'
|
|
1718
|
+
tabindex: '-1',
|
|
1719
|
+
'[attr.aria-haspopup]': '"menu"',
|
|
1720
|
+
'[attr.aria-expanded]': 'submenuContext.isOpen()',
|
|
1721
|
+
'[attr.aria-disabled]': 'disabled() ? true : undefined',
|
|
1722
|
+
'[attr.disabled]': 'nativeButtonState() && disabled() ? "" : undefined',
|
|
1723
|
+
'[attr.data-state]': 'submenuContext.isOpen() ? "open" : "closed"',
|
|
1724
|
+
'[attr.data-popup-open]': 'submenuContext.isOpen() ? "" : undefined',
|
|
1725
|
+
'[attr.data-highlighted]': 'highlighted() ? "" : undefined',
|
|
1726
|
+
'[attr.data-disabled]': 'disabled() ? "" : undefined',
|
|
1727
|
+
'[attr.data-label]': 'label() ?? undefined',
|
|
1728
|
+
'(focus)': 'onFocus()',
|
|
1729
|
+
'(blur)': 'onBlur()',
|
|
1730
|
+
'(click)': 'onClick()',
|
|
1731
|
+
'(keydown.arrowright)': 'onArrowRight($event)',
|
|
1732
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
1733
|
+
'(pointerleave)': 'onPointerLeave()',
|
|
1734
|
+
'(rdx-menu-subtrigger-clear-highlight)': 'clearHighlight()'
|
|
1735
|
+
}
|
|
1736
|
+
}]
|
|
1737
|
+
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], nativeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "nativeButton", required: false }] }], openOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnHover", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
|
|
1738
|
+
|
|
1739
|
+
const numberOrUndefined = (value) => (value == null ? undefined : numberAttribute(value));
|
|
1740
|
+
/**
|
|
1741
|
+
* A button that opens the menu.
|
|
1742
|
+
*/
|
|
1743
|
+
class RdxMenuTrigger {
|
|
1744
|
+
constructor() {
|
|
1745
|
+
this.rootContext = injectRdxMenuRootContext();
|
|
1746
|
+
this.elementRef = inject(ElementRef);
|
|
1747
|
+
this.destroyRef = inject(DestroyRef);
|
|
1748
|
+
this.dismissableLayersContext = inject(RdxDismissableLayersContextToken);
|
|
1749
|
+
/** Whether this trigger should be treated as a native button. Auto-detected for `<button>`. */
|
|
1750
|
+
this.nativeButton = input(false, { ...(ngDevMode ? { debugName: "nativeButton" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1751
|
+
/** Whether this trigger is disabled. */
|
|
1752
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1753
|
+
/** Whether hovering the trigger opens the menu. */
|
|
1754
|
+
this.openOnHover = input(false, { ...(ngDevMode ? { debugName: "openOnHover" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1755
|
+
/** Delay before hover opens the menu, in milliseconds. */
|
|
1756
|
+
this.delay = input(undefined, { ...(ngDevMode ? { debugName: "delay" } : /* istanbul ignore next */ {}), transform: numberOrUndefined });
|
|
1757
|
+
/** Delay before hover leave closes the menu, in milliseconds. */
|
|
1758
|
+
this.closeDelay = input(undefined, { ...(ngDevMode ? { debugName: "closeDelay" } : /* istanbul ignore next */ {}), transform: numberOrUndefined });
|
|
1759
|
+
this.nativeButtonState = computed(() => this.nativeButton() || this.elementRef.nativeElement.tagName === 'BUTTON', ...(ngDevMode ? [{ debugName: "nativeButtonState" }] : /* istanbul ignore next */ []));
|
|
1760
|
+
this.isDisabled = computed(() => this.rootContext.disabled() || this.disabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
1761
|
+
effect((onCleanup) => {
|
|
1762
|
+
const el = this.elementRef.nativeElement;
|
|
1763
|
+
const unregister = this.rootContext.registerTrigger(el);
|
|
1764
|
+
onCleanup(unregister);
|
|
1765
|
+
});
|
|
1766
|
+
// When a coordinator (e.g. the menubar) drives this trigger, hover-switching focuses the
|
|
1767
|
+
// trigger and opens the popup without pulling focus inside it. Register the trigger as a
|
|
1768
|
+
// dismissable-layer branch so that focus/pointer interactions on it are treated as "inside"
|
|
1769
|
+
// and do not dismiss the just-opened popup.
|
|
1770
|
+
effect((onCleanup) => {
|
|
1771
|
+
if (!this.rootContext.hasTriggerInteractionHandler()) {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const el = this.elementRef.nativeElement;
|
|
1775
|
+
this.dismissableLayersContext.branches.update((branches) => [...branches, el]);
|
|
1776
|
+
onCleanup(() => {
|
|
1777
|
+
this.dismissableLayersContext.branches.update((branches) => branches.filter((b) => b !== el));
|
|
1778
|
+
});
|
|
1779
|
+
});
|
|
1780
|
+
this.destroyRef.onDestroy(() => {
|
|
1781
|
+
this.clearOpenTimer();
|
|
1782
|
+
this.clearCloseTimer();
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
handleClick() {
|
|
1786
|
+
if (this.isDisabled()) {
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
if (this.rootContext.handleTriggerInteraction({ type: 'click' })) {
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
this.rootContext.toggle();
|
|
1793
|
+
}
|
|
1794
|
+
handleArrowDown(event) {
|
|
1795
|
+
if (this.rootContext.handleTriggerInteraction({ type: 'arrowdown', event })) {
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
event.preventDefault();
|
|
1799
|
+
if (!this.isDisabled() && !this.rootContext.isOpen()) {
|
|
1800
|
+
this.rootContext.show('first');
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
handleArrowUp(event) {
|
|
1804
|
+
if (this.rootContext.handleTriggerInteraction({ type: 'arrowup', event })) {
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
event.preventDefault();
|
|
1808
|
+
if (!this.isDisabled() && !this.rootContext.isOpen()) {
|
|
1809
|
+
this.rootContext.show('last');
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
handleArrowLeft(event) {
|
|
1813
|
+
this.rootContext.handleTriggerInteraction({ type: 'arrowleft', event });
|
|
1814
|
+
}
|
|
1815
|
+
handleArrowRight(event) {
|
|
1816
|
+
this.rootContext.handleTriggerInteraction({ type: 'arrowright', event });
|
|
1817
|
+
}
|
|
1818
|
+
handleHome(event) {
|
|
1819
|
+
this.rootContext.handleTriggerInteraction({ type: 'home', event });
|
|
1820
|
+
}
|
|
1821
|
+
handleEnd(event) {
|
|
1822
|
+
this.rootContext.handleTriggerInteraction({ type: 'end', event });
|
|
1823
|
+
}
|
|
1824
|
+
handleEscape(event) {
|
|
1825
|
+
this.rootContext.handleTriggerInteraction({ type: 'escape', event });
|
|
1826
|
+
}
|
|
1827
|
+
handleKeyboardToggle(event) {
|
|
1828
|
+
if (this.nativeButtonState()) {
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
event.preventDefault();
|
|
1832
|
+
this.handleClick();
|
|
1833
|
+
}
|
|
1834
|
+
handlePointerEnter(event) {
|
|
1835
|
+
if (this.rootContext.handleTriggerInteraction({ type: 'pointerenter', event })) {
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
if (event.pointerType === 'touch' || !this.openOnHover() || this.isDisabled()) {
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
this.clearCloseTimer();
|
|
1842
|
+
this.clearOpenTimer();
|
|
1843
|
+
const delay = this.delay() ?? 0;
|
|
1844
|
+
if (delay <= 0) {
|
|
1845
|
+
this.rootContext.show();
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
this.openTimer = setTimeout(() => {
|
|
1849
|
+
this.openTimer = undefined;
|
|
1850
|
+
this.rootContext.show();
|
|
1851
|
+
}, delay);
|
|
1852
|
+
}
|
|
1853
|
+
handlePointerLeave(event) {
|
|
1854
|
+
if (event.pointerType === 'touch' || !this.openOnHover()) {
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
this.clearOpenTimer();
|
|
1858
|
+
this.clearCloseTimer();
|
|
1859
|
+
const closeDelay = this.closeDelay() ?? 0;
|
|
1860
|
+
if (closeDelay <= 0) {
|
|
1861
|
+
this.rootContext.close();
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
this.closeTimer = setTimeout(() => {
|
|
1865
|
+
this.closeTimer = undefined;
|
|
1866
|
+
this.rootContext.close();
|
|
1867
|
+
}, closeDelay);
|
|
1868
|
+
}
|
|
1869
|
+
clearOpenTimer() {
|
|
1870
|
+
clearTimeout(this.openTimer);
|
|
1871
|
+
this.openTimer = undefined;
|
|
1872
|
+
}
|
|
1873
|
+
clearCloseTimer() {
|
|
1874
|
+
clearTimeout(this.closeTimer);
|
|
1875
|
+
this.closeTimer = undefined;
|
|
1876
|
+
}
|
|
1877
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1878
|
+
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: { "click": "handleClick()", "pointerenter": "handlePointerEnter($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.tabindex": "rootContext.hasTriggerInteractionHandler() ? \"-1\" : undefined", "attr.aria-haspopup": "\"menu\"", "attr.aria-expanded": "rootContext.isOpen()", "attr.aria-disabled": "isDisabled() ? true : undefined", "attr.disabled": "nativeButtonState() && isDisabled() ? \"\" : undefined", "attr.data-state": "rootContext.isOpen() ? \"open\" : \"closed\"", "attr.data-disabled": "isDisabled() ? \"\" : undefined", "attr.data-popup-open": "rootContext.isOpen() ? \"\" : undefined" } }, exportAs: ["rdxMenuTrigger"], hostDirectives: [{ directive: i1.RdxPopperAnchor }], ngImport: i0 }); }
|
|
1879
|
+
}
|
|
1880
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuTrigger, decorators: [{
|
|
1881
|
+
type: Directive,
|
|
1882
|
+
args: [{
|
|
1883
|
+
selector: '[rdxMenuTrigger]',
|
|
1884
|
+
exportAs: 'rdxMenuTrigger',
|
|
1885
|
+
hostDirectives: [RdxPopperAnchor],
|
|
1886
|
+
host: {
|
|
1887
|
+
'[attr.type]': 'nativeButtonState() ? "button" : undefined',
|
|
1888
|
+
'[attr.role]': 'rootContext.hasTriggerInteractionHandler() ? "menuitem" : nativeButtonState() ? undefined : "button"',
|
|
1889
|
+
'[attr.tabindex]': 'rootContext.hasTriggerInteractionHandler() ? "-1" : undefined',
|
|
1890
|
+
'[attr.aria-haspopup]': '"menu"',
|
|
1891
|
+
'[attr.aria-expanded]': 'rootContext.isOpen()',
|
|
1892
|
+
'[attr.aria-disabled]': 'isDisabled() ? true : undefined',
|
|
1893
|
+
'[attr.disabled]': 'nativeButtonState() && isDisabled() ? "" : undefined',
|
|
1894
|
+
'[attr.data-state]': 'rootContext.isOpen() ? "open" : "closed"',
|
|
1895
|
+
'[attr.data-disabled]': 'isDisabled() ? "" : undefined',
|
|
1896
|
+
'[attr.data-popup-open]': 'rootContext.isOpen() ? "" : undefined',
|
|
1897
|
+
'(click)': 'handleClick()',
|
|
1898
|
+
'(pointerenter)': 'handlePointerEnter($event)',
|
|
1899
|
+
'(pointerleave)': 'handlePointerLeave($event)',
|
|
1900
|
+
'(keydown.arrowdown)': 'handleArrowDown($event)',
|
|
1901
|
+
'(keydown.arrowup)': 'handleArrowUp($event)',
|
|
1902
|
+
'(keydown.arrowleft)': 'handleArrowLeft($event)',
|
|
1903
|
+
'(keydown.arrowright)': 'handleArrowRight($event)',
|
|
1904
|
+
'(keydown.home)': 'handleHome($event)',
|
|
1905
|
+
'(keydown.end)': 'handleEnd($event)',
|
|
1906
|
+
'(keydown.escape)': 'handleEscape($event)',
|
|
1907
|
+
'(keydown.enter)': 'handleKeyboardToggle($event)',
|
|
1908
|
+
'(keydown.space)': 'handleKeyboardToggle($event)'
|
|
1909
|
+
}
|
|
1910
|
+
}]
|
|
1911
|
+
}], ctorParameters: () => [], propDecorators: { nativeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "nativeButton", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], openOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnHover", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }] } });
|
|
1912
|
+
|
|
1913
|
+
/**
|
|
1914
|
+
* A viewport that smoothly animates the popup size when its content changes
|
|
1915
|
+
* (e.g. switching menubar menus of different sizes, or expanding a section).
|
|
1916
|
+
*
|
|
1917
|
+
* It measures its content with a `ResizeObserver` and exposes the current size
|
|
1918
|
+
* as `--popup-width` / `--popup-height` CSS variables on the host. Drive the
|
|
1919
|
+
* animation from the consumer side, for example:
|
|
1920
|
+
*
|
|
1921
|
+
* ```css
|
|
1922
|
+
* [rdxMenuPopup] {
|
|
1923
|
+
* width: var(--popup-width);
|
|
1924
|
+
* height: var(--popup-height);
|
|
1925
|
+
* transition: width 200ms, height 200ms;
|
|
1926
|
+
* }
|
|
1927
|
+
* ```
|
|
1928
|
+
*
|
|
1929
|
+
* `data-transitioning` is present while a size change is in flight.
|
|
1930
|
+
*/
|
|
1931
|
+
class RdxMenuViewport {
|
|
1932
|
+
constructor() {
|
|
1933
|
+
this.elementRef = inject(ElementRef);
|
|
1934
|
+
this.destroyRef = inject(DestroyRef);
|
|
1935
|
+
this.width = signal(undefined, ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
1936
|
+
this.height = signal(undefined, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
1937
|
+
this.transitioning = signal(false, ...(ngDevMode ? [{ debugName: "transitioning" }] : /* istanbul ignore next */ []));
|
|
1938
|
+
afterNextRender(() => {
|
|
1939
|
+
const el = this.elementRef.nativeElement;
|
|
1940
|
+
// Seed the initial size without marking a transition.
|
|
1941
|
+
this.width.set(el.offsetWidth);
|
|
1942
|
+
this.height.set(el.offsetHeight);
|
|
1943
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
this.observer = new ResizeObserver((entries) => {
|
|
1947
|
+
const entry = entries[0];
|
|
1948
|
+
if (!entry) {
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
const nextWidth = Math.round(entry.contentRect.width);
|
|
1952
|
+
const nextHeight = Math.round(entry.contentRect.height);
|
|
1953
|
+
if (nextWidth === this.width() && nextHeight === this.height()) {
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
this.width.set(nextWidth);
|
|
1957
|
+
this.height.set(nextHeight);
|
|
1958
|
+
this.markTransitioning();
|
|
1959
|
+
});
|
|
1960
|
+
this.observer.observe(el);
|
|
1961
|
+
});
|
|
1962
|
+
this.destroyRef.onDestroy(() => {
|
|
1963
|
+
this.observer?.disconnect();
|
|
1964
|
+
clearTimeout(this.transitionTimer);
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
markTransitioning() {
|
|
1968
|
+
this.transitioning.set(true);
|
|
1969
|
+
clearTimeout(this.transitionTimer);
|
|
1970
|
+
const duration = getMaxTransitionDuration(this.elementRef.nativeElement);
|
|
1971
|
+
this.transitionTimer = setTimeout(() => this.transitioning.set(false), duration > 0 ? duration + 50 : 0);
|
|
1972
|
+
}
|
|
1973
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuViewport, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1974
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: RdxMenuViewport, isStandalone: true, selector: "[rdxMenuViewport]", host: { properties: { "attr.data-transitioning": "transitioning() ? \"\" : undefined", "style.--popup-width.px": "width()", "style.--popup-height.px": "height()" } }, exportAs: ["rdxMenuViewport"], ngImport: i0 }); }
|
|
1975
|
+
}
|
|
1976
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuViewport, decorators: [{
|
|
1977
|
+
type: Directive,
|
|
1978
|
+
args: [{
|
|
1979
|
+
selector: '[rdxMenuViewport]',
|
|
1980
|
+
exportAs: 'rdxMenuViewport',
|
|
1981
|
+
host: {
|
|
1982
|
+
'[attr.data-transitioning]': 'transitioning() ? "" : undefined',
|
|
1983
|
+
'[style.--popup-width.px]': 'width()',
|
|
1984
|
+
'[style.--popup-height.px]': 'height()'
|
|
465
1985
|
}
|
|
466
1986
|
}]
|
|
467
|
-
}], ctorParameters: () => []
|
|
1987
|
+
}], ctorParameters: () => [] });
|
|
468
1988
|
|
|
469
1989
|
const menuImports = [
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
1990
|
+
RdxMenuRoot,
|
|
1991
|
+
RdxMenuTrigger,
|
|
1992
|
+
RdxMenuSubTrigger,
|
|
1993
|
+
RdxMenuPortal,
|
|
1994
|
+
RdxMenuPositioner,
|
|
1995
|
+
RdxMenuPopup,
|
|
1996
|
+
RdxMenuViewport,
|
|
1997
|
+
RdxMenuBackdrop,
|
|
1998
|
+
RdxMenuArrow,
|
|
1999
|
+
RdxMenuItem,
|
|
2000
|
+
RdxMenuLinkItem,
|
|
2001
|
+
RdxMenuGroup,
|
|
2002
|
+
RdxMenuGroupLabel,
|
|
2003
|
+
RdxMenuSeparator,
|
|
2004
|
+
RdxMenuCheckboxItem,
|
|
2005
|
+
RdxMenuCheckboxItemIndicator,
|
|
2006
|
+
RdxMenuRadioGroup,
|
|
2007
|
+
RdxMenuRadioItem,
|
|
2008
|
+
RdxMenuRadioItemIndicator
|
|
481
2009
|
];
|
|
482
2010
|
class RdxMenuModule {
|
|
483
2011
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
484
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuModule, imports: [
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
2012
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuModule, imports: [RdxMenuRoot,
|
|
2013
|
+
RdxMenuTrigger,
|
|
2014
|
+
RdxMenuSubTrigger,
|
|
2015
|
+
RdxMenuPortal,
|
|
2016
|
+
RdxMenuPositioner,
|
|
2017
|
+
RdxMenuPopup,
|
|
2018
|
+
RdxMenuViewport,
|
|
2019
|
+
RdxMenuBackdrop,
|
|
2020
|
+
RdxMenuArrow,
|
|
2021
|
+
RdxMenuItem,
|
|
2022
|
+
RdxMenuLinkItem,
|
|
2023
|
+
RdxMenuGroup,
|
|
2024
|
+
RdxMenuGroupLabel,
|
|
2025
|
+
RdxMenuSeparator,
|
|
2026
|
+
RdxMenuCheckboxItem,
|
|
2027
|
+
RdxMenuCheckboxItemIndicator,
|
|
2028
|
+
RdxMenuRadioGroup,
|
|
2029
|
+
RdxMenuRadioItem,
|
|
2030
|
+
RdxMenuRadioItemIndicator], exports: [RdxMenuRoot,
|
|
2031
|
+
RdxMenuTrigger,
|
|
2032
|
+
RdxMenuSubTrigger,
|
|
2033
|
+
RdxMenuPortal,
|
|
2034
|
+
RdxMenuPositioner,
|
|
2035
|
+
RdxMenuPopup,
|
|
2036
|
+
RdxMenuViewport,
|
|
2037
|
+
RdxMenuBackdrop,
|
|
2038
|
+
RdxMenuArrow,
|
|
2039
|
+
RdxMenuItem,
|
|
2040
|
+
RdxMenuLinkItem,
|
|
2041
|
+
RdxMenuGroup,
|
|
2042
|
+
RdxMenuGroupLabel,
|
|
2043
|
+
RdxMenuSeparator,
|
|
2044
|
+
RdxMenuCheckboxItem,
|
|
2045
|
+
RdxMenuCheckboxItemIndicator,
|
|
2046
|
+
RdxMenuRadioGroup,
|
|
2047
|
+
RdxMenuRadioItem,
|
|
2048
|
+
RdxMenuRadioItemIndicator] }); }
|
|
505
2049
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuModule }); }
|
|
506
2050
|
}
|
|
507
2051
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxMenuModule, decorators: [{
|
|
@@ -516,5 +2060,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
516
2060
|
* Generated bundle index. Do not edit.
|
|
517
2061
|
*/
|
|
518
2062
|
|
|
519
|
-
export {
|
|
2063
|
+
export { RdxMenuArrow, RdxMenuBackdrop, RdxMenuCheckboxItem, RdxMenuCheckboxItemIndicator, RdxMenuGroup, RdxMenuGroupLabel, RdxMenuItem, RdxMenuLinkItem, RdxMenuModule, RdxMenuPopup, RdxMenuPortal, RdxMenuPositioner, RdxMenuRadioGroup, RdxMenuRadioItem, RdxMenuRadioItemIndicator, RdxMenuRoot, RdxMenuSeparator, RdxMenuSubTrigger, RdxMenuTrigger, RdxMenuViewport, getCheckedState, injectRdxMenuCheckboxItemContext, injectRdxMenuRadioGroupContext, injectRdxMenuRadioItemContext, injectRdxMenuRootContext, isIndeterminate, provideRdxMenuCheckboxItemContext, provideRdxMenuRadioGroupContext, provideRdxMenuRadioItemContext, provideRdxMenuRootContext };
|
|
520
2064
|
//# sourceMappingURL=radix-ng-primitives-menu.mjs.map
|