ropav 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/accordion.css +17 -17
- package/dist/accordion.js +123 -155
- package/dist/alert.css +18 -18
- package/dist/alert.js +10 -11
- package/dist/aria.js +14 -0
- package/dist/aspect-ratio.js +1 -1
- package/dist/attributes.js +9 -0
- package/dist/attributes2.js +29 -0
- package/dist/avatar.css +19 -19
- package/dist/avatar.js +9 -17
- package/dist/badge.css +16 -16
- package/dist/badge.js +5 -5
- package/dist/button-group.js +1 -1
- package/dist/button-link.js +4 -3
- package/dist/button.js +4 -3
- package/dist/button.scss_vue_type_style_index_0_src_true_lang.js +1 -1
- package/dist/card.js +1 -1
- package/dist/checkbox.css +32 -32
- package/dist/checkbox.js +22 -28
- package/dist/collapse.css +6 -6
- package/dist/collapse.js +7 -6
- package/dist/collectionNavigation.js +2 -99
- package/dist/color-input.css +19 -19
- package/dist/color-input.js +14 -13
- package/dist/color-picker.css +40 -40
- package/dist/color-picker.js +221 -200
- package/dist/color-picker2.js +1 -9
- package/dist/color-swatch.css +4 -4
- package/dist/color-swatch.js +6 -8
- package/dist/color.js +5 -10
- package/dist/componentColors.js +125 -84
- package/dist/componentRef.js +26 -0
- package/dist/components/accordion/accordionContext.d.ts +3 -0
- package/dist/components/accordion/accordionModel.d.ts +14 -0
- package/dist/components/accordion/index.d.ts +2 -1
- package/dist/components/accordion/index.js +1 -1
- package/dist/components/accordion/types.d.ts +1 -2
- package/dist/components/accordion/useAccordion.d.ts +2 -2
- package/dist/components/accordion/useAccordionItem.d.ts +2 -0
- package/dist/components/checkbox/useCheckbox.d.ts +1 -2
- package/dist/components/color-picker/index.js +2 -2
- package/dist/components/color-picker/types.d.ts +2 -2
- package/dist/components/color-picker/useColorPickerSaturation.d.ts +22 -0
- package/dist/components/color-picker/useColorPickerSlider.d.ts +20 -0
- package/dist/components/color-picker/useColorPickerValue.d.ts +1 -1
- package/dist/components/dialog/{dialog-core.d.ts → dialogContext.d.ts} +1 -5
- package/dist/components/dialog/useDialogContentInteractions.d.ts +18 -0
- package/dist/components/dialog/useDialogRootState.d.ts +19 -0
- package/dist/components/dropdown-menu/dropdown-menu-item-row.d.ts +1 -1
- package/dist/components/dropdown-menu/dropdown-menu-items.d.ts +1 -1
- package/dist/components/dropdown-menu/dropdown-menu-model.d.ts +8 -0
- package/dist/components/dropdown-menu/dropdown-menu-root.d.ts +2 -2
- package/dist/components/dropdown-menu/dropdown-menu-sub-trigger.d.ts +1 -1
- package/dist/components/dropdown-menu/dropdown-menu-sub.d.ts +1 -1
- package/dist/components/dropdown-menu/{dropdown-menu-primitive-core.d.ts → dropdownMenuContext.d.ts} +16 -18
- package/dist/components/dropdown-menu/dropdownMenuDataModel.d.ts +20 -0
- package/dist/components/dropdown-menu/dropdownMenuInteraction.d.ts +3 -0
- package/dist/components/dropdown-menu/dropdownMenuInteractionNavigation.d.ts +24 -0
- package/dist/components/dropdown-menu/dropdownMenuInteractionRegistry.d.ts +42 -0
- package/dist/components/dropdown-menu/dropdownMenuInteractionTypes.d.ts +85 -0
- package/dist/components/dropdown-menu/useDropdownMenu.d.ts +11 -11
- package/dist/components/dropdown-menu/useDropdownMenuContextTrigger.d.ts +9 -0
- package/dist/components/dropdown-menu/useDropdownMenuDataController.d.ts +34 -0
- package/dist/components/dropdown-menu/useDropdownMenuDataRegistration.d.ts +22 -0
- package/dist/components/dropdown-menu/useDropdownMenuHoverIntent.d.ts +6 -5
- package/dist/components/dropdown-menu/useDropdownMenuInteractionDismissal.d.ts +17 -0
- package/dist/components/dropdown-menu/useDropdownMenuInteractionKeyboard.d.ts +19 -0
- package/dist/components/dropdown-menu/useDropdownMenuPortalPosition.d.ts +0 -1
- package/dist/components/dropdown-menu/useDropdownMenuPresentation.d.ts +29 -0
- package/dist/components/dropdown-menu/useDropdownMenuPrimitiveContent.d.ts +2 -2
- package/dist/components/dropdown-menu/useDropdownMenuRenderItems.d.ts +1 -1
- package/dist/components/dropdown-menu/useDropdownMenuTargetBindings.d.ts +19 -0
- package/dist/components/floating/hoverDisclosureInteractionModel.d.ts +42 -0
- package/dist/components/floating/index.js +1 -1
- package/dist/components/floating/useFloatingPosition.d.ts +0 -1
- package/dist/components/floating/useHoverDisclosureInteractions.d.ts +32 -0
- package/dist/components/floating/useHoverDisclosureOpenState.d.ts +25 -0
- package/dist/components/floating/useHoverDisclosureTargetBinding.d.ts +27 -0
- package/dist/components/number-input/numberInputModel.d.ts +15 -0
- package/dist/components/number-input/useNumberInput.d.ts +3 -17
- package/dist/components/pagination/index.d.ts +1 -1
- package/dist/components/pagination/index.js +1 -1
- package/dist/components/pagination/paginationModel.d.ts +4 -0
- package/dist/components/pagination/types.d.ts +15 -0
- package/dist/components/pagination/usePagination.d.ts +3 -19
- package/dist/components/popover/usePopoverBindings.d.ts +16 -0
- package/dist/components/progress/progressModel.d.ts +8 -0
- package/dist/components/progress/useProgress.d.ts +0 -6
- package/dist/components/radio/useRadio.d.ts +1 -2
- package/dist/components/scroll-area/scroll-area.d.ts +1 -1
- package/dist/components/scroll-area/scrollAreaModel.d.ts +64 -0
- package/dist/components/scroll-area/useScrollArea.d.ts +70 -53
- package/dist/components/scroll-area/{useScrollAreaPresentation.d.ts → useScrollAreaAttributes.d.ts} +37 -17
- package/dist/components/scroll-area/useScrollAreaDerivedState.d.ts +8 -0
- package/dist/components/scroll-area/useScrollAreaMeasurement.d.ts +35 -0
- package/dist/components/scroll-area/useScrollAreaPointer.d.ts +10 -8
- package/dist/components/scroll-area/useScrollAreaVisibility.d.ts +15 -20
- package/dist/components/slider/rangeSliderModel.d.ts +41 -0
- package/dist/components/slider/{sliderCore.d.ts → sliderModel.d.ts} +0 -1
- package/dist/components/slider/useRangeSlider.d.ts +8 -16
- package/dist/components/slider/useRangeSliderValueState.d.ts +40 -0
- package/dist/components/slider/useSlider.d.ts +7 -13
- package/dist/components/slider/useSliderPointerPreview.d.ts +22 -0
- package/dist/components/slider/useSliderTooltipState.d.ts +40 -0
- package/dist/components/slider/useSliderValueState.d.ts +33 -0
- package/dist/components/teleport-provider/index.js +1 -1
- package/dist/components/teleport-provider/useTeleportTarget.d.ts +1 -2
- package/dist/components/toast/useToastLifecycle.d.ts +19 -0
- package/dist/components/tooltip/useTooltip.d.ts +1 -2
- package/dist/css.js +12 -0
- package/dist/dialog.js +226 -218
- package/dist/dropdown-menu.js +1458 -1097
- package/dist/events.js +59 -0
- package/dist/field.css +8 -8
- package/dist/field.js +13 -25
- package/dist/floating.js +548 -319
- package/dist/floatingOffset.js +11 -0
- package/dist/focus-trap.js +7 -5
- package/dist/focusNavigation.js +37 -0
- package/dist/icon-button.css +8 -8
- package/dist/icon-button.js +7 -6
- package/dist/index.js +6 -6
- package/dist/input.css +24 -24
- package/dist/input.js +19 -31
- package/dist/interactive.js +18 -0
- package/dist/modal.js +1 -1
- package/dist/number-input.css +18 -18
- package/dist/number-input.js +14 -12
- package/dist/number.js +22 -0
- package/dist/overlay.js +3 -2
- package/dist/pagination.css +28 -28
- package/dist/pagination.js +65 -63
- package/dist/pointer.js +9 -0
- package/dist/popover.css +34 -34
- package/dist/popover.js +85 -86
- package/dist/progress.js +10 -13
- package/dist/query.js +40 -0
- package/dist/radio.css +18 -18
- package/dist/radio.js +30 -36
- package/dist/rafScheduler.js +34 -0
- package/dist/scroll-area.css +28 -28
- package/dist/scroll-area.js +512 -516
- package/dist/select.css +45 -45
- package/dist/select.js +36 -44
- package/dist/slider.css +191 -191
- package/dist/slider.js +691 -618
- package/dist/styles-api.d.ts +0 -1
- package/dist/styles-api.js +1 -4
- package/dist/switch.css +17 -17
- package/dist/switch.js +14 -15
- package/dist/tabs.css +43 -43
- package/dist/tabs.js +29 -56
- package/dist/text.js +17 -0
- package/dist/textarea.css +26 -26
- package/dist/textarea.js +21 -32
- package/dist/toast.css +26 -26
- package/dist/toast.js +141 -118
- package/dist/tooltip.css +12 -12
- package/dist/tooltip.js +36 -40
- package/dist/useCollapse.js +8 -11
- package/dist/useControlState.js +3 -6
- package/dist/useFloatingPosition.js +140 -10
- package/dist/useOverlayZIndex.js +1 -5
- package/dist/useTeleportTarget.js +3 -14
- package/dist/useTypeahead.js +94 -0
- package/dist/utils/aria.d.ts +3 -0
- package/dist/utils/attributes.d.ts +2 -0
- package/dist/utils/bem.d.ts +3 -0
- package/dist/utils/collectionNavigation.d.ts +2 -0
- package/dist/utils/color.d.ts +7 -0
- package/dist/{components/color-picker/color-picker-utils.d.ts → utils/colorPicker.d.ts} +5 -4
- package/dist/utils/componentColors.d.ts +7 -0
- package/dist/utils/css.d.ts +3 -0
- package/dist/utils/dom/ancestry.d.ts +7 -0
- package/dist/utils/dom/attributes.d.ts +16 -0
- package/dist/utils/dom/componentRef.d.ts +4 -0
- package/dist/utils/dom/events.d.ts +5 -0
- package/dist/utils/dom/focusNavigation.d.ts +7 -0
- package/dist/utils/dom/interactive.d.ts +2 -0
- package/dist/utils/dom/pointer.d.ts +2 -0
- package/dist/utils/dom/query.d.ts +4 -0
- package/dist/utils/dom/scroll.d.ts +23 -0
- package/dist/utils/floatingOffset.d.ts +10 -0
- package/dist/utils/geometry.d.ts +14 -0
- package/dist/utils/indexPath.d.ts +6 -0
- package/dist/utils/number.d.ts +4 -0
- package/dist/utils/rafScheduler.d.ts +4 -0
- package/dist/utils/text.d.ts +2 -0
- package/docs/code-architecture.md +118 -0
- package/docs/public-floating-api.md +6 -5
- package/package.json +13 -12
- package/dist/components/dropdown-menu/dropdown-menu-outside.d.ts +0 -3
- package/dist/components/dropdown-menu/dropdown-menu-utils.d.ts +0 -21
- package/dist/components/dropdown-menu/useDropdownMenuDisclosure.d.ts +0 -36
- package/dist/components/dropdown-menu/useDropdownMenuDom.d.ts +0 -29
- package/dist/components/dropdown-menu/useDropdownMenuInteractions.d.ts +0 -52
- package/dist/components/dropdown-menu/useDropdownMenuNavigation.d.ts +0 -17
- package/dist/components/dropdown-menu/useDropdownSubmenus.d.ts +0 -18
- package/dist/components/scroll-area/scrollAreaCore.d.ts +0 -30
- package/dist/components/scroll-area/useScrollAreaControls.d.ts +0 -25
- package/dist/components/scroll-area/useScrollAreaMetrics.d.ts +0 -38
- /package/dist/components/alert/{useAlertColor.d.ts → alertColor.d.ts} +0 -0
- /package/dist/components/avatar/{useAvatarColor.d.ts → avatarColor.d.ts} +0 -0
- /package/dist/components/badge/{useBadgeColor.d.ts → badgeColor.d.ts} +0 -0
- /package/dist/components/button/{useButtonColor.d.ts → buttonColor.d.ts} +0 -0
- /package/dist/components/color-swatch/{useColorSwatchColor.d.ts → colorSwatchColor.d.ts} +0 -0
- /package/dist/components/toast/{useToastColor.d.ts → toastColor.d.ts} +0 -0
package/dist/dropdown-menu.js
CHANGED
|
@@ -1,41 +1,49 @@
|
|
|
1
1
|
import './dropdown-menu.css';
|
|
2
2
|
import { t as useControllableValue } from "./useControllableValue.js";
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
3
|
+
import { t as useStylesApi } from "./styles-api.js";
|
|
4
|
+
import { n as toPresenceAttribute, t as toOptionalAttribute } from "./attributes.js";
|
|
5
5
|
import { t as bem } from "./bem.js";
|
|
6
|
+
import { t as isElement } from "./query.js";
|
|
7
|
+
import { t as useRequiredInject } from "./useRequiredInject.js";
|
|
8
|
+
import { t as clamp } from "./number.js";
|
|
9
|
+
import { a as snapshotAttributes, i as restoreAttributes } from "./attributes2.js";
|
|
10
|
+
import { t as resolveHTMLElementRef } from "./componentRef.js";
|
|
11
|
+
import { n as isEventWithinElement, r as isEventWithinTargets, t as createCancelableCustomEvent } from "./events.js";
|
|
6
12
|
import { n as useOverlayZIndex, r as useOverlayLayer } from "./useOverlayZIndex.js";
|
|
7
|
-
import { n as
|
|
8
|
-
import { n as
|
|
9
|
-
import {
|
|
13
|
+
import { n as useFloatingTarget, t as useFloatingPosition } from "./useFloatingPosition.js";
|
|
14
|
+
import { n as useTeleportTarget, t as provideTeleportTarget } from "./useTeleportTarget.js";
|
|
15
|
+
import { t as useTypeahead } from "./useTypeahead.js";
|
|
10
16
|
import { t as chevron_right_default } from "./chevron-right.js";
|
|
11
|
-
import { VaporTeleport, VaporTransition, child, computed, createComponent, createComponentWithFallback, createDynamicComponent, createFor, createIf, createSlot, createTemplateRefSetter, defineVaporComponent, extend, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, ref, renderEffect, resolveComponent, setAttr, setDynamicProps, setInsertionState,
|
|
12
|
-
//#region src/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function optionalAttr(value) {
|
|
19
|
-
return value || void 0;
|
|
17
|
+
import { VaporTeleport, VaporTransition, child, computed, createComponent, createComponentWithFallback, createDynamicComponent, createFor, createIf, createSlot, createTemplateRefSetter, defineVaporComponent, extend, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, ref, renderEffect, resolveComponent, setAttr, setDynamicProps, setInsertionState, setStyle, setTemplateRefBinding, setText, shallowRef, template, toDisplayString, txt, unref, useAttrs, useId, watch } from "vue";
|
|
18
|
+
//#region src/utils/geometry.ts
|
|
19
|
+
function getClientPoint(event) {
|
|
20
|
+
return {
|
|
21
|
+
x: event.clientX,
|
|
22
|
+
y: event.clientY
|
|
23
|
+
};
|
|
20
24
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
function hasMeasuredRect(rect) {
|
|
26
|
+
return rect.width > 0 || rect.height > 0;
|
|
27
|
+
}
|
|
28
|
+
function isPointInRect(point, rect, padding = 0) {
|
|
29
|
+
return point.x >= rect.left - padding && point.x <= rect.right + padding && point.y >= rect.top - padding && point.y <= rect.bottom + padding;
|
|
30
|
+
}
|
|
31
|
+
function getTriangleArea(a, b, c) {
|
|
32
|
+
return Math.abs((a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2);
|
|
24
33
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
return fallbackId && typeof document !== "undefined" ? document.getElementById(fallbackId) : null;
|
|
34
|
+
function isPointInTriangle(point, triangle, tolerance = .5) {
|
|
35
|
+
const [a, b, c] = triangle;
|
|
36
|
+
const area = getTriangleArea(a, b, c);
|
|
37
|
+
const area1 = getTriangleArea(point, b, c);
|
|
38
|
+
const area2 = getTriangleArea(a, point, c);
|
|
39
|
+
const area3 = getTriangleArea(a, b, point);
|
|
40
|
+
return Math.abs(area - (area1 + area2 + area3)) < tolerance;
|
|
33
41
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
function clampPointToRect(point, rect) {
|
|
43
|
+
return {
|
|
44
|
+
x: clamp(point.x, rect.left, rect.right),
|
|
45
|
+
y: clamp(point.y, rect.top, rect.bottom)
|
|
46
|
+
};
|
|
39
47
|
}
|
|
40
48
|
function createPointRect(point) {
|
|
41
49
|
return {
|
|
@@ -50,202 +58,72 @@ function createPointRect(point) {
|
|
|
50
58
|
toJSON: () => ({})
|
|
51
59
|
};
|
|
52
60
|
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/components/dropdown-menu/dropdownMenuContext.ts
|
|
63
|
+
var rootKey = Symbol("dropdown-menu-root");
|
|
64
|
+
var menuKey = Symbol("dropdown-menu-content");
|
|
65
|
+
var subKey = Symbol("dropdown-menu-sub");
|
|
66
|
+
var radioGroupKey = Symbol("dropdown-menu-radio-group");
|
|
67
|
+
var checkedKey = Symbol("dropdown-menu-checked");
|
|
53
68
|
function createVirtualAnchor(point) {
|
|
54
69
|
return { getBoundingClientRect: () => createPointRect(point) };
|
|
55
70
|
}
|
|
56
|
-
function createCustomEvent(type, detail, originalEvent) {
|
|
57
|
-
const target = originalEvent.target;
|
|
58
|
-
return new (((target instanceof Node ? target.ownerDocument?.defaultView : null)?.CustomEvent) ?? CustomEvent)(type, {
|
|
59
|
-
bubbles: false,
|
|
60
|
-
cancelable: true,
|
|
61
|
-
detail
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
71
|
function createSelectEvent(originalEvent, value) {
|
|
65
|
-
return
|
|
72
|
+
return createCancelableCustomEvent("dropdown-menu-select", {
|
|
66
73
|
originalEvent,
|
|
67
74
|
value
|
|
68
75
|
}, originalEvent);
|
|
69
76
|
}
|
|
70
|
-
function createOutsideEvent(originalEvent) {
|
|
71
|
-
return createCustomEvent("dropdown-menu-interact-outside", { originalEvent }, originalEvent);
|
|
72
|
-
}
|
|
73
|
-
function sortItems(items) {
|
|
74
|
-
return [...items].sort((left, right) => {
|
|
75
|
-
const leftElement = left.element();
|
|
76
|
-
const rightElement = right.element();
|
|
77
|
-
if (!leftElement || !rightElement || leftElement === rightElement) return 0;
|
|
78
|
-
const position = leftElement.compareDocumentPosition(rightElement);
|
|
79
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
80
|
-
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
81
|
-
return 0;
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function getPlacementSide(placement) {
|
|
85
|
-
return placement.split("-")[0];
|
|
86
|
-
}
|
|
87
|
-
function getOpenDirection(sub) {
|
|
88
|
-
return getPlacementSide(sub.actualPlacement.value) === "left" ? "ArrowLeft" : "ArrowRight";
|
|
89
|
-
}
|
|
90
|
-
function getCloseDirection(menu) {
|
|
91
|
-
return getPlacementSide(menu.actualPlacement.value) === "left" ? "ArrowRight" : "ArrowLeft";
|
|
92
|
-
}
|
|
93
|
-
function blockDocumentClick(event) {
|
|
94
|
-
if (event.cancelable) event.preventDefault();
|
|
95
|
-
event.stopPropagation();
|
|
96
|
-
document.removeEventListener("click", blockDocumentClick, true);
|
|
97
|
-
}
|
|
98
|
-
function blockNextDocumentClick() {
|
|
99
|
-
if (typeof document === "undefined") return;
|
|
100
|
-
document.addEventListener("click", blockDocumentClick, true);
|
|
101
|
-
window.setTimeout(() => document.removeEventListener("click", blockDocumentClick, true), 1e3);
|
|
102
|
-
}
|
|
103
77
|
function createMenuContext(options) {
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
item.element()?.scrollIntoView?.({ block: "nearest" });
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function unregisterItem(id) {
|
|
121
|
-
items.value = items.value.filter((item) => item.id !== id);
|
|
122
|
-
if (activeId.value === id) activeId.value = null;
|
|
123
|
-
}
|
|
124
|
-
function registerSub(sub) {
|
|
125
|
-
submenus.add(sub);
|
|
126
|
-
}
|
|
127
|
-
function unregisterSub(sub) {
|
|
128
|
-
submenus.delete(sub);
|
|
129
|
-
}
|
|
130
|
-
function closeSubmenus(except) {
|
|
131
|
-
for (const submenu of submenus) if (submenu !== except) submenu.close(false);
|
|
132
|
-
}
|
|
133
|
-
function setActive(id) {
|
|
134
|
-
const item = items.value.find((current) => current.id === id);
|
|
135
|
-
if (!item || item.disabled()) return;
|
|
136
|
-
activeId.value = id;
|
|
137
|
-
nextTick(() => item.element()?.scrollIntoView?.({ block: "nearest" }));
|
|
138
|
-
}
|
|
139
|
-
function focus(target = "first") {
|
|
140
|
-
const enabledItems = getEnabledItems();
|
|
141
|
-
const item = target === "last" ? enabledItems[enabledItems.length - 1] : enabledItems[0];
|
|
142
|
-
if (!item) {
|
|
143
|
-
activeId.value = null;
|
|
144
|
-
options.element.value?.focus();
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
activeId.value = item.id;
|
|
148
|
-
options.element.value?.focus();
|
|
149
|
-
item.element()?.scrollIntoView?.({ block: "nearest" });
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
function focusElement() {
|
|
153
|
-
options.element.value?.focus();
|
|
154
|
-
}
|
|
155
|
-
function move(direction) {
|
|
156
|
-
const enabledItems = getEnabledItems();
|
|
157
|
-
if (enabledItems.length === 0) return;
|
|
158
|
-
const currentIndex = enabledItems.findIndex((item) => item.id === activeId.value);
|
|
159
|
-
const item = enabledItems[((currentIndex < 0 ? direction === 1 ? -1 : 0 : currentIndex) + direction + enabledItems.length) % enabledItems.length];
|
|
160
|
-
if (item) setActive(item.id);
|
|
161
|
-
}
|
|
162
|
-
const typeahead = useTypeahead({
|
|
163
|
-
items: () => sortItems(items.value),
|
|
164
|
-
activeIndex: () => sortItems(items.value).findIndex((item) => item.id === activeId.value),
|
|
165
|
-
getKey: (item) => item.id,
|
|
166
|
-
getTextValue: (item) => item.textValue(),
|
|
167
|
-
isDisabled: (item) => item.disabled(),
|
|
168
|
-
onMatch: (item) => setActive(item.id)
|
|
78
|
+
const id = options.parentSub?.menuId ?? options.root.interaction.rootMenuId;
|
|
79
|
+
const interaction = options.root.interaction;
|
|
80
|
+
const activeId = interaction.getActiveId(id);
|
|
81
|
+
const cleanupMenu = interaction.registerMenu({
|
|
82
|
+
id,
|
|
83
|
+
parentItemId: () => options.parentSub?.trigger.value?.id,
|
|
84
|
+
element: () => options.element.value,
|
|
85
|
+
placement: () => options.actualPlacement.value,
|
|
86
|
+
isOpen: () => options.parentSub?.isOpen.value ?? options.root.isOpen.value,
|
|
87
|
+
setOpen: options.parentSub?.setOpen,
|
|
88
|
+
stopKeyPropagation: true,
|
|
89
|
+
onEscape: options.onEscape
|
|
169
90
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
function onKeydown(event) {
|
|
186
|
-
if (typeahead.handleKey(event)) {
|
|
187
|
-
event.stopPropagation();
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const active = items.value.find((item) => item.id === activeId.value);
|
|
191
|
-
switch (event.key) {
|
|
192
|
-
case "ArrowDown":
|
|
193
|
-
event.preventDefault();
|
|
194
|
-
event.stopPropagation();
|
|
195
|
-
move(1);
|
|
196
|
-
break;
|
|
197
|
-
case "ArrowUp":
|
|
198
|
-
event.preventDefault();
|
|
199
|
-
event.stopPropagation();
|
|
200
|
-
move(-1);
|
|
201
|
-
break;
|
|
202
|
-
case "Home":
|
|
203
|
-
event.preventDefault();
|
|
204
|
-
event.stopPropagation();
|
|
205
|
-
focus("first");
|
|
206
|
-
break;
|
|
207
|
-
case "End":
|
|
208
|
-
event.preventDefault();
|
|
209
|
-
event.stopPropagation();
|
|
210
|
-
focus("last");
|
|
211
|
-
break;
|
|
212
|
-
case "ArrowRight":
|
|
213
|
-
case "ArrowLeft":
|
|
214
|
-
onHorizontalKeydown(event, active);
|
|
215
|
-
break;
|
|
216
|
-
case "Enter":
|
|
217
|
-
case " ":
|
|
218
|
-
event.preventDefault();
|
|
219
|
-
event.stopPropagation();
|
|
220
|
-
active?.activate(event);
|
|
221
|
-
break;
|
|
222
|
-
case "Escape":
|
|
223
|
-
event.preventDefault();
|
|
224
|
-
event.stopPropagation();
|
|
225
|
-
options.onEscape(event);
|
|
226
|
-
break;
|
|
227
|
-
case "Tab":
|
|
228
|
-
options.root.close({ returnFocus: false });
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
91
|
+
function registerItem(item) {
|
|
92
|
+
interaction.registerItem({
|
|
93
|
+
get id() {
|
|
94
|
+
return item.id;
|
|
95
|
+
},
|
|
96
|
+
menuId: id,
|
|
97
|
+
element: item.element,
|
|
98
|
+
textValue: item.textValue,
|
|
99
|
+
disabled: item.disabled,
|
|
100
|
+
submenuId: () => item.submenu?.menuId,
|
|
101
|
+
submenuDirection: () => item.submenu?.actualPlacement.value.startsWith("left") ? "left" : "right",
|
|
102
|
+
select: item.activate,
|
|
103
|
+
closeOnSelect: item.closeOnSelect
|
|
104
|
+
});
|
|
231
105
|
}
|
|
232
106
|
const context = {
|
|
233
107
|
root: options.root,
|
|
108
|
+
id,
|
|
234
109
|
element: options.element,
|
|
235
110
|
activeId,
|
|
236
111
|
actualPlacement: options.actualPlacement,
|
|
237
112
|
parentSub: options.parentSub,
|
|
238
113
|
registerItem,
|
|
239
|
-
unregisterItem,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
isActive:
|
|
245
|
-
focus,
|
|
246
|
-
focusElement,
|
|
247
|
-
|
|
114
|
+
unregisterItem: interaction.unregisterItem,
|
|
115
|
+
closeSubmenus: (except) => interaction.closeSubmenus(id, except?.menuId),
|
|
116
|
+
setActive: (itemId) => {
|
|
117
|
+
interaction.setActive(itemId);
|
|
118
|
+
},
|
|
119
|
+
isActive: interaction.isActive,
|
|
120
|
+
focus: (target = "first") => interaction.focusMenu(id, target),
|
|
121
|
+
focusElement: () => interaction.focusMenuElement(id),
|
|
122
|
+
activate: interaction.activateItem,
|
|
123
|
+
hover: interaction.hoverItem,
|
|
124
|
+
onKeydown: (event) => interaction.onMenuKeydown(id, event)
|
|
248
125
|
};
|
|
126
|
+
onBeforeUnmount(cleanupMenu);
|
|
249
127
|
return context;
|
|
250
128
|
}
|
|
251
129
|
function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
@@ -255,12 +133,12 @@ function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
|
255
133
|
const element = ref(null);
|
|
256
134
|
const isDisabled = computed(() => Boolean(menu.root.disabled.value || props.disabled));
|
|
257
135
|
const focused = computed(() => menu.isActive(id.value));
|
|
258
|
-
function
|
|
259
|
-
if (isDisabled.value) return;
|
|
136
|
+
function emitSelection(originalEvent) {
|
|
137
|
+
if (isDisabled.value) return void 0;
|
|
260
138
|
const selectEvent = createSelectEvent(originalEvent, props.value);
|
|
261
139
|
emitSelect(selectEvent);
|
|
262
140
|
options.afterSelect?.();
|
|
263
|
-
|
|
141
|
+
return selectEvent;
|
|
264
142
|
}
|
|
265
143
|
const registration = {
|
|
266
144
|
get id() {
|
|
@@ -269,27 +147,33 @@ function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
|
269
147
|
element: () => element.value,
|
|
270
148
|
textValue: () => props.textValue ?? element.value?.textContent?.trim() ?? "",
|
|
271
149
|
disabled: () => isDisabled.value,
|
|
272
|
-
activate
|
|
150
|
+
activate: emitSelection,
|
|
151
|
+
closeOnSelect: () => props.closeOnSelect ?? options.defaultCloseOnSelect
|
|
273
152
|
};
|
|
274
153
|
menu.registerItem(registration);
|
|
275
154
|
watch(id, (nextId, previousId) => {
|
|
155
|
+
const wasActive = menu.activeId.value === previousId;
|
|
276
156
|
menu.unregisterItem(previousId);
|
|
277
157
|
menu.registerItem(registration);
|
|
278
|
-
if (
|
|
279
|
-
});
|
|
158
|
+
if (wasActive) menu.setActive(nextId);
|
|
159
|
+
}, { flush: "sync" });
|
|
160
|
+
watch(isDisabled, () => menu.root.interaction.reconcile(menu.id));
|
|
280
161
|
onBeforeUnmount(() => menu.unregisterItem(id.value));
|
|
281
162
|
function setElement(value) {
|
|
282
163
|
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
283
164
|
element.value = resolved;
|
|
165
|
+
menu.root.interaction.reconcile(menu.id);
|
|
284
166
|
});
|
|
285
167
|
}
|
|
168
|
+
function activate(originalEvent) {
|
|
169
|
+
menu.activate(id.value, originalEvent);
|
|
170
|
+
}
|
|
286
171
|
function onPointerenter() {
|
|
287
172
|
if (isDisabled.value) return;
|
|
288
|
-
menu.
|
|
289
|
-
menu.setActive(id.value);
|
|
173
|
+
menu.hover(id.value);
|
|
290
174
|
}
|
|
291
175
|
function select() {
|
|
292
|
-
activate(new Event("select"));
|
|
176
|
+
menu.activate(id.value, new Event("select"));
|
|
293
177
|
}
|
|
294
178
|
return {
|
|
295
179
|
menu,
|
|
@@ -369,12 +253,12 @@ var dropdown_menu_checkbox_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
369
253
|
type: props.as === "button" ? "button" : void 0,
|
|
370
254
|
role: "menuitemcheckbox",
|
|
371
255
|
tabindex: -1,
|
|
372
|
-
disabled: props.as === "button" ?
|
|
373
|
-
"aria-disabled":
|
|
256
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
257
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
374
258
|
"aria-checked": checked.value,
|
|
375
|
-
"data-disabled":
|
|
376
|
-
"data-focused":
|
|
377
|
-
"data-highlighted":
|
|
259
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
260
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
261
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
378
262
|
"data-state": state.value,
|
|
379
263
|
class: bem("rp-dropdown-menu__item", {
|
|
380
264
|
focused: focused.value,
|
|
@@ -396,31 +280,6 @@ var dropdown_menu_checkbox_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
396
280
|
}
|
|
397
281
|
});
|
|
398
282
|
//#endregion
|
|
399
|
-
//#region src/components/dropdown-menu/dropdown-menu-outside.ts
|
|
400
|
-
function isNode(value) {
|
|
401
|
-
return typeof value === "object" && value !== null && "nodeType" in value;
|
|
402
|
-
}
|
|
403
|
-
function isEventWithinElement(event, element) {
|
|
404
|
-
const path = event.composedPath();
|
|
405
|
-
if (path.length > 0) return path.some((entry) => entry === element || isNode(entry) && element.contains(entry));
|
|
406
|
-
return isNode(event.target) && element.contains(event.target);
|
|
407
|
-
}
|
|
408
|
-
function isEventWithinTargets(event, targets) {
|
|
409
|
-
for (const source of targets) {
|
|
410
|
-
const target = isRef(source) ? source.value : source;
|
|
411
|
-
if (!target) continue;
|
|
412
|
-
if (typeof target === "string") {
|
|
413
|
-
if (typeof document === "undefined") continue;
|
|
414
|
-
try {
|
|
415
|
-
if ([...document.querySelectorAll(target)].some((element) => isEventWithinElement(event, element))) return true;
|
|
416
|
-
} catch {}
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
if (isEventWithinElement(event, target)) return true;
|
|
420
|
-
}
|
|
421
|
-
return false;
|
|
422
|
-
}
|
|
423
|
-
//#endregion
|
|
424
283
|
//#region src/components/dropdown-menu/useDropdownMenuPrimitiveContent.ts
|
|
425
284
|
function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
426
285
|
const componentName = submenu ? "RpDropdownMenuSubContent" : "RpDropdownMenuContent";
|
|
@@ -434,20 +293,23 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
434
293
|
const actualPlacement = ref(props.placement ?? defaultPlacement);
|
|
435
294
|
const isOpen = computed(() => sub ? sub.isOpen.value : root.isOpen.value);
|
|
436
295
|
const reference = computed(() => sub ? sub.trigger.value : root.reference.value);
|
|
437
|
-
const teleportPositioningKey = useTeleportPositioningKey();
|
|
438
296
|
const menu = createMenuContext({
|
|
439
297
|
root,
|
|
440
298
|
element,
|
|
441
299
|
actualPlacement,
|
|
442
300
|
parentSub: sub,
|
|
443
301
|
onEscape(event) {
|
|
444
|
-
const customEvent =
|
|
302
|
+
const customEvent = createCancelableCustomEvent("dropdown-menu-escape-key-down", { originalEvent: event }, event);
|
|
445
303
|
events.escapeKeyDown(customEvent);
|
|
446
|
-
|
|
447
|
-
if (sub) sub.close(true);
|
|
448
|
-
else root.close({ returnFocus: true });
|
|
304
|
+
return !customEvent.defaultPrevented;
|
|
449
305
|
}
|
|
450
306
|
});
|
|
307
|
+
const cleanupDismissal = submenu ? void 0 : root.interaction.registerDismissal({
|
|
308
|
+
ignoredTargets: () => props.ignore ?? [],
|
|
309
|
+
pointerDownOutside: events.pointerDownOutside,
|
|
310
|
+
focusOutside: events.focusOutside,
|
|
311
|
+
interactOutside: events.interactOutside
|
|
312
|
+
});
|
|
451
313
|
const floating = useFloatingPosition({
|
|
452
314
|
reference,
|
|
453
315
|
floating: element,
|
|
@@ -460,8 +322,7 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
460
322
|
flipOptions: () => props.flipOptions,
|
|
461
323
|
shift: () => props.shift !== false,
|
|
462
324
|
collisionPadding: () => props.collisionPadding ?? 8,
|
|
463
|
-
autoUpdateOptions: () => props.autoUpdateOptions
|
|
464
|
-
restartKey: teleportPositioningKey
|
|
325
|
+
autoUpdateOptions: () => props.autoUpdateOptions
|
|
465
326
|
});
|
|
466
327
|
watch(floating.actualPlacement, (value) => {
|
|
467
328
|
actualPlacement.value = value;
|
|
@@ -482,44 +343,9 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
482
343
|
else if (resolved) layerBranchCleanup = root.layer.registerBranch(resolved);
|
|
483
344
|
});
|
|
484
345
|
}
|
|
485
|
-
function emitOutside(type, originalEvent) {
|
|
486
|
-
const outsideEvent = createOutsideEvent(originalEvent);
|
|
487
|
-
if (type === "pointer") events.pointerDownOutside(outsideEvent);
|
|
488
|
-
else events.focusOutside(outsideEvent);
|
|
489
|
-
events.interactOutside(outsideEvent);
|
|
490
|
-
return outsideEvent;
|
|
491
|
-
}
|
|
492
|
-
function onDocumentPointer(event) {
|
|
493
|
-
if (!root.layer.isTopLayer() || root.isInside(event) || isEventWithinTargets(event, props.ignore ?? [])) return;
|
|
494
|
-
const outsideEvent = emitOutside("pointer", event);
|
|
495
|
-
if (root.modal.value) {
|
|
496
|
-
if (event.cancelable) event.preventDefault();
|
|
497
|
-
event.stopPropagation();
|
|
498
|
-
if (event.type === "pointerdown") blockNextDocumentClick();
|
|
499
|
-
}
|
|
500
|
-
if (!outsideEvent.defaultPrevented) root.close({ returnFocus: root.modal.value });
|
|
501
|
-
}
|
|
502
|
-
function onDocumentFocus(event) {
|
|
503
|
-
if (!root.layer.isTopLayer() || root.isInside(event) || isEventWithinTargets(event, props.ignore ?? [])) return;
|
|
504
|
-
const outsideEvent = emitOutside("focus", event);
|
|
505
|
-
if (root.modal.value) {
|
|
506
|
-
if (event.cancelable) event.preventDefault();
|
|
507
|
-
event.stopPropagation();
|
|
508
|
-
}
|
|
509
|
-
if (!outsideEvent.defaultPrevented) root.close({ returnFocus: root.modal.value });
|
|
510
|
-
else if (root.modal.value) nextTick(menu.focusElement);
|
|
511
|
-
}
|
|
512
|
-
function setDocumentListeners(active) {
|
|
513
|
-
if (submenu || typeof document === "undefined") return;
|
|
514
|
-
const method = active ? "addEventListener" : "removeEventListener";
|
|
515
|
-
document[method]("pointerdown", onDocumentPointer, true);
|
|
516
|
-
document[method]("focusin", onDocumentFocus, true);
|
|
517
|
-
}
|
|
518
346
|
watch(isOpen, (open) => {
|
|
519
|
-
setDocumentListeners(open);
|
|
520
347
|
if (!open) {
|
|
521
|
-
menu.
|
|
522
|
-
menu.closeSubmenus();
|
|
348
|
+
if (sub) root.interaction.closeMenu(menu.id, false);
|
|
523
349
|
return;
|
|
524
350
|
}
|
|
525
351
|
nextTick(() => {
|
|
@@ -536,7 +362,7 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
536
362
|
if (isOpen.value) menu.focus((sub ? sub.pendingFocus.value : root.pendingFocus.value) || "first");
|
|
537
363
|
});
|
|
538
364
|
onBeforeUnmount(() => {
|
|
539
|
-
|
|
365
|
+
cleanupDismissal?.();
|
|
540
366
|
layerBranchCleanup?.();
|
|
541
367
|
if (element.value) root.unregisterInside(element.value);
|
|
542
368
|
if (!sub && root.layer.element.value === element.value) root.layer.element.value = null;
|
|
@@ -549,7 +375,7 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
549
375
|
id: id.value,
|
|
550
376
|
role: "menu",
|
|
551
377
|
tabindex: -1,
|
|
552
|
-
hidden:
|
|
378
|
+
hidden: toOptionalAttribute(!isOpen.value),
|
|
553
379
|
class: submenu ? bem("rp-dropdown-menu__submenu", {
|
|
554
380
|
compound: true,
|
|
555
381
|
open: isOpen.value
|
|
@@ -644,15 +470,16 @@ var dropdown_menu_content_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
644
470
|
focusOutside: (event) => emit("focusOutside", event),
|
|
645
471
|
interactOutside: (event) => emit("interactOutside", event)
|
|
646
472
|
}, false);
|
|
473
|
+
const templateRefs = { arrow: arrowElement };
|
|
647
474
|
const _setTemplateRef = createTemplateRefSetter();
|
|
648
475
|
return createIf(() => unref(shouldRender), () => {
|
|
649
476
|
const n6 = createDynamicComponent(() => __props.as, { $: [() => unref(rootAttrs)] }, extend(() => {
|
|
650
477
|
return [createIf(() => __props.arrow, () => {
|
|
651
478
|
const n4 = t0$2();
|
|
652
|
-
_setTemplateRef(n4, arrowElement, null, "arrowElement");
|
|
653
479
|
renderEffect(() => {
|
|
654
480
|
setAttr(n4, "data-side", unref(placementSide));
|
|
655
481
|
setStyle(n4, unref(floating).arrowStyle.value);
|
|
482
|
+
_setTemplateRef(n4, templateRefs.arrow);
|
|
656
483
|
});
|
|
657
484
|
return n4;
|
|
658
485
|
}, null, 129), createSlot("default", {
|
|
@@ -667,6 +494,117 @@ var dropdown_menu_content_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
667
494
|
}
|
|
668
495
|
});
|
|
669
496
|
//#endregion
|
|
497
|
+
//#region src/components/dropdown-menu/useDropdownMenuContextTrigger.ts
|
|
498
|
+
function useDropdownMenuContextTrigger(props) {
|
|
499
|
+
const attrs = useAttrs();
|
|
500
|
+
const root = useRequiredInject(rootKey, "RpDropdownMenuContextTrigger");
|
|
501
|
+
const generatedId = useId();
|
|
502
|
+
const id = computed(() => props.id ?? `${generatedId}-context-trigger`);
|
|
503
|
+
const element = ref(null);
|
|
504
|
+
const isDisabled = computed(() => root.disabled.value || props.disabled);
|
|
505
|
+
let timer;
|
|
506
|
+
let pointerId;
|
|
507
|
+
let startPoint;
|
|
508
|
+
let longPressOpened = false;
|
|
509
|
+
let suppressUntil = 0;
|
|
510
|
+
function setElement(value) {
|
|
511
|
+
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
512
|
+
const previous = element.value;
|
|
513
|
+
if (previous) root.unregisterInside(previous);
|
|
514
|
+
element.value = resolved;
|
|
515
|
+
if (resolved) root.registerInside(resolved);
|
|
516
|
+
if (!root.triggerId.value) root.triggerId.value = id.value;
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
function clearLongPress() {
|
|
520
|
+
if (timer) clearTimeout(timer);
|
|
521
|
+
timer = void 0;
|
|
522
|
+
pointerId = void 0;
|
|
523
|
+
startPoint = void 0;
|
|
524
|
+
element.value?.ownerDocument.defaultView?.removeEventListener("scroll", clearLongPress, true);
|
|
525
|
+
}
|
|
526
|
+
function openAt(point) {
|
|
527
|
+
root.setReturnFocus(element.value);
|
|
528
|
+
root.openAt(point);
|
|
529
|
+
}
|
|
530
|
+
function onContextmenu(event) {
|
|
531
|
+
if (isDisabled.value) return;
|
|
532
|
+
event.preventDefault();
|
|
533
|
+
if (Date.now() < suppressUntil) return;
|
|
534
|
+
openAt({
|
|
535
|
+
x: event.clientX,
|
|
536
|
+
y: event.clientY
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
function onKeydown(event) {
|
|
540
|
+
if (isDisabled.value) return;
|
|
541
|
+
if (event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) return;
|
|
542
|
+
event.preventDefault();
|
|
543
|
+
const rect = element.value?.getBoundingClientRect();
|
|
544
|
+
openAt({
|
|
545
|
+
x: rect?.left ?? 0,
|
|
546
|
+
y: rect?.bottom ?? 0
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
function onPointerdown(event) {
|
|
550
|
+
if (isDisabled.value || event.pointerType !== "touch" && event.pointerType !== "pen") return;
|
|
551
|
+
clearLongPress();
|
|
552
|
+
pointerId = event.pointerId;
|
|
553
|
+
startPoint = {
|
|
554
|
+
x: event.clientX,
|
|
555
|
+
y: event.clientY
|
|
556
|
+
};
|
|
557
|
+
longPressOpened = false;
|
|
558
|
+
(element.value?.ownerDocument.defaultView)?.addEventListener("scroll", clearLongPress, true);
|
|
559
|
+
timer = setTimeout(() => {
|
|
560
|
+
if (!startPoint) return;
|
|
561
|
+
longPressOpened = true;
|
|
562
|
+
suppressUntil = Date.now() + 1e3;
|
|
563
|
+
openAt(startPoint);
|
|
564
|
+
timer = void 0;
|
|
565
|
+
}, props.longPressDelay);
|
|
566
|
+
}
|
|
567
|
+
function onPointermove(event) {
|
|
568
|
+
if (event.pointerId !== pointerId || !startPoint) return;
|
|
569
|
+
if (Math.hypot(event.clientX - startPoint.x, event.clientY - startPoint.y) > (props.longPressTolerance ?? 0)) clearLongPress();
|
|
570
|
+
}
|
|
571
|
+
function finishPointer(event) {
|
|
572
|
+
if (event.pointerId !== pointerId) return;
|
|
573
|
+
if (longPressOpened) event.preventDefault();
|
|
574
|
+
clearLongPress();
|
|
575
|
+
}
|
|
576
|
+
function onClick(event) {
|
|
577
|
+
if (Date.now() >= suppressUntil) return;
|
|
578
|
+
event.preventDefault();
|
|
579
|
+
event.stopPropagation();
|
|
580
|
+
}
|
|
581
|
+
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
582
|
+
id: id.value,
|
|
583
|
+
"aria-controls": root.contentId.value,
|
|
584
|
+
"aria-haspopup": "menu",
|
|
585
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
586
|
+
"data-state": root.isOpen.value ? "open" : "closed",
|
|
587
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
588
|
+
onClick,
|
|
589
|
+
onContextmenu,
|
|
590
|
+
onKeydown,
|
|
591
|
+
onPointerdown,
|
|
592
|
+
onPointermove,
|
|
593
|
+
onPointerup: finishPointer,
|
|
594
|
+
onPointercancel: finishPointer
|
|
595
|
+
}));
|
|
596
|
+
onBeforeUnmount(() => {
|
|
597
|
+
clearLongPress();
|
|
598
|
+
if (element.value) root.unregisterInside(element.value);
|
|
599
|
+
if (root.triggerId.value === id.value) root.triggerId.value = void 0;
|
|
600
|
+
});
|
|
601
|
+
return {
|
|
602
|
+
isOpen: root.isOpen,
|
|
603
|
+
rootAttrs,
|
|
604
|
+
setElement
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
//#endregion
|
|
670
608
|
//#region src/components/dropdown-menu/dropdown-menu-context-trigger.vue
|
|
671
609
|
var dropdown_menu_context_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
672
610
|
name: "RpDropdownMenuContextTrigger",
|
|
@@ -683,113 +621,11 @@ var dropdown_menu_context_trigger_default = /* @__PURE__ */ defineVaporComponent
|
|
|
683
621
|
longPressTolerance: { default: 10 }
|
|
684
622
|
},
|
|
685
623
|
setup(__props) {
|
|
686
|
-
const
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
const generatedId = useId();
|
|
690
|
-
const id = computed(() => props.id ?? `${generatedId}-context-trigger`);
|
|
691
|
-
const element = ref(null);
|
|
692
|
-
const isDisabled = computed(() => root.disabled.value || props.disabled);
|
|
693
|
-
let timer;
|
|
694
|
-
let pointerId;
|
|
695
|
-
let startPoint;
|
|
696
|
-
let longPressOpened = false;
|
|
697
|
-
let suppressUntil = 0;
|
|
698
|
-
function setElement(value) {
|
|
699
|
-
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
700
|
-
const previous = element.value;
|
|
701
|
-
if (previous) root.unregisterInside(previous);
|
|
702
|
-
element.value = resolved;
|
|
703
|
-
if (resolved) root.registerInside(resolved);
|
|
704
|
-
if (!root.triggerId.value) root.triggerId.value = id.value;
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
function clearLongPress() {
|
|
708
|
-
if (timer) clearTimeout(timer);
|
|
709
|
-
timer = void 0;
|
|
710
|
-
pointerId = void 0;
|
|
711
|
-
startPoint = void 0;
|
|
712
|
-
element.value?.ownerDocument.defaultView?.removeEventListener("scroll", clearLongPress, true);
|
|
713
|
-
}
|
|
714
|
-
function openAt(point) {
|
|
715
|
-
root.setReturnFocus(element.value);
|
|
716
|
-
root.openAt(point);
|
|
717
|
-
}
|
|
718
|
-
function onContextmenu(event) {
|
|
719
|
-
if (isDisabled.value) return;
|
|
720
|
-
event.preventDefault();
|
|
721
|
-
if (Date.now() < suppressUntil) return;
|
|
722
|
-
openAt({
|
|
723
|
-
x: event.clientX,
|
|
724
|
-
y: event.clientY
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
function onKeydown(event) {
|
|
728
|
-
if (isDisabled.value) return;
|
|
729
|
-
if (event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) return;
|
|
730
|
-
event.preventDefault();
|
|
731
|
-
const rect = element.value?.getBoundingClientRect();
|
|
732
|
-
openAt({
|
|
733
|
-
x: rect?.left ?? 0,
|
|
734
|
-
y: rect?.bottom ?? 0
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
function onPointerdown(event) {
|
|
738
|
-
if (isDisabled.value || event.pointerType !== "touch" && event.pointerType !== "pen") return;
|
|
739
|
-
clearLongPress();
|
|
740
|
-
pointerId = event.pointerId;
|
|
741
|
-
startPoint = {
|
|
742
|
-
x: event.clientX,
|
|
743
|
-
y: event.clientY
|
|
744
|
-
};
|
|
745
|
-
longPressOpened = false;
|
|
746
|
-
(element.value?.ownerDocument.defaultView)?.addEventListener("scroll", clearLongPress, true);
|
|
747
|
-
timer = setTimeout(() => {
|
|
748
|
-
if (!startPoint) return;
|
|
749
|
-
longPressOpened = true;
|
|
750
|
-
suppressUntil = Date.now() + 1e3;
|
|
751
|
-
openAt(startPoint);
|
|
752
|
-
timer = void 0;
|
|
753
|
-
}, props.longPressDelay);
|
|
754
|
-
}
|
|
755
|
-
function onPointermove(event) {
|
|
756
|
-
if (event.pointerId !== pointerId || !startPoint) return;
|
|
757
|
-
if (Math.hypot(event.clientX - startPoint.x, event.clientY - startPoint.y) > props.longPressTolerance) clearLongPress();
|
|
758
|
-
}
|
|
759
|
-
function finishPointer(event) {
|
|
760
|
-
if (event.pointerId !== pointerId) return;
|
|
761
|
-
if (longPressOpened) event.preventDefault();
|
|
762
|
-
clearLongPress();
|
|
763
|
-
}
|
|
764
|
-
function onClick(event) {
|
|
765
|
-
if (Date.now() >= suppressUntil) return;
|
|
766
|
-
event.preventDefault();
|
|
767
|
-
event.stopPropagation();
|
|
768
|
-
}
|
|
769
|
-
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
770
|
-
id: id.value,
|
|
771
|
-
"aria-controls": root.contentId.value,
|
|
772
|
-
"aria-haspopup": "menu",
|
|
773
|
-
"aria-disabled": optionalAttr(isDisabled.value),
|
|
774
|
-
"data-state": root.isOpen.value ? "open" : "closed",
|
|
775
|
-
"data-disabled": optionalAttr(isDisabled.value),
|
|
776
|
-
onClick,
|
|
777
|
-
onContextmenu,
|
|
778
|
-
onKeydown,
|
|
779
|
-
onPointerdown,
|
|
780
|
-
onPointermove,
|
|
781
|
-
onPointerup: finishPointer,
|
|
782
|
-
onPointercancel: finishPointer
|
|
783
|
-
}));
|
|
784
|
-
onBeforeUnmount(() => {
|
|
785
|
-
clearLongPress();
|
|
786
|
-
if (element.value) root.unregisterInside(element.value);
|
|
787
|
-
if (root.triggerId.value === id.value) root.triggerId.value = void 0;
|
|
788
|
-
});
|
|
789
|
-
const n1 = createDynamicComponent(() => __props.as, { $: [() => rootAttrs.value] }, extend(() => {
|
|
790
|
-
return createSlot("default", { isOpen: () => unref(root).isOpen.value });
|
|
624
|
+
const { isOpen, rootAttrs, setElement } = useDropdownMenuContextTrigger(__props);
|
|
625
|
+
const n1 = createDynamicComponent(() => __props.as, { $: [() => unref(rootAttrs)] }, extend(() => {
|
|
626
|
+
return createSlot("default", { isOpen: () => unref(isOpen) });
|
|
791
627
|
}, { _: 8 }), 1);
|
|
792
|
-
setTemplateRefBinding(n1, () => setElement);
|
|
628
|
+
setTemplateRefBinding(n1, () => setElement, void 0, void 0, "setElement");
|
|
793
629
|
return n1;
|
|
794
630
|
}
|
|
795
631
|
});
|
|
@@ -831,11 +667,11 @@ var dropdown_menu_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
831
667
|
type: props.as === "button" ? "button" : void 0,
|
|
832
668
|
role: "menuitem",
|
|
833
669
|
tabindex: -1,
|
|
834
|
-
disabled: props.as === "button" ?
|
|
835
|
-
"aria-disabled":
|
|
836
|
-
"data-disabled":
|
|
837
|
-
"data-focused":
|
|
838
|
-
"data-highlighted":
|
|
670
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
671
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
672
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
673
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
674
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
839
675
|
class: bem("rp-dropdown-menu__item", {
|
|
840
676
|
focused: focused.value,
|
|
841
677
|
disabled: isDisabled.value,
|
|
@@ -931,7 +767,7 @@ var dropdown_menu_portal_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
931
767
|
const props = __props;
|
|
932
768
|
const teleportTo = provideTeleportTarget({ get teleportTo() {
|
|
933
769
|
return props.to ?? props.teleportTo;
|
|
934
|
-
} }
|
|
770
|
+
} });
|
|
935
771
|
return createComponent(VaporTeleport, {
|
|
936
772
|
to: () => unref(teleportTo),
|
|
937
773
|
disabled: () => __props.disabled || !__props.teleport
|
|
@@ -1038,12 +874,12 @@ var dropdown_menu_radio_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1038
874
|
type: props.as === "button" ? "button" : void 0,
|
|
1039
875
|
role: "menuitemradio",
|
|
1040
876
|
tabindex: -1,
|
|
1041
|
-
disabled: props.as === "button" ?
|
|
1042
|
-
"aria-disabled":
|
|
877
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
878
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
1043
879
|
"aria-checked": checked.value,
|
|
1044
|
-
"data-disabled":
|
|
1045
|
-
"data-focused":
|
|
1046
|
-
"data-highlighted":
|
|
880
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
881
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
882
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
1047
883
|
"data-state": state.value,
|
|
1048
884
|
class: bem("rp-dropdown-menu__item", {
|
|
1049
885
|
focused: focused.value,
|
|
@@ -1065,21 +901,657 @@ var dropdown_menu_radio_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1065
901
|
}
|
|
1066
902
|
});
|
|
1067
903
|
//#endregion
|
|
1068
|
-
//#region src/components/dropdown-menu/
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
904
|
+
//#region src/components/dropdown-menu/dropdownMenuInteractionNavigation.ts
|
|
905
|
+
function createDropdownMenuInteractionNavigation({ host, registry, closeRoot }) {
|
|
906
|
+
const state = registry.state;
|
|
907
|
+
function closeMenu(menuId, focusParent = false) {
|
|
908
|
+
const menu = registry.getMenu(menuId);
|
|
909
|
+
const menuState = state.getMenuState(menuId);
|
|
910
|
+
if (!menu && !menuState || menuId === host.rootMenuId) return false;
|
|
911
|
+
const wasOpen = registry.isMenuOpen(menuId);
|
|
912
|
+
closeSubmenus(menuId);
|
|
913
|
+
const shouldRestoreParent = focusParent || registry.activeMenuId.value === menuId;
|
|
914
|
+
if (wasOpen) state.setMenuOpen(menuId, false);
|
|
915
|
+
state.clearPendingMenuFocus(menuId);
|
|
916
|
+
state.clearMenuState(menuId);
|
|
917
|
+
if (shouldRestoreParent) {
|
|
918
|
+
const parentItem = state.getParentItem(menuId);
|
|
919
|
+
if (!parentItem || !registry.setActive(parentItem.id, focusParent)) {
|
|
920
|
+
const parentMenuId = parentItem?.menuId ?? host.rootMenuId;
|
|
921
|
+
registry.activeMenuId.value = parentMenuId;
|
|
922
|
+
registry.activeItemId.value = state.getActiveIdValue(parentMenuId);
|
|
923
|
+
if (focusParent) registry.focusMenuElement(parentMenuId);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return wasOpen;
|
|
927
|
+
}
|
|
928
|
+
function closeSubmenus(menuId, exceptMenuId) {
|
|
929
|
+
for (const item of state.getItems(menuId)) {
|
|
930
|
+
const submenuId = item.submenuId?.();
|
|
931
|
+
if (!submenuId || submenuId === exceptMenuId) continue;
|
|
932
|
+
closeMenu(submenuId, false);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
function closeAllSubmenus() {
|
|
936
|
+
closeSubmenus(host.rootMenuId);
|
|
937
|
+
for (const menuId of state.getMenuIds()) if (menuId !== host.rootMenuId && registry.isMenuOpen(menuId)) closeMenu(menuId, false);
|
|
938
|
+
}
|
|
939
|
+
function focusMenu(menuId, target = "first") {
|
|
940
|
+
const enabledItems = state.getEnabledItems(menuId);
|
|
941
|
+
const item = target === "last" ? enabledItems.at(-1) : enabledItems[0];
|
|
942
|
+
registry.focusMenuElement(menuId);
|
|
943
|
+
if (!item) {
|
|
944
|
+
state.clearMenuState(menuId);
|
|
945
|
+
registry.activeMenuId.value = menuId;
|
|
946
|
+
const parentItem = state.getParentItem(menuId);
|
|
947
|
+
if (parentItem) registry.activeItemId.value = parentItem.id;
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
return registry.setActive(item.id);
|
|
951
|
+
}
|
|
952
|
+
function openMenu(menuId, focus = "first") {
|
|
953
|
+
const menu = registry.getMenu(menuId);
|
|
954
|
+
const menuState = state.getMenuState(menuId);
|
|
955
|
+
if (!menu && !menuState || menuId === host.rootMenuId) return false;
|
|
956
|
+
const parentItem = state.getParentItem(menuId);
|
|
957
|
+
if (!parentItem || parentItem.disabled()) return false;
|
|
958
|
+
closeSubmenus(parentItem.menuId, menuId);
|
|
959
|
+
state.setPendingMenuFocus(menuId, focus);
|
|
960
|
+
state.setMenuOpen(menuId, true);
|
|
961
|
+
if (focus && menu) focusMenu(menuId, focus);
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
964
|
+
function selectItem(id, originalEvent = new Event("select")) {
|
|
965
|
+
const item = registry.getItem(id);
|
|
966
|
+
if (!item || item.disabled()) return;
|
|
967
|
+
const selectEvent = item.select?.(originalEvent);
|
|
968
|
+
if (selectEvent && !selectEvent.defaultPrevented && (item.closeOnSelect?.() ?? true)) closeRoot({ focusTrigger: true });
|
|
969
|
+
}
|
|
970
|
+
function activateItem(id, originalEvent = new Event("select")) {
|
|
971
|
+
const item = registry.getItem(id);
|
|
972
|
+
if (!item || item.disabled()) return;
|
|
973
|
+
const submenuId = item.submenuId?.();
|
|
974
|
+
if (submenuId) {
|
|
975
|
+
openMenu(submenuId, "first");
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
selectItem(id, originalEvent);
|
|
979
|
+
}
|
|
980
|
+
function hoverItem(id, openSubmenu = false) {
|
|
981
|
+
const item = registry.getItem(id);
|
|
982
|
+
if (!item || item.disabled()) return;
|
|
983
|
+
registry.setActive(id);
|
|
984
|
+
const submenuId = item.submenuId?.();
|
|
985
|
+
if (openSubmenu && submenuId) openMenu(submenuId, false);
|
|
986
|
+
else closeSubmenus(item.menuId, submenuId && registry.isMenuOpen(submenuId) ? submenuId : void 0);
|
|
987
|
+
}
|
|
988
|
+
function reconcileOpenSubmenus() {
|
|
989
|
+
for (const menuId of state.getMenuIds()) {
|
|
990
|
+
if (menuId === host.rootMenuId || !registry.isMenuOpen(menuId)) continue;
|
|
991
|
+
const parentItem = state.getParentItem(menuId);
|
|
992
|
+
if (!parentItem || parentItem.disabled()) closeMenu(menuId, false);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
function reconcile(menuId) {
|
|
996
|
+
const menuIds = menuId ? [menuId] : state.getRegisteredMenuIds();
|
|
997
|
+
for (const id of menuIds) {
|
|
998
|
+
const activeId = state.getActiveIdValue(id);
|
|
999
|
+
if (!activeId) continue;
|
|
1000
|
+
const currentItems = state.getItems(id);
|
|
1001
|
+
const activeIndex = currentItems.findIndex((item) => item.id === activeId);
|
|
1002
|
+
const activeItem = currentItems[activeIndex];
|
|
1003
|
+
if (activeItem && !activeItem.disabled()) continue;
|
|
1004
|
+
state.chooseNeighbor(id, Math.max(0, activeIndex));
|
|
1005
|
+
}
|
|
1006
|
+
reconcileOpenSubmenus();
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
closeMenu,
|
|
1010
|
+
closeSubmenus,
|
|
1011
|
+
closeAllSubmenus,
|
|
1012
|
+
focusMenu,
|
|
1013
|
+
openMenu,
|
|
1014
|
+
selectItem,
|
|
1015
|
+
activateItem,
|
|
1016
|
+
hoverItem,
|
|
1017
|
+
reconcile,
|
|
1018
|
+
reconcileOpenSubmenus
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
//#endregion
|
|
1022
|
+
//#region src/components/dropdown-menu/dropdownMenuInteractionRegistry.ts
|
|
1023
|
+
function compareItems(left, right) {
|
|
1024
|
+
const leftElement = left.element();
|
|
1025
|
+
const rightElement = right.element();
|
|
1026
|
+
if (leftElement && rightElement && leftElement !== rightElement && typeof Node !== "undefined") {
|
|
1027
|
+
const position = leftElement.compareDocumentPosition(rightElement);
|
|
1028
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
1029
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
1030
|
+
}
|
|
1031
|
+
return (left.order?.() ?? 0) - (right.order?.() ?? 0);
|
|
1032
|
+
}
|
|
1033
|
+
function scrollItemIntoView(item) {
|
|
1034
|
+
nextTick(() => item.element()?.scrollIntoView?.({ block: "nearest" }));
|
|
1035
|
+
}
|
|
1036
|
+
function createDropdownMenuInteractionRegistry(host, navigation) {
|
|
1037
|
+
const menus = /* @__PURE__ */ new Map();
|
|
1038
|
+
const menuStates = /* @__PURE__ */ new Map();
|
|
1039
|
+
const items = /* @__PURE__ */ new Map();
|
|
1040
|
+
const activeIds = ref(/* @__PURE__ */ new Map());
|
|
1041
|
+
const activeItemId = ref(null);
|
|
1042
|
+
const activeMenuId = ref(host.rootMenuId);
|
|
1043
|
+
const pendingRootFocus = ref("first");
|
|
1044
|
+
const pendingMenuFocus = /* @__PURE__ */ new Map();
|
|
1045
|
+
function getMenu(id) {
|
|
1046
|
+
return menus.get(id);
|
|
1047
|
+
}
|
|
1048
|
+
function getMenuState(id) {
|
|
1049
|
+
return menuStates.get(id);
|
|
1050
|
+
}
|
|
1051
|
+
function getItem(id) {
|
|
1052
|
+
return items.get(id);
|
|
1053
|
+
}
|
|
1054
|
+
function getItems(menuId) {
|
|
1055
|
+
return [...items.values()].filter((item) => item.menuId === menuId).sort(compareItems);
|
|
1056
|
+
}
|
|
1057
|
+
function getEnabledItems(menuId) {
|
|
1058
|
+
return getItems(menuId).filter((item) => !item.disabled());
|
|
1059
|
+
}
|
|
1060
|
+
function getActiveIdValue(menuId) {
|
|
1061
|
+
return activeIds.value.get(menuId) ?? null;
|
|
1062
|
+
}
|
|
1063
|
+
function setActiveId(menuId, id) {
|
|
1064
|
+
const next = new Map(activeIds.value);
|
|
1065
|
+
if (id) next.set(menuId, id);
|
|
1066
|
+
else next.delete(menuId);
|
|
1067
|
+
activeIds.value = next;
|
|
1068
|
+
}
|
|
1069
|
+
function getActiveId(menuId) {
|
|
1070
|
+
return computed(() => getActiveIdValue(menuId));
|
|
1071
|
+
}
|
|
1072
|
+
function isMenuOpen(menuId) {
|
|
1073
|
+
if (menuId === host.rootMenuId) return host.isOpen.value;
|
|
1074
|
+
return menuStates.get(menuId)?.isOpen() ?? menus.get(menuId)?.isOpen() ?? false;
|
|
1075
|
+
}
|
|
1076
|
+
function focusMenuElement(menuId) {
|
|
1077
|
+
nextTick(() => {
|
|
1078
|
+
const menu = menus.get(menuId);
|
|
1079
|
+
(menu?.focusTarget?.() ?? menu?.element())?.focus();
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
function clearMenuState(menuId) {
|
|
1083
|
+
const activeId = getActiveIdValue(menuId);
|
|
1084
|
+
if (activeId && activeItemId.value === activeId) activeItemId.value = null;
|
|
1085
|
+
setActiveId(menuId, null);
|
|
1086
|
+
}
|
|
1087
|
+
function setActive(id, focusElement = false) {
|
|
1088
|
+
if (id === null) {
|
|
1089
|
+
clearMenuState(activeMenuId.value);
|
|
1090
|
+
activeItemId.value = null;
|
|
1091
|
+
return true;
|
|
1092
|
+
}
|
|
1093
|
+
const item = items.get(id);
|
|
1094
|
+
if (!item || item.disabled()) return false;
|
|
1095
|
+
setActiveId(item.menuId, item.id);
|
|
1096
|
+
activeItemId.value = item.id;
|
|
1097
|
+
activeMenuId.value = item.menuId;
|
|
1098
|
+
pendingMenuFocus.delete(item.menuId);
|
|
1099
|
+
if (focusElement) focusMenuElement(item.menuId);
|
|
1100
|
+
scrollItemIntoView(item);
|
|
1101
|
+
return true;
|
|
1102
|
+
}
|
|
1103
|
+
function isActive(id) {
|
|
1104
|
+
return getActiveIdValue(items.get(id)?.menuId ?? "") === id;
|
|
1105
|
+
}
|
|
1106
|
+
function getParentItem(menuId) {
|
|
1107
|
+
const parentItemId = menus.get(menuId)?.parentItemId?.();
|
|
1108
|
+
if (parentItemId) {
|
|
1109
|
+
const parentItem = items.get(parentItemId);
|
|
1110
|
+
if (parentItem) return parentItem;
|
|
1111
|
+
}
|
|
1112
|
+
return [...items.values()].find((item) => item.submenuId?.() === menuId);
|
|
1113
|
+
}
|
|
1114
|
+
function setMenuOpen(menuId, open) {
|
|
1115
|
+
const state = menuStates.get(menuId);
|
|
1116
|
+
if (state) state.setOpen(open);
|
|
1117
|
+
else menus.get(menuId)?.setOpen?.(open);
|
|
1118
|
+
}
|
|
1119
|
+
function chooseNeighbor(menuId, previousIndex) {
|
|
1120
|
+
const currentItems = getItems(menuId);
|
|
1121
|
+
const nextCandidates = currentItems.slice(Math.max(0, previousIndex));
|
|
1122
|
+
const previousCandidates = [];
|
|
1123
|
+
for (let index = Math.max(0, previousIndex) - 1; index >= 0; index -= 1) {
|
|
1124
|
+
const item = currentItems[index];
|
|
1125
|
+
if (item) previousCandidates.push(item);
|
|
1126
|
+
}
|
|
1127
|
+
const next = [...nextCandidates, ...previousCandidates].find((item) => !item.disabled());
|
|
1128
|
+
if (next) setActive(next.id);
|
|
1129
|
+
else {
|
|
1130
|
+
clearMenuState(menuId);
|
|
1131
|
+
focusMenuElement(menuId);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
function unregisterItem(id) {
|
|
1135
|
+
const item = items.get(id);
|
|
1136
|
+
if (!item) return;
|
|
1137
|
+
const previousIndex = getItems(item.menuId).findIndex((current) => current.id === id);
|
|
1138
|
+
const submenuId = item.submenuId?.();
|
|
1139
|
+
if (submenuId) navigation.closeMenu(submenuId, false);
|
|
1140
|
+
items.delete(id);
|
|
1141
|
+
if (getActiveIdValue(item.menuId) === id) chooseNeighbor(item.menuId, previousIndex);
|
|
1142
|
+
navigation.reconcileOpenSubmenus();
|
|
1143
|
+
}
|
|
1144
|
+
function registerItem(registration) {
|
|
1145
|
+
const previous = items.get(registration.id);
|
|
1146
|
+
if (previous && previous.menuId !== registration.menuId && getActiveIdValue(previous.menuId) === previous.id) clearMenuState(previous.menuId);
|
|
1147
|
+
items.set(registration.id, registration);
|
|
1148
|
+
if (isMenuOpen(registration.menuId) && !getActiveIdValue(registration.menuId) && !registration.disabled()) {
|
|
1149
|
+
const enabledItems = getEnabledItems(registration.menuId);
|
|
1150
|
+
const candidate = pendingMenuFocus.get(registration.menuId) === "last" ? enabledItems.at(-1) : enabledItems[0];
|
|
1151
|
+
if (candidate) setActive(candidate.id);
|
|
1152
|
+
} else navigation.reconcile(registration.menuId);
|
|
1153
|
+
return () => {
|
|
1154
|
+
if (items.get(registration.id) === registration) unregisterItem(registration.id);
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
function unregisterMenu(id) {
|
|
1158
|
+
if (!menus.get(id)) return;
|
|
1159
|
+
navigation.closeSubmenus(id);
|
|
1160
|
+
if (id !== host.rootMenuId) navigation.closeMenu(id, false);
|
|
1161
|
+
clearMenuState(id);
|
|
1162
|
+
menus.delete(id);
|
|
1163
|
+
}
|
|
1164
|
+
function registerMenu(registration) {
|
|
1165
|
+
menus.set(registration.id, registration);
|
|
1166
|
+
const pending = pendingMenuFocus.get(registration.id);
|
|
1167
|
+
if (registration.isOpen() && pending) nextTick(() => navigation.focusMenu(registration.id, pending));
|
|
1168
|
+
return () => {
|
|
1169
|
+
if (menus.get(registration.id) === registration) unregisterMenu(registration.id);
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function registerMenuState(registration) {
|
|
1173
|
+
menuStates.set(registration.id, registration);
|
|
1174
|
+
return () => {
|
|
1175
|
+
if (menuStates.get(registration.id) !== registration) return;
|
|
1176
|
+
menuStates.delete(registration.id);
|
|
1177
|
+
pendingMenuFocus.delete(registration.id);
|
|
1178
|
+
if (!menus.has(registration.id)) clearMenuState(registration.id);
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
return {
|
|
1182
|
+
activeItemId,
|
|
1183
|
+
activeMenuId,
|
|
1184
|
+
pendingRootFocus,
|
|
1185
|
+
registerMenu,
|
|
1186
|
+
unregisterMenu,
|
|
1187
|
+
registerMenuState,
|
|
1188
|
+
registerItem,
|
|
1189
|
+
unregisterItem,
|
|
1190
|
+
getActiveId,
|
|
1191
|
+
getItem,
|
|
1192
|
+
getMenu,
|
|
1193
|
+
isActive,
|
|
1194
|
+
isMenuOpen,
|
|
1195
|
+
setActive,
|
|
1196
|
+
focusMenuElement,
|
|
1197
|
+
state: {
|
|
1198
|
+
getMenuState,
|
|
1199
|
+
getItems,
|
|
1200
|
+
getEnabledItems,
|
|
1201
|
+
getActiveIdValue,
|
|
1202
|
+
clearMenuState,
|
|
1203
|
+
getParentItem,
|
|
1204
|
+
setMenuOpen,
|
|
1205
|
+
chooseNeighbor,
|
|
1206
|
+
getMenuIds: () => /* @__PURE__ */ new Set([...menus.keys(), ...menuStates.keys()]),
|
|
1207
|
+
getRegisteredMenuIds: () => [...menus.keys()],
|
|
1208
|
+
getPendingMenuFocus: (menuId) => pendingMenuFocus.get(menuId),
|
|
1209
|
+
setPendingMenuFocus: (menuId, focus) => pendingMenuFocus.set(menuId, focus),
|
|
1210
|
+
clearPendingMenuFocus: (menuId) => pendingMenuFocus.delete(menuId)
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
//#endregion
|
|
1215
|
+
//#region src/components/dropdown-menu/useDropdownMenuInteractionDismissal.ts
|
|
1216
|
+
function createOutsideEvent(originalEvent) {
|
|
1217
|
+
return createCancelableCustomEvent("dropdown-menu-interact-outside", { originalEvent }, originalEvent);
|
|
1218
|
+
}
|
|
1219
|
+
function blockDocumentClick(event) {
|
|
1220
|
+
if (event.cancelable) event.preventDefault();
|
|
1221
|
+
event.stopPropagation();
|
|
1222
|
+
document.removeEventListener("click", blockDocumentClick, true);
|
|
1223
|
+
}
|
|
1224
|
+
function blockNextDocumentClick() {
|
|
1225
|
+
if (typeof document === "undefined") return;
|
|
1226
|
+
document.addEventListener("click", blockDocumentClick, true);
|
|
1227
|
+
window.setTimeout(() => document.removeEventListener("click", blockDocumentClick, true), 1e3);
|
|
1228
|
+
}
|
|
1229
|
+
function useDropdownMenuInteractionDismissal({ host, registry, closeRoot }) {
|
|
1230
|
+
const inside = /* @__PURE__ */ new Set();
|
|
1231
|
+
let dismissal;
|
|
1232
|
+
let isListening = false;
|
|
1233
|
+
function registerInside(element) {
|
|
1234
|
+
inside.add(element);
|
|
1235
|
+
}
|
|
1236
|
+
function unregisterInside(element) {
|
|
1237
|
+
inside.delete(element);
|
|
1238
|
+
}
|
|
1239
|
+
function isInside(event) {
|
|
1240
|
+
return [...inside].some((element) => isEventWithinElement(event, element));
|
|
1241
|
+
}
|
|
1242
|
+
function emitOutside(type, originalEvent) {
|
|
1243
|
+
const outsideEvent = createOutsideEvent(originalEvent);
|
|
1244
|
+
if (type === "pointer") dismissal?.pointerDownOutside?.(outsideEvent);
|
|
1245
|
+
else dismissal?.focusOutside?.(outsideEvent);
|
|
1246
|
+
dismissal?.interactOutside?.(outsideEvent);
|
|
1247
|
+
return outsideEvent;
|
|
1248
|
+
}
|
|
1249
|
+
function blockModalInteraction(event) {
|
|
1250
|
+
if (!host.modal.value) return;
|
|
1251
|
+
if (event.cancelable) event.preventDefault();
|
|
1252
|
+
event.stopPropagation();
|
|
1253
|
+
if (event.type === "pointerdown") blockNextDocumentClick();
|
|
1254
|
+
}
|
|
1255
|
+
function shouldIgnoreOutside(event) {
|
|
1256
|
+
const ignoredTargets = (dismissal?.ignoredTargets() ?? []).map((target) => isRef(target) ? target.value : target);
|
|
1257
|
+
return isInside(event) || isEventWithinTargets(event, ignoredTargets);
|
|
1258
|
+
}
|
|
1259
|
+
function onDocumentPointer(event) {
|
|
1260
|
+
if (!host.isTopLayer() || shouldIgnoreOutside(event)) return;
|
|
1261
|
+
const outsideEvent = emitOutside("pointer", event);
|
|
1262
|
+
blockModalInteraction(event);
|
|
1263
|
+
if (!outsideEvent.defaultPrevented) closeRoot({ focusTrigger: host.modal.value });
|
|
1264
|
+
}
|
|
1265
|
+
function onDocumentFocus(event) {
|
|
1266
|
+
if (!host.isTopLayer() || shouldIgnoreOutside(event)) return;
|
|
1267
|
+
const outsideEvent = emitOutside("focus", event);
|
|
1268
|
+
blockModalInteraction(event);
|
|
1269
|
+
if (!outsideEvent.defaultPrevented) closeRoot({ focusTrigger: host.modal.value });
|
|
1270
|
+
else if (host.modal.value) registry.focusMenuElement(registry.activeMenuId.value);
|
|
1271
|
+
}
|
|
1272
|
+
function setDocumentListeners(active) {
|
|
1273
|
+
if (typeof document === "undefined" || active === isListening) return;
|
|
1274
|
+
isListening = active;
|
|
1275
|
+
const method = active ? "addEventListener" : "removeEventListener";
|
|
1276
|
+
document[method]("pointerdown", onDocumentPointer, true);
|
|
1277
|
+
document[method]("focusin", onDocumentFocus, true);
|
|
1278
|
+
}
|
|
1279
|
+
function registerDismissal(registration) {
|
|
1280
|
+
dismissal = registration;
|
|
1281
|
+
setDocumentListeners(host.isOpen.value);
|
|
1282
|
+
return () => {
|
|
1283
|
+
if (dismissal !== registration) return;
|
|
1284
|
+
dismissal = void 0;
|
|
1285
|
+
setDocumentListeners(false);
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
watch(host.isOpen, (open) => setDocumentListeners(open && Boolean(dismissal)));
|
|
1289
|
+
onBeforeUnmount(() => setDocumentListeners(false));
|
|
1290
|
+
return {
|
|
1291
|
+
registerInside,
|
|
1292
|
+
unregisterInside,
|
|
1293
|
+
registerDismissal
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
//#endregion
|
|
1297
|
+
//#region src/components/dropdown-menu/useDropdownMenuInteractionKeyboard.ts
|
|
1298
|
+
function getPlacementSide(placement) {
|
|
1299
|
+
return placement.split("-")[0];
|
|
1300
|
+
}
|
|
1301
|
+
function useDropdownMenuInteractionKeyboard({ host, registry, navigation, openRoot, closeRoot }) {
|
|
1302
|
+
const state = registry.state;
|
|
1303
|
+
const typeaheadMenuId = ref(host.rootMenuId);
|
|
1304
|
+
const typeahead = useTypeahead({
|
|
1305
|
+
items: () => state.getItems(typeaheadMenuId.value),
|
|
1306
|
+
activeIndex: () => state.getItems(typeaheadMenuId.value).findIndex((item) => item.id === state.getActiveIdValue(typeaheadMenuId.value)),
|
|
1307
|
+
getKey: (item) => item.id,
|
|
1308
|
+
getTextValue: (item) => item.textValue(),
|
|
1309
|
+
isDisabled: (item) => item.disabled(),
|
|
1310
|
+
scopeKey: () => typeaheadMenuId.value,
|
|
1311
|
+
onMatch(item) {
|
|
1312
|
+
registry.setActive(item.id);
|
|
1313
|
+
navigation.closeSubmenus(item.menuId);
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
function move(menuId, direction) {
|
|
1317
|
+
const enabledItems = state.getEnabledItems(menuId);
|
|
1318
|
+
if (enabledItems.length === 0) {
|
|
1319
|
+
state.clearMenuState(menuId);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const currentIndex = enabledItems.findIndex((item) => item.id === state.getActiveIdValue(menuId));
|
|
1323
|
+
const item = enabledItems[((currentIndex < 0 ? direction === 1 ? -1 : 0 : currentIndex) + direction + enabledItems.length) % enabledItems.length];
|
|
1324
|
+
if (item) {
|
|
1325
|
+
registry.setActive(item.id);
|
|
1326
|
+
navigation.closeSubmenus(menuId);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
function handleHorizontalKey(menuId, event, activeItem) {
|
|
1330
|
+
const menu = registry.getMenu(menuId);
|
|
1331
|
+
const isRight = event.key === "ArrowRight";
|
|
1332
|
+
if (menuId !== host.rootMenuId && menu) {
|
|
1333
|
+
if (isRight === (getPlacementSide(menu.placement()) === "left")) {
|
|
1334
|
+
event.preventDefault();
|
|
1335
|
+
if (menu.stopKeyPropagation) event.stopPropagation();
|
|
1336
|
+
navigation.closeMenu(menuId, true);
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
const submenuId = activeItem?.submenuId?.();
|
|
1341
|
+
if (!activeItem || activeItem.disabled() || !submenuId) return;
|
|
1342
|
+
const submenu = registry.getMenu(submenuId);
|
|
1343
|
+
if (isRight !== (activeItem.submenuDirection?.() !== "left" && (!submenu || getPlacementSide(submenu.placement()) !== "left"))) return;
|
|
1344
|
+
event.preventDefault();
|
|
1345
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1346
|
+
navigation.openMenu(submenuId, "first");
|
|
1347
|
+
}
|
|
1348
|
+
function onMenuKeydown(menuId, event) {
|
|
1349
|
+
const menu = registry.getMenu(menuId);
|
|
1350
|
+
typeaheadMenuId.value = menuId;
|
|
1351
|
+
if (typeahead.handleKey(event)) {
|
|
1352
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const activeId = state.getActiveIdValue(menuId);
|
|
1356
|
+
const activeItem = activeId ? registry.getItem(activeId) : void 0;
|
|
1357
|
+
const stop = () => {
|
|
1358
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1359
|
+
};
|
|
1360
|
+
switch (event.key) {
|
|
1361
|
+
case "ArrowDown":
|
|
1362
|
+
event.preventDefault();
|
|
1363
|
+
stop();
|
|
1364
|
+
move(menuId, 1);
|
|
1365
|
+
break;
|
|
1366
|
+
case "ArrowUp":
|
|
1367
|
+
event.preventDefault();
|
|
1368
|
+
stop();
|
|
1369
|
+
move(menuId, -1);
|
|
1370
|
+
break;
|
|
1371
|
+
case "Home":
|
|
1372
|
+
event.preventDefault();
|
|
1373
|
+
stop();
|
|
1374
|
+
navigation.focusMenu(menuId, "first");
|
|
1375
|
+
navigation.closeSubmenus(menuId);
|
|
1376
|
+
break;
|
|
1377
|
+
case "End":
|
|
1378
|
+
event.preventDefault();
|
|
1379
|
+
stop();
|
|
1380
|
+
navigation.focusMenu(menuId, "last");
|
|
1381
|
+
navigation.closeSubmenus(menuId);
|
|
1382
|
+
break;
|
|
1383
|
+
case "ArrowRight":
|
|
1384
|
+
case "ArrowLeft":
|
|
1385
|
+
handleHorizontalKey(menuId, event, activeItem);
|
|
1386
|
+
break;
|
|
1387
|
+
case "Enter":
|
|
1388
|
+
case " ":
|
|
1389
|
+
event.preventDefault();
|
|
1390
|
+
stop();
|
|
1391
|
+
if (activeItem) navigation.activateItem(activeItem.id, event);
|
|
1392
|
+
break;
|
|
1393
|
+
case "Escape":
|
|
1394
|
+
event.preventDefault();
|
|
1395
|
+
stop();
|
|
1396
|
+
if (menu?.onEscape && !menu.onEscape(event)) return;
|
|
1397
|
+
if (!navigation.closeMenu(menuId, true)) closeRoot({ focusTrigger: true });
|
|
1398
|
+
break;
|
|
1399
|
+
case "Tab":
|
|
1400
|
+
closeRoot();
|
|
1401
|
+
break;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
function onTriggerKeydown(event, beforeOpen) {
|
|
1405
|
+
if (host.disabled.value) return;
|
|
1406
|
+
switch (event.key) {
|
|
1407
|
+
case "Enter":
|
|
1408
|
+
case " ":
|
|
1409
|
+
case "ArrowDown":
|
|
1410
|
+
event.preventDefault();
|
|
1411
|
+
beforeOpen?.();
|
|
1412
|
+
openRoot("first");
|
|
1413
|
+
break;
|
|
1414
|
+
case "ArrowUp":
|
|
1415
|
+
event.preventDefault();
|
|
1416
|
+
beforeOpen?.();
|
|
1417
|
+
openRoot("last");
|
|
1418
|
+
break;
|
|
1419
|
+
case "Escape":
|
|
1420
|
+
closeRoot({ focusTrigger: true });
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return {
|
|
1425
|
+
onMenuKeydown,
|
|
1426
|
+
onTriggerKeydown,
|
|
1427
|
+
resetTypeahead: typeahead.reset
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/components/dropdown-menu/dropdownMenuInteraction.ts
|
|
1432
|
+
function resolveOpenFocusTarget(options) {
|
|
1433
|
+
if (typeof options === "string") return options;
|
|
1434
|
+
return options?.focus ?? "first";
|
|
1435
|
+
}
|
|
1436
|
+
function useDropdownMenuInteraction(host) {
|
|
1437
|
+
let navigation;
|
|
1438
|
+
const registry = createDropdownMenuInteractionRegistry(host, {
|
|
1439
|
+
closeMenu: (menuId, focusParent) => navigation.closeMenu(menuId, focusParent),
|
|
1440
|
+
closeSubmenus: (menuId, exceptMenuId) => navigation.closeSubmenus(menuId, exceptMenuId),
|
|
1441
|
+
focusMenu: (menuId, target) => navigation.focusMenu(menuId, target),
|
|
1442
|
+
reconcile: (menuId) => navigation.reconcile(menuId),
|
|
1443
|
+
reconcileOpenSubmenus: () => navigation.reconcileOpenSubmenus()
|
|
1444
|
+
});
|
|
1445
|
+
function open(options) {
|
|
1446
|
+
if (host.disabled.value) return;
|
|
1447
|
+
host.beforeOpen?.();
|
|
1448
|
+
registry.pendingRootFocus.value = resolveOpenFocusTarget(options);
|
|
1449
|
+
host.setOpen(true);
|
|
1450
|
+
navigation.focusMenu(host.rootMenuId, registry.pendingRootFocus.value);
|
|
1451
|
+
}
|
|
1452
|
+
function close(options = {}) {
|
|
1453
|
+
host.beforeClose?.();
|
|
1454
|
+
host.setOpen(false);
|
|
1455
|
+
registry.pendingRootFocus.value = false;
|
|
1456
|
+
navigation.closeAllSubmenus();
|
|
1457
|
+
registry.state.clearMenuState(host.rootMenuId);
|
|
1458
|
+
registry.activeItemId.value = null;
|
|
1459
|
+
registry.activeMenuId.value = host.rootMenuId;
|
|
1460
|
+
keyboard.resetTypeahead();
|
|
1461
|
+
if (options.focusTrigger || options.returnFocus) host.focusTrigger();
|
|
1462
|
+
}
|
|
1463
|
+
function toggle() {
|
|
1464
|
+
if (host.isOpen.value) close({ returnFocus: true });
|
|
1465
|
+
else open();
|
|
1466
|
+
}
|
|
1467
|
+
function onTriggerClick(beforeToggle) {
|
|
1468
|
+
beforeToggle?.();
|
|
1469
|
+
toggle();
|
|
1470
|
+
}
|
|
1471
|
+
navigation = createDropdownMenuInteractionNavigation({
|
|
1472
|
+
host,
|
|
1473
|
+
registry,
|
|
1474
|
+
closeRoot: close
|
|
1475
|
+
});
|
|
1476
|
+
const keyboard = useDropdownMenuInteractionKeyboard({
|
|
1477
|
+
host,
|
|
1478
|
+
registry,
|
|
1479
|
+
navigation,
|
|
1480
|
+
openRoot: open,
|
|
1481
|
+
closeRoot: close
|
|
1482
|
+
});
|
|
1483
|
+
const dismissal = useDropdownMenuInteractionDismissal({
|
|
1484
|
+
host,
|
|
1485
|
+
registry,
|
|
1486
|
+
closeRoot: close
|
|
1487
|
+
});
|
|
1488
|
+
watch(host.disabled, (disabled) => {
|
|
1489
|
+
if (disabled) close();
|
|
1490
|
+
});
|
|
1491
|
+
watch(host.isOpen, (isOpen) => {
|
|
1492
|
+
if (!isOpen) {
|
|
1493
|
+
navigation.closeAllSubmenus();
|
|
1494
|
+
registry.state.clearMenuState(host.rootMenuId);
|
|
1495
|
+
registry.activeItemId.value = null;
|
|
1496
|
+
registry.activeMenuId.value = host.rootMenuId;
|
|
1497
|
+
keyboard.resetTypeahead();
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const focus = registry.pendingRootFocus.value || "first";
|
|
1501
|
+
navigation.focusMenu(host.rootMenuId, focus);
|
|
1502
|
+
}, { immediate: true });
|
|
1503
|
+
return {
|
|
1504
|
+
rootMenuId: host.rootMenuId,
|
|
1505
|
+
activeItemId: registry.activeItemId,
|
|
1506
|
+
activeMenuId: registry.activeMenuId,
|
|
1507
|
+
pendingRootFocus: registry.pendingRootFocus,
|
|
1508
|
+
registerMenu: registry.registerMenu,
|
|
1509
|
+
unregisterMenu: registry.unregisterMenu,
|
|
1510
|
+
registerMenuState: registry.registerMenuState,
|
|
1511
|
+
registerItem: registry.registerItem,
|
|
1512
|
+
unregisterItem: registry.unregisterItem,
|
|
1513
|
+
registerInside: dismissal.registerInside,
|
|
1514
|
+
unregisterInside: dismissal.unregisterInside,
|
|
1515
|
+
registerDismissal: dismissal.registerDismissal,
|
|
1516
|
+
getActiveId: registry.getActiveId,
|
|
1517
|
+
getItem: registry.getItem,
|
|
1518
|
+
getMenu: registry.getMenu,
|
|
1519
|
+
isActive: registry.isActive,
|
|
1520
|
+
isMenuOpen: registry.isMenuOpen,
|
|
1521
|
+
setActive: registry.setActive,
|
|
1522
|
+
focusMenu: navigation.focusMenu,
|
|
1523
|
+
focusMenuElement: registry.focusMenuElement,
|
|
1524
|
+
open,
|
|
1525
|
+
close,
|
|
1526
|
+
toggle,
|
|
1527
|
+
openMenu: navigation.openMenu,
|
|
1528
|
+
closeMenu: navigation.closeMenu,
|
|
1529
|
+
closeSubmenus: navigation.closeSubmenus,
|
|
1530
|
+
selectItem: navigation.selectItem,
|
|
1531
|
+
activateItem: navigation.activateItem,
|
|
1532
|
+
hoverItem: navigation.hoverItem,
|
|
1533
|
+
reconcile: navigation.reconcile,
|
|
1534
|
+
onTriggerClick,
|
|
1535
|
+
onTriggerKeydown: keyboard.onTriggerKeydown,
|
|
1536
|
+
onMenuKeydown: keyboard.onMenuKeydown
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
//#endregion
|
|
1540
|
+
//#region src/components/dropdown-menu/dropdown-menu-root.vue
|
|
1541
|
+
var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
1542
|
+
name: "RpDropdownMenuRoot",
|
|
1543
|
+
__name: "dropdown-menu-root",
|
|
1544
|
+
props: {
|
|
1545
|
+
id: {},
|
|
1546
|
+
open: {
|
|
1547
|
+
type: Boolean,
|
|
1548
|
+
default: void 0
|
|
1549
|
+
},
|
|
1550
|
+
defaultOpen: {
|
|
1551
|
+
type: Boolean,
|
|
1552
|
+
default: false
|
|
1553
|
+
},
|
|
1554
|
+
baseZIndex: {},
|
|
1083
1555
|
disabled: {
|
|
1084
1556
|
type: Boolean,
|
|
1085
1557
|
default: false
|
|
@@ -1111,9 +1583,7 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1111
1583
|
const activeReference = shallowRef(null);
|
|
1112
1584
|
const { reference: configuredReference } = useFloatingTarget(() => props.target ?? props.virtualAnchor, trigger);
|
|
1113
1585
|
const reference = computed(() => activeReference.value ?? configuredReference.value);
|
|
1114
|
-
const pendingFocus = ref("first");
|
|
1115
1586
|
const contentElement = ref(null);
|
|
1116
|
-
const inside = /* @__PURE__ */ new Set();
|
|
1117
1587
|
let returnFocusElement = null;
|
|
1118
1588
|
const baseZIndex = useOverlayZIndex({
|
|
1119
1589
|
baseZIndex: () => props.baseZIndex,
|
|
@@ -1134,34 +1604,30 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1134
1604
|
const activeElement = document.activeElement;
|
|
1135
1605
|
if (activeElement instanceof HTMLElement) returnFocusElement = activeElement;
|
|
1136
1606
|
}
|
|
1137
|
-
function open(options) {
|
|
1138
|
-
if (disabled.value) return;
|
|
1139
|
-
rememberFocus();
|
|
1140
|
-
pendingFocus.value = getFocusTarget(options);
|
|
1141
|
-
setOpen(true);
|
|
1142
|
-
}
|
|
1143
1607
|
function focusReturnTarget() {
|
|
1144
1608
|
const target = returnFocusElement ?? trigger.value;
|
|
1145
1609
|
nextTick(() => target?.focus());
|
|
1146
1610
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1611
|
+
const interaction = useDropdownMenuInteraction({
|
|
1612
|
+
rootMenuId: `${generatedId}-interaction-root`,
|
|
1613
|
+
isOpen,
|
|
1614
|
+
disabled,
|
|
1615
|
+
modal,
|
|
1616
|
+
setOpen,
|
|
1617
|
+
isTopLayer: layer.isTopLayer,
|
|
1618
|
+
focusTrigger: focusReturnTarget,
|
|
1619
|
+
beforeOpen: rememberFocus
|
|
1620
|
+
});
|
|
1621
|
+
const { pendingRootFocus: pendingFocus, open, close, toggle } = interaction;
|
|
1156
1622
|
function openAt(point, options) {
|
|
1157
1623
|
activeReference.value = createVirtualAnchor(point);
|
|
1158
1624
|
open(options);
|
|
1159
1625
|
}
|
|
1160
1626
|
function setTrigger(element, nextId) {
|
|
1161
|
-
if (trigger.value && trigger.value !== element)
|
|
1627
|
+
if (trigger.value && trigger.value !== element) interaction.unregisterInside(trigger.value);
|
|
1162
1628
|
trigger.value = element;
|
|
1163
1629
|
triggerId.value = nextId;
|
|
1164
|
-
if (element)
|
|
1630
|
+
if (element) interaction.registerInside(element);
|
|
1165
1631
|
}
|
|
1166
1632
|
const context = {
|
|
1167
1633
|
id,
|
|
@@ -1174,6 +1640,7 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1174
1640
|
reference,
|
|
1175
1641
|
pendingFocus,
|
|
1176
1642
|
layer,
|
|
1643
|
+
interaction,
|
|
1177
1644
|
open,
|
|
1178
1645
|
close,
|
|
1179
1646
|
toggle,
|
|
@@ -1186,13 +1653,10 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1186
1653
|
returnFocusElement = element;
|
|
1187
1654
|
},
|
|
1188
1655
|
registerInside(element) {
|
|
1189
|
-
|
|
1656
|
+
interaction.registerInside(element);
|
|
1190
1657
|
},
|
|
1191
1658
|
unregisterInside(element) {
|
|
1192
|
-
|
|
1193
|
-
},
|
|
1194
|
-
isInside(event) {
|
|
1195
|
-
return [...inside].some((element) => isEventWithinElement(event, element));
|
|
1659
|
+
interaction.unregisterInside(element);
|
|
1196
1660
|
}
|
|
1197
1661
|
};
|
|
1198
1662
|
const slotProps = computed(() => ({
|
|
@@ -1202,9 +1666,6 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1202
1666
|
toggle,
|
|
1203
1667
|
openAt
|
|
1204
1668
|
}));
|
|
1205
|
-
watch(disabled, (value) => {
|
|
1206
|
-
if (value) close();
|
|
1207
|
-
});
|
|
1208
1669
|
watch(isOpen, (value) => {
|
|
1209
1670
|
if (!value) activeReference.value = null;
|
|
1210
1671
|
}, { flush: "sync" });
|
|
@@ -1263,6 +1724,7 @@ var dropdown_menu_sub_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1263
1724
|
const props = __props;
|
|
1264
1725
|
const emit = __emit;
|
|
1265
1726
|
const parentMenu = useRequiredInject(menuKey, "RpDropdownMenuSub");
|
|
1727
|
+
const menuId = `${useId()}-interaction-menu`;
|
|
1266
1728
|
const controllableOpen = useControllableValue({
|
|
1267
1729
|
modelValue: () => props.open,
|
|
1268
1730
|
defaultValue: () => props.defaultOpen,
|
|
@@ -1276,35 +1738,31 @@ var dropdown_menu_sub_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1276
1738
|
function setOpen(value) {
|
|
1277
1739
|
if (isOpen.value !== value) controllableOpen.setValue(value);
|
|
1278
1740
|
}
|
|
1741
|
+
const cleanupMenuState = parentMenu.root.interaction.registerMenuState({
|
|
1742
|
+
id: menuId,
|
|
1743
|
+
isOpen: () => isOpen.value,
|
|
1744
|
+
setOpen
|
|
1745
|
+
});
|
|
1279
1746
|
const context = {
|
|
1747
|
+
menuId,
|
|
1280
1748
|
isOpen,
|
|
1281
1749
|
trigger,
|
|
1282
1750
|
contentId,
|
|
1283
1751
|
actualPlacement,
|
|
1284
1752
|
pendingFocus,
|
|
1285
1753
|
menu: null,
|
|
1754
|
+
setOpen,
|
|
1286
1755
|
open(focus = "first") {
|
|
1287
|
-
parentMenu.closeSubmenus(context);
|
|
1288
1756
|
pendingFocus.value = focus;
|
|
1289
|
-
setOpen(true);
|
|
1290
|
-
if (focus) nextTick(() => context.menu?.focus(focus));
|
|
1757
|
+
if (!parentMenu.root.interaction.openMenu(menuId, focus)) setOpen(true);
|
|
1291
1758
|
},
|
|
1292
1759
|
close(focusParent = false) {
|
|
1293
|
-
setOpen(false);
|
|
1294
1760
|
pendingFocus.value = false;
|
|
1295
|
-
|
|
1296
|
-
if (focusParent) {
|
|
1297
|
-
parentMenu.setActive(trigger.value?.id ?? "");
|
|
1298
|
-
parentMenu.focusElement();
|
|
1299
|
-
}
|
|
1761
|
+
if (!parentMenu.root.interaction.closeMenu(menuId, focusParent)) setOpen(false);
|
|
1300
1762
|
}
|
|
1301
1763
|
};
|
|
1302
|
-
parentMenu.registerSub(context);
|
|
1303
1764
|
provide(subKey, context);
|
|
1304
|
-
|
|
1305
|
-
if (!open) context.close(false);
|
|
1306
|
-
});
|
|
1307
|
-
onBeforeUnmount(() => parentMenu.unregisterSub(context));
|
|
1765
|
+
onBeforeUnmount(cleanupMenuState);
|
|
1308
1766
|
return createSlot("default", {
|
|
1309
1767
|
isOpen: () => unref(isOpen),
|
|
1310
1768
|
open: () => context.open,
|
|
@@ -1402,10 +1860,17 @@ var dropdown_menu_sub_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1402
1860
|
element: () => sub.trigger.value,
|
|
1403
1861
|
textValue: () => props.textValue ?? sub.trigger.value?.textContent?.trim() ?? "",
|
|
1404
1862
|
disabled: () => isDisabled.value,
|
|
1405
|
-
activate: () =>
|
|
1863
|
+
activate: () => void 0,
|
|
1406
1864
|
submenu: sub
|
|
1407
1865
|
};
|
|
1408
1866
|
menu.registerItem(registration);
|
|
1867
|
+
watch(id, (nextId, previousId) => {
|
|
1868
|
+
const wasActive = menu.activeId.value === previousId;
|
|
1869
|
+
menu.unregisterItem(previousId);
|
|
1870
|
+
menu.registerItem(registration);
|
|
1871
|
+
if (wasActive) menu.setActive(nextId);
|
|
1872
|
+
}, { flush: "sync" });
|
|
1873
|
+
watch(isDisabled, () => menu.root.interaction.reconcile(menu.id));
|
|
1409
1874
|
onBeforeUnmount(() => menu.unregisterItem(id.value));
|
|
1410
1875
|
function setElement(value) {
|
|
1411
1876
|
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
@@ -1414,25 +1879,24 @@ var dropdown_menu_sub_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1414
1879
|
}
|
|
1415
1880
|
function onMouseenter() {
|
|
1416
1881
|
if (isDisabled.value) return;
|
|
1417
|
-
menu.
|
|
1418
|
-
sub.open(false);
|
|
1882
|
+
menu.hover(id.value, true);
|
|
1419
1883
|
}
|
|
1420
1884
|
function onClick(event) {
|
|
1421
|
-
if (!event.defaultPrevented && !isDisabled.value)
|
|
1885
|
+
if (!event.defaultPrevented && !isDisabled.value) menu.activate(id.value, event);
|
|
1422
1886
|
}
|
|
1423
1887
|
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
1424
1888
|
id: id.value,
|
|
1425
1889
|
type: props.as === "button" ? "button" : void 0,
|
|
1426
1890
|
role: "menuitem",
|
|
1427
1891
|
tabindex: -1,
|
|
1428
|
-
disabled: props.as === "button" ?
|
|
1429
|
-
"aria-disabled":
|
|
1892
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
1893
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
1430
1894
|
"aria-haspopup": "menu",
|
|
1431
1895
|
"aria-expanded": sub.isOpen.value,
|
|
1432
1896
|
"aria-controls": sub.contentId.value,
|
|
1433
|
-
"data-disabled":
|
|
1434
|
-
"data-focused":
|
|
1435
|
-
"data-highlighted":
|
|
1897
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
1898
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
1899
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
1436
1900
|
"data-state": sub.isOpen.value ? "open" : "closed",
|
|
1437
1901
|
class: bem("rp-dropdown-menu__item", {
|
|
1438
1902
|
focused: focused.value,
|
|
@@ -1484,41 +1948,28 @@ var dropdown_menu_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1484
1948
|
root.setTrigger(resolved, id.value);
|
|
1485
1949
|
});
|
|
1486
1950
|
}
|
|
1487
|
-
function
|
|
1951
|
+
function prepareReference() {
|
|
1488
1952
|
root.setReference(element.value);
|
|
1489
1953
|
root.setReturnFocus(element.value);
|
|
1490
|
-
root.open({ focus });
|
|
1491
1954
|
}
|
|
1492
1955
|
function onClick(event) {
|
|
1493
1956
|
if (event.defaultPrevented || isDisabled.value) return;
|
|
1494
|
-
root.
|
|
1495
|
-
root.setReturnFocus(element.value);
|
|
1496
|
-
root.toggle();
|
|
1957
|
+
root.interaction.onTriggerClick(prepareReference);
|
|
1497
1958
|
}
|
|
1498
1959
|
function onKeydown(event) {
|
|
1499
1960
|
if (isDisabled.value) return;
|
|
1500
|
-
|
|
1501
|
-
event.preventDefault();
|
|
1502
|
-
openWithReference("last");
|
|
1503
|
-
} else if ([
|
|
1504
|
-
"Enter",
|
|
1505
|
-
" ",
|
|
1506
|
-
"ArrowDown"
|
|
1507
|
-
].includes(event.key)) {
|
|
1508
|
-
event.preventDefault();
|
|
1509
|
-
openWithReference("first");
|
|
1510
|
-
} else if (event.key === "Escape") root.close({ focusTrigger: true });
|
|
1961
|
+
root.interaction.onTriggerKeydown(event, prepareReference);
|
|
1511
1962
|
}
|
|
1512
1963
|
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
1513
1964
|
id: id.value,
|
|
1514
1965
|
type: props.as === "button" ? "button" : void 0,
|
|
1515
|
-
disabled: props.as === "button" ?
|
|
1966
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
1516
1967
|
"aria-controls": root.contentId.value,
|
|
1517
1968
|
"aria-expanded": root.isOpen.value,
|
|
1518
1969
|
"aria-haspopup": "menu",
|
|
1519
|
-
"aria-disabled": props.as === "button" ? void 0 :
|
|
1970
|
+
"aria-disabled": props.as === "button" ? void 0 : toOptionalAttribute(isDisabled.value),
|
|
1520
1971
|
"data-state": root.isOpen.value ? "open" : "closed",
|
|
1521
|
-
"data-disabled":
|
|
1972
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
1522
1973
|
onClick,
|
|
1523
1974
|
onKeydown
|
|
1524
1975
|
}));
|
|
@@ -1530,31 +1981,10 @@ var dropdown_menu_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1530
1981
|
return n1;
|
|
1531
1982
|
}
|
|
1532
1983
|
});
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
return
|
|
1537
|
-
}
|
|
1538
|
-
function getItemClass(item, focused, disabled, hasSubmenu, submenuOpen) {
|
|
1539
|
-
return bem("rp-dropdown-menu__item", {
|
|
1540
|
-
focused,
|
|
1541
|
-
disabled,
|
|
1542
|
-
destructive: item.destructive,
|
|
1543
|
-
submenu: hasSubmenu,
|
|
1544
|
-
open: submenuOpen
|
|
1545
|
-
});
|
|
1546
|
-
}
|
|
1547
|
-
function hasItemSubmenu(item) {
|
|
1548
|
-
return (item.children?.length ?? 0) > 0;
|
|
1549
|
-
}
|
|
1550
|
-
function hasNestedItems(items) {
|
|
1551
|
-
return items.some(hasItemSubmenu);
|
|
1552
|
-
}
|
|
1553
|
-
function getPathKey(path) {
|
|
1554
|
-
return path.length === 0 ? "root" : path.join("-");
|
|
1555
|
-
}
|
|
1556
|
-
function getParentPath(path) {
|
|
1557
|
-
return path.slice(0, -1);
|
|
1984
|
+
//#endregion
|
|
1985
|
+
//#region src/utils/indexPath.ts
|
|
1986
|
+
function getPathKey(path) {
|
|
1987
|
+
return path.length === 0 ? "root" : path.join("-");
|
|
1558
1988
|
}
|
|
1559
1989
|
function arePathsEqual(a, b) {
|
|
1560
1990
|
return a.length === b.length && a.every((part, index) => part === b[index]);
|
|
@@ -1565,17 +1995,21 @@ function isPathPrefix(prefix, path) {
|
|
|
1565
1995
|
function normalizePath(indexOrPath) {
|
|
1566
1996
|
return Array.isArray(indexOrPath) ? indexOrPath : [indexOrPath];
|
|
1567
1997
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1998
|
+
var DEFAULT_FOCUS_TARGET = "first";
|
|
1999
|
+
function getItemClass(item, focused, disabled, hasSubmenu, submenuOpen) {
|
|
2000
|
+
return bem("rp-dropdown-menu__item", {
|
|
2001
|
+
focused,
|
|
2002
|
+
disabled,
|
|
2003
|
+
destructive: item.destructive,
|
|
2004
|
+
submenu: hasSubmenu,
|
|
2005
|
+
open: submenuOpen
|
|
2006
|
+
});
|
|
1573
2007
|
}
|
|
1574
|
-
function
|
|
1575
|
-
return
|
|
2008
|
+
function hasItemSubmenu(item) {
|
|
2009
|
+
return (item.children?.length ?? 0) > 0;
|
|
1576
2010
|
}
|
|
1577
|
-
function
|
|
1578
|
-
return
|
|
2011
|
+
function hasNestedItems(items) {
|
|
2012
|
+
return items.some(hasItemSubmenu);
|
|
1579
2013
|
}
|
|
1580
2014
|
//#endregion
|
|
1581
2015
|
//#region src/components/dropdown-menu/dropdown-menu-item-row.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
@@ -1607,6 +2041,10 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1607
2041
|
const slotProps = computed(() => props.context.getItemSlotProps(props.item, path.value, focused.value, disabled.value, submenuOpen.value));
|
|
1608
2042
|
const itemElement = ref(null);
|
|
1609
2043
|
const submenuElement = ref(null);
|
|
2044
|
+
const templateRefs = {
|
|
2045
|
+
item: itemElement,
|
|
2046
|
+
submenu: submenuElement
|
|
2047
|
+
};
|
|
1610
2048
|
const { actualPlacement, floatingStyle } = useFloatingPosition({
|
|
1611
2049
|
reference: itemElement,
|
|
1612
2050
|
floating: submenuElement,
|
|
@@ -1632,14 +2070,13 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1632
2070
|
function getChildKey(index, child) {
|
|
1633
2071
|
return `${getPathKey([...path.value, index])}:${String(child.value)}`;
|
|
1634
2072
|
}
|
|
1635
|
-
const _setTemplateRef = createTemplateRefSetter();
|
|
1636
2073
|
const _component_DropdownMenuItemRow__self = resolveComponent("DropdownMenuItemRow", true);
|
|
1637
2074
|
const n10 = t1$1();
|
|
1638
2075
|
const n1 = child(n10);
|
|
1639
2076
|
renderEffect(() => setDynamicProps(n1, [publicItemProps.value]));
|
|
1640
2077
|
setInsertionState(n1, null, 0);
|
|
1641
2078
|
createSlot("item", { $: [() => slotProps.value] });
|
|
1642
|
-
|
|
2079
|
+
setTemplateRefBinding(n1, () => templateRefs.item);
|
|
1643
2080
|
setInsertionState(n10, null, 1);
|
|
1644
2081
|
createIf(() => hasSubmenu.value && submenuOpen.value, () => {
|
|
1645
2082
|
const n9 = t0$1();
|
|
@@ -1659,7 +2096,7 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1659
2096
|
return createSlot("item", { $: [() => childSlotProps] });
|
|
1660
2097
|
}, { _: 8 }) });
|
|
1661
2098
|
}, (child, childIndex) => getChildKey(childIndex, child), 3);
|
|
1662
|
-
|
|
2099
|
+
setTemplateRefBinding(n9, () => templateRefs.submenu);
|
|
1663
2100
|
return n9;
|
|
1664
2101
|
});
|
|
1665
2102
|
return n10;
|
|
@@ -1693,151 +2130,167 @@ var dropdown_menu_items_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1693
2130
|
}
|
|
1694
2131
|
});
|
|
1695
2132
|
//#endregion
|
|
1696
|
-
//#region src/components/dropdown-menu/
|
|
1697
|
-
function
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
return outsideEvent;
|
|
1739
|
-
}
|
|
1740
|
-
function isInside(event) {
|
|
1741
|
-
return isEventWithinTargets(event, [
|
|
1742
|
-
rootRef,
|
|
1743
|
-
menuRef,
|
|
1744
|
-
targetRef,
|
|
1745
|
-
...props.ignore ?? []
|
|
1746
|
-
]);
|
|
1747
|
-
}
|
|
1748
|
-
function blockModalInteraction(event) {
|
|
1749
|
-
if (!props.modal) return;
|
|
1750
|
-
if (event.cancelable) event.preventDefault();
|
|
1751
|
-
event.stopPropagation();
|
|
1752
|
-
if (event.type === "pointerdown") blockNextDocumentClick();
|
|
1753
|
-
}
|
|
1754
|
-
function onDocumentPointerdown(event) {
|
|
1755
|
-
if (!layer.isTopLayer()) return;
|
|
1756
|
-
if (isInside(event)) return;
|
|
1757
|
-
const outsideEvent = emitOutside("pointer", event);
|
|
1758
|
-
blockModalInteraction(event);
|
|
1759
|
-
if (!outsideEvent.defaultPrevented) close({ focusTrigger: Boolean(props.modal) });
|
|
1760
|
-
}
|
|
1761
|
-
function onDocumentFocus(event) {
|
|
1762
|
-
if (!layer.isTopLayer()) return;
|
|
1763
|
-
if (isInside(event)) return;
|
|
1764
|
-
const outsideEvent = emitOutside("focus", event);
|
|
1765
|
-
blockModalInteraction(event);
|
|
1766
|
-
if (!outsideEvent.defaultPrevented) close({ focusTrigger: Boolean(props.modal) });
|
|
1767
|
-
else if (props.modal) focusMenu();
|
|
1768
|
-
}
|
|
1769
|
-
let isListening = false;
|
|
1770
|
-
function setDocumentListeners(active) {
|
|
1771
|
-
if (typeof document === "undefined" || active === isListening) return;
|
|
1772
|
-
isListening = active;
|
|
1773
|
-
const method = active ? "addEventListener" : "removeEventListener";
|
|
1774
|
-
document[method]("pointerdown", onDocumentPointerdown, true);
|
|
1775
|
-
document[method]("focusin", onDocumentFocus, true);
|
|
2133
|
+
//#region src/components/dropdown-menu/dropdownMenuDataModel.ts
|
|
2134
|
+
function createDataIndexState(rootMenuId) {
|
|
2135
|
+
return {
|
|
2136
|
+
entries: [],
|
|
2137
|
+
itemIdByPath: /* @__PURE__ */ new Map(),
|
|
2138
|
+
pathByItemId: /* @__PURE__ */ new Map(),
|
|
2139
|
+
menuIdByPath: /* @__PURE__ */ new Map([["root", rootMenuId]]),
|
|
2140
|
+
pathByMenuId: /* @__PURE__ */ new Map([[rootMenuId, []]]),
|
|
2141
|
+
primaryItemId: /* @__PURE__ */ new WeakMap(),
|
|
2142
|
+
occurrences: /* @__PURE__ */ new Map()
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
function getOccurrenceItemId(item, state, getStableItemId) {
|
|
2146
|
+
const occurrence = state.occurrences.get(item) ?? 0;
|
|
2147
|
+
state.occurrences.set(item, occurrence + 1);
|
|
2148
|
+
const stableItemId = getStableItemId(item);
|
|
2149
|
+
return {
|
|
2150
|
+
occurrence,
|
|
2151
|
+
itemId: occurrence === 0 ? stableItemId : `${stableItemId}-copy-${occurrence}`
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
function indexItems(items, parentPath, ownerMenuId, state, getStableItemId) {
|
|
2155
|
+
for (const [order, item] of items.entries()) {
|
|
2156
|
+
const path = [...parentPath, order];
|
|
2157
|
+
const pathKey = getPathKey(path);
|
|
2158
|
+
const { itemId, occurrence } = getOccurrenceItemId(item, state, getStableItemId);
|
|
2159
|
+
const submenuMenuId = hasItemSubmenu(item) ? `${itemId}-menu` : void 0;
|
|
2160
|
+
state.entries.push({
|
|
2161
|
+
item,
|
|
2162
|
+
path,
|
|
2163
|
+
itemId,
|
|
2164
|
+
ownerMenuId,
|
|
2165
|
+
order,
|
|
2166
|
+
submenuMenuId
|
|
2167
|
+
});
|
|
2168
|
+
state.itemIdByPath.set(pathKey, itemId);
|
|
2169
|
+
state.pathByItemId.set(itemId, path);
|
|
2170
|
+
if (occurrence === 0) state.primaryItemId.set(item, itemId);
|
|
2171
|
+
if (!submenuMenuId) continue;
|
|
2172
|
+
state.menuIdByPath.set(pathKey, submenuMenuId);
|
|
2173
|
+
state.pathByMenuId.set(submenuMenuId, path);
|
|
2174
|
+
indexItems(item.children ?? [], path, submenuMenuId, state, getStableItemId);
|
|
1776
2175
|
}
|
|
1777
|
-
|
|
1778
|
-
|
|
2176
|
+
}
|
|
2177
|
+
function buildDropdownMenuDataIndex(items, rootMenuId, getStableItemId) {
|
|
2178
|
+
const state = createDataIndexState(rootMenuId);
|
|
2179
|
+
indexItems(items, [], rootMenuId, state, getStableItemId);
|
|
1779
2180
|
return {
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2181
|
+
entries: state.entries,
|
|
2182
|
+
itemIdByPath: state.itemIdByPath,
|
|
2183
|
+
pathByItemId: state.pathByItemId,
|
|
2184
|
+
menuIdByPath: state.menuIdByPath,
|
|
2185
|
+
pathByMenuId: state.pathByMenuId,
|
|
2186
|
+
primaryItemId: state.primaryItemId
|
|
1784
2187
|
};
|
|
1785
2188
|
}
|
|
2189
|
+
function getDropdownMenuDataCollectionState(items) {
|
|
2190
|
+
const state = [];
|
|
2191
|
+
function collect(currentItems) {
|
|
2192
|
+
state.push(currentItems.length);
|
|
2193
|
+
for (const item of currentItems) {
|
|
2194
|
+
const children = item.children;
|
|
2195
|
+
state.push(item, Boolean(item.disabled), children);
|
|
2196
|
+
if (children) collect(children);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
collect(items);
|
|
2200
|
+
return state;
|
|
2201
|
+
}
|
|
1786
2202
|
//#endregion
|
|
1787
|
-
//#region src/components/dropdown-menu/
|
|
1788
|
-
function
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2203
|
+
//#region src/components/dropdown-menu/useDropdownMenuDataRegistration.ts
|
|
2204
|
+
function getCurrentPath(index, entry) {
|
|
2205
|
+
return index.pathByItemId.get(entry.itemId) ?? entry.path;
|
|
2206
|
+
}
|
|
2207
|
+
function useDropdownMenuDataRegistration({ props, items, rootMenuId, interaction, menuRef, getItemElement, getSubmenuElement, isSubmenuOpeningLeft, onSelect }) {
|
|
2208
|
+
const openMenuIds = ref(/* @__PURE__ */ new Set());
|
|
2209
|
+
const itemIdentity = /* @__PURE__ */ new WeakMap();
|
|
2210
|
+
let nextItemIdentity = 0;
|
|
2211
|
+
let registeredItemIds = /* @__PURE__ */ new Set();
|
|
2212
|
+
let registeredMenuIds = /* @__PURE__ */ new Set();
|
|
2213
|
+
function getStableItemId(item) {
|
|
2214
|
+
const existing = itemIdentity.get(item);
|
|
2215
|
+
if (existing) return existing;
|
|
2216
|
+
nextItemIdentity += 1;
|
|
2217
|
+
const id = `${rootMenuId}-item-${nextItemIdentity}`;
|
|
2218
|
+
itemIdentity.set(item, id);
|
|
2219
|
+
return id;
|
|
2220
|
+
}
|
|
2221
|
+
const registrationIndex = shallowRef(buildDropdownMenuDataIndex([], rootMenuId, getStableItemId));
|
|
2222
|
+
const collectionState = computed(() => getDropdownMenuDataCollectionState(items.value));
|
|
2223
|
+
function setMenuOpen(id, open) {
|
|
2224
|
+
const next = new Set(openMenuIds.value);
|
|
2225
|
+
if (open) next.add(id);
|
|
2226
|
+
else next.delete(id);
|
|
2227
|
+
openMenuIds.value = next;
|
|
2228
|
+
}
|
|
2229
|
+
function createMenuRegistration(index, entry) {
|
|
2230
|
+
const submenuMenuId = entry.submenuMenuId;
|
|
2231
|
+
if (!submenuMenuId) return void 0;
|
|
2232
|
+
return {
|
|
2233
|
+
id: submenuMenuId,
|
|
2234
|
+
parentItemId: () => entry.itemId,
|
|
2235
|
+
element: () => getSubmenuElement(getCurrentPath(index, entry)),
|
|
2236
|
+
focusTarget: () => menuRef.value,
|
|
2237
|
+
placement: () => {
|
|
2238
|
+
return getSubmenuElement(getCurrentPath(index, entry))?.dataset.placement ?? "right-start";
|
|
2239
|
+
},
|
|
2240
|
+
isOpen: () => openMenuIds.value.has(submenuMenuId),
|
|
2241
|
+
setOpen: (open) => setMenuOpen(submenuMenuId, open)
|
|
2242
|
+
};
|
|
1792
2243
|
}
|
|
1793
|
-
function
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2244
|
+
function createSelectEvent(entry, originalEvent) {
|
|
2245
|
+
const event = new CustomEvent("dropdown-menu-select", {
|
|
2246
|
+
cancelable: true,
|
|
2247
|
+
detail: {
|
|
2248
|
+
originalEvent,
|
|
2249
|
+
value: entry.item.value
|
|
1798
2250
|
}
|
|
1799
|
-
|
|
2251
|
+
});
|
|
2252
|
+
onSelect?.(entry.item, event);
|
|
2253
|
+
return event;
|
|
2254
|
+
}
|
|
2255
|
+
function registerEntry(index, entry) {
|
|
2256
|
+
const menuRegistration = createMenuRegistration(index, entry);
|
|
2257
|
+
if (menuRegistration) interaction.registerMenu(menuRegistration);
|
|
2258
|
+
interaction.registerItem({
|
|
2259
|
+
id: entry.itemId,
|
|
2260
|
+
menuId: entry.ownerMenuId,
|
|
2261
|
+
element: () => getItemElement(getCurrentPath(index, entry)),
|
|
2262
|
+
textValue: () => entry.item.label,
|
|
2263
|
+
disabled: () => Boolean(entry.item.disabled || props.disabled),
|
|
2264
|
+
order: () => entry.order,
|
|
2265
|
+
submenuId: () => entry.submenuMenuId,
|
|
2266
|
+
submenuDirection: () => isSubmenuOpeningLeft(getCurrentPath(index, entry)) ? "left" : "right",
|
|
2267
|
+
select: (originalEvent) => createSelectEvent(entry, originalEvent),
|
|
2268
|
+
closeOnSelect: () => props.closeOnSelect !== false
|
|
1800
2269
|
});
|
|
1801
2270
|
}
|
|
1802
|
-
function
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
return document.getElementById(getItemId(path));
|
|
1810
|
-
}
|
|
1811
|
-
function getSubmenuElement(path) {
|
|
1812
|
-
return document.getElementById(getSubmenuId(path));
|
|
1813
|
-
}
|
|
1814
|
-
function isSubmenuOpeningLeft(path) {
|
|
1815
|
-
const submenuRect = getSubmenuElement(path)?.getBoundingClientRect();
|
|
1816
|
-
const itemRect = getItemElement(path)?.getBoundingClientRect();
|
|
1817
|
-
if (submenuRect && itemRect && hasMeasuredRect(submenuRect) && hasMeasuredRect(itemRect)) return submenuRect.right <= itemRect.left;
|
|
1818
|
-
return placement.value.endsWith("end");
|
|
1819
|
-
}
|
|
1820
|
-
function getMenuActiveDescendant(menuPath) {
|
|
1821
|
-
return arePathsEqual(getParentPath(focusedPath.value), menuPath) ? getItemId(focusedPath.value) : void 0;
|
|
2271
|
+
function unregisterStaleEntries(nextRegisteredItemIds, nextRegisteredMenuIds) {
|
|
2272
|
+
for (const id of registeredItemIds) if (!nextRegisteredItemIds.has(id)) interaction.unregisterItem(id);
|
|
2273
|
+
for (const id of registeredMenuIds) {
|
|
2274
|
+
if (nextRegisteredMenuIds.has(id)) continue;
|
|
2275
|
+
interaction.unregisterMenu(id);
|
|
2276
|
+
setMenuOpen(id, false);
|
|
2277
|
+
}
|
|
1822
2278
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
const
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
2279
|
+
function registerItems() {
|
|
2280
|
+
const nextIndex = buildDropdownMenuDataIndex(items.value, rootMenuId, getStableItemId);
|
|
2281
|
+
const nextRegisteredItemIds = new Set(nextIndex.entries.map((entry) => entry.itemId));
|
|
2282
|
+
const nextRegisteredMenuIds = new Set(nextIndex.entries.flatMap((entry) => entry.submenuMenuId ? [entry.submenuMenuId] : []));
|
|
2283
|
+
for (const entry of nextIndex.entries) registerEntry(nextIndex, entry);
|
|
2284
|
+
unregisterStaleEntries(nextRegisteredItemIds, nextRegisteredMenuIds);
|
|
2285
|
+
registeredItemIds = nextRegisteredItemIds;
|
|
2286
|
+
registeredMenuIds = nextRegisteredMenuIds;
|
|
2287
|
+
registrationIndex.value = nextIndex;
|
|
2288
|
+
interaction.reconcile();
|
|
2289
|
+
}
|
|
2290
|
+
watch(collectionState, registerItems, { immediate: true });
|
|
1831
2291
|
return {
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
focusTrigger,
|
|
1835
|
-
getItemId,
|
|
1836
|
-
getSubmenuId,
|
|
1837
|
-
getItemElement,
|
|
1838
|
-
getSubmenuElement,
|
|
1839
|
-
isSubmenuOpeningLeft,
|
|
1840
|
-
getMenuActiveDescendant
|
|
2292
|
+
openMenuIds,
|
|
2293
|
+
registrationIndex
|
|
1841
2294
|
};
|
|
1842
2295
|
}
|
|
1843
2296
|
//#endregion
|
|
@@ -1845,26 +2298,6 @@ function useDropdownMenuDom({ menuId, rootRef, menuRef, targetRef, placement, fo
|
|
|
1845
2298
|
var SAFE_TRIANGLE_PADDING = 2;
|
|
1846
2299
|
var SAFE_TRIANGLE_ORIGIN_OFFSET = 2;
|
|
1847
2300
|
var SAFE_TRIANGLE_TIMEOUT = 400;
|
|
1848
|
-
function getTriangleArea(a, b, c) {
|
|
1849
|
-
return Math.abs((a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2);
|
|
1850
|
-
}
|
|
1851
|
-
function isPointInTriangle(point, triangle) {
|
|
1852
|
-
const [a, b, c] = triangle;
|
|
1853
|
-
const area = getTriangleArea(a, b, c);
|
|
1854
|
-
const area1 = getTriangleArea(point, b, c);
|
|
1855
|
-
const area2 = getTriangleArea(a, point, c);
|
|
1856
|
-
const area3 = getTriangleArea(a, b, point);
|
|
1857
|
-
return Math.abs(area - (area1 + area2 + area3)) < .5;
|
|
1858
|
-
}
|
|
1859
|
-
function clamp(value, min, max) {
|
|
1860
|
-
return Math.min(Math.max(value, min), max);
|
|
1861
|
-
}
|
|
1862
|
-
function clampPointToRect(point, rect) {
|
|
1863
|
-
return {
|
|
1864
|
-
x: clamp(point.x, rect.left, rect.right),
|
|
1865
|
-
y: clamp(point.y, rect.top, rect.bottom)
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
2301
|
function getDropdownMenuSafeTriangle({ itemRect, submenuRect, origin }) {
|
|
1869
2302
|
const measuredItemRect = itemRect && hasMeasuredRect(itemRect) ? itemRect : null;
|
|
1870
2303
|
const opensRight = !measuredItemRect || submenuRect.left >= measuredItemRect.right;
|
|
@@ -1961,7 +2394,7 @@ function useDropdownMenuHoverIntent({ openSubmenuPath, getItemElement, getSubmen
|
|
|
1961
2394
|
}, SAFE_TRIANGLE_TIMEOUT);
|
|
1962
2395
|
}
|
|
1963
2396
|
function handleItemHover(item, path, event, commit) {
|
|
1964
|
-
const point = event ?
|
|
2397
|
+
const point = event ? getClientPoint(event) : void 0;
|
|
1965
2398
|
latestPointerPoint = point ?? latestPointerPoint;
|
|
1966
2399
|
if (point && shouldDelayHover(path, point)) {
|
|
1967
2400
|
delayHoveredItem(item, path, commit);
|
|
@@ -1970,7 +2403,7 @@ function useDropdownMenuHoverIntent({ openSubmenuPath, getItemElement, getSubmen
|
|
|
1970
2403
|
commit(item, path, point);
|
|
1971
2404
|
}
|
|
1972
2405
|
function handleMenuMousemove(event, commit) {
|
|
1973
|
-
const point =
|
|
2406
|
+
const point = getClientPoint(event);
|
|
1974
2407
|
latestPointerPoint = point;
|
|
1975
2408
|
updateSafeTriangleOrigin(point);
|
|
1976
2409
|
if (!pendingHover) return;
|
|
@@ -1988,221 +2421,131 @@ function useDropdownMenuHoverIntent({ openSubmenuPath, getItemElement, getSubmen
|
|
|
1988
2421
|
};
|
|
1989
2422
|
}
|
|
1990
2423
|
//#endregion
|
|
1991
|
-
//#region src/components/dropdown-menu/
|
|
1992
|
-
function
|
|
1993
|
-
function
|
|
1994
|
-
|
|
1995
|
-
if (hasItemSubmenu(item)) {
|
|
1996
|
-
openSubmenu(path, DEFAULT_FOCUS_TARGET, event instanceof MouseEvent ? getEventPoint(event) : void 0);
|
|
1997
|
-
return;
|
|
1998
|
-
}
|
|
1999
|
-
selectItem(item, event);
|
|
2424
|
+
//#region src/components/dropdown-menu/useDropdownMenuDataController.ts
|
|
2425
|
+
function useDropdownMenuDataController({ props, items, rootMenuId, menuId, menuRef, actualPlacement, interaction, onSelect }) {
|
|
2426
|
+
function getItemId(path) {
|
|
2427
|
+
return `${menuId.value}-item-${getPathKey(path)}`;
|
|
2000
2428
|
}
|
|
2001
|
-
function
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2429
|
+
function getSubmenuId(path) {
|
|
2430
|
+
return `${menuId.value}-submenu-${getPathKey(path)}`;
|
|
2431
|
+
}
|
|
2432
|
+
function getItemElement(path) {
|
|
2433
|
+
return typeof document === "undefined" ? null : document.getElementById(getItemId(path));
|
|
2434
|
+
}
|
|
2435
|
+
function getSubmenuElement(path) {
|
|
2436
|
+
return typeof document === "undefined" ? null : document.getElementById(getSubmenuId(path));
|
|
2437
|
+
}
|
|
2438
|
+
function isSubmenuOpeningLeft(path) {
|
|
2439
|
+
const submenuRect = getSubmenuElement(path)?.getBoundingClientRect();
|
|
2440
|
+
const itemRect = getItemElement(path)?.getBoundingClientRect();
|
|
2441
|
+
if (submenuRect && itemRect && hasMeasuredRect(submenuRect) && hasMeasuredRect(itemRect)) return submenuRect.right <= itemRect.left;
|
|
2442
|
+
return actualPlacement.value.endsWith("end");
|
|
2443
|
+
}
|
|
2444
|
+
const { openMenuIds, registrationIndex } = useDropdownMenuDataRegistration({
|
|
2445
|
+
props,
|
|
2446
|
+
items,
|
|
2447
|
+
rootMenuId,
|
|
2448
|
+
interaction,
|
|
2449
|
+
menuRef,
|
|
2450
|
+
getItemElement,
|
|
2451
|
+
getSubmenuElement,
|
|
2452
|
+
isSubmenuOpeningLeft,
|
|
2453
|
+
onSelect
|
|
2454
|
+
});
|
|
2455
|
+
function getDataItemId(path) {
|
|
2456
|
+
return registrationIndex.value.itemIdByPath.get(getPathKey(path));
|
|
2012
2457
|
}
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2458
|
+
const focusedPath = computed({
|
|
2459
|
+
get() {
|
|
2460
|
+
const id = interaction.activeItemId.value;
|
|
2461
|
+
return id ? [...registrationIndex.value.pathByItemId.get(id) ?? []] : [];
|
|
2462
|
+
},
|
|
2463
|
+
set(path) {
|
|
2464
|
+
interaction.setActive(path.length > 0 ? getDataItemId(path) ?? null : null);
|
|
2465
|
+
}
|
|
2466
|
+
});
|
|
2467
|
+
const focusedIndex = computed(() => focusedPath.value[0] ?? -1);
|
|
2468
|
+
const activeDescendantId = computed(() => focusedPath.value.length === 0 ? void 0 : getItemId(focusedPath.value));
|
|
2469
|
+
const openSubmenuPath = computed(() => {
|
|
2470
|
+
let deepest = [];
|
|
2471
|
+
for (const id of openMenuIds.value) {
|
|
2472
|
+
const path = registrationIndex.value.pathByMenuId.get(id);
|
|
2473
|
+
if (path && path.length > deepest.length) deepest = path;
|
|
2474
|
+
}
|
|
2475
|
+
return [...deepest];
|
|
2476
|
+
});
|
|
2477
|
+
function isItemFocused(indexOrPath) {
|
|
2478
|
+
const id = getDataItemId(normalizePath(indexOrPath));
|
|
2479
|
+
return Boolean(id && interaction.activeItemId.value === id);
|
|
2480
|
+
}
|
|
2481
|
+
function isSubmenuOpen(path) {
|
|
2482
|
+
const itemId = getDataItemId(path);
|
|
2483
|
+
const submenuId = itemId ? interaction.getItem(itemId)?.submenuId?.() : void 0;
|
|
2484
|
+
return Boolean(submenuId && interaction.isMenuOpen(submenuId));
|
|
2016
2485
|
}
|
|
2017
2486
|
function openSubmenu(path, focus = DEFAULT_FOCUS_TARGET, point) {
|
|
2018
|
-
const
|
|
2019
|
-
|
|
2020
|
-
return
|
|
2487
|
+
const itemId = getDataItemId(path);
|
|
2488
|
+
const submenuId = itemId ? interaction.getItem(itemId)?.submenuId?.() : void 0;
|
|
2489
|
+
if (!submenuId || !interaction.openMenu(submenuId, focus)) return false;
|
|
2490
|
+
hoverIntent.trackSubmenuOpen(path, point);
|
|
2491
|
+
return true;
|
|
2021
2492
|
}
|
|
2022
2493
|
function closeSubmenu(path) {
|
|
2023
|
-
const
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
}
|
|
2027
|
-
function closeCurrentSubmenu() {
|
|
2028
|
-
const closed = submenus.closeCurrentSubmenu();
|
|
2494
|
+
const itemId = getDataItemId(path);
|
|
2495
|
+
const submenuId = itemId ? interaction.getItem(itemId)?.submenuId?.() : void 0;
|
|
2496
|
+
const closed = submenuId ? interaction.closeMenu(submenuId, false) : false;
|
|
2029
2497
|
if (closed) hoverIntent.resetHoverIntent();
|
|
2030
2498
|
return closed;
|
|
2031
2499
|
}
|
|
2032
2500
|
function commitHoveredItem(item, path, point) {
|
|
2501
|
+
const itemId = getDataItemId(path);
|
|
2502
|
+
const itemRegistration = itemId ? interaction.getItem(itemId) : void 0;
|
|
2503
|
+
if (!itemRegistration) return;
|
|
2033
2504
|
hoverIntent.clearPendingHover();
|
|
2034
|
-
|
|
2505
|
+
interaction.setActive(itemRegistration.id);
|
|
2035
2506
|
if (hasItemSubmenu(item)) openSubmenu(path, false, point);
|
|
2036
|
-
else
|
|
2507
|
+
else interaction.closeSubmenus(itemRegistration.menuId);
|
|
2037
2508
|
}
|
|
2509
|
+
const hoverIntent = useDropdownMenuHoverIntent({
|
|
2510
|
+
openSubmenuPath,
|
|
2511
|
+
getItemElement,
|
|
2512
|
+
getSubmenuElement
|
|
2513
|
+
});
|
|
2038
2514
|
function focusHoveredItem(item, indexOrPath, event) {
|
|
2039
2515
|
if (item.disabled) return;
|
|
2040
|
-
|
|
2041
|
-
hoverIntent.handleItemHover(item, path, event, commitHoveredItem);
|
|
2042
|
-
}
|
|
2043
|
-
function selectFocusedItem(event) {
|
|
2044
|
-
const item = getItemAtPath(focusedPath.value);
|
|
2045
|
-
if (!item) return;
|
|
2046
|
-
activateItem(item, focusedPath.value, event);
|
|
2047
|
-
}
|
|
2048
|
-
function moveFocusedItem(direction) {
|
|
2049
|
-
const menuPath = moveFocus(direction);
|
|
2050
|
-
if (menuPath) closeSubmenusAfter(menuPath);
|
|
2051
|
-
}
|
|
2052
|
-
function onTriggerClick() {
|
|
2053
|
-
disclosure.toggle();
|
|
2054
|
-
}
|
|
2055
|
-
function onTriggerKeydown(event) {
|
|
2056
|
-
if (isDisabled.value) return;
|
|
2057
|
-
switch (event.key) {
|
|
2058
|
-
case "Enter":
|
|
2059
|
-
case " ":
|
|
2060
|
-
case "ArrowDown":
|
|
2061
|
-
event.preventDefault();
|
|
2062
|
-
disclosure.open();
|
|
2063
|
-
break;
|
|
2064
|
-
case "ArrowUp":
|
|
2065
|
-
event.preventDefault();
|
|
2066
|
-
disclosure.open({ focus: "last" });
|
|
2067
|
-
break;
|
|
2068
|
-
case "Escape":
|
|
2069
|
-
disclosure.close({ focusTrigger: true });
|
|
2070
|
-
break;
|
|
2071
|
-
}
|
|
2516
|
+
hoverIntent.handleItemHover(item, normalizePath(indexOrPath), event, commitHoveredItem);
|
|
2072
2517
|
}
|
|
2073
|
-
function
|
|
2074
|
-
|
|
2075
|
-
if (
|
|
2076
|
-
switch (event.key) {
|
|
2077
|
-
case "ArrowDown":
|
|
2078
|
-
event.preventDefault();
|
|
2079
|
-
moveFocusedItem(1);
|
|
2080
|
-
break;
|
|
2081
|
-
case "ArrowUp":
|
|
2082
|
-
event.preventDefault();
|
|
2083
|
-
moveFocusedItem(-1);
|
|
2084
|
-
break;
|
|
2085
|
-
case "Home":
|
|
2086
|
-
event.preventDefault();
|
|
2087
|
-
focusItem("first", getParentPath(focusedPath.value));
|
|
2088
|
-
break;
|
|
2089
|
-
case "End":
|
|
2090
|
-
event.preventDefault();
|
|
2091
|
-
focusItem("last", getParentPath(focusedPath.value));
|
|
2092
|
-
break;
|
|
2093
|
-
case "ArrowRight":
|
|
2094
|
-
case "ArrowLeft":
|
|
2095
|
-
onMenuHorizontalKeydown(event);
|
|
2096
|
-
break;
|
|
2097
|
-
case "Enter":
|
|
2098
|
-
case " ":
|
|
2099
|
-
event.preventDefault();
|
|
2100
|
-
selectFocusedItem(event);
|
|
2101
|
-
break;
|
|
2102
|
-
case "Escape":
|
|
2103
|
-
event.preventDefault();
|
|
2104
|
-
if (!closeCurrentSubmenu()) disclosure.close({ focusTrigger: true });
|
|
2105
|
-
break;
|
|
2106
|
-
case "Tab":
|
|
2107
|
-
disclosure.close();
|
|
2108
|
-
break;
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
function onMenuHorizontalKeydown(event) {
|
|
2112
|
-
const isRight = event.key === "ArrowRight";
|
|
2113
|
-
const currentMenuPath = getParentPath(focusedPath.value);
|
|
2114
|
-
const closePath = focusedPath.value.length > 1 ? currentMenuPath : arePathsEqual(focusedPath.value, openSubmenuPath.value) ? focusedPath.value : void 0;
|
|
2115
|
-
if (closePath && isRight === isSubmenuOpeningLeft(closePath)) {
|
|
2116
|
-
event.preventDefault();
|
|
2117
|
-
closeSubmenu(closePath);
|
|
2118
|
-
return;
|
|
2119
|
-
}
|
|
2120
|
-
const item = getItemAtPath(focusedPath.value);
|
|
2121
|
-
if (!item || item.disabled || !hasItemSubmenu(item)) return;
|
|
2122
|
-
if (isRight === isSubmenuOpeningLeft(focusedPath.value)) return;
|
|
2123
|
-
event.preventDefault();
|
|
2124
|
-
openSubmenu(focusedPath.value);
|
|
2125
|
-
}
|
|
2126
|
-
function onMenuMousemove(event) {
|
|
2127
|
-
hoverIntent.handleMenuMousemove(event, commitHoveredItem);
|
|
2128
|
-
}
|
|
2129
|
-
function onMenuMouseleave() {
|
|
2130
|
-
hoverIntent.resetHoverIntent();
|
|
2131
|
-
}
|
|
2132
|
-
return {
|
|
2133
|
-
activateItem,
|
|
2134
|
-
selectItem,
|
|
2135
|
-
openSubmenu,
|
|
2136
|
-
closeSubmenu,
|
|
2137
|
-
focusHoveredItem,
|
|
2138
|
-
onTriggerClick,
|
|
2139
|
-
onTriggerKeydown,
|
|
2140
|
-
onMenuKeydown,
|
|
2141
|
-
onMenuMousemove,
|
|
2142
|
-
onMenuMouseleave
|
|
2143
|
-
};
|
|
2144
|
-
}
|
|
2145
|
-
//#endregion
|
|
2146
|
-
//#region src/components/dropdown-menu/useDropdownMenuNavigation.ts
|
|
2147
|
-
function useDropdownMenuNavigation(items) {
|
|
2148
|
-
const focusedPath = ref([]);
|
|
2149
|
-
const focusedIndex = computed(() => focusedPath.value[0] ?? -1);
|
|
2150
|
-
function getItemsAtPath(path) {
|
|
2151
|
-
let currentItems = items.value;
|
|
2152
|
-
for (const index of path) {
|
|
2153
|
-
const item = currentItems[index];
|
|
2154
|
-
if (!item) return [];
|
|
2155
|
-
currentItems = item.children ?? [];
|
|
2156
|
-
}
|
|
2157
|
-
return currentItems;
|
|
2158
|
-
}
|
|
2159
|
-
function getItemAtPath(path) {
|
|
2160
|
-
if (path.length === 0) return void 0;
|
|
2161
|
-
return getItemsAtPath(getParentPath(path))[path[path.length - 1]];
|
|
2162
|
-
}
|
|
2163
|
-
function focusItem(target, menuPath = []) {
|
|
2164
|
-
const enabledIndexes = getEnabledIndexes(getItemsAtPath(menuPath), (item) => Boolean(item.disabled));
|
|
2165
|
-
const index = target === "last" ? enabledIndexes[enabledIndexes.length - 1] : enabledIndexes[0];
|
|
2166
|
-
if (index === void 0) {
|
|
2167
|
-
if (menuPath.length === 0) focusedPath.value = [];
|
|
2168
|
-
return false;
|
|
2169
|
-
}
|
|
2170
|
-
focusedPath.value = [...menuPath, index];
|
|
2171
|
-
return true;
|
|
2518
|
+
function selectItem(item, originalEvent = new Event("select")) {
|
|
2519
|
+
const id = registrationIndex.value.primaryItemId.get(item);
|
|
2520
|
+
if (id) interaction.selectItem(id, originalEvent);
|
|
2172
2521
|
}
|
|
2173
|
-
function
|
|
2174
|
-
|
|
2522
|
+
function activateItem(_item, path, event) {
|
|
2523
|
+
const id = getDataItemId(path);
|
|
2524
|
+
if (id) interaction.activateItem(id, event);
|
|
2175
2525
|
}
|
|
2176
|
-
function
|
|
2177
|
-
const
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
return
|
|
2181
|
-
}
|
|
2182
|
-
function isItemFocused(indexOrPath) {
|
|
2183
|
-
return arePathsEqual(normalizePath(indexOrPath), focusedPath.value);
|
|
2184
|
-
}
|
|
2185
|
-
function moveFocus(direction) {
|
|
2186
|
-
const menuPath = getParentPath(focusedPath.value);
|
|
2187
|
-
const itemsAtPath = getItemsAtPath(menuPath);
|
|
2188
|
-
const nextIndex = getNextEnabledIndex(itemsAtPath, focusedPath.value.length === 0 ? direction === 1 ? -1 : itemsAtPath.length : focusedPath.value[focusedPath.value.length - 1], direction, (item) => Boolean(item.disabled));
|
|
2189
|
-
if (nextIndex === void 0) {
|
|
2190
|
-
focusedPath.value = [];
|
|
2191
|
-
return;
|
|
2192
|
-
}
|
|
2193
|
-
focusedPath.value = [...menuPath, nextIndex];
|
|
2194
|
-
return menuPath;
|
|
2526
|
+
function getMenuActiveDescendant(path) {
|
|
2527
|
+
const pathKey = getPathKey(path);
|
|
2528
|
+
const activeId = interaction.getActiveId(registrationIndex.value.menuIdByPath.get(pathKey) ?? rootMenuId).value;
|
|
2529
|
+
const activePath = activeId ? registrationIndex.value.pathByItemId.get(activeId) : void 0;
|
|
2530
|
+
return activePath ? getItemId(activePath) : void 0;
|
|
2195
2531
|
}
|
|
2196
2532
|
return {
|
|
2197
2533
|
focusedPath,
|
|
2198
2534
|
focusedIndex,
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2535
|
+
activeDescendantId,
|
|
2536
|
+
getItemId,
|
|
2537
|
+
getSubmenuId,
|
|
2538
|
+
getItemElement,
|
|
2539
|
+
getMenuActiveDescendant,
|
|
2204
2540
|
isItemFocused,
|
|
2205
|
-
|
|
2541
|
+
isSubmenuOpen,
|
|
2542
|
+
openSubmenu,
|
|
2543
|
+
closeSubmenu,
|
|
2544
|
+
focusHoveredItem,
|
|
2545
|
+
onMenuMousemove: (event) => hoverIntent.handleMenuMousemove(event, commitHoveredItem),
|
|
2546
|
+
resetHoverIntent: hoverIntent.resetHoverIntent,
|
|
2547
|
+
selectItem,
|
|
2548
|
+
activateItem
|
|
2206
2549
|
};
|
|
2207
2550
|
}
|
|
2208
2551
|
//#endregion
|
|
@@ -2220,8 +2563,7 @@ function useDropdownMenuPortalPosition(options) {
|
|
|
2220
2563
|
flipOptions: () => options.props.flipOptions,
|
|
2221
2564
|
shift: () => options.props.shift !== false,
|
|
2222
2565
|
collisionPadding: () => options.props.collisionPadding ?? 8,
|
|
2223
|
-
autoUpdateOptions: () => options.props.autoUpdateOptions
|
|
2224
|
-
restartKey: options.restartKey
|
|
2566
|
+
autoUpdateOptions: () => options.props.autoUpdateOptions
|
|
2225
2567
|
});
|
|
2226
2568
|
return {
|
|
2227
2569
|
actualPlacement: floating.actualPlacement,
|
|
@@ -2230,6 +2572,67 @@ function useDropdownMenuPortalPosition(options) {
|
|
|
2230
2572
|
};
|
|
2231
2573
|
}
|
|
2232
2574
|
//#endregion
|
|
2575
|
+
//#region src/components/dropdown-menu/useDropdownMenuPresentation.ts
|
|
2576
|
+
function useDropdownMenuPresentation({ props, rootMenuId, menuId, isDisabled, isVisible, isExplicitTarget, actualPlacement, contentHasSubmenu, activeDescendantId, interaction, resetHoverIntent, onMenuMousemove, open, close, toggle }) {
|
|
2577
|
+
const rootClass = computed(() => bem("rp-dropdown-menu", {
|
|
2578
|
+
[`placement-${actualPlacement.value}`]: true,
|
|
2579
|
+
target: isExplicitTarget.value,
|
|
2580
|
+
open: isVisible.value,
|
|
2581
|
+
disabled: isDisabled.value
|
|
2582
|
+
}));
|
|
2583
|
+
const contentClass = computed(() => bem("rp-dropdown-menu__content", { "has-submenu": contentHasSubmenu.value }));
|
|
2584
|
+
const triggerProps = computed(() => ({
|
|
2585
|
+
"aria-controls": isDisabled.value ? void 0 : menuId.value,
|
|
2586
|
+
"aria-expanded": isDisabled.value ? void 0 : isVisible.value,
|
|
2587
|
+
"aria-haspopup": "menu",
|
|
2588
|
+
disabled: isDisabled.value || void 0,
|
|
2589
|
+
onClick: () => interaction.onTriggerClick(),
|
|
2590
|
+
onKeydown: (event) => interaction.onTriggerKeydown(event)
|
|
2591
|
+
}));
|
|
2592
|
+
function getKeyboardMenuId(event) {
|
|
2593
|
+
const activeItem = interaction.activeItemId.value ? interaction.getItem(interaction.activeItemId.value) : void 0;
|
|
2594
|
+
const openSubmenuId = activeItem?.submenuId?.();
|
|
2595
|
+
if (openSubmenuId && interaction.isMenuOpen(openSubmenuId)) {
|
|
2596
|
+
if (event.key === "Escape") return openSubmenuId;
|
|
2597
|
+
const opensLeft = activeItem?.submenuDirection?.() === "left" || interaction.getMenu(openSubmenuId)?.placement().startsWith("left");
|
|
2598
|
+
if (event.key === (opensLeft ? "ArrowRight" : "ArrowLeft")) return openSubmenuId;
|
|
2599
|
+
}
|
|
2600
|
+
if ([
|
|
2601
|
+
"ArrowLeft",
|
|
2602
|
+
"ArrowRight",
|
|
2603
|
+
"Escape"
|
|
2604
|
+
].includes(event.key) && interaction.activeMenuId.value !== rootMenuId) return interaction.activeMenuId.value;
|
|
2605
|
+
return activeItem?.menuId ?? interaction.activeMenuId.value;
|
|
2606
|
+
}
|
|
2607
|
+
function onMenuKeydown(event) {
|
|
2608
|
+
resetHoverIntent();
|
|
2609
|
+
interaction.onMenuKeydown(getKeyboardMenuId(event), event);
|
|
2610
|
+
}
|
|
2611
|
+
return {
|
|
2612
|
+
rootClass,
|
|
2613
|
+
contentClass,
|
|
2614
|
+
triggerProps,
|
|
2615
|
+
contentProps: computed(() => ({
|
|
2616
|
+
id: menuId.value,
|
|
2617
|
+
role: "menu",
|
|
2618
|
+
tabindex: -1,
|
|
2619
|
+
"aria-label": props.ariaLabel || void 0,
|
|
2620
|
+
"aria-activedescendant": activeDescendantId.value,
|
|
2621
|
+
onKeydown: onMenuKeydown,
|
|
2622
|
+
onMousemove: onMenuMousemove,
|
|
2623
|
+
onMouseleave: resetHoverIntent
|
|
2624
|
+
})),
|
|
2625
|
+
slotProps: computed(() => ({
|
|
2626
|
+
triggerProps: triggerProps.value,
|
|
2627
|
+
isOpen: isVisible.value,
|
|
2628
|
+
open,
|
|
2629
|
+
close,
|
|
2630
|
+
toggle
|
|
2631
|
+
})),
|
|
2632
|
+
onMenuKeydown
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
//#endregion
|
|
2233
2636
|
//#region src/components/dropdown-menu/useDropdownMenuRenderItems.ts
|
|
2234
2637
|
function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId, getSubmenuId, getMenuActiveDescendant, getItemElement, isItemFocused, isSubmenuOpen, activateItem, focusHoveredItem, selectItem, openSubmenu, closeSubmenu, close }) {
|
|
2235
2638
|
const renderedItems = computed(() => getRenderedItems(items.value));
|
|
@@ -2272,9 +2675,9 @@ function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId,
|
|
|
2272
2675
|
"aria-expanded": hasSubmenu ? resolvedSubmenuOpen : void 0,
|
|
2273
2676
|
"aria-haspopup": hasSubmenu ? "menu" : void 0,
|
|
2274
2677
|
"aria-disabled": disabled || void 0,
|
|
2275
|
-
"data-disabled": disabled
|
|
2276
|
-
"data-highlighted": focused
|
|
2277
|
-
"data-submenu": hasSubmenu
|
|
2678
|
+
"data-disabled": toPresenceAttribute(disabled),
|
|
2679
|
+
"data-highlighted": toPresenceAttribute(focused),
|
|
2680
|
+
"data-submenu": toPresenceAttribute(hasSubmenu),
|
|
2278
2681
|
onClick: (event) => activateItem(item, path, event),
|
|
2279
2682
|
onMouseenter: (event) => focusHoveredItem(item, path, event)
|
|
2280
2683
|
};
|
|
@@ -2332,45 +2735,66 @@ function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId,
|
|
|
2332
2735
|
};
|
|
2333
2736
|
}
|
|
2334
2737
|
//#endregion
|
|
2335
|
-
//#region src/components/dropdown-menu/
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2738
|
+
//#region src/components/dropdown-menu/useDropdownMenuTargetBindings.ts
|
|
2739
|
+
var TARGET_ATTRIBUTES = [
|
|
2740
|
+
"aria-controls",
|
|
2741
|
+
"aria-expanded",
|
|
2742
|
+
"aria-haspopup",
|
|
2743
|
+
"aria-disabled"
|
|
2744
|
+
];
|
|
2745
|
+
function syncTargetAttributes(target, id, visible, disabled) {
|
|
2746
|
+
if (disabled) {
|
|
2747
|
+
target.removeAttribute("aria-controls");
|
|
2748
|
+
target.removeAttribute("aria-expanded");
|
|
2749
|
+
target.removeAttribute("aria-haspopup");
|
|
2750
|
+
target.setAttribute("aria-disabled", "true");
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
target.setAttribute("aria-controls", id);
|
|
2754
|
+
target.setAttribute("aria-expanded", String(visible));
|
|
2755
|
+
target.setAttribute("aria-haspopup", "menu");
|
|
2756
|
+
target.removeAttribute("aria-disabled");
|
|
2757
|
+
}
|
|
2758
|
+
function useDropdownMenuTargetBindings({ interaction, rootRef, menuRef, targetElement, isExplicitTarget, menuId, isVisible, isDisabled, ignoredTargets, pointerDownOutside, focusOutside, interactOutside }) {
|
|
2759
|
+
function watchInside(source) {
|
|
2760
|
+
watch(source, (element, previous) => {
|
|
2761
|
+
if (previous) interaction.unregisterInside(previous);
|
|
2762
|
+
if (element) interaction.registerInside(element);
|
|
2763
|
+
}, { immediate: true });
|
|
2764
|
+
}
|
|
2765
|
+
watchInside(rootRef);
|
|
2766
|
+
watchInside(menuRef);
|
|
2767
|
+
watchInside(targetElement);
|
|
2768
|
+
const cleanupDismissal = interaction.registerDismissal({
|
|
2769
|
+
ignoredTargets,
|
|
2770
|
+
pointerDownOutside,
|
|
2771
|
+
focusOutside,
|
|
2772
|
+
interactOutside
|
|
2773
|
+
});
|
|
2774
|
+
watch([isExplicitTarget, targetElement], ([explicit, target], _previous, onCleanup) => {
|
|
2775
|
+
if (!explicit || !target) return;
|
|
2776
|
+
const onClick = () => interaction.onTriggerClick();
|
|
2777
|
+
const onKeydown = (event) => interaction.onTriggerKeydown(event);
|
|
2778
|
+
target.addEventListener("click", onClick);
|
|
2779
|
+
target.addEventListener("keydown", onKeydown);
|
|
2780
|
+
onCleanup(() => {
|
|
2781
|
+
target.removeEventListener("click", onClick);
|
|
2782
|
+
target.removeEventListener("keydown", onKeydown);
|
|
2783
|
+
});
|
|
2784
|
+
}, { flush: "sync" });
|
|
2785
|
+
watch([
|
|
2786
|
+
isExplicitTarget,
|
|
2787
|
+
targetElement,
|
|
2788
|
+
menuId,
|
|
2789
|
+
isVisible,
|
|
2790
|
+
isDisabled
|
|
2791
|
+
], ([explicit, target, id, visible, disabled], _previous, onCleanup) => {
|
|
2792
|
+
if (!explicit || !target) return;
|
|
2793
|
+
const snapshot = snapshotAttributes(target, TARGET_ATTRIBUTES);
|
|
2794
|
+
syncTargetAttributes(target, id, visible, disabled);
|
|
2795
|
+
onCleanup(() => restoreAttributes(target, snapshot));
|
|
2796
|
+
}, { flush: "sync" });
|
|
2797
|
+
onBeforeUnmount(cleanupDismissal);
|
|
2374
2798
|
}
|
|
2375
2799
|
//#endregion
|
|
2376
2800
|
//#region src/components/dropdown-menu/useDropdownMenu.ts
|
|
@@ -2378,21 +2802,22 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2378
2802
|
const rootRef = ref(null);
|
|
2379
2803
|
const menuRef = ref(null);
|
|
2380
2804
|
const arrowRef = ref(null);
|
|
2805
|
+
const generatedId = useId();
|
|
2806
|
+
const interactionRootMenuId = `${generatedId}-interaction-root`;
|
|
2381
2807
|
const controllableOpen = useControllableValue({
|
|
2382
2808
|
modelValue: () => props.open,
|
|
2383
2809
|
defaultValue: () => false,
|
|
2384
2810
|
onChange: (open) => emit.openChange?.(open)
|
|
2385
2811
|
});
|
|
2386
|
-
const generatedId = useId();
|
|
2387
2812
|
const menuId = computed(() => props.id ?? `${generatedId}-menu`);
|
|
2388
2813
|
const placement = computed(() => props.placement ?? "bottom-start");
|
|
2389
2814
|
const teleportTo = useTeleportTarget(() => props.teleportTo);
|
|
2390
|
-
const teleportPositioningKey = useTeleportPositioningKey();
|
|
2391
2815
|
const shouldTeleport = computed(() => props.teleport !== false);
|
|
2392
2816
|
const { isExplicitTarget, reference, resolvedTarget } = useFloatingTarget(() => props.target, rootRef);
|
|
2393
|
-
const targetElement = computed(() =>
|
|
2817
|
+
const targetElement = computed(() => isElement(resolvedTarget.value) ? resolvedTarget.value : null);
|
|
2394
2818
|
const visibleItems = computed(() => props.items ?? []);
|
|
2395
2819
|
const isDisabled = computed(() => Boolean(props.disabled));
|
|
2820
|
+
const modal = computed(() => Boolean(props.modal));
|
|
2396
2821
|
const isOpen = controllableOpen.value;
|
|
2397
2822
|
const isVisible = computed(() => isOpen.value && !isDisabled.value);
|
|
2398
2823
|
const layer = useOverlayLayer({
|
|
@@ -2412,173 +2837,107 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2412
2837
|
menuRef,
|
|
2413
2838
|
arrowRef,
|
|
2414
2839
|
isVisible,
|
|
2415
|
-
placement
|
|
2416
|
-
restartKey: () => [
|
|
2417
|
-
shouldTeleport.value,
|
|
2418
|
-
teleportTo.value,
|
|
2419
|
-
teleportPositioningKey.value
|
|
2420
|
-
]
|
|
2840
|
+
placement
|
|
2421
2841
|
});
|
|
2422
2842
|
const placementSide = computed(() => actualPlacement.value.split("-")[0]);
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2843
|
+
function focusTrigger() {
|
|
2844
|
+
nextTick(() => {
|
|
2845
|
+
if (targetElement.value instanceof HTMLElement) {
|
|
2846
|
+
targetElement.value.focus();
|
|
2847
|
+
return;
|
|
2848
|
+
}
|
|
2849
|
+
rootRef.value?.querySelector("[aria-haspopup=\"menu\"]")?.focus();
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
function setOpen(nextOpen) {
|
|
2853
|
+
if (nextOpen && isDisabled.value) return;
|
|
2854
|
+
if (isOpen.value !== nextOpen) controllableOpen.setValue(nextOpen);
|
|
2855
|
+
}
|
|
2856
|
+
let resetHoverIntent;
|
|
2857
|
+
const interaction = useDropdownMenuInteraction({
|
|
2858
|
+
rootMenuId: interactionRootMenuId,
|
|
2859
|
+
isOpen: isVisible,
|
|
2860
|
+
disabled: isDisabled,
|
|
2861
|
+
modal,
|
|
2862
|
+
setOpen,
|
|
2863
|
+
isTopLayer: layer.isTopLayer,
|
|
2864
|
+
focusTrigger,
|
|
2865
|
+
beforeOpen: () => resetHoverIntent(),
|
|
2866
|
+
beforeClose: () => resetHoverIntent()
|
|
2428
2867
|
});
|
|
2429
|
-
const
|
|
2430
|
-
const
|
|
2431
|
-
const
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
scopeKey: () => activeMenuPath.value.join("/"),
|
|
2438
|
-
onMatch(_item, index) {
|
|
2439
|
-
const menuPath = activeMenuPath.value;
|
|
2440
|
-
if (setFocusedIndex(index, menuPath)) submenus.closeSubmenusAfter(menuPath);
|
|
2441
|
-
}
|
|
2868
|
+
const open = interaction.open;
|
|
2869
|
+
const close = (options = {}) => interaction.close(options);
|
|
2870
|
+
const toggle = interaction.toggle;
|
|
2871
|
+
const cleanupRootMenu = interaction.registerMenu({
|
|
2872
|
+
id: interactionRootMenuId,
|
|
2873
|
+
element: () => menuRef.value,
|
|
2874
|
+
placement: () => actualPlacement.value,
|
|
2875
|
+
isOpen: () => isVisible.value
|
|
2442
2876
|
});
|
|
2443
|
-
const
|
|
2877
|
+
const dataController = useDropdownMenuDataController({
|
|
2878
|
+
props,
|
|
2879
|
+
items: visibleItems,
|
|
2880
|
+
rootMenuId: interactionRootMenuId,
|
|
2444
2881
|
menuId,
|
|
2445
|
-
rootRef,
|
|
2446
2882
|
menuRef,
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
});
|
|
2451
|
-
const hoverIntent = useDropdownMenuHoverIntent({
|
|
2452
|
-
openSubmenuPath,
|
|
2453
|
-
getItemElement,
|
|
2454
|
-
getSubmenuElement
|
|
2883
|
+
actualPlacement,
|
|
2884
|
+
interaction,
|
|
2885
|
+
onSelect: (item, event) => emit.select?.(item, event)
|
|
2455
2886
|
});
|
|
2456
|
-
|
|
2887
|
+
resetHoverIntent = dataController.resetHoverIntent;
|
|
2888
|
+
const { renderedItems, renderContext, getItemProps, getItemSlotProps } = useDropdownMenuRenderItems({
|
|
2457
2889
|
props,
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
focusTrigger,
|
|
2473
|
-
layer
|
|
2890
|
+
actualPlacement,
|
|
2891
|
+
items: visibleItems,
|
|
2892
|
+
getItemId: dataController.getItemId,
|
|
2893
|
+
getSubmenuId: dataController.getSubmenuId,
|
|
2894
|
+
getMenuActiveDescendant: dataController.getMenuActiveDescendant,
|
|
2895
|
+
getItemElement: dataController.getItemElement,
|
|
2896
|
+
isItemFocused: dataController.isItemFocused,
|
|
2897
|
+
isSubmenuOpen: dataController.isSubmenuOpen,
|
|
2898
|
+
activateItem: dataController.activateItem,
|
|
2899
|
+
focusHoveredItem: dataController.focusHoveredItem,
|
|
2900
|
+
selectItem: dataController.selectItem,
|
|
2901
|
+
openSubmenu: dataController.openSubmenu,
|
|
2902
|
+
closeSubmenu: dataController.closeSubmenu,
|
|
2903
|
+
close
|
|
2474
2904
|
});
|
|
2475
|
-
const
|
|
2476
|
-
const { activateItem, selectItem, openSubmenu, closeSubmenu, focusHoveredItem, onTriggerClick, onTriggerKeydown, onMenuKeydown, onMenuMousemove, onMenuMouseleave } = useDropdownMenuInteractions({
|
|
2905
|
+
const presentation = useDropdownMenuPresentation({
|
|
2477
2906
|
props,
|
|
2478
|
-
|
|
2907
|
+
rootMenuId: interactionRootMenuId,
|
|
2908
|
+
menuId,
|
|
2479
2909
|
isDisabled,
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
disclosure,
|
|
2489
|
-
isSubmenuOpeningLeft
|
|
2490
|
-
});
|
|
2491
|
-
const rootClass = computed(() => bem("rp-dropdown-menu", {
|
|
2492
|
-
[`placement-${actualPlacement.value}`]: true,
|
|
2493
|
-
target: isExplicitTarget.value,
|
|
2494
|
-
open: isVisible.value,
|
|
2495
|
-
disabled: isDisabled.value
|
|
2496
|
-
}));
|
|
2497
|
-
const contentClass = computed(() => bem("rp-dropdown-menu__content", { "has-submenu": contentHasSubmenu.value }));
|
|
2498
|
-
const triggerProps = computed(() => ({
|
|
2499
|
-
"aria-controls": isDisabled.value ? void 0 : menuId.value,
|
|
2500
|
-
"aria-expanded": isDisabled.value ? void 0 : isVisible.value,
|
|
2501
|
-
"aria-haspopup": "menu",
|
|
2502
|
-
disabled: isDisabled.value || void 0,
|
|
2503
|
-
onClick: onTriggerClick,
|
|
2504
|
-
onKeydown: onTriggerKeydown
|
|
2505
|
-
}));
|
|
2506
|
-
const contentProps = computed(() => ({
|
|
2507
|
-
id: menuId.value,
|
|
2508
|
-
role: "menu",
|
|
2509
|
-
tabindex: -1,
|
|
2510
|
-
"aria-label": props.ariaLabel || void 0,
|
|
2511
|
-
"aria-activedescendant": activeDescendantId.value,
|
|
2512
|
-
onKeydown: onMenuKeydown,
|
|
2513
|
-
onMousemove: onMenuMousemove,
|
|
2514
|
-
onMouseleave: onMenuMouseleave
|
|
2515
|
-
}));
|
|
2516
|
-
const slotProps = computed(() => ({
|
|
2517
|
-
triggerProps: triggerProps.value,
|
|
2518
|
-
isOpen: isVisible.value,
|
|
2910
|
+
isVisible,
|
|
2911
|
+
isExplicitTarget,
|
|
2912
|
+
actualPlacement,
|
|
2913
|
+
contentHasSubmenu,
|
|
2914
|
+
activeDescendantId: dataController.activeDescendantId,
|
|
2915
|
+
interaction,
|
|
2916
|
+
resetHoverIntent,
|
|
2917
|
+
onMenuMousemove: dataController.onMenuMousemove,
|
|
2519
2918
|
open,
|
|
2520
2919
|
close,
|
|
2521
2920
|
toggle
|
|
2522
|
-
}));
|
|
2523
|
-
const { renderedItems, renderContext, getItemProps, getItemSlotProps } = useDropdownMenuRenderItems({
|
|
2524
|
-
props,
|
|
2525
|
-
actualPlacement,
|
|
2526
|
-
items: visibleItems,
|
|
2527
|
-
getItemId,
|
|
2528
|
-
getSubmenuId,
|
|
2529
|
-
getMenuActiveDescendant,
|
|
2530
|
-
getItemElement,
|
|
2531
|
-
isItemFocused,
|
|
2532
|
-
isSubmenuOpen,
|
|
2533
|
-
activateItem,
|
|
2534
|
-
focusHoveredItem,
|
|
2535
|
-
selectItem,
|
|
2536
|
-
openSubmenu,
|
|
2537
|
-
closeSubmenu,
|
|
2538
|
-
close
|
|
2539
2921
|
});
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
onCleanup(() => {
|
|
2545
|
-
target.removeEventListener("click", onTriggerClick);
|
|
2546
|
-
target.removeEventListener("keydown", onTriggerKeydown);
|
|
2547
|
-
});
|
|
2548
|
-
}, { flush: "sync" });
|
|
2549
|
-
watch(isVisible, (visible) => {
|
|
2550
|
-
if (!visible) typeahead.reset();
|
|
2551
|
-
}, { flush: "sync" });
|
|
2552
|
-
watch([
|
|
2553
|
-
isExplicitTarget,
|
|
2922
|
+
useDropdownMenuTargetBindings({
|
|
2923
|
+
interaction,
|
|
2924
|
+
rootRef,
|
|
2925
|
+
menuRef,
|
|
2554
2926
|
targetElement,
|
|
2927
|
+
isExplicitTarget,
|
|
2555
2928
|
menuId,
|
|
2556
2929
|
isVisible,
|
|
2557
|
-
isDisabled
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
target.removeAttribute("aria-expanded");
|
|
2569
|
-
target.removeAttribute("aria-haspopup");
|
|
2570
|
-
target.setAttribute("aria-disabled", "true");
|
|
2571
|
-
} else {
|
|
2572
|
-
target.setAttribute("aria-controls", id);
|
|
2573
|
-
target.setAttribute("aria-expanded", String(visible));
|
|
2574
|
-
target.setAttribute("aria-haspopup", "menu");
|
|
2575
|
-
target.removeAttribute("aria-disabled");
|
|
2576
|
-
}
|
|
2577
|
-
onCleanup(() => {
|
|
2578
|
-
for (const [attribute, value] of snapshot) if (value == null) target.removeAttribute(attribute);
|
|
2579
|
-
else target.setAttribute(attribute, value);
|
|
2580
|
-
});
|
|
2581
|
-
}, { flush: "sync" });
|
|
2930
|
+
isDisabled,
|
|
2931
|
+
ignoredTargets: () => props.ignore ?? [],
|
|
2932
|
+
pointerDownOutside: emit.pointerDownOutside,
|
|
2933
|
+
focusOutside: emit.focusOutside,
|
|
2934
|
+
interactOutside: emit.interactOutside
|
|
2935
|
+
});
|
|
2936
|
+
const layeredContentStyle = computed(() => ({
|
|
2937
|
+
...contentStyle.value,
|
|
2938
|
+
zIndex: layer.zIndex.value
|
|
2939
|
+
}));
|
|
2940
|
+
onBeforeUnmount(cleanupRootMenu);
|
|
2582
2941
|
return {
|
|
2583
2942
|
rootRef,
|
|
2584
2943
|
menuRef,
|
|
@@ -2589,33 +2948,30 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2589
2948
|
visibleItems,
|
|
2590
2949
|
renderedItems,
|
|
2591
2950
|
renderContext,
|
|
2592
|
-
focusedIndex,
|
|
2593
|
-
focusedPath,
|
|
2594
|
-
activeDescendantId,
|
|
2595
|
-
rootClass,
|
|
2596
|
-
contentClass,
|
|
2597
|
-
contentStyle:
|
|
2598
|
-
...contentStyle.value,
|
|
2599
|
-
zIndex: layer.zIndex.value
|
|
2600
|
-
})),
|
|
2951
|
+
focusedIndex: dataController.focusedIndex,
|
|
2952
|
+
focusedPath: dataController.focusedPath,
|
|
2953
|
+
activeDescendantId: dataController.activeDescendantId,
|
|
2954
|
+
rootClass: presentation.rootClass,
|
|
2955
|
+
contentClass: presentation.contentClass,
|
|
2956
|
+
contentStyle: layeredContentStyle,
|
|
2601
2957
|
arrowStyle,
|
|
2602
2958
|
actualPlacement,
|
|
2603
2959
|
placementSide,
|
|
2604
2960
|
isTargetMode: isExplicitTarget,
|
|
2605
2961
|
teleportTo,
|
|
2606
2962
|
shouldTeleport,
|
|
2607
|
-
triggerProps,
|
|
2608
|
-
contentProps,
|
|
2609
|
-
slotProps,
|
|
2963
|
+
triggerProps: presentation.triggerProps,
|
|
2964
|
+
contentProps: presentation.contentProps,
|
|
2965
|
+
slotProps: presentation.slotProps,
|
|
2610
2966
|
open,
|
|
2611
2967
|
close,
|
|
2612
2968
|
toggle,
|
|
2613
|
-
selectItem,
|
|
2614
|
-
openSubmenu,
|
|
2615
|
-
closeSubmenu,
|
|
2616
|
-
onItemMouseenter: focusHoveredItem,
|
|
2617
|
-
onTriggerKeydown,
|
|
2618
|
-
onMenuKeydown,
|
|
2969
|
+
selectItem: dataController.selectItem,
|
|
2970
|
+
openSubmenu: dataController.openSubmenu,
|
|
2971
|
+
closeSubmenu: dataController.closeSubmenu,
|
|
2972
|
+
onItemMouseenter: dataController.focusHoveredItem,
|
|
2973
|
+
onTriggerKeydown: (event) => interaction.onTriggerKeydown(event),
|
|
2974
|
+
onMenuKeydown: presentation.onMenuKeydown,
|
|
2619
2975
|
getItemProps,
|
|
2620
2976
|
getItemSlotProps
|
|
2621
2977
|
};
|
|
@@ -2701,12 +3057,17 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2701
3057
|
focusOutside: (event) => emit("focusOutside", event),
|
|
2702
3058
|
interactOutside: (event) => emit("interactOutside", event)
|
|
2703
3059
|
});
|
|
3060
|
+
const templateRefs = {
|
|
3061
|
+
root: rootRef,
|
|
3062
|
+
menu: menuRef,
|
|
3063
|
+
arrow: arrowRef
|
|
3064
|
+
};
|
|
2704
3065
|
const { getPartAttrs, getRootAttrs } = useStylesApi(props, "root");
|
|
2705
3066
|
const state = computed(() => isVisible.value ? "open" : "closed");
|
|
2706
3067
|
const rootAttrs = computed(() => getRootAttrs({
|
|
2707
3068
|
class: rootClass.value,
|
|
2708
3069
|
"data-state": state.value,
|
|
2709
|
-
"data-disabled":
|
|
3070
|
+
"data-disabled": toPresenceAttribute(props.disabled)
|
|
2710
3071
|
}));
|
|
2711
3072
|
const publicSlotProps = computed(() => {
|
|
2712
3073
|
const partAttrs = getPartAttrs("trigger");
|
|
@@ -2717,7 +3078,7 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2717
3078
|
...props.classNames?.trigger !== void 0 ? { class: partAttrs.class } : {},
|
|
2718
3079
|
...props.styles?.trigger !== void 0 ? { style: partAttrs.style } : {},
|
|
2719
3080
|
"data-state": state.value,
|
|
2720
|
-
"data-disabled":
|
|
3081
|
+
"data-disabled": toPresenceAttribute(props.disabled)
|
|
2721
3082
|
}
|
|
2722
3083
|
};
|
|
2723
3084
|
});
|
|
@@ -2753,10 +3114,10 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2753
3114
|
setInsertionState(n26, null, 0);
|
|
2754
3115
|
createIf(() => __props.arrow, () => {
|
|
2755
3116
|
const n7 = t0();
|
|
2756
|
-
_setTemplateRef(n7, arrowRef, null, "arrowRef");
|
|
2757
3117
|
renderEffect(() => {
|
|
2758
3118
|
setAttr(n7, "data-side", unref(placementSide));
|
|
2759
3119
|
setStyle(n7, unref(arrowStyle));
|
|
3120
|
+
_setTemplateRef(n7, templateRefs.arrow);
|
|
2760
3121
|
});
|
|
2761
3122
|
return n7;
|
|
2762
3123
|
});
|
|
@@ -2799,12 +3160,12 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2799
3160
|
return n23;
|
|
2800
3161
|
}, null, 129)];
|
|
2801
3162
|
}, { _: 8 }) });
|
|
2802
|
-
|
|
3163
|
+
setTemplateRefBinding(n26, () => templateRefs.menu, _setTemplateRef);
|
|
2803
3164
|
return n26;
|
|
2804
3165
|
}, null, 129);
|
|
2805
3166
|
}, { _: 8 }));
|
|
2806
3167
|
});
|
|
2807
|
-
|
|
3168
|
+
setTemplateRefBinding(n29, () => templateRefs.root);
|
|
2808
3169
|
return n29;
|
|
2809
3170
|
}
|
|
2810
3171
|
});
|