ropav 0.1.6 → 0.1.8
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 +7 -1
- 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/ancestry.js +136 -0
- 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/calendar.css +173 -0
- package/dist/calendar.js +714 -0
- package/dist/calendar2.js +37 -0
- package/dist/card.js +1 -1
- package/dist/checkbox.css +32 -32
- package/dist/checkbox.js +22 -28
- package/dist/chevron-left.js +12 -0
- 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 +247 -276
- 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/combobox.css +251 -0
- package/dist/combobox.js +410 -0
- 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/calendar/calendar.d.ts +30 -0
- package/dist/components/calendar/calendarBehavior.d.ts +49 -0
- package/dist/components/calendar/index.d.ts +3 -0
- package/dist/components/calendar/index.js +3 -0
- package/dist/components/calendar/types.d.ts +53 -0
- package/dist/components/calendar/useCalendar.d.ts +24 -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/useColorPickerDrag.d.ts +1 -1
- 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/combobox/combobox.d.ts +29 -0
- package/dist/components/combobox/comboboxModel.d.ts +4 -0
- package/dist/components/combobox/index.d.ts +3 -0
- package/dist/components/combobox/index.js +2 -0
- package/dist/components/combobox/types.d.ts +43 -0
- package/dist/components/combobox/useCombobox.d.ts +45 -0
- package/dist/components/date-picker/date-picker.d.ts +33 -0
- package/dist/components/date-picker/datePickerModel.d.ts +10 -0
- package/dist/components/date-picker/index.d.ts +4 -0
- package/dist/components/date-picker/index.js +2 -0
- package/dist/components/date-picker/types.d.ts +57 -0
- package/dist/components/date-picker/useDatePicker.d.ts +29 -0
- package/dist/components/date-picker/useDatePickerValueState.d.ts +21 -0
- 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-content.d.ts +2 -2
- 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-content.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.d.ts +2 -2
- package/dist/components/dropdown-menu/{dropdown-menu-primitive-core.d.ts → dropdownMenuContext.d.ts} +17 -30
- 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 +114 -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 +35 -0
- package/dist/components/dropdown-menu/useDropdownMenuDataRegistration.d.ts +24 -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 +28 -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/dropzone/dropzone.d.ts +31 -0
- package/dist/components/dropzone/dropzoneModel.d.ts +16 -0
- package/dist/components/dropzone/index.d.ts +3 -0
- package/dist/components/dropzone/index.js +2 -0
- package/dist/components/dropzone/types.d.ts +56 -0
- package/dist/components/dropzone/useDropzone.d.ts +25 -0
- package/dist/components/file-input/file-input.d.ts +29 -0
- package/dist/components/file-input/index.d.ts +3 -0
- package/dist/components/file-input/index.js +2 -0
- package/dist/components/file-input/types.d.ts +37 -0
- package/dist/components/file-input/useFileInput.d.ts +15 -0
- package/dist/components/floating/index.js +2 -2
- package/dist/components/floating/useFloatingPosition.d.ts +1 -14
- package/dist/components/floating/useFloatingTargetLifecycle.d.ts +32 -0
- package/dist/components/floating/useHoverDisclosure.d.ts +10 -0
- package/dist/components/hover-card/hover-card.d.ts +25 -0
- package/dist/components/hover-card/index.d.ts +3 -0
- package/dist/components/hover-card/index.js +2 -0
- package/dist/components/hover-card/types.d.ts +45 -0
- package/dist/components/hover-card/useHoverCard.d.ts +22 -0
- package/dist/components/hover-card/useHoverCardDisclosure.d.ts +19 -0
- package/dist/components/multi-select/index.d.ts +3 -0
- package/dist/components/multi-select/index.js +2 -0
- package/dist/components/multi-select/multi-select.d.ts +30 -0
- package/dist/components/multi-select/multiSelectModel.d.ts +3 -0
- package/dist/components/multi-select/types.d.ts +49 -0
- package/dist/components/multi-select/useMultiSelect.d.ts +46 -0
- package/dist/components/number-input/numberInputModel.d.ts +15 -0
- package/dist/components/number-input/useNumberInput.d.ts +3 -19
- 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 +13 -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 +11 -9
- package/dist/components/scroll-area/useScrollAreaVisibility.d.ts +15 -20
- package/dist/components/segmented-control/index.d.ts +3 -0
- package/dist/components/segmented-control/index.js +2 -0
- package/dist/components/segmented-control/segmented-control.d.ts +26 -0
- package/dist/components/segmented-control/types.d.ts +47 -0
- package/dist/components/segmented-control/useSegmentedControl.d.ts +15 -0
- package/dist/components/select/useSelect.d.ts +31 -19
- 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 +9 -17
- package/dist/components/slider/useRangeSliderPointer.d.ts +1 -1
- 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/tags-input/index.d.ts +3 -0
- package/dist/components/tags-input/index.js +2 -0
- package/dist/components/tags-input/tags-input.d.ts +27 -0
- package/dist/components/tags-input/tagsInputModel.d.ts +12 -0
- package/dist/components/tags-input/types.d.ts +37 -0
- package/dist/components/tags-input/useTagsInput.d.ts +23 -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/components/tooltip/useTooltipTargetBindings.d.ts +12 -0
- package/dist/css.js +12 -0
- package/dist/date-picker.css +49 -0
- package/dist/date-picker.js +809 -0
- package/dist/dialog.js +215 -218
- package/dist/direction.js +6 -0
- package/dist/dropdown-menu.css +21 -3
- package/dist/dropdown-menu.js +1626 -1185
- package/dist/dropzone.css +135 -0
- package/dist/dropzone.js +431 -0
- package/dist/events.js +59 -0
- package/dist/field.css +8 -8
- package/dist/field.js +13 -25
- package/dist/file-input.css +135 -0
- package/dist/file-input.js +198 -0
- package/dist/floatingOffset.js +11 -0
- package/dist/focus-trap.js +7 -5
- package/dist/focusNavigation.js +37 -0
- package/dist/hover-card.css +80 -0
- package/dist/hover-card.js +402 -0
- package/dist/icon-button.css +8 -8
- package/dist/icon-button.js +7 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.js +20 -9
- package/dist/input.css +24 -24
- package/dist/input.js +19 -31
- package/dist/interactive.js +18 -0
- package/dist/internal/composables/useOverlayLayer.d.ts +12 -0
- package/dist/modal.js +2 -2
- package/dist/multi-select.css +316 -0
- package/dist/multi-select.js +481 -0
- package/dist/nativeChoice.js +169 -0
- package/dist/number-input.css +18 -18
- package/dist/number-input.js +44 -44
- package/dist/number.js +22 -0
- package/dist/overlay.js +3 -2
- package/dist/pagination.css +28 -28
- package/dist/pagination.js +66 -73
- package/dist/pointerSession.js +130 -0
- package/dist/popover.css +55 -37
- package/dist/popover.js +75 -101
- 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 +540 -554
- package/dist/segmented-control.css +176 -0
- package/dist/segmented-control.js +382 -0
- package/dist/select.css +50 -48
- package/dist/select.js +131 -289
- package/dist/slider.css +191 -191
- package/dist/slider.js +720 -706
- 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/tags-input.css +197 -0
- package/dist/tags-input.js +380 -0
- 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 +64 -63
- package/dist/useCollapse.js +8 -11
- package/dist/useControlState.js +3 -6
- package/dist/useEditableOptionList.js +216 -0
- package/dist/useFlatOptionCollection.js +134 -0
- package/dist/useFloatingPosition.js +14 -40
- package/dist/useFloatingTargetLifecycle.js +127 -0
- package/dist/useFormControl.js +1 -0
- package/dist/useHoverDisclosure.js +561 -0
- package/dist/useNativeChoiceTransaction.js +46 -0
- package/dist/useNativeFileSelection.js +86 -0
- package/dist/useOverlayZIndex.js +246 -19
- 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/date.d.ts +13 -0
- package/dist/utils/dateAvailability.d.ts +7 -0
- package/dist/utils/dom/ancestry.d.ts +8 -0
- package/dist/utils/dom/attributes.d.ts +16 -0
- package/dist/utils/dom/componentRef.d.ts +4 -0
- package/dist/utils/dom/direction.d.ts +2 -0
- package/dist/utils/dom/events.d.ts +5 -0
- package/dist/utils/dom/files.d.ts +3 -0
- package/dist/utils/dom/focusNavigation.d.ts +7 -0
- package/dist/utils/dom/interactive.d.ts +2 -0
- package/dist/utils/dom/nativeChoice.d.ts +17 -0
- package/dist/utils/dom/pointerSession.d.ts +20 -0
- package/dist/utils/dom/query.d.ts +4 -0
- package/dist/utils/dom/scroll.d.ts +24 -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/optionFilter.d.ts +5 -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 +13 -9
- package/docs/public-styles-api.md +25 -12
- package/package.json +51 -14
- package/src/styles/_mixins.scss +26 -0
- package/src/styles/styles-manifest.json +1 -2
- 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/select/useSelectNativeControl.d.ts +0 -9
- package/dist/components/select/useSelectNativeValue.d.ts +0 -9
- package/dist/floating.js +0 -415
- /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,48 @@
|
|
|
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 {
|
|
7
|
-
import {
|
|
8
|
-
import { n as useTeleportPositioningKey, r as useTeleportTarget, t as provideTeleportTarget } from "./useTeleportTarget.js";
|
|
9
|
-
import { n as getNextEnabledIndex, r as useTypeahead, t as getEnabledIndexes } from "./collectionNavigation.js";
|
|
6
|
+
import { t as useRequiredInject } from "./useRequiredInject.js";
|
|
7
|
+
import { t as clamp } from "./number.js";
|
|
10
8
|
import { t as chevron_right_default } from "./chevron-right.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
import { t as resolveHTMLElementRef } from "./componentRef.js";
|
|
10
|
+
import { r as isEventWithinTargets, t as createCancelableCustomEvent } from "./events.js";
|
|
11
|
+
import { n as useOverlayZIndex, r as useOverlayLayer } from "./useOverlayZIndex.js";
|
|
12
|
+
import { t as useFloatingPosition } from "./useFloatingPosition.js";
|
|
13
|
+
import { t as useFloatingTargetLifecycle } from "./useFloatingTargetLifecycle.js";
|
|
14
|
+
import { n as useTeleportTarget, t as provideTeleportTarget } from "./useTeleportTarget.js";
|
|
15
|
+
import { t as useTypeahead } from "./useTypeahead.js";
|
|
16
|
+
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";
|
|
17
|
+
//#region src/utils/geometry.ts
|
|
18
|
+
function getClientPoint(event) {
|
|
19
|
+
return {
|
|
20
|
+
x: event.clientX,
|
|
21
|
+
y: event.clientY
|
|
22
|
+
};
|
|
20
23
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
function hasMeasuredRect(rect) {
|
|
25
|
+
return rect.width > 0 || rect.height > 0;
|
|
26
|
+
}
|
|
27
|
+
function isPointInRect(point, rect, padding = 0) {
|
|
28
|
+
return point.x >= rect.left - padding && point.x <= rect.right + padding && point.y >= rect.top - padding && point.y <= rect.bottom + padding;
|
|
24
29
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
function getTriangleArea(a, b, c) {
|
|
31
|
+
return Math.abs((a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2);
|
|
32
|
+
}
|
|
33
|
+
function isPointInTriangle(point, triangle, tolerance = .5) {
|
|
34
|
+
const [a, b, c] = triangle;
|
|
35
|
+
const area = getTriangleArea(a, b, c);
|
|
36
|
+
const area1 = getTriangleArea(point, b, c);
|
|
37
|
+
const area2 = getTriangleArea(a, point, c);
|
|
38
|
+
const area3 = getTriangleArea(a, b, point);
|
|
39
|
+
return Math.abs(area - (area1 + area2 + area3)) < tolerance;
|
|
33
40
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
function clampPointToRect(point, rect) {
|
|
42
|
+
return {
|
|
43
|
+
x: clamp(point.x, rect.left, rect.right),
|
|
44
|
+
y: clamp(point.y, rect.top, rect.bottom)
|
|
45
|
+
};
|
|
39
46
|
}
|
|
40
47
|
function createPointRect(point) {
|
|
41
48
|
return {
|
|
@@ -50,202 +57,57 @@ function createPointRect(point) {
|
|
|
50
57
|
toJSON: () => ({})
|
|
51
58
|
};
|
|
52
59
|
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/components/dropdown-menu/dropdownMenuContext.ts
|
|
62
|
+
var rootKey = Symbol("dropdown-menu-root");
|
|
63
|
+
var menuKey = Symbol("dropdown-menu-content");
|
|
64
|
+
var subKey = Symbol("dropdown-menu-sub");
|
|
65
|
+
var radioGroupKey = Symbol("dropdown-menu-radio-group");
|
|
66
|
+
var checkedKey = Symbol("dropdown-menu-checked");
|
|
53
67
|
function createVirtualAnchor(point) {
|
|
54
68
|
return { getBoundingClientRect: () => createPointRect(point) };
|
|
55
69
|
}
|
|
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
70
|
function createSelectEvent(originalEvent, value) {
|
|
65
|
-
return
|
|
71
|
+
return createCancelableCustomEvent("dropdown-menu-select", {
|
|
66
72
|
originalEvent,
|
|
67
73
|
value
|
|
68
74
|
}, originalEvent);
|
|
69
75
|
}
|
|
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
76
|
function createMenuContext(options) {
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
options.element.value?.focus();
|
|
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)
|
|
77
|
+
const id = options.parentSub?.menuId ?? options.root.interactionRootMenuId;
|
|
78
|
+
const interaction = options.parentSub ? options.parentSub.interaction.connectContent({
|
|
79
|
+
element: () => options.element.value,
|
|
80
|
+
placement: () => options.actualPlacement.value,
|
|
81
|
+
stopKeyPropagation: true,
|
|
82
|
+
onEscape: options.onEscape
|
|
83
|
+
}) : options.root.interaction.connectRootMenu({
|
|
84
|
+
element: () => options.element.value,
|
|
85
|
+
placement: () => options.actualPlacement.value,
|
|
86
|
+
stopKeyPropagation: true,
|
|
87
|
+
onEscape: options.onEscape
|
|
169
88
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
event.preventDefault();
|
|
182
|
-
event.stopPropagation();
|
|
183
|
-
active.submenu.open("first");
|
|
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
|
-
}
|
|
89
|
+
function connectItem(item) {
|
|
90
|
+
return interaction.connectItem({
|
|
91
|
+
id: item.id,
|
|
92
|
+
element: item.element,
|
|
93
|
+
textValue: item.textValue,
|
|
94
|
+
disabled: item.disabled,
|
|
95
|
+
submenu: item.submenu?.interaction,
|
|
96
|
+
submenuDirection: () => item.submenu?.actualPlacement.value.startsWith("left") ? "left" : "right",
|
|
97
|
+
select: item.activate,
|
|
98
|
+
closeOnSelect: item.closeOnSelect
|
|
99
|
+
});
|
|
231
100
|
}
|
|
232
101
|
const context = {
|
|
233
102
|
root: options.root,
|
|
103
|
+
id,
|
|
234
104
|
element: options.element,
|
|
235
|
-
activeId,
|
|
236
105
|
actualPlacement: options.actualPlacement,
|
|
237
106
|
parentSub: options.parentSub,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
registerSub,
|
|
241
|
-
unregisterSub,
|
|
242
|
-
closeSubmenus,
|
|
243
|
-
setActive,
|
|
244
|
-
isActive: (id) => activeId.value === id,
|
|
245
|
-
focus,
|
|
246
|
-
focusElement,
|
|
247
|
-
onKeydown
|
|
107
|
+
interaction,
|
|
108
|
+
connectItem
|
|
248
109
|
};
|
|
110
|
+
onBeforeUnmount(interaction.dispose);
|
|
249
111
|
return context;
|
|
250
112
|
}
|
|
251
113
|
function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
@@ -254,13 +116,12 @@ function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
|
254
116
|
const id = computed(() => props.id ?? `${generatedId}-item`);
|
|
255
117
|
const element = ref(null);
|
|
256
118
|
const isDisabled = computed(() => Boolean(menu.root.disabled.value || props.disabled));
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (isDisabled.value) return;
|
|
119
|
+
function emitSelection(originalEvent) {
|
|
120
|
+
if (isDisabled.value) return void 0;
|
|
260
121
|
const selectEvent = createSelectEvent(originalEvent, props.value);
|
|
261
122
|
emitSelect(selectEvent);
|
|
262
123
|
options.afterSelect?.();
|
|
263
|
-
|
|
124
|
+
return selectEvent;
|
|
264
125
|
}
|
|
265
126
|
const registration = {
|
|
266
127
|
get id() {
|
|
@@ -269,27 +130,35 @@ function usePrimitiveItem(componentName, props, emitSelect, options) {
|
|
|
269
130
|
element: () => element.value,
|
|
270
131
|
textValue: () => props.textValue ?? element.value?.textContent?.trim() ?? "",
|
|
271
132
|
disabled: () => isDisabled.value,
|
|
272
|
-
activate
|
|
133
|
+
activate: emitSelection,
|
|
134
|
+
closeOnSelect: () => props.closeOnSelect ?? options.defaultCloseOnSelect
|
|
273
135
|
};
|
|
274
|
-
menu.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
menu.registerItem(registration);
|
|
278
|
-
if (menu.activeId.value === previousId) menu.activeId.value = nextId;
|
|
136
|
+
let itemInteraction = menu.connectItem(registration);
|
|
137
|
+
const focused = computed(() => {
|
|
138
|
+
return id.value === registration.id && itemInteraction.active.value;
|
|
279
139
|
});
|
|
280
|
-
|
|
140
|
+
watch(id, () => {
|
|
141
|
+
const previous = itemInteraction;
|
|
142
|
+
const wasActive = previous.active.value;
|
|
143
|
+
itemInteraction = menu.connectItem(registration);
|
|
144
|
+
previous.dispose();
|
|
145
|
+
if (wasActive) itemInteraction.setActive();
|
|
146
|
+
}, { flush: "sync" });
|
|
147
|
+
onBeforeUnmount(() => itemInteraction.dispose());
|
|
281
148
|
function setElement(value) {
|
|
282
149
|
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
283
150
|
element.value = resolved;
|
|
284
151
|
});
|
|
285
152
|
}
|
|
153
|
+
function activate(originalEvent) {
|
|
154
|
+
itemInteraction.activate(originalEvent);
|
|
155
|
+
}
|
|
286
156
|
function onPointerenter() {
|
|
287
157
|
if (isDisabled.value) return;
|
|
288
|
-
|
|
289
|
-
menu.setActive(id.value);
|
|
158
|
+
itemInteraction.hover();
|
|
290
159
|
}
|
|
291
160
|
function select() {
|
|
292
|
-
activate(new Event("select"));
|
|
161
|
+
itemInteraction.activate(new Event("select"));
|
|
293
162
|
}
|
|
294
163
|
return {
|
|
295
164
|
menu,
|
|
@@ -369,12 +238,12 @@ var dropdown_menu_checkbox_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
369
238
|
type: props.as === "button" ? "button" : void 0,
|
|
370
239
|
role: "menuitemcheckbox",
|
|
371
240
|
tabindex: -1,
|
|
372
|
-
disabled: props.as === "button" ?
|
|
373
|
-
"aria-disabled":
|
|
241
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
242
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
374
243
|
"aria-checked": checked.value,
|
|
375
|
-
"data-disabled":
|
|
376
|
-
"data-focused":
|
|
377
|
-
"data-highlighted":
|
|
244
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
245
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
246
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
378
247
|
"data-state": state.value,
|
|
379
248
|
class: bem("rp-dropdown-menu__item", {
|
|
380
249
|
focused: focused.value,
|
|
@@ -396,31 +265,6 @@ var dropdown_menu_checkbox_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
396
265
|
}
|
|
397
266
|
});
|
|
398
267
|
//#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
268
|
//#region src/components/dropdown-menu/useDropdownMenuPrimitiveContent.ts
|
|
425
269
|
function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
426
270
|
const componentName = submenu ? "RpDropdownMenuSubContent" : "RpDropdownMenuContent";
|
|
@@ -434,20 +278,23 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
434
278
|
const actualPlacement = ref(props.placement ?? defaultPlacement);
|
|
435
279
|
const isOpen = computed(() => sub ? sub.isOpen.value : root.isOpen.value);
|
|
436
280
|
const reference = computed(() => sub ? sub.trigger.value : root.reference.value);
|
|
437
|
-
const teleportPositioningKey = useTeleportPositioningKey();
|
|
438
281
|
const menu = createMenuContext({
|
|
439
282
|
root,
|
|
440
283
|
element,
|
|
441
284
|
actualPlacement,
|
|
442
285
|
parentSub: sub,
|
|
443
286
|
onEscape(event) {
|
|
444
|
-
const customEvent =
|
|
287
|
+
const customEvent = createCancelableCustomEvent("dropdown-menu-escape-key-down", { originalEvent: event }, event);
|
|
445
288
|
events.escapeKeyDown(customEvent);
|
|
446
|
-
|
|
447
|
-
if (sub) sub.close(true);
|
|
448
|
-
else root.close({ returnFocus: true });
|
|
289
|
+
return !customEvent.defaultPrevented;
|
|
449
290
|
}
|
|
450
291
|
});
|
|
292
|
+
const cleanupDismissal = submenu ? void 0 : root.interaction.connectDismissal({
|
|
293
|
+
ignoredTargets: () => props.ignore ?? [],
|
|
294
|
+
pointerDownOutside: events.pointerDownOutside,
|
|
295
|
+
focusOutside: events.focusOutside,
|
|
296
|
+
interactOutside: events.interactOutside
|
|
297
|
+
});
|
|
451
298
|
const floating = useFloatingPosition({
|
|
452
299
|
reference,
|
|
453
300
|
floating: element,
|
|
@@ -460,72 +307,31 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
460
307
|
flipOptions: () => props.flipOptions,
|
|
461
308
|
shift: () => props.shift !== false,
|
|
462
309
|
collisionPadding: () => props.collisionPadding ?? 8,
|
|
463
|
-
autoUpdateOptions: () => props.autoUpdateOptions
|
|
464
|
-
restartKey: teleportPositioningKey
|
|
310
|
+
autoUpdateOptions: () => props.autoUpdateOptions
|
|
465
311
|
});
|
|
466
312
|
watch(floating.actualPlacement, (value) => {
|
|
467
313
|
actualPlacement.value = value;
|
|
468
314
|
}, { immediate: true });
|
|
469
315
|
const shouldRender = computed(() => props.forceMount === true || isOpen.value);
|
|
470
316
|
let layerBranchCleanup;
|
|
317
|
+
let disconnectInside;
|
|
471
318
|
provide(menuKey, menu);
|
|
472
319
|
if (sub) sub.menu = menu;
|
|
473
320
|
function setElement(value) {
|
|
474
321
|
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
475
|
-
|
|
476
|
-
|
|
322
|
+
disconnectInside?.();
|
|
323
|
+
disconnectInside = void 0;
|
|
477
324
|
layerBranchCleanup?.();
|
|
478
325
|
layerBranchCleanup = void 0;
|
|
479
326
|
element.value = resolved;
|
|
480
|
-
if (resolved) root.
|
|
327
|
+
if (resolved) disconnectInside = root.connectInside(resolved);
|
|
481
328
|
if (!sub) root.layer.element.value = resolved;
|
|
482
329
|
else if (resolved) layerBranchCleanup = root.layer.registerBranch(resolved);
|
|
483
330
|
});
|
|
484
331
|
}
|
|
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
332
|
watch(isOpen, (open) => {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
menu.activeId.value = null;
|
|
522
|
-
menu.closeSubmenus();
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
nextTick(() => {
|
|
526
|
-
const focus = sub ? sub.pendingFocus.value : root.pendingFocus.value;
|
|
527
|
-
menu.focus(focus || "first");
|
|
528
|
-
});
|
|
333
|
+
if (!open) return;
|
|
334
|
+
nextTick(menu.interaction.focusPending);
|
|
529
335
|
}, {
|
|
530
336
|
flush: "post",
|
|
531
337
|
immediate: true
|
|
@@ -533,12 +339,12 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
533
339
|
onMounted(() => {
|
|
534
340
|
if (sub) sub.contentId.value = id.value;
|
|
535
341
|
else root.contentId.value = id.value;
|
|
536
|
-
if (isOpen.value) menu.
|
|
342
|
+
if (isOpen.value) menu.interaction.focusPending();
|
|
537
343
|
});
|
|
538
344
|
onBeforeUnmount(() => {
|
|
539
|
-
|
|
345
|
+
cleanupDismissal?.();
|
|
346
|
+
disconnectInside?.();
|
|
540
347
|
layerBranchCleanup?.();
|
|
541
|
-
if (element.value) root.unregisterInside(element.value);
|
|
542
348
|
if (!sub && root.layer.element.value === element.value) root.layer.element.value = null;
|
|
543
349
|
if (sub) sub.menu = null;
|
|
544
350
|
else if (root.contentId.value === id.value) root.contentId.value = void 0;
|
|
@@ -549,7 +355,7 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
549
355
|
id: id.value,
|
|
550
356
|
role: "menu",
|
|
551
357
|
tabindex: -1,
|
|
552
|
-
hidden:
|
|
358
|
+
hidden: toOptionalAttribute(!isOpen.value),
|
|
553
359
|
class: submenu ? bem("rp-dropdown-menu__submenu", {
|
|
554
360
|
compound: true,
|
|
555
361
|
open: isOpen.value
|
|
@@ -565,12 +371,12 @@ function useDropdownMenuPrimitiveContent(props, attrs, events, submenu) {
|
|
|
565
371
|
"aria-label": props.ariaLabel,
|
|
566
372
|
"aria-labelledby": props.ariaLabelledby ?? (submenu ? void 0 : root.triggerId.value),
|
|
567
373
|
"aria-describedby": props.ariaDescribedby,
|
|
568
|
-
"aria-activedescendant": menu.activeId.value ?? void 0,
|
|
374
|
+
"aria-activedescendant": menu.interaction.activeId.value ?? void 0,
|
|
569
375
|
"data-state": isOpen.value ? "open" : "closed",
|
|
570
376
|
"data-placement": floating.actualPlacement.value,
|
|
571
377
|
"data-side": placementSide.value,
|
|
572
378
|
"data-align": placementAlign.value,
|
|
573
|
-
onKeydown: menu.onKeydown
|
|
379
|
+
onKeydown: menu.interaction.onKeydown
|
|
574
380
|
}));
|
|
575
381
|
function close() {
|
|
576
382
|
if (sub) sub.close(true);
|
|
@@ -644,15 +450,16 @@ var dropdown_menu_content_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
644
450
|
focusOutside: (event) => emit("focusOutside", event),
|
|
645
451
|
interactOutside: (event) => emit("interactOutside", event)
|
|
646
452
|
}, false);
|
|
453
|
+
const templateRefs = { arrow: arrowElement };
|
|
647
454
|
const _setTemplateRef = createTemplateRefSetter();
|
|
648
455
|
return createIf(() => unref(shouldRender), () => {
|
|
649
456
|
const n6 = createDynamicComponent(() => __props.as, { $: [() => unref(rootAttrs)] }, extend(() => {
|
|
650
457
|
return [createIf(() => __props.arrow, () => {
|
|
651
458
|
const n4 = t0$2();
|
|
652
|
-
_setTemplateRef(n4, arrowElement, null, "arrowElement");
|
|
653
459
|
renderEffect(() => {
|
|
654
460
|
setAttr(n4, "data-side", unref(placementSide));
|
|
655
461
|
setStyle(n4, unref(floating).arrowStyle.value);
|
|
462
|
+
_setTemplateRef(n4, templateRefs.arrow);
|
|
656
463
|
});
|
|
657
464
|
return n4;
|
|
658
465
|
}, null, 129), createSlot("default", {
|
|
@@ -667,6 +474,118 @@ var dropdown_menu_content_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
667
474
|
}
|
|
668
475
|
});
|
|
669
476
|
//#endregion
|
|
477
|
+
//#region src/components/dropdown-menu/useDropdownMenuContextTrigger.ts
|
|
478
|
+
function useDropdownMenuContextTrigger(props) {
|
|
479
|
+
const attrs = useAttrs();
|
|
480
|
+
const root = useRequiredInject(rootKey, "RpDropdownMenuContextTrigger");
|
|
481
|
+
const generatedId = useId();
|
|
482
|
+
const id = computed(() => props.id ?? `${generatedId}-context-trigger`);
|
|
483
|
+
const element = ref(null);
|
|
484
|
+
const isDisabled = computed(() => root.disabled.value || props.disabled);
|
|
485
|
+
let timer;
|
|
486
|
+
let pointerId;
|
|
487
|
+
let startPoint;
|
|
488
|
+
let longPressOpened = false;
|
|
489
|
+
let suppressUntil = 0;
|
|
490
|
+
let disconnectInside;
|
|
491
|
+
function setElement(value) {
|
|
492
|
+
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
493
|
+
disconnectInside?.();
|
|
494
|
+
disconnectInside = void 0;
|
|
495
|
+
element.value = resolved;
|
|
496
|
+
if (resolved) disconnectInside = root.connectInside(resolved);
|
|
497
|
+
if (!root.triggerId.value) root.triggerId.value = id.value;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function clearLongPress() {
|
|
501
|
+
if (timer) clearTimeout(timer);
|
|
502
|
+
timer = void 0;
|
|
503
|
+
pointerId = void 0;
|
|
504
|
+
startPoint = void 0;
|
|
505
|
+
element.value?.ownerDocument.defaultView?.removeEventListener("scroll", clearLongPress, true);
|
|
506
|
+
}
|
|
507
|
+
function openAt(point) {
|
|
508
|
+
root.setReturnFocus(element.value);
|
|
509
|
+
root.openAt(point);
|
|
510
|
+
}
|
|
511
|
+
function onContextmenu(event) {
|
|
512
|
+
if (isDisabled.value) return;
|
|
513
|
+
event.preventDefault();
|
|
514
|
+
if (Date.now() < suppressUntil) return;
|
|
515
|
+
openAt({
|
|
516
|
+
x: event.clientX,
|
|
517
|
+
y: event.clientY
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
function onKeydown(event) {
|
|
521
|
+
if (isDisabled.value) return;
|
|
522
|
+
if (event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) return;
|
|
523
|
+
event.preventDefault();
|
|
524
|
+
const rect = element.value?.getBoundingClientRect();
|
|
525
|
+
openAt({
|
|
526
|
+
x: rect?.left ?? 0,
|
|
527
|
+
y: rect?.bottom ?? 0
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
function onPointerdown(event) {
|
|
531
|
+
if (isDisabled.value || event.pointerType !== "touch" && event.pointerType !== "pen") return;
|
|
532
|
+
clearLongPress();
|
|
533
|
+
pointerId = event.pointerId;
|
|
534
|
+
startPoint = {
|
|
535
|
+
x: event.clientX,
|
|
536
|
+
y: event.clientY
|
|
537
|
+
};
|
|
538
|
+
longPressOpened = false;
|
|
539
|
+
(element.value?.ownerDocument.defaultView)?.addEventListener("scroll", clearLongPress, true);
|
|
540
|
+
timer = setTimeout(() => {
|
|
541
|
+
if (!startPoint) return;
|
|
542
|
+
longPressOpened = true;
|
|
543
|
+
suppressUntil = Date.now() + 1e3;
|
|
544
|
+
openAt(startPoint);
|
|
545
|
+
timer = void 0;
|
|
546
|
+
}, props.longPressDelay);
|
|
547
|
+
}
|
|
548
|
+
function onPointermove(event) {
|
|
549
|
+
if (event.pointerId !== pointerId || !startPoint) return;
|
|
550
|
+
if (Math.hypot(event.clientX - startPoint.x, event.clientY - startPoint.y) > (props.longPressTolerance ?? 0)) clearLongPress();
|
|
551
|
+
}
|
|
552
|
+
function finishPointer(event) {
|
|
553
|
+
if (event.pointerId !== pointerId) return;
|
|
554
|
+
if (longPressOpened) event.preventDefault();
|
|
555
|
+
clearLongPress();
|
|
556
|
+
}
|
|
557
|
+
function onClick(event) {
|
|
558
|
+
if (Date.now() >= suppressUntil) return;
|
|
559
|
+
event.preventDefault();
|
|
560
|
+
event.stopPropagation();
|
|
561
|
+
}
|
|
562
|
+
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
563
|
+
id: id.value,
|
|
564
|
+
"aria-controls": root.contentId.value,
|
|
565
|
+
"aria-haspopup": "menu",
|
|
566
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
567
|
+
"data-state": root.isOpen.value ? "open" : "closed",
|
|
568
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
569
|
+
onClick,
|
|
570
|
+
onContextmenu,
|
|
571
|
+
onKeydown,
|
|
572
|
+
onPointerdown,
|
|
573
|
+
onPointermove,
|
|
574
|
+
onPointerup: finishPointer,
|
|
575
|
+
onPointercancel: finishPointer
|
|
576
|
+
}));
|
|
577
|
+
onBeforeUnmount(() => {
|
|
578
|
+
clearLongPress();
|
|
579
|
+
disconnectInside?.();
|
|
580
|
+
if (root.triggerId.value === id.value) root.triggerId.value = void 0;
|
|
581
|
+
});
|
|
582
|
+
return {
|
|
583
|
+
isOpen: root.isOpen,
|
|
584
|
+
rootAttrs,
|
|
585
|
+
setElement
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
//#endregion
|
|
670
589
|
//#region src/components/dropdown-menu/dropdown-menu-context-trigger.vue
|
|
671
590
|
var dropdown_menu_context_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
672
591
|
name: "RpDropdownMenuContextTrigger",
|
|
@@ -683,113 +602,11 @@ var dropdown_menu_context_trigger_default = /* @__PURE__ */ defineVaporComponent
|
|
|
683
602
|
longPressTolerance: { default: 10 }
|
|
684
603
|
},
|
|
685
604
|
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 });
|
|
605
|
+
const { isOpen, rootAttrs, setElement } = useDropdownMenuContextTrigger(__props);
|
|
606
|
+
const n1 = createDynamicComponent(() => __props.as, { $: [() => unref(rootAttrs)] }, extend(() => {
|
|
607
|
+
return createSlot("default", { isOpen: () => unref(isOpen) });
|
|
791
608
|
}, { _: 8 }), 1);
|
|
792
|
-
setTemplateRefBinding(n1, () => setElement);
|
|
609
|
+
setTemplateRefBinding(n1, () => setElement, void 0, void 0, "setElement");
|
|
793
610
|
return n1;
|
|
794
611
|
}
|
|
795
612
|
});
|
|
@@ -831,11 +648,11 @@ var dropdown_menu_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
831
648
|
type: props.as === "button" ? "button" : void 0,
|
|
832
649
|
role: "menuitem",
|
|
833
650
|
tabindex: -1,
|
|
834
|
-
disabled: props.as === "button" ?
|
|
835
|
-
"aria-disabled":
|
|
836
|
-
"data-disabled":
|
|
837
|
-
"data-focused":
|
|
838
|
-
"data-highlighted":
|
|
651
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
652
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
653
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
654
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
655
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
839
656
|
class: bem("rp-dropdown-menu__item", {
|
|
840
657
|
focused: focused.value,
|
|
841
658
|
disabled: isDisabled.value,
|
|
@@ -931,7 +748,7 @@ var dropdown_menu_portal_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
931
748
|
const props = __props;
|
|
932
749
|
const teleportTo = provideTeleportTarget({ get teleportTo() {
|
|
933
750
|
return props.to ?? props.teleportTo;
|
|
934
|
-
} }
|
|
751
|
+
} });
|
|
935
752
|
return createComponent(VaporTeleport, {
|
|
936
753
|
to: () => unref(teleportTo),
|
|
937
754
|
disabled: () => __props.disabled || !__props.teleport
|
|
@@ -1038,12 +855,12 @@ var dropdown_menu_radio_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1038
855
|
type: props.as === "button" ? "button" : void 0,
|
|
1039
856
|
role: "menuitemradio",
|
|
1040
857
|
tabindex: -1,
|
|
1041
|
-
disabled: props.as === "button" ?
|
|
1042
|
-
"aria-disabled":
|
|
858
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
859
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
1043
860
|
"aria-checked": checked.value,
|
|
1044
|
-
"data-disabled":
|
|
1045
|
-
"data-focused":
|
|
1046
|
-
"data-highlighted":
|
|
861
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
862
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
863
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
1047
864
|
"data-state": state.value,
|
|
1048
865
|
class: bem("rp-dropdown-menu__item", {
|
|
1049
866
|
focused: focused.value,
|
|
@@ -1065,37 +882,785 @@ var dropdown_menu_radio_item_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1065
882
|
}
|
|
1066
883
|
});
|
|
1067
884
|
//#endregion
|
|
1068
|
-
//#region src/components/dropdown-menu/
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
885
|
+
//#region src/components/dropdown-menu/dropdownMenuInteractionNavigation.ts
|
|
886
|
+
function createDropdownMenuInteractionNavigation({ host, registry, closeRoot }) {
|
|
887
|
+
const state = registry.state;
|
|
888
|
+
function closeMenu(menuId, focusParent = false) {
|
|
889
|
+
const menu = registry.getMenu(menuId);
|
|
890
|
+
const menuState = state.getMenuState(menuId);
|
|
891
|
+
if (!menu && !menuState || menuId === host.rootMenuId) return false;
|
|
892
|
+
const wasOpen = registry.isMenuOpen(menuId);
|
|
893
|
+
closeSubmenus(menuId);
|
|
894
|
+
const shouldRestoreParent = focusParent || registry.activeMenuId.value === menuId;
|
|
895
|
+
if (wasOpen) state.setMenuOpen(menuId, false);
|
|
896
|
+
state.clearPendingMenuFocus(menuId);
|
|
897
|
+
state.clearMenuState(menuId);
|
|
898
|
+
if (shouldRestoreParent) {
|
|
899
|
+
const parentItem = state.getParentItem(menuId);
|
|
900
|
+
if (!parentItem || !registry.setActive(parentItem.id, focusParent)) {
|
|
901
|
+
const parentMenuId = parentItem?.menuId ?? host.rootMenuId;
|
|
902
|
+
registry.activeMenuId.value = parentMenuId;
|
|
903
|
+
registry.activeItemId.value = state.getActiveIdValue(parentMenuId);
|
|
904
|
+
if (focusParent) registry.focusMenuElement(parentMenuId);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return wasOpen;
|
|
908
|
+
}
|
|
909
|
+
function closeSubmenus(menuId, exceptMenuId) {
|
|
910
|
+
for (const item of state.getItems(menuId)) {
|
|
911
|
+
const submenuId = item.submenuId?.();
|
|
912
|
+
if (!submenuId || submenuId === exceptMenuId) continue;
|
|
913
|
+
closeMenu(submenuId, false);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function closeAllSubmenus() {
|
|
917
|
+
closeSubmenus(host.rootMenuId);
|
|
918
|
+
for (const menuId of state.getMenuIds()) if (menuId !== host.rootMenuId && registry.isMenuOpen(menuId)) closeMenu(menuId, false);
|
|
919
|
+
}
|
|
920
|
+
function focusMenu(menuId, target = "first") {
|
|
921
|
+
const enabledItems = state.getEnabledItems(menuId);
|
|
922
|
+
const item = target === "last" ? enabledItems.at(-1) : enabledItems[0];
|
|
923
|
+
registry.focusMenuElement(menuId);
|
|
924
|
+
if (!item) {
|
|
925
|
+
state.clearMenuState(menuId);
|
|
926
|
+
registry.activeMenuId.value = menuId;
|
|
927
|
+
const parentItem = state.getParentItem(menuId);
|
|
928
|
+
if (parentItem) registry.activeItemId.value = parentItem.id;
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
return registry.setActive(item.id);
|
|
932
|
+
}
|
|
933
|
+
function openMenu(menuId, focus = "first") {
|
|
934
|
+
const menu = registry.getMenu(menuId);
|
|
935
|
+
const menuState = state.getMenuState(menuId);
|
|
936
|
+
if (!menu && !menuState || menuId === host.rootMenuId) return false;
|
|
937
|
+
const parentItem = state.getParentItem(menuId);
|
|
938
|
+
if (!parentItem || parentItem.disabled()) return false;
|
|
939
|
+
closeSubmenus(parentItem.menuId, menuId);
|
|
940
|
+
state.setPendingMenuFocus(menuId, focus);
|
|
941
|
+
state.setMenuOpen(menuId, true);
|
|
942
|
+
if (focus && menu) focusMenu(menuId, focus);
|
|
943
|
+
return true;
|
|
944
|
+
}
|
|
945
|
+
function selectItem(id, originalEvent = new Event("select")) {
|
|
946
|
+
const item = registry.getItem(id);
|
|
947
|
+
if (!item || item.disabled()) return;
|
|
948
|
+
const selectEvent = item.select?.(originalEvent);
|
|
949
|
+
if (selectEvent && !selectEvent.defaultPrevented && (item.closeOnSelect?.() ?? true)) closeRoot({ focusTrigger: true });
|
|
950
|
+
}
|
|
951
|
+
function activateItem(id, originalEvent = new Event("select")) {
|
|
952
|
+
const item = registry.getItem(id);
|
|
953
|
+
if (!item || item.disabled()) return;
|
|
954
|
+
const submenuId = item.submenuId?.();
|
|
955
|
+
if (submenuId) {
|
|
956
|
+
openMenu(submenuId, "first");
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
selectItem(id, originalEvent);
|
|
960
|
+
}
|
|
961
|
+
function hoverItem(id, openSubmenu = false) {
|
|
962
|
+
const item = registry.getItem(id);
|
|
963
|
+
if (!item || item.disabled()) return;
|
|
964
|
+
registry.setActive(id);
|
|
965
|
+
const submenuId = item.submenuId?.();
|
|
966
|
+
if (openSubmenu && submenuId) openMenu(submenuId, false);
|
|
967
|
+
else closeSubmenus(item.menuId, submenuId && registry.isMenuOpen(submenuId) ? submenuId : void 0);
|
|
968
|
+
}
|
|
969
|
+
function reconcileOpenSubmenus() {
|
|
970
|
+
for (const menuId of state.getMenuIds()) {
|
|
971
|
+
if (menuId === host.rootMenuId || !registry.isMenuOpen(menuId)) continue;
|
|
972
|
+
const parentItem = state.getParentItem(menuId);
|
|
973
|
+
if (!parentItem || parentItem.disabled()) closeMenu(menuId, false);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
function reconcile(menuId) {
|
|
977
|
+
const menuIds = menuId ? [menuId] : state.getRegisteredMenuIds();
|
|
978
|
+
for (const id of menuIds) {
|
|
979
|
+
const activeId = state.getActiveIdValue(id);
|
|
980
|
+
if (!activeId) continue;
|
|
981
|
+
const currentItems = state.getItems(id);
|
|
982
|
+
const activeIndex = currentItems.findIndex((item) => item.id === activeId);
|
|
983
|
+
const activeItem = currentItems[activeIndex];
|
|
984
|
+
if (activeItem && !activeItem.disabled()) continue;
|
|
985
|
+
state.chooseNeighbor(id, Math.max(0, activeIndex));
|
|
986
|
+
}
|
|
987
|
+
reconcileOpenSubmenus();
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
closeMenu,
|
|
991
|
+
closeSubmenus,
|
|
992
|
+
closeAllSubmenus,
|
|
993
|
+
focusMenu,
|
|
994
|
+
openMenu,
|
|
995
|
+
selectItem,
|
|
996
|
+
activateItem,
|
|
997
|
+
hoverItem,
|
|
998
|
+
reconcile,
|
|
999
|
+
reconcileOpenSubmenus
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
//#endregion
|
|
1003
|
+
//#region src/components/dropdown-menu/dropdownMenuInteractionRegistry.ts
|
|
1004
|
+
function compareItems(left, right) {
|
|
1005
|
+
const leftElement = left.element();
|
|
1006
|
+
const rightElement = right.element();
|
|
1007
|
+
if (leftElement && rightElement && leftElement !== rightElement && typeof Node !== "undefined") {
|
|
1008
|
+
const position = leftElement.compareDocumentPosition(rightElement);
|
|
1009
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
|
|
1010
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
|
|
1011
|
+
}
|
|
1012
|
+
return (left.order?.() ?? 0) - (right.order?.() ?? 0);
|
|
1013
|
+
}
|
|
1014
|
+
function scrollItemIntoView(item) {
|
|
1015
|
+
nextTick(() => item.element()?.scrollIntoView?.({ block: "nearest" }));
|
|
1016
|
+
}
|
|
1017
|
+
function createDropdownMenuInteractionRegistry(host, navigation) {
|
|
1018
|
+
const menus = /* @__PURE__ */ new Map();
|
|
1019
|
+
const menuStates = /* @__PURE__ */ new Map();
|
|
1020
|
+
const items = /* @__PURE__ */ new Map();
|
|
1021
|
+
const activeIds = ref(/* @__PURE__ */ new Map());
|
|
1022
|
+
const activeItemId = ref(null);
|
|
1023
|
+
const activeMenuId = ref(host.rootMenuId);
|
|
1024
|
+
const pendingRootFocus = ref("first");
|
|
1025
|
+
const pendingMenuFocus = /* @__PURE__ */ new Map();
|
|
1026
|
+
function getMenu(id) {
|
|
1027
|
+
return menus.get(id);
|
|
1028
|
+
}
|
|
1029
|
+
function getMenuState(id) {
|
|
1030
|
+
return menuStates.get(id);
|
|
1031
|
+
}
|
|
1032
|
+
function getItem(id) {
|
|
1033
|
+
return items.get(id);
|
|
1034
|
+
}
|
|
1035
|
+
function getItems(menuId) {
|
|
1036
|
+
return [...items.values()].filter((item) => item.menuId === menuId).sort(compareItems);
|
|
1037
|
+
}
|
|
1038
|
+
function getEnabledItems(menuId) {
|
|
1039
|
+
return getItems(menuId).filter((item) => !item.disabled());
|
|
1040
|
+
}
|
|
1041
|
+
function getActiveIdValue(menuId) {
|
|
1042
|
+
return activeIds.value.get(menuId) ?? null;
|
|
1043
|
+
}
|
|
1044
|
+
function setActiveId(menuId, id) {
|
|
1045
|
+
const next = new Map(activeIds.value);
|
|
1046
|
+
if (id) next.set(menuId, id);
|
|
1047
|
+
else next.delete(menuId);
|
|
1048
|
+
activeIds.value = next;
|
|
1049
|
+
}
|
|
1050
|
+
function getActiveId(menuId) {
|
|
1051
|
+
return computed(() => getActiveIdValue(menuId));
|
|
1052
|
+
}
|
|
1053
|
+
function isMenuOpen(menuId) {
|
|
1054
|
+
if (menuId === host.rootMenuId) return host.isOpen.value;
|
|
1055
|
+
return menuStates.get(menuId)?.isOpen() ?? menus.get(menuId)?.isOpen() ?? false;
|
|
1056
|
+
}
|
|
1057
|
+
function focusMenuElement(menuId) {
|
|
1058
|
+
nextTick(() => {
|
|
1059
|
+
const menu = menus.get(menuId);
|
|
1060
|
+
(menu?.focusTarget?.() ?? menu?.element())?.focus();
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
function clearMenuState(menuId) {
|
|
1064
|
+
const activeId = getActiveIdValue(menuId);
|
|
1065
|
+
if (activeId && activeItemId.value === activeId) activeItemId.value = null;
|
|
1066
|
+
setActiveId(menuId, null);
|
|
1067
|
+
}
|
|
1068
|
+
function setActive(id, focusElement = false) {
|
|
1069
|
+
if (id === null) {
|
|
1070
|
+
clearMenuState(activeMenuId.value);
|
|
1071
|
+
activeItemId.value = null;
|
|
1072
|
+
return true;
|
|
1073
|
+
}
|
|
1074
|
+
const item = items.get(id);
|
|
1075
|
+
if (!item || item.disabled()) return false;
|
|
1076
|
+
setActiveId(item.menuId, item.id);
|
|
1077
|
+
activeItemId.value = item.id;
|
|
1078
|
+
activeMenuId.value = item.menuId;
|
|
1079
|
+
pendingMenuFocus.delete(item.menuId);
|
|
1080
|
+
if (focusElement) focusMenuElement(item.menuId);
|
|
1081
|
+
scrollItemIntoView(item);
|
|
1082
|
+
return true;
|
|
1083
|
+
}
|
|
1084
|
+
function isActive(id) {
|
|
1085
|
+
return getActiveIdValue(items.get(id)?.menuId ?? "") === id;
|
|
1086
|
+
}
|
|
1087
|
+
function getParentItem(menuId) {
|
|
1088
|
+
const parentItemId = menus.get(menuId)?.parentItemId?.();
|
|
1089
|
+
if (parentItemId) {
|
|
1090
|
+
const parentItem = items.get(parentItemId);
|
|
1091
|
+
if (parentItem) return parentItem;
|
|
1092
|
+
}
|
|
1093
|
+
return [...items.values()].find((item) => item.submenuId?.() === menuId);
|
|
1094
|
+
}
|
|
1095
|
+
function setMenuOpen(menuId, open) {
|
|
1096
|
+
const state = menuStates.get(menuId);
|
|
1097
|
+
if (state) state.setOpen(open);
|
|
1098
|
+
else menus.get(menuId)?.setOpen?.(open);
|
|
1099
|
+
}
|
|
1100
|
+
function chooseNeighbor(menuId, previousIndex) {
|
|
1101
|
+
const currentItems = getItems(menuId);
|
|
1102
|
+
const nextCandidates = currentItems.slice(Math.max(0, previousIndex));
|
|
1103
|
+
const previousCandidates = [];
|
|
1104
|
+
for (let index = Math.max(0, previousIndex) - 1; index >= 0; index -= 1) {
|
|
1105
|
+
const item = currentItems[index];
|
|
1106
|
+
if (item) previousCandidates.push(item);
|
|
1107
|
+
}
|
|
1108
|
+
const next = [...nextCandidates, ...previousCandidates].find((item) => !item.disabled());
|
|
1109
|
+
if (next) setActive(next.id);
|
|
1110
|
+
else {
|
|
1111
|
+
clearMenuState(menuId);
|
|
1112
|
+
focusMenuElement(menuId);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
function unregisterItem(id) {
|
|
1116
|
+
const item = items.get(id);
|
|
1117
|
+
if (!item) return;
|
|
1118
|
+
const previousIndex = getItems(item.menuId).findIndex((current) => current.id === id);
|
|
1119
|
+
const submenuId = item.submenuId?.();
|
|
1120
|
+
if (submenuId) navigation.closeMenu(submenuId, false);
|
|
1121
|
+
items.delete(id);
|
|
1122
|
+
if (getActiveIdValue(item.menuId) === id) chooseNeighbor(item.menuId, previousIndex);
|
|
1123
|
+
navigation.reconcileOpenSubmenus();
|
|
1124
|
+
}
|
|
1125
|
+
function registerItem(registration) {
|
|
1126
|
+
const previous = items.get(registration.id);
|
|
1127
|
+
if (previous && previous.menuId !== registration.menuId && getActiveIdValue(previous.menuId) === previous.id) clearMenuState(previous.menuId);
|
|
1128
|
+
items.set(registration.id, registration);
|
|
1129
|
+
if (isMenuOpen(registration.menuId) && !getActiveIdValue(registration.menuId) && !registration.disabled()) {
|
|
1130
|
+
const enabledItems = getEnabledItems(registration.menuId);
|
|
1131
|
+
const candidate = pendingMenuFocus.get(registration.menuId) === "last" ? enabledItems.at(-1) : enabledItems[0];
|
|
1132
|
+
if (candidate) setActive(candidate.id);
|
|
1133
|
+
} else navigation.reconcile(registration.menuId);
|
|
1134
|
+
return () => {
|
|
1135
|
+
if (items.get(registration.id) === registration) unregisterItem(registration.id);
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function unregisterMenu(id) {
|
|
1139
|
+
if (!menus.get(id)) return;
|
|
1140
|
+
navigation.closeSubmenus(id);
|
|
1141
|
+
if (id !== host.rootMenuId) navigation.closeMenu(id, false);
|
|
1142
|
+
clearMenuState(id);
|
|
1143
|
+
menus.delete(id);
|
|
1144
|
+
}
|
|
1145
|
+
function registerMenu(registration) {
|
|
1146
|
+
menus.set(registration.id, registration);
|
|
1147
|
+
const pending = pendingMenuFocus.get(registration.id);
|
|
1148
|
+
if (registration.isOpen() && pending) nextTick(() => navigation.focusMenu(registration.id, pending));
|
|
1149
|
+
return () => {
|
|
1150
|
+
if (menus.get(registration.id) === registration) unregisterMenu(registration.id);
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function registerMenuState(registration) {
|
|
1154
|
+
menuStates.set(registration.id, registration);
|
|
1155
|
+
return () => {
|
|
1156
|
+
if (menuStates.get(registration.id) !== registration) return;
|
|
1157
|
+
menuStates.delete(registration.id);
|
|
1158
|
+
pendingMenuFocus.delete(registration.id);
|
|
1159
|
+
if (!menus.has(registration.id)) clearMenuState(registration.id);
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
activeItemId,
|
|
1164
|
+
activeMenuId,
|
|
1165
|
+
pendingRootFocus,
|
|
1166
|
+
registerMenu,
|
|
1167
|
+
unregisterMenu,
|
|
1168
|
+
registerMenuState,
|
|
1169
|
+
registerItem,
|
|
1170
|
+
unregisterItem,
|
|
1171
|
+
getActiveId,
|
|
1172
|
+
getItem,
|
|
1173
|
+
getMenu,
|
|
1174
|
+
isActive,
|
|
1175
|
+
isMenuOpen,
|
|
1176
|
+
setActive,
|
|
1177
|
+
focusMenuElement,
|
|
1178
|
+
state: {
|
|
1179
|
+
getMenuState,
|
|
1180
|
+
getItems,
|
|
1181
|
+
getEnabledItems,
|
|
1182
|
+
getActiveIdValue,
|
|
1183
|
+
clearMenuState,
|
|
1184
|
+
getParentItem,
|
|
1185
|
+
setMenuOpen,
|
|
1186
|
+
chooseNeighbor,
|
|
1187
|
+
getMenuIds: () => /* @__PURE__ */ new Set([...menus.keys(), ...menuStates.keys()]),
|
|
1188
|
+
getRegisteredMenuIds: () => [...menus.keys()],
|
|
1189
|
+
getPendingMenuFocus: (menuId) => pendingMenuFocus.get(menuId),
|
|
1190
|
+
setPendingMenuFocus: (menuId, focus) => pendingMenuFocus.set(menuId, focus),
|
|
1191
|
+
clearPendingMenuFocus: (menuId) => pendingMenuFocus.delete(menuId)
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
//#endregion
|
|
1196
|
+
//#region src/components/dropdown-menu/useDropdownMenuInteractionDismissal.ts
|
|
1197
|
+
function createOutsideEvent(originalEvent) {
|
|
1198
|
+
return createCancelableCustomEvent("dropdown-menu-interact-outside", { originalEvent }, originalEvent);
|
|
1199
|
+
}
|
|
1200
|
+
function blockNextDocumentClick(document) {
|
|
1201
|
+
function blockDocumentClick(event) {
|
|
1202
|
+
if (event.cancelable) event.preventDefault();
|
|
1203
|
+
event.stopPropagation();
|
|
1204
|
+
document.removeEventListener("click", blockDocumentClick, true);
|
|
1205
|
+
}
|
|
1206
|
+
document.addEventListener("click", blockDocumentClick, true);
|
|
1207
|
+
document.defaultView?.setTimeout(() => document.removeEventListener("click", blockDocumentClick, true), 1e3);
|
|
1208
|
+
}
|
|
1209
|
+
function useDropdownMenuInteractionDismissal({ host, registry, closeRoot }) {
|
|
1210
|
+
const inside = /* @__PURE__ */ new Set();
|
|
1211
|
+
let dismissal;
|
|
1212
|
+
let layerInteraction;
|
|
1213
|
+
function registerInside(element) {
|
|
1214
|
+
inside.add(element);
|
|
1215
|
+
layerInteraction?.refresh();
|
|
1216
|
+
}
|
|
1217
|
+
function unregisterInside(element) {
|
|
1218
|
+
inside.delete(element);
|
|
1219
|
+
layerInteraction?.refresh();
|
|
1220
|
+
}
|
|
1221
|
+
function emitOutside(type, originalEvent) {
|
|
1222
|
+
const outsideEvent = createOutsideEvent(originalEvent);
|
|
1223
|
+
if (type === "pointer") dismissal?.pointerDownOutside?.(outsideEvent);
|
|
1224
|
+
else dismissal?.focusOutside?.(outsideEvent);
|
|
1225
|
+
dismissal?.interactOutside?.(outsideEvent);
|
|
1226
|
+
return outsideEvent;
|
|
1227
|
+
}
|
|
1228
|
+
function blockModalInteraction(event) {
|
|
1229
|
+
if (!host.modal.value) return;
|
|
1230
|
+
if (event.cancelable) event.preventDefault();
|
|
1231
|
+
event.stopPropagation();
|
|
1232
|
+
const listenerDocument = event.currentTarget;
|
|
1233
|
+
if (event.type === "pointerdown" && listenerDocument?.nodeType === 9) blockNextDocumentClick(listenerDocument);
|
|
1234
|
+
}
|
|
1235
|
+
function shouldIgnoreOutside(event) {
|
|
1236
|
+
return isEventWithinTargets(event, (dismissal?.ignoredTargets() ?? []).map((target) => isRef(target) ? target.value : target));
|
|
1237
|
+
}
|
|
1238
|
+
function onDocumentPointer(event) {
|
|
1239
|
+
if (shouldIgnoreOutside(event)) return;
|
|
1240
|
+
const outsideEvent = emitOutside("pointer", event);
|
|
1241
|
+
blockModalInteraction(event);
|
|
1242
|
+
if (!outsideEvent.defaultPrevented) closeRoot({ focusTrigger: host.modal.value });
|
|
1243
|
+
}
|
|
1244
|
+
function onDocumentFocus(event) {
|
|
1245
|
+
if (shouldIgnoreOutside(event)) return;
|
|
1246
|
+
const outsideEvent = emitOutside("focus", event);
|
|
1247
|
+
blockModalInteraction(event);
|
|
1248
|
+
if (!outsideEvent.defaultPrevented) closeRoot({ focusTrigger: host.modal.value });
|
|
1249
|
+
else if (host.modal.value) registry.focusMenuElement(registry.activeMenuId.value);
|
|
1250
|
+
}
|
|
1251
|
+
function registerDismissal(registration) {
|
|
1252
|
+
layerInteraction?.();
|
|
1253
|
+
dismissal = registration;
|
|
1254
|
+
layerInteraction = host.connectLayerInteraction({
|
|
1255
|
+
inside: () => [...inside],
|
|
1256
|
+
pointerDownOutside: onDocumentPointer,
|
|
1257
|
+
focusOutside: onDocumentFocus
|
|
1258
|
+
});
|
|
1259
|
+
return () => {
|
|
1260
|
+
if (dismissal !== registration) return;
|
|
1261
|
+
dismissal = void 0;
|
|
1262
|
+
layerInteraction?.();
|
|
1263
|
+
layerInteraction = void 0;
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
registerInside,
|
|
1268
|
+
unregisterInside,
|
|
1269
|
+
registerDismissal
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
//#endregion
|
|
1273
|
+
//#region src/components/dropdown-menu/useDropdownMenuInteractionKeyboard.ts
|
|
1274
|
+
function getPlacementSide(placement) {
|
|
1275
|
+
return placement.split("-")[0];
|
|
1276
|
+
}
|
|
1277
|
+
function useDropdownMenuInteractionKeyboard({ host, registry, navigation, openRoot, closeRoot }) {
|
|
1278
|
+
const state = registry.state;
|
|
1279
|
+
const typeaheadMenuId = ref(host.rootMenuId);
|
|
1280
|
+
const typeahead = useTypeahead({
|
|
1281
|
+
items: () => state.getItems(typeaheadMenuId.value),
|
|
1282
|
+
activeIndex: () => state.getItems(typeaheadMenuId.value).findIndex((item) => item.id === state.getActiveIdValue(typeaheadMenuId.value)),
|
|
1283
|
+
getKey: (item) => item.id,
|
|
1284
|
+
getTextValue: (item) => item.textValue(),
|
|
1285
|
+
isDisabled: (item) => item.disabled(),
|
|
1286
|
+
scopeKey: () => typeaheadMenuId.value,
|
|
1287
|
+
onMatch(item) {
|
|
1288
|
+
registry.setActive(item.id);
|
|
1289
|
+
navigation.closeSubmenus(item.menuId);
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
function move(menuId, direction) {
|
|
1293
|
+
const enabledItems = state.getEnabledItems(menuId);
|
|
1294
|
+
if (enabledItems.length === 0) {
|
|
1295
|
+
state.clearMenuState(menuId);
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
const currentIndex = enabledItems.findIndex((item) => item.id === state.getActiveIdValue(menuId));
|
|
1299
|
+
const item = enabledItems[((currentIndex < 0 ? direction === 1 ? -1 : 0 : currentIndex) + direction + enabledItems.length) % enabledItems.length];
|
|
1300
|
+
if (item) {
|
|
1301
|
+
registry.setActive(item.id);
|
|
1302
|
+
navigation.closeSubmenus(menuId);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
function handleHorizontalKey(menuId, event, activeItem) {
|
|
1306
|
+
const menu = registry.getMenu(menuId);
|
|
1307
|
+
const isRight = event.key === "ArrowRight";
|
|
1308
|
+
if (menuId !== host.rootMenuId && menu) {
|
|
1309
|
+
if (isRight === (getPlacementSide(menu.placement()) === "left")) {
|
|
1310
|
+
event.preventDefault();
|
|
1311
|
+
if (menu.stopKeyPropagation) event.stopPropagation();
|
|
1312
|
+
navigation.closeMenu(menuId, true);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
const submenuId = activeItem?.submenuId?.();
|
|
1317
|
+
if (!activeItem || activeItem.disabled() || !submenuId) return;
|
|
1318
|
+
const submenu = registry.getMenu(submenuId);
|
|
1319
|
+
if (isRight !== (activeItem.submenuDirection?.() !== "left" && (!submenu || getPlacementSide(submenu.placement()) !== "left"))) return;
|
|
1320
|
+
event.preventDefault();
|
|
1321
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1322
|
+
navigation.openMenu(submenuId, "first");
|
|
1323
|
+
}
|
|
1324
|
+
function onMenuKeydown(menuId, event) {
|
|
1325
|
+
const menu = registry.getMenu(menuId);
|
|
1326
|
+
typeaheadMenuId.value = menuId;
|
|
1327
|
+
if (typeahead.handleKey(event)) {
|
|
1328
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const activeId = state.getActiveIdValue(menuId);
|
|
1332
|
+
const activeItem = activeId ? registry.getItem(activeId) : void 0;
|
|
1333
|
+
const stop = () => {
|
|
1334
|
+
if (menu?.stopKeyPropagation) event.stopPropagation();
|
|
1335
|
+
};
|
|
1336
|
+
switch (event.key) {
|
|
1337
|
+
case "ArrowDown":
|
|
1338
|
+
event.preventDefault();
|
|
1339
|
+
stop();
|
|
1340
|
+
move(menuId, 1);
|
|
1341
|
+
break;
|
|
1342
|
+
case "ArrowUp":
|
|
1343
|
+
event.preventDefault();
|
|
1344
|
+
stop();
|
|
1345
|
+
move(menuId, -1);
|
|
1346
|
+
break;
|
|
1347
|
+
case "Home":
|
|
1348
|
+
event.preventDefault();
|
|
1349
|
+
stop();
|
|
1350
|
+
navigation.focusMenu(menuId, "first");
|
|
1351
|
+
navigation.closeSubmenus(menuId);
|
|
1352
|
+
break;
|
|
1353
|
+
case "End":
|
|
1354
|
+
event.preventDefault();
|
|
1355
|
+
stop();
|
|
1356
|
+
navigation.focusMenu(menuId, "last");
|
|
1357
|
+
navigation.closeSubmenus(menuId);
|
|
1358
|
+
break;
|
|
1359
|
+
case "ArrowRight":
|
|
1360
|
+
case "ArrowLeft":
|
|
1361
|
+
handleHorizontalKey(menuId, event, activeItem);
|
|
1362
|
+
break;
|
|
1363
|
+
case "Enter":
|
|
1364
|
+
case " ":
|
|
1365
|
+
event.preventDefault();
|
|
1366
|
+
stop();
|
|
1367
|
+
if (activeItem) navigation.activateItem(activeItem.id, event);
|
|
1368
|
+
break;
|
|
1369
|
+
case "Escape":
|
|
1370
|
+
event.preventDefault();
|
|
1371
|
+
stop();
|
|
1372
|
+
if (menu?.onEscape && !menu.onEscape(event)) return;
|
|
1373
|
+
if (!navigation.closeMenu(menuId, true)) closeRoot({ focusTrigger: true });
|
|
1374
|
+
break;
|
|
1375
|
+
case "Tab":
|
|
1376
|
+
closeRoot();
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
function onTriggerKeydown(event, beforeOpen) {
|
|
1381
|
+
if (host.disabled.value) return;
|
|
1382
|
+
switch (event.key) {
|
|
1383
|
+
case "Enter":
|
|
1384
|
+
case " ":
|
|
1385
|
+
case "ArrowDown":
|
|
1386
|
+
event.preventDefault();
|
|
1387
|
+
beforeOpen?.();
|
|
1388
|
+
openRoot("first");
|
|
1389
|
+
break;
|
|
1390
|
+
case "ArrowUp":
|
|
1391
|
+
event.preventDefault();
|
|
1392
|
+
beforeOpen?.();
|
|
1393
|
+
openRoot("last");
|
|
1394
|
+
break;
|
|
1395
|
+
case "Escape":
|
|
1396
|
+
closeRoot({ focusTrigger: true });
|
|
1397
|
+
break;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return {
|
|
1401
|
+
onMenuKeydown,
|
|
1402
|
+
onTriggerKeydown,
|
|
1403
|
+
resetTypeahead: typeahead.reset
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
//#endregion
|
|
1407
|
+
//#region src/components/dropdown-menu/dropdownMenuInteraction.ts
|
|
1408
|
+
function resolveOpenFocusTarget(options) {
|
|
1409
|
+
if (typeof options === "string") return options;
|
|
1410
|
+
return options?.focus ?? "first";
|
|
1411
|
+
}
|
|
1412
|
+
function resolveKeyboardMenuId(rootMenuId, registry, event) {
|
|
1413
|
+
const activeItemId = registry.activeItemId.value;
|
|
1414
|
+
const activeItem = activeItemId ? registry.getItem(activeItemId) : void 0;
|
|
1415
|
+
const openSubmenuId = activeItem?.submenuId?.();
|
|
1416
|
+
if (openSubmenuId && registry.isMenuOpen(openSubmenuId)) {
|
|
1417
|
+
if (event.key === "Escape") return openSubmenuId;
|
|
1418
|
+
const opensLeft = activeItem?.submenuDirection?.() === "left" || registry.getMenu(openSubmenuId)?.placement().startsWith("left");
|
|
1419
|
+
if (event.key === (opensLeft ? "ArrowRight" : "ArrowLeft")) return openSubmenuId;
|
|
1420
|
+
}
|
|
1421
|
+
if ([
|
|
1422
|
+
"ArrowLeft",
|
|
1423
|
+
"ArrowRight",
|
|
1424
|
+
"Escape"
|
|
1425
|
+
].includes(event.key) && registry.activeMenuId.value !== rootMenuId) return registry.activeMenuId.value;
|
|
1426
|
+
return activeItem?.menuId ?? registry.activeMenuId.value;
|
|
1427
|
+
}
|
|
1428
|
+
function useDropdownMenuInteraction(host) {
|
|
1429
|
+
let navigation;
|
|
1430
|
+
const registry = createDropdownMenuInteractionRegistry(host, {
|
|
1431
|
+
closeMenu: (menuId, focusParent) => navigation.closeMenu(menuId, focusParent),
|
|
1432
|
+
closeSubmenus: (menuId, exceptMenuId) => navigation.closeSubmenus(menuId, exceptMenuId),
|
|
1433
|
+
focusMenu: (menuId, target) => navigation.focusMenu(menuId, target),
|
|
1434
|
+
reconcile: (menuId) => navigation.reconcile(menuId),
|
|
1435
|
+
reconcileOpenSubmenus: () => navigation.reconcileOpenSubmenus()
|
|
1436
|
+
});
|
|
1437
|
+
function open(options) {
|
|
1438
|
+
if (host.disabled.value) return;
|
|
1439
|
+
host.beforeOpen?.();
|
|
1440
|
+
registry.pendingRootFocus.value = resolveOpenFocusTarget(options);
|
|
1441
|
+
host.setOpen(true);
|
|
1442
|
+
navigation.focusMenu(host.rootMenuId, registry.pendingRootFocus.value);
|
|
1443
|
+
}
|
|
1444
|
+
function close(options = {}) {
|
|
1445
|
+
host.beforeClose?.();
|
|
1446
|
+
host.setOpen(false);
|
|
1447
|
+
registry.pendingRootFocus.value = false;
|
|
1448
|
+
navigation.closeAllSubmenus();
|
|
1449
|
+
registry.state.clearMenuState(host.rootMenuId);
|
|
1450
|
+
registry.activeItemId.value = null;
|
|
1451
|
+
registry.activeMenuId.value = host.rootMenuId;
|
|
1452
|
+
keyboard.resetTypeahead();
|
|
1453
|
+
if (options.focusTrigger || options.returnFocus) host.focusTrigger();
|
|
1454
|
+
}
|
|
1455
|
+
function toggle() {
|
|
1456
|
+
if (host.isOpen.value) close({ returnFocus: true });
|
|
1457
|
+
else open();
|
|
1458
|
+
}
|
|
1459
|
+
function onTriggerClick(beforeToggle) {
|
|
1460
|
+
beforeToggle?.();
|
|
1461
|
+
toggle();
|
|
1462
|
+
}
|
|
1463
|
+
navigation = createDropdownMenuInteractionNavigation({
|
|
1464
|
+
host,
|
|
1465
|
+
registry,
|
|
1466
|
+
closeRoot: close
|
|
1467
|
+
});
|
|
1468
|
+
const keyboard = useDropdownMenuInteractionKeyboard({
|
|
1469
|
+
host,
|
|
1470
|
+
registry,
|
|
1471
|
+
navigation,
|
|
1472
|
+
openRoot: open,
|
|
1473
|
+
closeRoot: close
|
|
1474
|
+
});
|
|
1475
|
+
const dismissal = useDropdownMenuInteractionDismissal({
|
|
1476
|
+
host,
|
|
1477
|
+
registry,
|
|
1478
|
+
closeRoot: close
|
|
1479
|
+
});
|
|
1480
|
+
function connectItem(menuId, options) {
|
|
1481
|
+
const registration = {
|
|
1482
|
+
id: options.id,
|
|
1483
|
+
menuId,
|
|
1484
|
+
element: options.element,
|
|
1485
|
+
textValue: options.textValue,
|
|
1486
|
+
disabled: options.disabled,
|
|
1487
|
+
order: options.order,
|
|
1488
|
+
submenuId: options.submenu ? () => options.submenu?.id : void 0,
|
|
1489
|
+
submenuDirection: options.submenuDirection,
|
|
1490
|
+
select: options.select,
|
|
1491
|
+
closeOnSelect: options.closeOnSelect
|
|
1492
|
+
};
|
|
1493
|
+
const disconnect = registry.registerItem(registration);
|
|
1494
|
+
const stopReconciliation = watch([
|
|
1495
|
+
options.disabled,
|
|
1496
|
+
options.element,
|
|
1497
|
+
() => options.submenu?.id
|
|
1498
|
+
], () => navigation.reconcile(menuId), { flush: "sync" });
|
|
1499
|
+
let disposed = false;
|
|
1500
|
+
return {
|
|
1501
|
+
active: computed(() => registry.isActive(options.id)),
|
|
1502
|
+
submenuOpen: computed(() => options.submenu ? registry.isMenuOpen(options.submenu.id) : false),
|
|
1503
|
+
setActive: (focusElement = false) => registry.setActive(options.id, focusElement),
|
|
1504
|
+
openSubmenu: (focus = "first") => options.submenu?.open(focus) ?? false,
|
|
1505
|
+
closeSubmenu: (focusParent = false) => options.submenu?.close(focusParent) ?? false,
|
|
1506
|
+
select: (originalEvent) => navigation.selectItem(options.id, originalEvent),
|
|
1507
|
+
activate: (originalEvent) => navigation.activateItem(options.id, originalEvent),
|
|
1508
|
+
hover(openSubmenu = false) {
|
|
1509
|
+
navigation.hoverItem(options.id, openSubmenu);
|
|
1510
|
+
return Boolean(options.submenu && registry.isMenuOpen(options.submenu.id));
|
|
1511
|
+
},
|
|
1512
|
+
dispose() {
|
|
1513
|
+
if (disposed) return;
|
|
1514
|
+
disposed = true;
|
|
1515
|
+
stopReconciliation();
|
|
1516
|
+
disconnect();
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
function connectMenu(id, options, state, getRequestedFocus) {
|
|
1521
|
+
const disconnect = registry.registerMenu({
|
|
1522
|
+
id,
|
|
1523
|
+
...options,
|
|
1524
|
+
...state
|
|
1525
|
+
});
|
|
1526
|
+
const items = /* @__PURE__ */ new Set();
|
|
1527
|
+
let disposed = false;
|
|
1528
|
+
return {
|
|
1529
|
+
activeId: registry.getActiveId(id),
|
|
1530
|
+
connectItem(itemOptions) {
|
|
1531
|
+
const item = connectItem(id, itemOptions);
|
|
1532
|
+
const dispose = item.dispose;
|
|
1533
|
+
item.dispose = () => {
|
|
1534
|
+
dispose();
|
|
1535
|
+
items.delete(item);
|
|
1536
|
+
};
|
|
1537
|
+
items.add(item);
|
|
1538
|
+
return item;
|
|
1539
|
+
},
|
|
1540
|
+
clearActive: () => {
|
|
1541
|
+
registry.setActive(null);
|
|
1542
|
+
},
|
|
1543
|
+
focusPending() {
|
|
1544
|
+
const pending = id === host.rootMenuId ? registry.pendingRootFocus.value : getRequestedFocus?.() ?? registry.state.getPendingMenuFocus(id);
|
|
1545
|
+
return navigation.focusMenu(id, pending || "first");
|
|
1546
|
+
},
|
|
1547
|
+
onKeydown: (event) => keyboard.onMenuKeydown(id, event),
|
|
1548
|
+
dispose() {
|
|
1549
|
+
if (disposed) return;
|
|
1550
|
+
disposed = true;
|
|
1551
|
+
for (const item of items) item.dispose();
|
|
1552
|
+
disconnect();
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
function connectRootMenu(options) {
|
|
1557
|
+
return connectMenu(host.rootMenuId, options, { isOpen: () => host.isOpen.value });
|
|
1558
|
+
}
|
|
1559
|
+
function connectSubmenu(options) {
|
|
1560
|
+
const disconnectState = registry.registerMenuState(options);
|
|
1561
|
+
let requestedFocus;
|
|
1562
|
+
const stopStateSync = watch(options.isOpen, (isOpen) => {
|
|
1563
|
+
if (isOpen) return;
|
|
1564
|
+
requestedFocus = void 0;
|
|
1565
|
+
navigation.closeMenu(options.id, false);
|
|
1566
|
+
}, { flush: "sync" });
|
|
1567
|
+
let content;
|
|
1568
|
+
let disposed = false;
|
|
1569
|
+
return {
|
|
1570
|
+
id: options.id,
|
|
1571
|
+
open(focus = "first") {
|
|
1572
|
+
requestedFocus = focus;
|
|
1573
|
+
return navigation.openMenu(options.id, focus);
|
|
1574
|
+
},
|
|
1575
|
+
close(focusParent = false) {
|
|
1576
|
+
requestedFocus = void 0;
|
|
1577
|
+
return navigation.closeMenu(options.id, focusParent);
|
|
1578
|
+
},
|
|
1579
|
+
connectContent(menuOptions) {
|
|
1580
|
+
const previous = content;
|
|
1581
|
+
content = connectMenu(options.id, menuOptions, options, () => requestedFocus);
|
|
1582
|
+
previous?.dispose();
|
|
1583
|
+
return content;
|
|
1584
|
+
},
|
|
1585
|
+
dispose() {
|
|
1586
|
+
if (disposed) return;
|
|
1587
|
+
disposed = true;
|
|
1588
|
+
content?.dispose();
|
|
1589
|
+
stopStateSync();
|
|
1590
|
+
disconnectState();
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
function connectInside(element) {
|
|
1595
|
+
dismissal.registerInside(element);
|
|
1596
|
+
let connected = true;
|
|
1597
|
+
return () => {
|
|
1598
|
+
if (!connected) return;
|
|
1599
|
+
connected = false;
|
|
1600
|
+
dismissal.unregisterInside(element);
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
watch(host.disabled, (disabled) => {
|
|
1604
|
+
if (disabled) close();
|
|
1605
|
+
});
|
|
1606
|
+
watch(host.isOpen, (isOpen) => {
|
|
1607
|
+
if (!isOpen) {
|
|
1608
|
+
navigation.closeAllSubmenus();
|
|
1609
|
+
registry.state.clearMenuState(host.rootMenuId);
|
|
1610
|
+
registry.activeItemId.value = null;
|
|
1611
|
+
registry.activeMenuId.value = host.rootMenuId;
|
|
1612
|
+
keyboard.resetTypeahead();
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
const focus = registry.pendingRootFocus.value || "first";
|
|
1616
|
+
navigation.focusMenu(host.rootMenuId, focus);
|
|
1617
|
+
}, { immediate: true });
|
|
1618
|
+
return {
|
|
1619
|
+
activeItemId: registry.activeItemId,
|
|
1620
|
+
connectRootMenu,
|
|
1621
|
+
connectSubmenu,
|
|
1622
|
+
connectInside,
|
|
1623
|
+
connectDismissal: dismissal.registerDismissal,
|
|
1624
|
+
open,
|
|
1625
|
+
close,
|
|
1626
|
+
toggle,
|
|
1627
|
+
onTriggerClick,
|
|
1628
|
+
onTriggerKeydown: keyboard.onTriggerKeydown,
|
|
1629
|
+
onMenuKeydown: (event) => keyboard.onMenuKeydown(resolveKeyboardMenuId(host.rootMenuId, registry, event), event)
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
//#endregion
|
|
1633
|
+
//#region src/components/dropdown-menu/dropdown-menu-root.vue
|
|
1634
|
+
var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
1635
|
+
name: "RpDropdownMenuRoot",
|
|
1636
|
+
__name: "dropdown-menu-root",
|
|
1637
|
+
props: {
|
|
1638
|
+
id: {},
|
|
1639
|
+
open: {
|
|
1640
|
+
type: Boolean,
|
|
1641
|
+
default: void 0
|
|
1642
|
+
},
|
|
1643
|
+
defaultOpen: {
|
|
1644
|
+
type: Boolean,
|
|
1645
|
+
default: false
|
|
1646
|
+
},
|
|
1647
|
+
baseZIndex: {},
|
|
1648
|
+
disabled: {
|
|
1649
|
+
type: Boolean,
|
|
1650
|
+
default: false
|
|
1651
|
+
},
|
|
1652
|
+
modal: {
|
|
1653
|
+
type: Boolean,
|
|
1654
|
+
default: true
|
|
1655
|
+
},
|
|
1656
|
+
target: { default: null },
|
|
1657
|
+
virtualAnchor: { default: null }
|
|
1658
|
+
},
|
|
1659
|
+
emits: ["update:open"],
|
|
1660
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
1661
|
+
const props = __props;
|
|
1662
|
+
const emit = __emit;
|
|
1663
|
+
const generatedId = useId();
|
|
1099
1664
|
const id = computed(() => props.id ?? `${generatedId}-dropdown-menu`);
|
|
1100
1665
|
const controllableOpen = useControllableValue({
|
|
1101
1666
|
modelValue: () => props.open,
|
|
@@ -1109,11 +1674,12 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1109
1674
|
const triggerId = ref();
|
|
1110
1675
|
const contentId = ref();
|
|
1111
1676
|
const activeReference = shallowRef(null);
|
|
1112
|
-
const { reference: configuredReference } =
|
|
1677
|
+
const { reference: configuredReference } = useFloatingTargetLifecycle({
|
|
1678
|
+
target: () => props.target ?? props.virtualAnchor,
|
|
1679
|
+
fallback: trigger
|
|
1680
|
+
});
|
|
1113
1681
|
const reference = computed(() => activeReference.value ?? configuredReference.value);
|
|
1114
|
-
const pendingFocus = ref("first");
|
|
1115
1682
|
const contentElement = ref(null);
|
|
1116
|
-
const inside = /* @__PURE__ */ new Set();
|
|
1117
1683
|
let returnFocusElement = null;
|
|
1118
1684
|
const baseZIndex = useOverlayZIndex({
|
|
1119
1685
|
baseZIndex: () => props.baseZIndex,
|
|
@@ -1134,34 +1700,33 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1134
1700
|
const activeElement = document.activeElement;
|
|
1135
1701
|
if (activeElement instanceof HTMLElement) returnFocusElement = activeElement;
|
|
1136
1702
|
}
|
|
1137
|
-
function open(options) {
|
|
1138
|
-
if (disabled.value) return;
|
|
1139
|
-
rememberFocus();
|
|
1140
|
-
pendingFocus.value = getFocusTarget(options);
|
|
1141
|
-
setOpen(true);
|
|
1142
|
-
}
|
|
1143
1703
|
function focusReturnTarget() {
|
|
1144
1704
|
const target = returnFocusElement ?? trigger.value;
|
|
1145
1705
|
nextTick(() => target?.focus());
|
|
1146
1706
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1707
|
+
const interactionRootMenuId = `${generatedId}-interaction-root`;
|
|
1708
|
+
const interaction = useDropdownMenuInteraction({
|
|
1709
|
+
rootMenuId: interactionRootMenuId,
|
|
1710
|
+
isOpen,
|
|
1711
|
+
disabled,
|
|
1712
|
+
modal,
|
|
1713
|
+
setOpen,
|
|
1714
|
+
connectLayerInteraction: layer.connectInteraction,
|
|
1715
|
+
focusTrigger: focusReturnTarget,
|
|
1716
|
+
beforeOpen: rememberFocus
|
|
1717
|
+
});
|
|
1718
|
+
const { open, close, toggle } = interaction;
|
|
1156
1719
|
function openAt(point, options) {
|
|
1157
1720
|
activeReference.value = createVirtualAnchor(point);
|
|
1158
1721
|
open(options);
|
|
1159
1722
|
}
|
|
1723
|
+
let disconnectTrigger;
|
|
1160
1724
|
function setTrigger(element, nextId) {
|
|
1161
|
-
|
|
1725
|
+
disconnectTrigger?.();
|
|
1726
|
+
disconnectTrigger = void 0;
|
|
1162
1727
|
trigger.value = element;
|
|
1163
1728
|
triggerId.value = nextId;
|
|
1164
|
-
if (element)
|
|
1729
|
+
if (element) disconnectTrigger = interaction.connectInside(element);
|
|
1165
1730
|
}
|
|
1166
1731
|
const context = {
|
|
1167
1732
|
id,
|
|
@@ -1172,8 +1737,9 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1172
1737
|
triggerId,
|
|
1173
1738
|
contentId,
|
|
1174
1739
|
reference,
|
|
1175
|
-
|
|
1740
|
+
interactionRootMenuId,
|
|
1176
1741
|
layer,
|
|
1742
|
+
interaction,
|
|
1177
1743
|
open,
|
|
1178
1744
|
close,
|
|
1179
1745
|
toggle,
|
|
@@ -1185,15 +1751,7 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1185
1751
|
setReturnFocus(element) {
|
|
1186
1752
|
returnFocusElement = element;
|
|
1187
1753
|
},
|
|
1188
|
-
|
|
1189
|
-
inside.add(element);
|
|
1190
|
-
},
|
|
1191
|
-
unregisterInside(element) {
|
|
1192
|
-
inside.delete(element);
|
|
1193
|
-
},
|
|
1194
|
-
isInside(event) {
|
|
1195
|
-
return [...inside].some((element) => isEventWithinElement(event, element));
|
|
1196
|
-
}
|
|
1754
|
+
connectInside: interaction.connectInside
|
|
1197
1755
|
};
|
|
1198
1756
|
const slotProps = computed(() => ({
|
|
1199
1757
|
isOpen: isOpen.value,
|
|
@@ -1202,13 +1760,11 @@ var dropdown_menu_root_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1202
1760
|
toggle,
|
|
1203
1761
|
openAt
|
|
1204
1762
|
}));
|
|
1205
|
-
watch(disabled, (value) => {
|
|
1206
|
-
if (value) close();
|
|
1207
|
-
});
|
|
1208
1763
|
watch(isOpen, (value) => {
|
|
1209
1764
|
if (!value) activeReference.value = null;
|
|
1210
1765
|
}, { flush: "sync" });
|
|
1211
1766
|
provide(rootKey, context);
|
|
1767
|
+
onBeforeUnmount(() => disconnectTrigger?.());
|
|
1212
1768
|
__expose({
|
|
1213
1769
|
open,
|
|
1214
1770
|
close,
|
|
@@ -1263,6 +1819,7 @@ var dropdown_menu_sub_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1263
1819
|
const props = __props;
|
|
1264
1820
|
const emit = __emit;
|
|
1265
1821
|
const parentMenu = useRequiredInject(menuKey, "RpDropdownMenuSub");
|
|
1822
|
+
const menuId = `${useId()}-interaction-menu`;
|
|
1266
1823
|
const controllableOpen = useControllableValue({
|
|
1267
1824
|
modelValue: () => props.open,
|
|
1268
1825
|
defaultValue: () => props.defaultOpen,
|
|
@@ -1272,39 +1829,32 @@ var dropdown_menu_sub_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1272
1829
|
const trigger = ref(null);
|
|
1273
1830
|
const contentId = ref();
|
|
1274
1831
|
const actualPlacement = ref("right-start");
|
|
1275
|
-
const pendingFocus = ref(false);
|
|
1276
1832
|
function setOpen(value) {
|
|
1277
1833
|
if (isOpen.value !== value) controllableOpen.setValue(value);
|
|
1278
1834
|
}
|
|
1835
|
+
const interaction = parentMenu.root.interaction.connectSubmenu({
|
|
1836
|
+
id: menuId,
|
|
1837
|
+
parentItemId: () => trigger.value?.id,
|
|
1838
|
+
isOpen: () => isOpen.value,
|
|
1839
|
+
setOpen
|
|
1840
|
+
});
|
|
1279
1841
|
const context = {
|
|
1842
|
+
menuId,
|
|
1280
1843
|
isOpen,
|
|
1281
1844
|
trigger,
|
|
1282
1845
|
contentId,
|
|
1283
1846
|
actualPlacement,
|
|
1284
|
-
pendingFocus,
|
|
1285
1847
|
menu: null,
|
|
1848
|
+
interaction,
|
|
1286
1849
|
open(focus = "first") {
|
|
1287
|
-
|
|
1288
|
-
pendingFocus.value = focus;
|
|
1289
|
-
setOpen(true);
|
|
1290
|
-
if (focus) nextTick(() => context.menu?.focus(focus));
|
|
1850
|
+
if (!interaction.open(focus)) setOpen(true);
|
|
1291
1851
|
},
|
|
1292
1852
|
close(focusParent = false) {
|
|
1293
|
-
setOpen(false);
|
|
1294
|
-
pendingFocus.value = false;
|
|
1295
|
-
context.menu?.closeSubmenus();
|
|
1296
|
-
if (focusParent) {
|
|
1297
|
-
parentMenu.setActive(trigger.value?.id ?? "");
|
|
1298
|
-
parentMenu.focusElement();
|
|
1299
|
-
}
|
|
1853
|
+
if (!interaction.close(focusParent)) setOpen(false);
|
|
1300
1854
|
}
|
|
1301
1855
|
};
|
|
1302
|
-
parentMenu.registerSub(context);
|
|
1303
1856
|
provide(subKey, context);
|
|
1304
|
-
|
|
1305
|
-
if (!open) context.close(false);
|
|
1306
|
-
});
|
|
1307
|
-
onBeforeUnmount(() => parentMenu.unregisterSub(context));
|
|
1857
|
+
onBeforeUnmount(interaction.dispose);
|
|
1308
1858
|
return createSlot("default", {
|
|
1309
1859
|
isOpen: () => unref(isOpen),
|
|
1310
1860
|
open: () => context.open,
|
|
@@ -1394,7 +1944,6 @@ var dropdown_menu_sub_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1394
1944
|
const generatedId = useId();
|
|
1395
1945
|
const id = computed(() => props.id ?? `${generatedId}-sub-trigger`);
|
|
1396
1946
|
const isDisabled = computed(() => menu.root.disabled.value || props.disabled);
|
|
1397
|
-
const focused = computed(() => menu.isActive(id.value));
|
|
1398
1947
|
const registration = {
|
|
1399
1948
|
get id() {
|
|
1400
1949
|
return id.value;
|
|
@@ -1402,11 +1951,21 @@ var dropdown_menu_sub_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1402
1951
|
element: () => sub.trigger.value,
|
|
1403
1952
|
textValue: () => props.textValue ?? sub.trigger.value?.textContent?.trim() ?? "",
|
|
1404
1953
|
disabled: () => isDisabled.value,
|
|
1405
|
-
activate: () =>
|
|
1954
|
+
activate: () => void 0,
|
|
1406
1955
|
submenu: sub
|
|
1407
1956
|
};
|
|
1408
|
-
menu.
|
|
1409
|
-
|
|
1957
|
+
let itemInteraction = menu.connectItem(registration);
|
|
1958
|
+
const focused = computed(() => {
|
|
1959
|
+
return id.value === registration.id && itemInteraction.active.value;
|
|
1960
|
+
});
|
|
1961
|
+
watch(id, () => {
|
|
1962
|
+
const previous = itemInteraction;
|
|
1963
|
+
const wasActive = previous.active.value;
|
|
1964
|
+
itemInteraction = menu.connectItem(registration);
|
|
1965
|
+
previous.dispose();
|
|
1966
|
+
if (wasActive) itemInteraction.setActive();
|
|
1967
|
+
}, { flush: "sync" });
|
|
1968
|
+
onBeforeUnmount(() => itemInteraction.dispose());
|
|
1410
1969
|
function setElement(value) {
|
|
1411
1970
|
resolveHTMLElementRef(value, id.value, (resolved) => {
|
|
1412
1971
|
sub.trigger.value = resolved;
|
|
@@ -1414,25 +1973,24 @@ var dropdown_menu_sub_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1414
1973
|
}
|
|
1415
1974
|
function onMouseenter() {
|
|
1416
1975
|
if (isDisabled.value) return;
|
|
1417
|
-
|
|
1418
|
-
sub.open(false);
|
|
1976
|
+
itemInteraction.hover(true);
|
|
1419
1977
|
}
|
|
1420
1978
|
function onClick(event) {
|
|
1421
|
-
if (!event.defaultPrevented && !isDisabled.value)
|
|
1979
|
+
if (!event.defaultPrevented && !isDisabled.value) itemInteraction.activate(event);
|
|
1422
1980
|
}
|
|
1423
1981
|
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
1424
1982
|
id: id.value,
|
|
1425
1983
|
type: props.as === "button" ? "button" : void 0,
|
|
1426
1984
|
role: "menuitem",
|
|
1427
1985
|
tabindex: -1,
|
|
1428
|
-
disabled: props.as === "button" ?
|
|
1429
|
-
"aria-disabled":
|
|
1986
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
1987
|
+
"aria-disabled": toOptionalAttribute(isDisabled.value),
|
|
1430
1988
|
"aria-haspopup": "menu",
|
|
1431
1989
|
"aria-expanded": sub.isOpen.value,
|
|
1432
1990
|
"aria-controls": sub.contentId.value,
|
|
1433
|
-
"data-disabled":
|
|
1434
|
-
"data-focused":
|
|
1435
|
-
"data-highlighted":
|
|
1991
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
1992
|
+
"data-focused": toOptionalAttribute(focused.value),
|
|
1993
|
+
"data-highlighted": toOptionalAttribute(focused.value),
|
|
1436
1994
|
"data-state": sub.isOpen.value ? "open" : "closed",
|
|
1437
1995
|
class: bem("rp-dropdown-menu__item", {
|
|
1438
1996
|
focused: focused.value,
|
|
@@ -1484,41 +2042,28 @@ var dropdown_menu_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1484
2042
|
root.setTrigger(resolved, id.value);
|
|
1485
2043
|
});
|
|
1486
2044
|
}
|
|
1487
|
-
function
|
|
2045
|
+
function prepareReference() {
|
|
1488
2046
|
root.setReference(element.value);
|
|
1489
2047
|
root.setReturnFocus(element.value);
|
|
1490
|
-
root.open({ focus });
|
|
1491
2048
|
}
|
|
1492
2049
|
function onClick(event) {
|
|
1493
2050
|
if (event.defaultPrevented || isDisabled.value) return;
|
|
1494
|
-
root.
|
|
1495
|
-
root.setReturnFocus(element.value);
|
|
1496
|
-
root.toggle();
|
|
2051
|
+
root.interaction.onTriggerClick(prepareReference);
|
|
1497
2052
|
}
|
|
1498
2053
|
function onKeydown(event) {
|
|
1499
2054
|
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 });
|
|
2055
|
+
root.interaction.onTriggerKeydown(event, prepareReference);
|
|
1511
2056
|
}
|
|
1512
2057
|
const rootAttrs = computed(() => mergeProps(attrs, {
|
|
1513
2058
|
id: id.value,
|
|
1514
2059
|
type: props.as === "button" ? "button" : void 0,
|
|
1515
|
-
disabled: props.as === "button" ?
|
|
2060
|
+
disabled: props.as === "button" ? toOptionalAttribute(isDisabled.value) : void 0,
|
|
1516
2061
|
"aria-controls": root.contentId.value,
|
|
1517
2062
|
"aria-expanded": root.isOpen.value,
|
|
1518
2063
|
"aria-haspopup": "menu",
|
|
1519
|
-
"aria-disabled": props.as === "button" ? void 0 :
|
|
2064
|
+
"aria-disabled": props.as === "button" ? void 0 : toOptionalAttribute(isDisabled.value),
|
|
1520
2065
|
"data-state": root.isOpen.value ? "open" : "closed",
|
|
1521
|
-
"data-disabled":
|
|
2066
|
+
"data-disabled": toOptionalAttribute(isDisabled.value),
|
|
1522
2067
|
onClick,
|
|
1523
2068
|
onKeydown
|
|
1524
2069
|
}));
|
|
@@ -1530,11 +2075,21 @@ var dropdown_menu_trigger_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1530
2075
|
return n1;
|
|
1531
2076
|
}
|
|
1532
2077
|
});
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
return
|
|
2078
|
+
//#endregion
|
|
2079
|
+
//#region src/utils/indexPath.ts
|
|
2080
|
+
function getPathKey(path) {
|
|
2081
|
+
return path.length === 0 ? "root" : path.join("-");
|
|
2082
|
+
}
|
|
2083
|
+
function arePathsEqual(a, b) {
|
|
2084
|
+
return a.length === b.length && a.every((part, index) => part === b[index]);
|
|
2085
|
+
}
|
|
2086
|
+
function isPathPrefix(prefix, path) {
|
|
2087
|
+
return prefix.length <= path.length && prefix.every((part, index) => part === path[index]);
|
|
2088
|
+
}
|
|
2089
|
+
function normalizePath(indexOrPath) {
|
|
2090
|
+
return Array.isArray(indexOrPath) ? indexOrPath : [indexOrPath];
|
|
1537
2091
|
}
|
|
2092
|
+
var DEFAULT_FOCUS_TARGET = "first";
|
|
1538
2093
|
function getItemClass(item, focused, disabled, hasSubmenu, submenuOpen) {
|
|
1539
2094
|
return bem("rp-dropdown-menu__item", {
|
|
1540
2095
|
focused,
|
|
@@ -1550,33 +2105,6 @@ function hasItemSubmenu(item) {
|
|
|
1550
2105
|
function hasNestedItems(items) {
|
|
1551
2106
|
return items.some(hasItemSubmenu);
|
|
1552
2107
|
}
|
|
1553
|
-
function getPathKey(path) {
|
|
1554
|
-
return path.length === 0 ? "root" : path.join("-");
|
|
1555
|
-
}
|
|
1556
|
-
function getParentPath(path) {
|
|
1557
|
-
return path.slice(0, -1);
|
|
1558
|
-
}
|
|
1559
|
-
function arePathsEqual(a, b) {
|
|
1560
|
-
return a.length === b.length && a.every((part, index) => part === b[index]);
|
|
1561
|
-
}
|
|
1562
|
-
function isPathPrefix(prefix, path) {
|
|
1563
|
-
return prefix.length <= path.length && prefix.every((part, index) => part === path[index]);
|
|
1564
|
-
}
|
|
1565
|
-
function normalizePath(indexOrPath) {
|
|
1566
|
-
return Array.isArray(indexOrPath) ? indexOrPath : [indexOrPath];
|
|
1567
|
-
}
|
|
1568
|
-
function getEventPoint(event) {
|
|
1569
|
-
return {
|
|
1570
|
-
x: event.clientX,
|
|
1571
|
-
y: event.clientY
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
function hasMeasuredRect(rect) {
|
|
1575
|
-
return rect.width > 0 || rect.height > 0;
|
|
1576
|
-
}
|
|
1577
|
-
function isPointInRect(point, rect, padding = 0) {
|
|
1578
|
-
return point.x >= rect.left - padding && point.x <= rect.right + padding && point.y >= rect.top - padding && point.y <= rect.bottom + padding;
|
|
1579
|
-
}
|
|
1580
2108
|
//#endregion
|
|
1581
2109
|
//#region src/components/dropdown-menu/dropdown-menu-item-row.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
1582
2110
|
var t0$1 = template("<div>");
|
|
@@ -1607,6 +2135,10 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1607
2135
|
const slotProps = computed(() => props.context.getItemSlotProps(props.item, path.value, focused.value, disabled.value, submenuOpen.value));
|
|
1608
2136
|
const itemElement = ref(null);
|
|
1609
2137
|
const submenuElement = ref(null);
|
|
2138
|
+
const templateRefs = {
|
|
2139
|
+
item: itemElement,
|
|
2140
|
+
submenu: submenuElement
|
|
2141
|
+
};
|
|
1610
2142
|
const { actualPlacement, floatingStyle } = useFloatingPosition({
|
|
1611
2143
|
reference: itemElement,
|
|
1612
2144
|
floating: submenuElement,
|
|
@@ -1632,14 +2164,13 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1632
2164
|
function getChildKey(index, child) {
|
|
1633
2165
|
return `${getPathKey([...path.value, index])}:${String(child.value)}`;
|
|
1634
2166
|
}
|
|
1635
|
-
const _setTemplateRef = createTemplateRefSetter();
|
|
1636
2167
|
const _component_DropdownMenuItemRow__self = resolveComponent("DropdownMenuItemRow", true);
|
|
1637
2168
|
const n10 = t1$1();
|
|
1638
2169
|
const n1 = child(n10);
|
|
1639
2170
|
renderEffect(() => setDynamicProps(n1, [publicItemProps.value]));
|
|
1640
2171
|
setInsertionState(n1, null, 0);
|
|
1641
2172
|
createSlot("item", { $: [() => slotProps.value] });
|
|
1642
|
-
|
|
2173
|
+
setTemplateRefBinding(n1, () => templateRefs.item);
|
|
1643
2174
|
setInsertionState(n10, null, 1);
|
|
1644
2175
|
createIf(() => hasSubmenu.value && submenuOpen.value, () => {
|
|
1645
2176
|
const n9 = t0$1();
|
|
@@ -1659,7 +2190,7 @@ var dropdown_menu_item_row_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1659
2190
|
return createSlot("item", { $: [() => childSlotProps] });
|
|
1660
2191
|
}, { _: 8 }) });
|
|
1661
2192
|
}, (child, childIndex) => getChildKey(childIndex, child), 3);
|
|
1662
|
-
|
|
2193
|
+
setTemplateRefBinding(n9, () => templateRefs.submenu);
|
|
1663
2194
|
return n9;
|
|
1664
2195
|
});
|
|
1665
2196
|
return n10;
|
|
@@ -1693,151 +2224,181 @@ var dropdown_menu_items_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
1693
2224
|
}
|
|
1694
2225
|
});
|
|
1695
2226
|
//#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) });
|
|
2227
|
+
//#region src/components/dropdown-menu/dropdownMenuDataModel.ts
|
|
2228
|
+
function createDataIndexState(rootMenuId) {
|
|
2229
|
+
return {
|
|
2230
|
+
entries: [],
|
|
2231
|
+
itemIdByPath: /* @__PURE__ */ new Map(),
|
|
2232
|
+
pathByItemId: /* @__PURE__ */ new Map(),
|
|
2233
|
+
menuIdByPath: /* @__PURE__ */ new Map([["root", rootMenuId]]),
|
|
2234
|
+
pathByMenuId: /* @__PURE__ */ new Map([[rootMenuId, []]]),
|
|
2235
|
+
primaryItemId: /* @__PURE__ */ new WeakMap(),
|
|
2236
|
+
occurrences: /* @__PURE__ */ new Map()
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
2239
|
+
function getOccurrenceItemId(item, state, getStableItemId) {
|
|
2240
|
+
const occurrence = state.occurrences.get(item) ?? 0;
|
|
2241
|
+
state.occurrences.set(item, occurrence + 1);
|
|
2242
|
+
const stableItemId = getStableItemId(item);
|
|
2243
|
+
return {
|
|
2244
|
+
occurrence,
|
|
2245
|
+
itemId: occurrence === 0 ? stableItemId : `${stableItemId}-copy-${occurrence}`
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
function indexItems(items, parentPath, ownerMenuId, state, getStableItemId) {
|
|
2249
|
+
for (const [order, item] of items.entries()) {
|
|
2250
|
+
const path = [...parentPath, order];
|
|
2251
|
+
const pathKey = getPathKey(path);
|
|
2252
|
+
const { itemId, occurrence } = getOccurrenceItemId(item, state, getStableItemId);
|
|
2253
|
+
const submenuMenuId = hasItemSubmenu(item) ? `${itemId}-menu` : void 0;
|
|
2254
|
+
state.entries.push({
|
|
2255
|
+
item,
|
|
2256
|
+
path,
|
|
2257
|
+
itemId,
|
|
2258
|
+
ownerMenuId,
|
|
2259
|
+
order,
|
|
2260
|
+
submenuMenuId
|
|
2261
|
+
});
|
|
2262
|
+
state.itemIdByPath.set(pathKey, itemId);
|
|
2263
|
+
state.pathByItemId.set(itemId, path);
|
|
2264
|
+
if (occurrence === 0) state.primaryItemId.set(item, itemId);
|
|
2265
|
+
if (!submenuMenuId) continue;
|
|
2266
|
+
state.menuIdByPath.set(pathKey, submenuMenuId);
|
|
2267
|
+
state.pathByMenuId.set(submenuMenuId, path);
|
|
2268
|
+
indexItems(item.children ?? [], path, submenuMenuId, state, getStableItemId);
|
|
1760
2269
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
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);
|
|
1776
|
-
}
|
|
1777
|
-
watch(isVisible, setDocumentListeners, { immediate: true });
|
|
1778
|
-
onBeforeUnmount(() => setDocumentListeners(false));
|
|
2270
|
+
}
|
|
2271
|
+
function buildDropdownMenuDataIndex(items, rootMenuId, getStableItemId) {
|
|
2272
|
+
const state = createDataIndexState(rootMenuId);
|
|
2273
|
+
indexItems(items, [], rootMenuId, state, getStableItemId);
|
|
1779
2274
|
return {
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2275
|
+
entries: state.entries,
|
|
2276
|
+
itemIdByPath: state.itemIdByPath,
|
|
2277
|
+
pathByItemId: state.pathByItemId,
|
|
2278
|
+
menuIdByPath: state.menuIdByPath,
|
|
2279
|
+
pathByMenuId: state.pathByMenuId,
|
|
2280
|
+
primaryItemId: state.primaryItemId
|
|
1784
2281
|
};
|
|
1785
2282
|
}
|
|
2283
|
+
function getDropdownMenuDataCollectionState(items) {
|
|
2284
|
+
const state = [];
|
|
2285
|
+
function collect(currentItems) {
|
|
2286
|
+
state.push(currentItems.length);
|
|
2287
|
+
for (const item of currentItems) {
|
|
2288
|
+
const children = item.children;
|
|
2289
|
+
state.push(item, Boolean(item.disabled), children);
|
|
2290
|
+
if (children) collect(children);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
collect(items);
|
|
2294
|
+
return state;
|
|
2295
|
+
}
|
|
1786
2296
|
//#endregion
|
|
1787
|
-
//#region src/components/dropdown-menu/
|
|
1788
|
-
function
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2297
|
+
//#region src/components/dropdown-menu/useDropdownMenuDataRegistration.ts
|
|
2298
|
+
function getCurrentPath(index, entry) {
|
|
2299
|
+
return index.pathByItemId.get(entry.itemId) ?? entry.path;
|
|
2300
|
+
}
|
|
2301
|
+
function useDropdownMenuDataRegistration({ props, items, rootMenuId, interaction, rootMenu, menuRef, getItemElement, getSubmenuElement, isSubmenuOpeningLeft, onSelect }) {
|
|
2302
|
+
const openMenuIds = ref(/* @__PURE__ */ new Set());
|
|
2303
|
+
const itemIdentity = /* @__PURE__ */ new WeakMap();
|
|
2304
|
+
let nextItemIdentity = 0;
|
|
2305
|
+
let itemInteractions = /* @__PURE__ */ new Map();
|
|
2306
|
+
let menuInteractions = /* @__PURE__ */ new Map([[rootMenuId, rootMenu]]);
|
|
2307
|
+
let submenuInteractions = /* @__PURE__ */ new Map();
|
|
2308
|
+
function getStableItemId(item) {
|
|
2309
|
+
const existing = itemIdentity.get(item);
|
|
2310
|
+
if (existing) return existing;
|
|
2311
|
+
nextItemIdentity += 1;
|
|
2312
|
+
const id = `${rootMenuId}-item-${nextItemIdentity}`;
|
|
2313
|
+
itemIdentity.set(item, id);
|
|
2314
|
+
return id;
|
|
2315
|
+
}
|
|
2316
|
+
const registrationIndex = shallowRef(buildDropdownMenuDataIndex([], rootMenuId, getStableItemId));
|
|
2317
|
+
const collectionState = computed(() => getDropdownMenuDataCollectionState(items.value));
|
|
2318
|
+
function setMenuOpen(id, open) {
|
|
2319
|
+
const next = new Set(openMenuIds.value);
|
|
2320
|
+
if (open) next.add(id);
|
|
2321
|
+
else next.delete(id);
|
|
2322
|
+
openMenuIds.value = next;
|
|
2323
|
+
}
|
|
2324
|
+
function connectSubmenu(index, entry) {
|
|
2325
|
+
const submenuMenuId = entry.submenuMenuId;
|
|
2326
|
+
if (!submenuMenuId) return void 0;
|
|
2327
|
+
const submenu = interaction.connectSubmenu({
|
|
2328
|
+
id: submenuMenuId,
|
|
2329
|
+
parentItemId: () => entry.itemId,
|
|
2330
|
+
isOpen: () => openMenuIds.value.has(submenuMenuId),
|
|
2331
|
+
setOpen: (open) => setMenuOpen(submenuMenuId, open)
|
|
2332
|
+
});
|
|
2333
|
+
return {
|
|
2334
|
+
menu: submenu.connectContent({
|
|
2335
|
+
element: () => getSubmenuElement(getCurrentPath(index, entry)),
|
|
2336
|
+
focusTarget: () => menuRef.value,
|
|
2337
|
+
placement: () => {
|
|
2338
|
+
return getSubmenuElement(getCurrentPath(index, entry))?.dataset.placement ?? "right-start";
|
|
2339
|
+
}
|
|
2340
|
+
}),
|
|
2341
|
+
submenu
|
|
2342
|
+
};
|
|
1792
2343
|
}
|
|
1793
|
-
function
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2344
|
+
function createSelectEvent(entry, originalEvent) {
|
|
2345
|
+
const event = new CustomEvent("dropdown-menu-select", {
|
|
2346
|
+
cancelable: true,
|
|
2347
|
+
detail: {
|
|
2348
|
+
originalEvent,
|
|
2349
|
+
value: entry.item.value
|
|
1798
2350
|
}
|
|
1799
|
-
(rootRef.value?.querySelector("[aria-haspopup=\"menu\"]"))?.focus();
|
|
1800
2351
|
});
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
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;
|
|
1822
|
-
}
|
|
1823
|
-
watch(focusedPath, (path) => {
|
|
1824
|
-
if (path.length === 0) return;
|
|
1825
|
-
const targetPath = [...path];
|
|
1826
|
-
nextTick(() => {
|
|
1827
|
-
if (!arePathsEqual(targetPath, focusedPath.value)) return;
|
|
1828
|
-
getItemElement(targetPath)?.scrollIntoView?.({ block: "nearest" });
|
|
2352
|
+
onSelect?.(entry.item, event);
|
|
2353
|
+
return event;
|
|
2354
|
+
}
|
|
2355
|
+
function connectItem(index, entry, nextMenus, nextSubmenus) {
|
|
2356
|
+
const menu = nextMenus.get(entry.ownerMenuId);
|
|
2357
|
+
if (!menu) return void 0;
|
|
2358
|
+
return menu.connectItem({
|
|
2359
|
+
id: entry.itemId,
|
|
2360
|
+
element: () => getItemElement(getCurrentPath(index, entry)),
|
|
2361
|
+
textValue: () => entry.item.label,
|
|
2362
|
+
disabled: () => Boolean(entry.item.disabled || props.disabled),
|
|
2363
|
+
order: () => entry.order,
|
|
2364
|
+
submenu: entry.submenuMenuId ? nextSubmenus.get(entry.submenuMenuId) : void 0,
|
|
2365
|
+
submenuDirection: () => isSubmenuOpeningLeft(getCurrentPath(index, entry)) ? "left" : "right",
|
|
2366
|
+
select: (originalEvent) => createSelectEvent(entry, originalEvent),
|
|
2367
|
+
closeOnSelect: () => props.closeOnSelect !== false
|
|
1829
2368
|
});
|
|
2369
|
+
}
|
|
2370
|
+
function registerItems() {
|
|
2371
|
+
const nextIndex = buildDropdownMenuDataIndex(items.value, rootMenuId, getStableItemId);
|
|
2372
|
+
const nextItems = /* @__PURE__ */ new Map();
|
|
2373
|
+
const nextMenus = /* @__PURE__ */ new Map([[rootMenuId, rootMenu]]);
|
|
2374
|
+
const nextSubmenus = /* @__PURE__ */ new Map();
|
|
2375
|
+
for (const entry of nextIndex.entries) {
|
|
2376
|
+
const connection = connectSubmenu(nextIndex, entry);
|
|
2377
|
+
if (!entry.submenuMenuId || !connection) continue;
|
|
2378
|
+
nextMenus.set(entry.submenuMenuId, connection.menu);
|
|
2379
|
+
nextSubmenus.set(entry.submenuMenuId, connection.submenu);
|
|
2380
|
+
}
|
|
2381
|
+
for (const entry of nextIndex.entries) {
|
|
2382
|
+
const item = connectItem(nextIndex, entry, nextMenus, nextSubmenus);
|
|
2383
|
+
if (item) nextItems.set(entry.itemId, item);
|
|
2384
|
+
}
|
|
2385
|
+
for (const item of itemInteractions.values()) item.dispose();
|
|
2386
|
+
for (const submenu of submenuInteractions.values()) submenu.dispose();
|
|
2387
|
+
itemInteractions = nextItems;
|
|
2388
|
+
menuInteractions = nextMenus;
|
|
2389
|
+
submenuInteractions = nextSubmenus;
|
|
2390
|
+
registrationIndex.value = nextIndex;
|
|
2391
|
+
}
|
|
2392
|
+
watch(collectionState, registerItems, { immediate: true });
|
|
2393
|
+
onBeforeUnmount(() => {
|
|
2394
|
+
for (const item of itemInteractions.values()) item.dispose();
|
|
2395
|
+
for (const submenu of submenuInteractions.values()) submenu.dispose();
|
|
1830
2396
|
});
|
|
1831
2397
|
return {
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
getSubmenuId,
|
|
1837
|
-
getItemElement,
|
|
1838
|
-
getSubmenuElement,
|
|
1839
|
-
isSubmenuOpeningLeft,
|
|
1840
|
-
getMenuActiveDescendant
|
|
2398
|
+
openMenuIds,
|
|
2399
|
+
registrationIndex,
|
|
2400
|
+
getItemInteraction: (id) => itemInteractions.get(id),
|
|
2401
|
+
getMenuInteraction: (id) => menuInteractions.get(id)
|
|
1841
2402
|
};
|
|
1842
2403
|
}
|
|
1843
2404
|
//#endregion
|
|
@@ -1845,26 +2406,6 @@ function useDropdownMenuDom({ menuId, rootRef, menuRef, targetRef, placement, fo
|
|
|
1845
2406
|
var SAFE_TRIANGLE_PADDING = 2;
|
|
1846
2407
|
var SAFE_TRIANGLE_ORIGIN_OFFSET = 2;
|
|
1847
2408
|
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
2409
|
function getDropdownMenuSafeTriangle({ itemRect, submenuRect, origin }) {
|
|
1869
2410
|
const measuredItemRect = itemRect && hasMeasuredRect(itemRect) ? itemRect : null;
|
|
1870
2411
|
const opensRight = !measuredItemRect || submenuRect.left >= measuredItemRect.right;
|
|
@@ -1949,260 +2490,170 @@ function useDropdownMenuHoverIntent({ openSubmenuPath, getItemElement, getSubmen
|
|
|
1949
2490
|
item,
|
|
1950
2491
|
path
|
|
1951
2492
|
};
|
|
1952
|
-
if (pendingHoverTimer !== void 0) window.clearTimeout(pendingHoverTimer);
|
|
1953
|
-
pendingHoverTimer = window.setTimeout(() => {
|
|
1954
|
-
if (!pendingHover) return;
|
|
1955
|
-
const nextHover = pendingHover;
|
|
1956
|
-
if (latestPointerPoint && isPointInCurrentSubmenu(latestPointerPoint)) {
|
|
1957
|
-
clearPendingHover();
|
|
1958
|
-
return;
|
|
1959
|
-
}
|
|
1960
|
-
commit(nextHover.item, nextHover.path);
|
|
1961
|
-
}, SAFE_TRIANGLE_TIMEOUT);
|
|
1962
|
-
}
|
|
1963
|
-
function handleItemHover(item, path, event, commit) {
|
|
1964
|
-
const point = event ? getEventPoint(event) : void 0;
|
|
1965
|
-
latestPointerPoint = point ?? latestPointerPoint;
|
|
1966
|
-
if (point && shouldDelayHover(path, point)) {
|
|
1967
|
-
delayHoveredItem(item, path, commit);
|
|
1968
|
-
return;
|
|
1969
|
-
}
|
|
1970
|
-
commit(item, path, point);
|
|
1971
|
-
}
|
|
1972
|
-
function handleMenuMousemove(event, commit) {
|
|
1973
|
-
const point = getEventPoint(event);
|
|
1974
|
-
latestPointerPoint = point;
|
|
1975
|
-
updateSafeTriangleOrigin(point);
|
|
1976
|
-
if (!pendingHover) return;
|
|
1977
|
-
if (shouldDelayHover(pendingHover.path, point)) return;
|
|
1978
|
-
const nextHover = pendingHover;
|
|
1979
|
-
commit(nextHover.item, nextHover.path, point);
|
|
1980
|
-
}
|
|
1981
|
-
onUnmounted(clearPendingHover);
|
|
1982
|
-
return {
|
|
1983
|
-
clearPendingHover,
|
|
1984
|
-
resetHoverIntent,
|
|
1985
|
-
trackSubmenuOpen,
|
|
1986
|
-
handleItemHover,
|
|
1987
|
-
handleMenuMousemove
|
|
1988
|
-
};
|
|
1989
|
-
}
|
|
1990
|
-
//#endregion
|
|
1991
|
-
//#region src/components/dropdown-menu/useDropdownMenuInteractions.ts
|
|
1992
|
-
function useDropdownMenuInteractions({ props, emit, isDisabled, focusedPath, openSubmenuPath, getItemAtPath, focusItem, moveFocus, handleTypeahead, submenus, hoverIntent, disclosure, isSubmenuOpeningLeft }) {
|
|
1993
|
-
function activateItem(item, path, event) {
|
|
1994
|
-
if (item.disabled) return;
|
|
1995
|
-
if (hasItemSubmenu(item)) {
|
|
1996
|
-
openSubmenu(path, DEFAULT_FOCUS_TARGET, event instanceof MouseEvent ? getEventPoint(event) : void 0);
|
|
1997
|
-
return;
|
|
1998
|
-
}
|
|
1999
|
-
selectItem(item, event);
|
|
2000
|
-
}
|
|
2001
|
-
function selectItem(item, originalEvent = new Event("select")) {
|
|
2002
|
-
if (item.disabled) return;
|
|
2003
|
-
const event = new CustomEvent("dropdown-menu-select", {
|
|
2004
|
-
cancelable: true,
|
|
2005
|
-
detail: {
|
|
2006
|
-
originalEvent,
|
|
2007
|
-
value: item.value
|
|
2008
|
-
}
|
|
2009
|
-
});
|
|
2010
|
-
emit.select?.(item, event);
|
|
2011
|
-
if (!event.defaultPrevented && props.closeOnSelect !== false) disclosure.close({ focusTrigger: true });
|
|
2012
|
-
}
|
|
2013
|
-
function closeSubmenusAfter(menuPath) {
|
|
2014
|
-
submenus.closeSubmenusAfter(menuPath);
|
|
2015
|
-
hoverIntent.resetHoverIntent();
|
|
2016
|
-
}
|
|
2017
|
-
function openSubmenu(path, focus = DEFAULT_FOCUS_TARGET, point) {
|
|
2018
|
-
const opened = submenus.openSubmenu(path, focus);
|
|
2019
|
-
if (opened) hoverIntent.trackSubmenuOpen(path, point);
|
|
2020
|
-
return opened;
|
|
2021
|
-
}
|
|
2022
|
-
function closeSubmenu(path) {
|
|
2023
|
-
const closed = submenus.closeSubmenu(path);
|
|
2024
|
-
if (closed) hoverIntent.resetHoverIntent();
|
|
2025
|
-
return closed;
|
|
2026
|
-
}
|
|
2027
|
-
function closeCurrentSubmenu() {
|
|
2028
|
-
const closed = submenus.closeCurrentSubmenu();
|
|
2029
|
-
if (closed) hoverIntent.resetHoverIntent();
|
|
2030
|
-
return closed;
|
|
2031
|
-
}
|
|
2032
|
-
function commitHoveredItem(item, path, point) {
|
|
2033
|
-
hoverIntent.clearPendingHover();
|
|
2034
|
-
focusedPath.value = [...path];
|
|
2035
|
-
if (hasItemSubmenu(item)) openSubmenu(path, false, point);
|
|
2036
|
-
else closeSubmenusAfter(getParentPath(path));
|
|
2037
|
-
}
|
|
2038
|
-
function focusHoveredItem(item, indexOrPath, event) {
|
|
2039
|
-
if (item.disabled) return;
|
|
2040
|
-
const path = normalizePath(indexOrPath);
|
|
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
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
function onMenuKeydown(event) {
|
|
2074
|
-
hoverIntent.resetHoverIntent();
|
|
2075
|
-
if (handleTypeahead(event)) return;
|
|
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
|
-
}
|
|
2493
|
+
if (pendingHoverTimer !== void 0) window.clearTimeout(pendingHoverTimer);
|
|
2494
|
+
pendingHoverTimer = window.setTimeout(() => {
|
|
2495
|
+
if (!pendingHover) return;
|
|
2496
|
+
const nextHover = pendingHover;
|
|
2497
|
+
if (latestPointerPoint && isPointInCurrentSubmenu(latestPointerPoint)) {
|
|
2498
|
+
clearPendingHover();
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2501
|
+
commit(nextHover.item, nextHover.path);
|
|
2502
|
+
}, SAFE_TRIANGLE_TIMEOUT);
|
|
2110
2503
|
}
|
|
2111
|
-
function
|
|
2112
|
-
const
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
event.preventDefault();
|
|
2117
|
-
closeSubmenu(closePath);
|
|
2504
|
+
function handleItemHover(item, path, event, commit) {
|
|
2505
|
+
const point = event ? getClientPoint(event) : void 0;
|
|
2506
|
+
latestPointerPoint = point ?? latestPointerPoint;
|
|
2507
|
+
if (point && shouldDelayHover(path, point)) {
|
|
2508
|
+
delayHoveredItem(item, path, commit);
|
|
2118
2509
|
return;
|
|
2119
2510
|
}
|
|
2120
|
-
|
|
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);
|
|
2511
|
+
commit(item, path, point);
|
|
2128
2512
|
}
|
|
2129
|
-
function
|
|
2130
|
-
|
|
2513
|
+
function handleMenuMousemove(event, commit) {
|
|
2514
|
+
const point = getClientPoint(event);
|
|
2515
|
+
latestPointerPoint = point;
|
|
2516
|
+
updateSafeTriangleOrigin(point);
|
|
2517
|
+
if (!pendingHover) return;
|
|
2518
|
+
if (shouldDelayHover(pendingHover.path, point)) return;
|
|
2519
|
+
const nextHover = pendingHover;
|
|
2520
|
+
commit(nextHover.item, nextHover.path, point);
|
|
2131
2521
|
}
|
|
2522
|
+
onUnmounted(clearPendingHover);
|
|
2132
2523
|
return {
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
onTriggerClick,
|
|
2139
|
-
onTriggerKeydown,
|
|
2140
|
-
onMenuKeydown,
|
|
2141
|
-
onMenuMousemove,
|
|
2142
|
-
onMenuMouseleave
|
|
2524
|
+
clearPendingHover,
|
|
2525
|
+
resetHoverIntent,
|
|
2526
|
+
trackSubmenuOpen,
|
|
2527
|
+
handleItemHover,
|
|
2528
|
+
handleMenuMousemove
|
|
2143
2529
|
};
|
|
2144
2530
|
}
|
|
2145
2531
|
//#endregion
|
|
2146
|
-
//#region src/components/dropdown-menu/
|
|
2147
|
-
function
|
|
2148
|
-
|
|
2532
|
+
//#region src/components/dropdown-menu/useDropdownMenuDataController.ts
|
|
2533
|
+
function useDropdownMenuDataController({ props, items, rootMenuId, menuId, menuRef, actualPlacement, interaction, rootMenu, onSelect }) {
|
|
2534
|
+
function getItemId(path) {
|
|
2535
|
+
return `${menuId.value}-item-${getPathKey(path)}`;
|
|
2536
|
+
}
|
|
2537
|
+
function getSubmenuId(path) {
|
|
2538
|
+
return `${menuId.value}-submenu-${getPathKey(path)}`;
|
|
2539
|
+
}
|
|
2540
|
+
function getItemElement(path) {
|
|
2541
|
+
return typeof document === "undefined" ? null : document.getElementById(getItemId(path));
|
|
2542
|
+
}
|
|
2543
|
+
function getSubmenuElement(path) {
|
|
2544
|
+
return typeof document === "undefined" ? null : document.getElementById(getSubmenuId(path));
|
|
2545
|
+
}
|
|
2546
|
+
function isSubmenuOpeningLeft(path) {
|
|
2547
|
+
const submenuRect = getSubmenuElement(path)?.getBoundingClientRect();
|
|
2548
|
+
const itemRect = getItemElement(path)?.getBoundingClientRect();
|
|
2549
|
+
if (submenuRect && itemRect && hasMeasuredRect(submenuRect) && hasMeasuredRect(itemRect)) return submenuRect.right <= itemRect.left;
|
|
2550
|
+
return actualPlacement.value.endsWith("end");
|
|
2551
|
+
}
|
|
2552
|
+
const { openMenuIds, registrationIndex, getItemInteraction, getMenuInteraction } = useDropdownMenuDataRegistration({
|
|
2553
|
+
props,
|
|
2554
|
+
items,
|
|
2555
|
+
rootMenuId,
|
|
2556
|
+
interaction,
|
|
2557
|
+
rootMenu,
|
|
2558
|
+
menuRef,
|
|
2559
|
+
getItemElement,
|
|
2560
|
+
getSubmenuElement,
|
|
2561
|
+
isSubmenuOpeningLeft,
|
|
2562
|
+
onSelect
|
|
2563
|
+
});
|
|
2564
|
+
function getDataItemId(path) {
|
|
2565
|
+
return registrationIndex.value.itemIdByPath.get(getPathKey(path));
|
|
2566
|
+
}
|
|
2567
|
+
const focusedPath = computed({
|
|
2568
|
+
get() {
|
|
2569
|
+
const id = interaction.activeItemId.value;
|
|
2570
|
+
return id ? [...registrationIndex.value.pathByItemId.get(id) ?? []] : [];
|
|
2571
|
+
},
|
|
2572
|
+
set(path) {
|
|
2573
|
+
const itemId = path.length > 0 ? getDataItemId(path) : void 0;
|
|
2574
|
+
if (itemId) getItemInteraction(itemId)?.setActive();
|
|
2575
|
+
else rootMenu.clearActive();
|
|
2576
|
+
}
|
|
2577
|
+
});
|
|
2149
2578
|
const focusedIndex = computed(() => focusedPath.value[0] ?? -1);
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2579
|
+
const activeDescendantId = computed(() => focusedPath.value.length === 0 ? void 0 : getItemId(focusedPath.value));
|
|
2580
|
+
const openSubmenuPath = computed(() => {
|
|
2581
|
+
let deepest = [];
|
|
2582
|
+
for (const id of openMenuIds.value) {
|
|
2583
|
+
const path = registrationIndex.value.pathByMenuId.get(id);
|
|
2584
|
+
if (path && path.length > deepest.length) deepest = path;
|
|
2156
2585
|
}
|
|
2157
|
-
return
|
|
2586
|
+
return [...deepest];
|
|
2587
|
+
});
|
|
2588
|
+
function isItemFocused(indexOrPath) {
|
|
2589
|
+
const id = getDataItemId(normalizePath(indexOrPath));
|
|
2590
|
+
return Boolean(id && interaction.activeItemId.value === id);
|
|
2158
2591
|
}
|
|
2159
|
-
function
|
|
2160
|
-
|
|
2161
|
-
return
|
|
2592
|
+
function isSubmenuOpen(path) {
|
|
2593
|
+
const itemId = getDataItemId(path);
|
|
2594
|
+
return itemId ? getItemInteraction(itemId)?.submenuOpen.value ?? false : false;
|
|
2162
2595
|
}
|
|
2163
|
-
function
|
|
2164
|
-
const
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
if (menuPath.length === 0) focusedPath.value = [];
|
|
2168
|
-
return false;
|
|
2169
|
-
}
|
|
2170
|
-
focusedPath.value = [...menuPath, index];
|
|
2596
|
+
function openSubmenu(path, focus = DEFAULT_FOCUS_TARGET, point) {
|
|
2597
|
+
const itemId = getDataItemId(path);
|
|
2598
|
+
if (!(itemId ? getItemInteraction(itemId) : void 0)?.openSubmenu(focus)) return false;
|
|
2599
|
+
hoverIntent.trackSubmenuOpen(path, point);
|
|
2171
2600
|
return true;
|
|
2172
2601
|
}
|
|
2173
|
-
function
|
|
2174
|
-
|
|
2602
|
+
function closeSubmenu(path) {
|
|
2603
|
+
const itemId = getDataItemId(path);
|
|
2604
|
+
const closed = itemId ? getItemInteraction(itemId)?.closeSubmenu(false) ?? false : false;
|
|
2605
|
+
if (closed) hoverIntent.resetHoverIntent();
|
|
2606
|
+
return closed;
|
|
2175
2607
|
}
|
|
2176
|
-
function
|
|
2177
|
-
const
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2608
|
+
function commitHoveredItem(item, path, point) {
|
|
2609
|
+
const itemId = getDataItemId(path);
|
|
2610
|
+
const itemInteraction = itemId ? getItemInteraction(itemId) : void 0;
|
|
2611
|
+
if (!itemInteraction) return;
|
|
2612
|
+
hoverIntent.clearPendingHover();
|
|
2613
|
+
const hasSubmenu = hasItemSubmenu(item);
|
|
2614
|
+
const opened = itemInteraction.hover(hasSubmenu);
|
|
2615
|
+
if (hasSubmenu && opened) hoverIntent.trackSubmenuOpen(path, point);
|
|
2181
2616
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2617
|
+
const hoverIntent = useDropdownMenuHoverIntent({
|
|
2618
|
+
openSubmenuPath,
|
|
2619
|
+
getItemElement,
|
|
2620
|
+
getSubmenuElement
|
|
2621
|
+
});
|
|
2622
|
+
function focusHoveredItem(item, indexOrPath, event) {
|
|
2623
|
+
if (item.disabled) return;
|
|
2624
|
+
hoverIntent.handleItemHover(item, normalizePath(indexOrPath), event, commitHoveredItem);
|
|
2625
|
+
}
|
|
2626
|
+
function selectItem(item, originalEvent = new Event("select")) {
|
|
2627
|
+
const id = registrationIndex.value.primaryItemId.get(item);
|
|
2628
|
+
if (id) getItemInteraction(id)?.select(originalEvent);
|
|
2629
|
+
}
|
|
2630
|
+
function activateItem(_item, path, event) {
|
|
2631
|
+
const id = getDataItemId(path);
|
|
2632
|
+
if (id) getItemInteraction(id)?.activate(event);
|
|
2633
|
+
}
|
|
2634
|
+
function getMenuActiveDescendant(path) {
|
|
2635
|
+
const pathKey = getPathKey(path);
|
|
2636
|
+
const activeId = getMenuInteraction(registrationIndex.value.menuIdByPath.get(pathKey) ?? rootMenuId)?.activeId.value;
|
|
2637
|
+
const activePath = activeId ? registrationIndex.value.pathByItemId.get(activeId) : void 0;
|
|
2638
|
+
return activePath ? getItemId(activePath) : void 0;
|
|
2195
2639
|
}
|
|
2196
2640
|
return {
|
|
2197
2641
|
focusedPath,
|
|
2198
2642
|
focusedIndex,
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2643
|
+
activeDescendantId,
|
|
2644
|
+
getItemId,
|
|
2645
|
+
getSubmenuId,
|
|
2646
|
+
getItemElement,
|
|
2647
|
+
getMenuActiveDescendant,
|
|
2204
2648
|
isItemFocused,
|
|
2205
|
-
|
|
2649
|
+
isSubmenuOpen,
|
|
2650
|
+
openSubmenu,
|
|
2651
|
+
closeSubmenu,
|
|
2652
|
+
focusHoveredItem,
|
|
2653
|
+
onMenuMousemove: (event) => hoverIntent.handleMenuMousemove(event, commitHoveredItem),
|
|
2654
|
+
resetHoverIntent: hoverIntent.resetHoverIntent,
|
|
2655
|
+
selectItem,
|
|
2656
|
+
activateItem
|
|
2206
2657
|
};
|
|
2207
2658
|
}
|
|
2208
2659
|
//#endregion
|
|
@@ -2220,8 +2671,7 @@ function useDropdownMenuPortalPosition(options) {
|
|
|
2220
2671
|
flipOptions: () => options.props.flipOptions,
|
|
2221
2672
|
shift: () => options.props.shift !== false,
|
|
2222
2673
|
collisionPadding: () => options.props.collisionPadding ?? 8,
|
|
2223
|
-
autoUpdateOptions: () => options.props.autoUpdateOptions
|
|
2224
|
-
restartKey: options.restartKey
|
|
2674
|
+
autoUpdateOptions: () => options.props.autoUpdateOptions
|
|
2225
2675
|
});
|
|
2226
2676
|
return {
|
|
2227
2677
|
actualPlacement: floating.actualPlacement,
|
|
@@ -2230,6 +2680,52 @@ function useDropdownMenuPortalPosition(options) {
|
|
|
2230
2680
|
};
|
|
2231
2681
|
}
|
|
2232
2682
|
//#endregion
|
|
2683
|
+
//#region src/components/dropdown-menu/useDropdownMenuPresentation.ts
|
|
2684
|
+
function useDropdownMenuPresentation({ props, menuId, isDisabled, isVisible, isExplicitTarget, actualPlacement, contentHasSubmenu, activeDescendantId, interaction, resetHoverIntent, onMenuMousemove, open, close, toggle }) {
|
|
2685
|
+
const rootClass = computed(() => bem("rp-dropdown-menu", {
|
|
2686
|
+
[`placement-${actualPlacement.value}`]: true,
|
|
2687
|
+
target: isExplicitTarget.value,
|
|
2688
|
+
open: isVisible.value,
|
|
2689
|
+
disabled: isDisabled.value
|
|
2690
|
+
}));
|
|
2691
|
+
const contentClass = computed(() => bem("rp-dropdown-menu__content", { "has-submenu": contentHasSubmenu.value }));
|
|
2692
|
+
const triggerProps = computed(() => ({
|
|
2693
|
+
"aria-controls": isDisabled.value ? void 0 : menuId.value,
|
|
2694
|
+
"aria-expanded": isDisabled.value ? void 0 : isVisible.value,
|
|
2695
|
+
"aria-haspopup": "menu",
|
|
2696
|
+
disabled: isDisabled.value || void 0,
|
|
2697
|
+
onClick: () => interaction.onTriggerClick(),
|
|
2698
|
+
onKeydown: (event) => interaction.onTriggerKeydown(event)
|
|
2699
|
+
}));
|
|
2700
|
+
function onMenuKeydown(event) {
|
|
2701
|
+
resetHoverIntent();
|
|
2702
|
+
interaction.onMenuKeydown(event);
|
|
2703
|
+
}
|
|
2704
|
+
return {
|
|
2705
|
+
rootClass,
|
|
2706
|
+
contentClass,
|
|
2707
|
+
triggerProps,
|
|
2708
|
+
contentProps: computed(() => ({
|
|
2709
|
+
id: menuId.value,
|
|
2710
|
+
role: "menu",
|
|
2711
|
+
tabindex: -1,
|
|
2712
|
+
"aria-label": props.ariaLabel || void 0,
|
|
2713
|
+
"aria-activedescendant": activeDescendantId.value,
|
|
2714
|
+
onKeydown: onMenuKeydown,
|
|
2715
|
+
onMousemove: onMenuMousemove,
|
|
2716
|
+
onMouseleave: resetHoverIntent
|
|
2717
|
+
})),
|
|
2718
|
+
slotProps: computed(() => ({
|
|
2719
|
+
triggerProps: triggerProps.value,
|
|
2720
|
+
isOpen: isVisible.value,
|
|
2721
|
+
open,
|
|
2722
|
+
close,
|
|
2723
|
+
toggle
|
|
2724
|
+
})),
|
|
2725
|
+
onMenuKeydown
|
|
2726
|
+
};
|
|
2727
|
+
}
|
|
2728
|
+
//#endregion
|
|
2233
2729
|
//#region src/components/dropdown-menu/useDropdownMenuRenderItems.ts
|
|
2234
2730
|
function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId, getSubmenuId, getMenuActiveDescendant, getItemElement, isItemFocused, isSubmenuOpen, activateItem, focusHoveredItem, selectItem, openSubmenu, closeSubmenu, close }) {
|
|
2235
2731
|
const renderedItems = computed(() => getRenderedItems(items.value));
|
|
@@ -2272,9 +2768,9 @@ function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId,
|
|
|
2272
2768
|
"aria-expanded": hasSubmenu ? resolvedSubmenuOpen : void 0,
|
|
2273
2769
|
"aria-haspopup": hasSubmenu ? "menu" : void 0,
|
|
2274
2770
|
"aria-disabled": disabled || void 0,
|
|
2275
|
-
"data-disabled": disabled
|
|
2276
|
-
"data-highlighted": focused
|
|
2277
|
-
"data-submenu": hasSubmenu
|
|
2771
|
+
"data-disabled": toPresenceAttribute(disabled),
|
|
2772
|
+
"data-highlighted": toPresenceAttribute(focused),
|
|
2773
|
+
"data-submenu": toPresenceAttribute(hasSubmenu),
|
|
2278
2774
|
onClick: (event) => activateItem(item, path, event),
|
|
2279
2775
|
onMouseenter: (event) => focusHoveredItem(item, path, event)
|
|
2280
2776
|
};
|
|
@@ -2332,45 +2828,53 @@ function useDropdownMenuRenderItems({ props, actualPlacement, items, getItemId,
|
|
|
2332
2828
|
};
|
|
2333
2829
|
}
|
|
2334
2830
|
//#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
|
-
|
|
2831
|
+
//#region src/components/dropdown-menu/useDropdownMenuTargetBindings.ts
|
|
2832
|
+
var TARGET_ATTRIBUTES = [
|
|
2833
|
+
"aria-controls",
|
|
2834
|
+
"aria-expanded",
|
|
2835
|
+
"aria-haspopup",
|
|
2836
|
+
"aria-disabled"
|
|
2837
|
+
];
|
|
2838
|
+
function syncTargetAttributes(target, id, visible, disabled) {
|
|
2839
|
+
if (disabled) {
|
|
2840
|
+
target.removeAttribute("aria-controls");
|
|
2841
|
+
target.removeAttribute("aria-expanded");
|
|
2842
|
+
target.removeAttribute("aria-haspopup");
|
|
2843
|
+
target.setAttribute("aria-disabled", "true");
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
target.setAttribute("aria-controls", id);
|
|
2847
|
+
target.setAttribute("aria-expanded", String(visible));
|
|
2848
|
+
target.setAttribute("aria-haspopup", "menu");
|
|
2849
|
+
target.removeAttribute("aria-disabled");
|
|
2850
|
+
}
|
|
2851
|
+
function useDropdownMenuTargetBindings({ interaction, rootRef, menuRef, targetLifecycle, menuId, isVisible, isDisabled, ignoredTargets, pointerDownOutside, focusOutside, interactOutside }) {
|
|
2852
|
+
function watchInside(source) {
|
|
2853
|
+
watch(source, (element, _previous, onCleanup) => {
|
|
2854
|
+
if (element) onCleanup(interaction.connectInside(element));
|
|
2855
|
+
}, { immediate: true });
|
|
2856
|
+
}
|
|
2857
|
+
watchInside(rootRef);
|
|
2858
|
+
watchInside(menuRef);
|
|
2859
|
+
const cleanupDismissal = interaction.connectDismissal({
|
|
2860
|
+
ignoredTargets,
|
|
2861
|
+
pointerDownOutside,
|
|
2862
|
+
focusOutside,
|
|
2863
|
+
interactOutside
|
|
2864
|
+
});
|
|
2865
|
+
const onClick = () => interaction.onTriggerClick();
|
|
2866
|
+
const onKeydown = (event) => interaction.onTriggerKeydown(event);
|
|
2867
|
+
targetLifecycle.bindTarget({
|
|
2868
|
+
connect: (target) => interaction.connectInside(target),
|
|
2869
|
+
listeners: [["click", onClick], ["keydown", onKeydown]],
|
|
2870
|
+
attributes: {
|
|
2871
|
+
names: TARGET_ATTRIBUTES,
|
|
2872
|
+
apply: (target) => {
|
|
2873
|
+
syncTargetAttributes(target, menuId.value, isVisible.value, isDisabled.value);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
});
|
|
2877
|
+
onBeforeUnmount(cleanupDismissal);
|
|
2374
2878
|
}
|
|
2375
2879
|
//#endregion
|
|
2376
2880
|
//#region src/components/dropdown-menu/useDropdownMenu.ts
|
|
@@ -2378,21 +2882,25 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2378
2882
|
const rootRef = ref(null);
|
|
2379
2883
|
const menuRef = ref(null);
|
|
2380
2884
|
const arrowRef = ref(null);
|
|
2885
|
+
const generatedId = useId();
|
|
2886
|
+
const interactionRootMenuId = `${generatedId}-interaction-root`;
|
|
2381
2887
|
const controllableOpen = useControllableValue({
|
|
2382
2888
|
modelValue: () => props.open,
|
|
2383
2889
|
defaultValue: () => false,
|
|
2384
2890
|
onChange: (open) => emit.openChange?.(open)
|
|
2385
2891
|
});
|
|
2386
|
-
const generatedId = useId();
|
|
2387
2892
|
const menuId = computed(() => props.id ?? `${generatedId}-menu`);
|
|
2388
2893
|
const placement = computed(() => props.placement ?? "bottom-start");
|
|
2389
2894
|
const teleportTo = useTeleportTarget(() => props.teleportTo);
|
|
2390
|
-
const teleportPositioningKey = useTeleportPositioningKey();
|
|
2391
2895
|
const shouldTeleport = computed(() => props.teleport !== false);
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2896
|
+
const targetLifecycle = useFloatingTargetLifecycle({
|
|
2897
|
+
target: () => props.target,
|
|
2898
|
+
fallback: rootRef
|
|
2899
|
+
});
|
|
2900
|
+
const { isExplicitTarget, reference, targetElement } = targetLifecycle;
|
|
2394
2901
|
const visibleItems = computed(() => props.items ?? []);
|
|
2395
2902
|
const isDisabled = computed(() => Boolean(props.disabled));
|
|
2903
|
+
const modal = computed(() => Boolean(props.modal));
|
|
2396
2904
|
const isOpen = controllableOpen.value;
|
|
2397
2905
|
const isVisible = computed(() => isOpen.value && !isDisabled.value);
|
|
2398
2906
|
const layer = useOverlayLayer({
|
|
@@ -2412,173 +2920,104 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2412
2920
|
menuRef,
|
|
2413
2921
|
arrowRef,
|
|
2414
2922
|
isVisible,
|
|
2415
|
-
placement
|
|
2416
|
-
restartKey: () => [
|
|
2417
|
-
shouldTeleport.value,
|
|
2418
|
-
teleportTo.value,
|
|
2419
|
-
teleportPositioningKey.value
|
|
2420
|
-
]
|
|
2923
|
+
placement
|
|
2421
2924
|
});
|
|
2422
2925
|
const placementSide = computed(() => actualPlacement.value.split("-")[0]);
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2926
|
+
function focusTrigger() {
|
|
2927
|
+
nextTick(() => {
|
|
2928
|
+
if (targetElement.value instanceof HTMLElement) {
|
|
2929
|
+
targetElement.value.focus();
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
rootRef.value?.querySelector("[aria-haspopup=\"menu\"]")?.focus();
|
|
2933
|
+
});
|
|
2934
|
+
}
|
|
2935
|
+
function setOpen(nextOpen) {
|
|
2936
|
+
if (nextOpen && isDisabled.value) return;
|
|
2937
|
+
if (isOpen.value !== nextOpen) controllableOpen.setValue(nextOpen);
|
|
2938
|
+
}
|
|
2939
|
+
let resetHoverIntent;
|
|
2940
|
+
const interaction = useDropdownMenuInteraction({
|
|
2941
|
+
rootMenuId: interactionRootMenuId,
|
|
2942
|
+
isOpen: isVisible,
|
|
2943
|
+
disabled: isDisabled,
|
|
2944
|
+
modal,
|
|
2945
|
+
setOpen,
|
|
2946
|
+
connectLayerInteraction: layer.connectInteraction,
|
|
2947
|
+
focusTrigger,
|
|
2948
|
+
beforeOpen: () => resetHoverIntent(),
|
|
2949
|
+
beforeClose: () => resetHoverIntent()
|
|
2428
2950
|
});
|
|
2429
|
-
const
|
|
2430
|
-
const
|
|
2431
|
-
const
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
getTextValue: (item) => item.label,
|
|
2436
|
-
isDisabled: (item) => Boolean(item.disabled),
|
|
2437
|
-
scopeKey: () => activeMenuPath.value.join("/"),
|
|
2438
|
-
onMatch(_item, index) {
|
|
2439
|
-
const menuPath = activeMenuPath.value;
|
|
2440
|
-
if (setFocusedIndex(index, menuPath)) submenus.closeSubmenusAfter(menuPath);
|
|
2441
|
-
}
|
|
2951
|
+
const open = interaction.open;
|
|
2952
|
+
const close = (options = {}) => interaction.close(options);
|
|
2953
|
+
const toggle = interaction.toggle;
|
|
2954
|
+
const rootMenu = interaction.connectRootMenu({
|
|
2955
|
+
element: () => menuRef.value,
|
|
2956
|
+
placement: () => actualPlacement.value
|
|
2442
2957
|
});
|
|
2443
|
-
const
|
|
2958
|
+
const dataController = useDropdownMenuDataController({
|
|
2959
|
+
props,
|
|
2960
|
+
items: visibleItems,
|
|
2961
|
+
rootMenuId: interactionRootMenuId,
|
|
2444
2962
|
menuId,
|
|
2445
|
-
rootRef,
|
|
2446
2963
|
menuRef,
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
const hoverIntent = useDropdownMenuHoverIntent({
|
|
2452
|
-
openSubmenuPath,
|
|
2453
|
-
getItemElement,
|
|
2454
|
-
getSubmenuElement
|
|
2964
|
+
actualPlacement,
|
|
2965
|
+
interaction,
|
|
2966
|
+
rootMenu,
|
|
2967
|
+
onSelect: (item, event) => emit.select?.(item, event)
|
|
2455
2968
|
});
|
|
2456
|
-
|
|
2969
|
+
resetHoverIntent = dataController.resetHoverIntent;
|
|
2970
|
+
const { renderedItems, renderContext, getItemProps, getItemSlotProps } = useDropdownMenuRenderItems({
|
|
2457
2971
|
props,
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
focusTrigger,
|
|
2473
|
-
layer
|
|
2972
|
+
actualPlacement,
|
|
2973
|
+
items: visibleItems,
|
|
2974
|
+
getItemId: dataController.getItemId,
|
|
2975
|
+
getSubmenuId: dataController.getSubmenuId,
|
|
2976
|
+
getMenuActiveDescendant: dataController.getMenuActiveDescendant,
|
|
2977
|
+
getItemElement: dataController.getItemElement,
|
|
2978
|
+
isItemFocused: dataController.isItemFocused,
|
|
2979
|
+
isSubmenuOpen: dataController.isSubmenuOpen,
|
|
2980
|
+
activateItem: dataController.activateItem,
|
|
2981
|
+
focusHoveredItem: dataController.focusHoveredItem,
|
|
2982
|
+
selectItem: dataController.selectItem,
|
|
2983
|
+
openSubmenu: dataController.openSubmenu,
|
|
2984
|
+
closeSubmenu: dataController.closeSubmenu,
|
|
2985
|
+
close
|
|
2474
2986
|
});
|
|
2475
|
-
const
|
|
2476
|
-
const { activateItem, selectItem, openSubmenu, closeSubmenu, focusHoveredItem, onTriggerClick, onTriggerKeydown, onMenuKeydown, onMenuMousemove, onMenuMouseleave } = useDropdownMenuInteractions({
|
|
2987
|
+
const presentation = useDropdownMenuPresentation({
|
|
2477
2988
|
props,
|
|
2478
|
-
|
|
2989
|
+
menuId,
|
|
2479
2990
|
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,
|
|
2991
|
+
isVisible,
|
|
2992
|
+
isExplicitTarget,
|
|
2993
|
+
actualPlacement,
|
|
2994
|
+
contentHasSubmenu,
|
|
2995
|
+
activeDescendantId: dataController.activeDescendantId,
|
|
2996
|
+
interaction,
|
|
2997
|
+
resetHoverIntent,
|
|
2998
|
+
onMenuMousemove: dataController.onMenuMousemove,
|
|
2519
2999
|
open,
|
|
2520
3000
|
close,
|
|
2521
3001
|
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
3002
|
});
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
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,
|
|
2554
|
-
targetElement,
|
|
3003
|
+
useDropdownMenuTargetBindings({
|
|
3004
|
+
interaction,
|
|
3005
|
+
rootRef,
|
|
3006
|
+
menuRef,
|
|
3007
|
+
targetLifecycle,
|
|
2555
3008
|
menuId,
|
|
2556
3009
|
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" });
|
|
3010
|
+
isDisabled,
|
|
3011
|
+
ignoredTargets: () => props.ignore ?? [],
|
|
3012
|
+
pointerDownOutside: emit.pointerDownOutside,
|
|
3013
|
+
focusOutside: emit.focusOutside,
|
|
3014
|
+
interactOutside: emit.interactOutside
|
|
3015
|
+
});
|
|
3016
|
+
const layeredContentStyle = computed(() => ({
|
|
3017
|
+
...contentStyle.value,
|
|
3018
|
+
zIndex: layer.zIndex.value
|
|
3019
|
+
}));
|
|
3020
|
+
onBeforeUnmount(rootMenu.dispose);
|
|
2582
3021
|
return {
|
|
2583
3022
|
rootRef,
|
|
2584
3023
|
menuRef,
|
|
@@ -2589,33 +3028,30 @@ function useDropdownMenu(props, emit = {}) {
|
|
|
2589
3028
|
visibleItems,
|
|
2590
3029
|
renderedItems,
|
|
2591
3030
|
renderContext,
|
|
2592
|
-
focusedIndex,
|
|
2593
|
-
focusedPath,
|
|
2594
|
-
activeDescendantId,
|
|
2595
|
-
rootClass,
|
|
2596
|
-
contentClass,
|
|
2597
|
-
contentStyle:
|
|
2598
|
-
...contentStyle.value,
|
|
2599
|
-
zIndex: layer.zIndex.value
|
|
2600
|
-
})),
|
|
3031
|
+
focusedIndex: dataController.focusedIndex,
|
|
3032
|
+
focusedPath: dataController.focusedPath,
|
|
3033
|
+
activeDescendantId: dataController.activeDescendantId,
|
|
3034
|
+
rootClass: presentation.rootClass,
|
|
3035
|
+
contentClass: presentation.contentClass,
|
|
3036
|
+
contentStyle: layeredContentStyle,
|
|
2601
3037
|
arrowStyle,
|
|
2602
3038
|
actualPlacement,
|
|
2603
3039
|
placementSide,
|
|
2604
3040
|
isTargetMode: isExplicitTarget,
|
|
2605
3041
|
teleportTo,
|
|
2606
3042
|
shouldTeleport,
|
|
2607
|
-
triggerProps,
|
|
2608
|
-
contentProps,
|
|
2609
|
-
slotProps,
|
|
3043
|
+
triggerProps: presentation.triggerProps,
|
|
3044
|
+
contentProps: presentation.contentProps,
|
|
3045
|
+
slotProps: presentation.slotProps,
|
|
2610
3046
|
open,
|
|
2611
3047
|
close,
|
|
2612
3048
|
toggle,
|
|
2613
|
-
selectItem,
|
|
2614
|
-
openSubmenu,
|
|
2615
|
-
closeSubmenu,
|
|
2616
|
-
onItemMouseenter: focusHoveredItem,
|
|
2617
|
-
onTriggerKeydown,
|
|
2618
|
-
onMenuKeydown,
|
|
3049
|
+
selectItem: dataController.selectItem,
|
|
3050
|
+
openSubmenu: dataController.openSubmenu,
|
|
3051
|
+
closeSubmenu: dataController.closeSubmenu,
|
|
3052
|
+
onItemMouseenter: dataController.focusHoveredItem,
|
|
3053
|
+
onTriggerKeydown: (event) => interaction.onTriggerKeydown(event),
|
|
3054
|
+
onMenuKeydown: presentation.onMenuKeydown,
|
|
2619
3055
|
getItemProps,
|
|
2620
3056
|
getItemSlotProps
|
|
2621
3057
|
};
|
|
@@ -2701,12 +3137,17 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2701
3137
|
focusOutside: (event) => emit("focusOutside", event),
|
|
2702
3138
|
interactOutside: (event) => emit("interactOutside", event)
|
|
2703
3139
|
});
|
|
3140
|
+
const templateRefs = {
|
|
3141
|
+
root: rootRef,
|
|
3142
|
+
menu: menuRef,
|
|
3143
|
+
arrow: arrowRef
|
|
3144
|
+
};
|
|
2704
3145
|
const { getPartAttrs, getRootAttrs } = useStylesApi(props, "root");
|
|
2705
3146
|
const state = computed(() => isVisible.value ? "open" : "closed");
|
|
2706
3147
|
const rootAttrs = computed(() => getRootAttrs({
|
|
2707
3148
|
class: rootClass.value,
|
|
2708
3149
|
"data-state": state.value,
|
|
2709
|
-
"data-disabled":
|
|
3150
|
+
"data-disabled": toPresenceAttribute(props.disabled)
|
|
2710
3151
|
}));
|
|
2711
3152
|
const publicSlotProps = computed(() => {
|
|
2712
3153
|
const partAttrs = getPartAttrs("trigger");
|
|
@@ -2717,7 +3158,7 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2717
3158
|
...props.classNames?.trigger !== void 0 ? { class: partAttrs.class } : {},
|
|
2718
3159
|
...props.styles?.trigger !== void 0 ? { style: partAttrs.style } : {},
|
|
2719
3160
|
"data-state": state.value,
|
|
2720
|
-
"data-disabled":
|
|
3161
|
+
"data-disabled": toPresenceAttribute(props.disabled)
|
|
2721
3162
|
}
|
|
2722
3163
|
};
|
|
2723
3164
|
});
|
|
@@ -2753,10 +3194,10 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2753
3194
|
setInsertionState(n26, null, 0);
|
|
2754
3195
|
createIf(() => __props.arrow, () => {
|
|
2755
3196
|
const n7 = t0();
|
|
2756
|
-
_setTemplateRef(n7, arrowRef, null, "arrowRef");
|
|
2757
3197
|
renderEffect(() => {
|
|
2758
3198
|
setAttr(n7, "data-side", unref(placementSide));
|
|
2759
3199
|
setStyle(n7, unref(arrowStyle));
|
|
3200
|
+
_setTemplateRef(n7, templateRefs.arrow);
|
|
2760
3201
|
});
|
|
2761
3202
|
return n7;
|
|
2762
3203
|
});
|
|
@@ -2799,12 +3240,12 @@ var dropdown_menu_default = /* @__PURE__ */ defineVaporComponent({
|
|
|
2799
3240
|
return n23;
|
|
2800
3241
|
}, null, 129)];
|
|
2801
3242
|
}, { _: 8 }) });
|
|
2802
|
-
|
|
3243
|
+
setTemplateRefBinding(n26, () => templateRefs.menu, _setTemplateRef);
|
|
2803
3244
|
return n26;
|
|
2804
3245
|
}, null, 129);
|
|
2805
3246
|
}, { _: 8 }));
|
|
2806
3247
|
});
|
|
2807
|
-
|
|
3248
|
+
setTemplateRefBinding(n29, () => templateRefs.root);
|
|
2808
3249
|
return n29;
|
|
2809
3250
|
}
|
|
2810
3251
|
});
|