@react-aria/menu 3.16.0 → 3.18.0
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/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/useMenu.main.js +6 -5
- package/dist/useMenu.main.js.map +1 -1
- package/dist/useMenu.mjs +7 -5
- package/dist/useMenu.module.js +7 -5
- package/dist/useMenu.module.js.map +1 -1
- package/dist/useMenuItem.main.js +30 -11
- package/dist/useMenuItem.main.js.map +1 -1
- package/dist/useMenuItem.mjs +30 -11
- package/dist/useMenuItem.module.js +30 -11
- package/dist/useMenuItem.module.js.map +1 -1
- package/dist/useMenuTrigger.main.js +9 -4
- package/dist/useMenuTrigger.main.js.map +1 -1
- package/dist/useMenuTrigger.mjs +10 -5
- package/dist/useMenuTrigger.module.js +10 -5
- package/dist/useMenuTrigger.module.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.main.js +9 -1
- package/dist/useSafelyMouseToSubmenu.main.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.mjs +9 -1
- package/dist/useSafelyMouseToSubmenu.module.js +9 -1
- package/dist/useSafelyMouseToSubmenu.module.js.map +1 -1
- package/dist/useSubmenuTrigger.main.js +20 -14
- package/dist/useSubmenuTrigger.main.js.map +1 -1
- package/dist/useSubmenuTrigger.mjs +20 -14
- package/dist/useSubmenuTrigger.module.js +20 -14
- package/dist/useSubmenuTrigger.module.js.map +1 -1
- package/dist/utils.main.js +20 -0
- package/dist/utils.main.js.map +1 -0
- package/dist/utils.mjs +15 -0
- package/dist/utils.module.js +15 -0
- package/dist/utils.module.js.map +1 -0
- package/package.json +15 -15
- package/src/useMenu.ts +10 -12
- package/src/useMenuItem.ts +44 -13
- package/src/useMenuTrigger.ts +8 -4
- package/src/useSafelyMouseToSubmenu.ts +19 -2
- package/src/useSubmenuTrigger.ts +32 -14
- package/src/utils.ts +22 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSubmenuTrigger.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaMenuItemProps} from './useMenuItem';\nimport {AriaMenuOptions} from './useMenu';\nimport type {AriaPopoverProps, OverlayProps} from '@react-aria/overlays';\nimport {FocusableElement, FocusStrategy, KeyboardEvent, Node, PressEvent, RefObject} from '@react-types/shared';\nimport type {SubmenuTriggerState} from '@react-stately/menu';\nimport {useCallback, useRef} from 'react';\nimport {useEffectEvent, useId, useLayoutEffect} from '@react-aria/utils';\nimport {useLocale} from '@react-aria/i18n';\nimport {useSafelyMouseToSubmenu} from './useSafelyMouseToSubmenu';\n\nexport interface AriaSubmenuTriggerProps {\n /**\n * An object representing the submenu trigger menu item. Contains all the relevant information that makes up the menu item.\n * @deprecated\n */\n node?: Node<unknown>,\n /** Whether the submenu trigger is disabled. */\n isDisabled?: boolean,\n /** The type of the contents that the submenu trigger opens. */\n type?: 'dialog' | 'menu',\n /** Ref of the menu that contains the submenu trigger. */\n parentMenuRef: RefObject<HTMLElement | null>,\n /** Ref of the submenu opened by the submenu trigger. */\n submenuRef: RefObject<HTMLElement | null>,\n /**\n * The delay time in milliseconds for the submenu to appear after hovering over the trigger.\n * @default 200\n */\n delay?: number\n}\n\ninterface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {\n /** Whether the submenu trigger is in an expanded state. */\n isOpen: boolean\n}\n\ninterface SubmenuProps<T> extends AriaMenuOptions<T> {\n /** The level of the submenu. */\n submenuLevel: number\n}\n\nexport interface SubmenuTriggerAria<T> {\n /** Props for the submenu trigger menu item. */\n submenuTriggerProps: SubmenuTriggerProps,\n /** Props for the submenu controlled by the submenu trigger menu item. */\n submenuProps: SubmenuProps<T>,\n /** Props for the submenu's popover container. */\n popoverProps: Pick<AriaPopoverProps, 'isNonModal' | 'shouldCloseOnInteractOutside'> & Pick<OverlayProps, 'disableFocusManagement'>\n}\n\n/**\n * Provides the behavior and accessibility implementation for a submenu trigger and its associated submenu.\n * @param props - Props for the submenu trigger and refs attach to its submenu and parent menu.\n * @param state - State for the submenu trigger.\n * @param ref - Ref to the submenu trigger element.\n */\nexport function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: SubmenuTriggerState, ref: RefObject<FocusableElement | null>): SubmenuTriggerAria<T> {\n let {parentMenuRef, submenuRef, type = 'menu', isDisabled, delay = 200} = props;\n let submenuTriggerId = useId();\n let overlayId = useId();\n let {direction} = useLocale();\n let openTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let cancelOpenTimeout = useCallback(() => {\n if (openTimeout.current) {\n clearTimeout(openTimeout.current);\n openTimeout.current = undefined;\n }\n }, [openTimeout]);\n\n let onSubmenuOpen = useEffectEvent((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n });\n\n let onSubmenuClose = useEffectEvent(() => {\n cancelOpenTimeout();\n state.close();\n });\n\n useLayoutEffect(() => {\n return () => {\n cancelOpenTimeout();\n };\n }, [cancelOpenTimeout]);\n\n let submenuKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n ref.current?.focus();\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n ref.current?.focus();\n }\n break;\n case 'Escape':\n e.stopPropagation();\n state.closeAll();\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n submenuRef.current.focus();\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n submenuRef.current.focus();\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n case 'Escape':\n state.closeAll();\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n let onBlur = (e) => {\n if (state.isOpen && parentMenuRef.current?.contains(e.relatedTarget)) {\n onSubmenuClose();\n }\n };\n\n let shouldCloseOnInteractOutside = (target) => {\n if (target !== ref.current) {\n return true;\n }\n\n return false;\n };\n\n useSafelyMouseToSubmenu({menuRef: parentMenuRef, submenuRef, isOpen: state.isOpen, isDisabled: isDisabled});\n\n return {\n submenuTriggerProps: {\n id: submenuTriggerId,\n 'aria-controls': state.isOpen ? overlayId : undefined,\n 'aria-haspopup': !isDisabled ? type : undefined,\n 'aria-expanded': state.isOpen ? 'true' : 'false',\n onPressStart,\n onPress,\n onHoverChange,\n onKeyDown: submenuTriggerKeyDown,\n onBlur,\n isOpen: state.isOpen\n },\n submenuProps,\n popoverProps: {\n isNonModal: true,\n disableFocusManagement: true,\n shouldCloseOnInteractOutside\n }\n };\n}\n"],"names":[],"version":3,"file":"useSubmenuTrigger.main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSubmenuTrigger.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaMenuItemProps} from './useMenuItem';\nimport {AriaMenuOptions} from './useMenu';\nimport type {AriaPopoverProps, OverlayProps} from '@react-aria/overlays';\nimport {FocusableElement, FocusStrategy, KeyboardEvent, Node, PressEvent, RefObject} from '@react-types/shared';\nimport {focusWithoutScrolling, useEffectEvent, useId, useLayoutEffect} from '@react-aria/utils';\nimport type {SubmenuTriggerState} from '@react-stately/menu';\nimport {useCallback, useRef} from 'react';\nimport {useLocale} from '@react-aria/i18n';\nimport {useSafelyMouseToSubmenu} from './useSafelyMouseToSubmenu';\n\nexport interface AriaSubmenuTriggerProps {\n /**\n * An object representing the submenu trigger menu item. Contains all the relevant information that makes up the menu item.\n * @deprecated\n */\n node?: Node<unknown>,\n /** Whether the submenu trigger is disabled. */\n isDisabled?: boolean,\n /** The type of the contents that the submenu trigger opens. */\n type?: 'dialog' | 'menu',\n /** Ref of the menu that contains the submenu trigger. */\n parentMenuRef: RefObject<HTMLElement | null>,\n /** Ref of the submenu opened by the submenu trigger. */\n submenuRef: RefObject<HTMLElement | null>,\n /**\n * The delay time in milliseconds for the submenu to appear after hovering over the trigger.\n * @default 200\n */\n delay?: number,\n /** Whether the submenu trigger uses virtual focus. */\n shouldUseVirtualFocus?: boolean\n}\n\ninterface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {\n /** Whether the submenu trigger is in an expanded state. */\n isOpen: boolean\n}\n\ninterface SubmenuProps<T> extends AriaMenuOptions<T> {\n /** The level of the submenu. */\n submenuLevel: number\n}\n\nexport interface SubmenuTriggerAria<T> {\n /** Props for the submenu trigger menu item. */\n submenuTriggerProps: SubmenuTriggerProps,\n /** Props for the submenu controlled by the submenu trigger menu item. */\n submenuProps: SubmenuProps<T>,\n /** Props for the submenu's popover container. */\n popoverProps: Pick<AriaPopoverProps, 'isNonModal' | 'shouldCloseOnInteractOutside'> & Pick<OverlayProps, 'disableFocusManagement'>\n}\n\n/**\n * Provides the behavior and accessibility implementation for a submenu trigger and its associated submenu.\n * @param props - Props for the submenu trigger and refs attach to its submenu and parent menu.\n * @param state - State for the submenu trigger.\n * @param ref - Ref to the submenu trigger element.\n */\nexport function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: SubmenuTriggerState, ref: RefObject<FocusableElement | null>): SubmenuTriggerAria<T> {\n let {parentMenuRef, submenuRef, type = 'menu', isDisabled, delay = 200, shouldUseVirtualFocus} = props;\n let submenuTriggerId = useId();\n let overlayId = useId();\n let {direction} = useLocale();\n let openTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let cancelOpenTimeout = useCallback(() => {\n if (openTimeout.current) {\n clearTimeout(openTimeout.current);\n openTimeout.current = undefined;\n }\n }, [openTimeout]);\n\n let onSubmenuOpen = useEffectEvent((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n });\n\n let onSubmenuClose = useEffectEvent(() => {\n cancelOpenTimeout();\n state.close();\n });\n\n useLayoutEffect(() => {\n return () => {\n cancelOpenTimeout();\n };\n }, [cancelOpenTimeout]);\n\n let submenuKeyDown = (e: KeyboardEvent) => {\n // If focus is not within the menu, assume virtual focus is being used.\n // This means some other input element is also within the popover, so we shouldn't close the menu.\n if (!e.currentTarget.contains(document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'Escape':\n // TODO: can remove this when we fix collection event leaks\n if (submenuRef.current?.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n let onBlur = (e) => {\n if (state.isOpen && (parentMenuRef.current?.contains(e.relatedTarget))) {\n onSubmenuClose();\n }\n };\n\n let shouldCloseOnInteractOutside = (target) => {\n if (target !== ref.current) {\n return true;\n }\n\n return false;\n };\n\n useSafelyMouseToSubmenu({menuRef: parentMenuRef, submenuRef, isOpen: state.isOpen, isDisabled: isDisabled});\n\n return {\n submenuTriggerProps: {\n id: submenuTriggerId,\n 'aria-controls': state.isOpen ? overlayId : undefined,\n 'aria-haspopup': !isDisabled ? type : undefined,\n 'aria-expanded': state.isOpen ? 'true' : 'false',\n onPressStart,\n onPress,\n onHoverChange,\n onKeyDown: submenuTriggerKeyDown,\n onBlur,\n isOpen: state.isOpen\n },\n submenuProps,\n popoverProps: {\n isNonModal: true,\n shouldCloseOnInteractOutside\n }\n };\n}\n"],"names":[],"version":3,"file":"useSubmenuTrigger.main.js.map"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {useSafelyMouseToSubmenu as $d275435c250248f8$export$85ec83e04c95f50a} from "./useSafelyMouseToSubmenu.mjs";
|
|
2
|
+
import {useId as $dXlYe$useId, useEffectEvent as $dXlYe$useEffectEvent, useLayoutEffect as $dXlYe$useLayoutEffect, focusWithoutScrolling as $dXlYe$focusWithoutScrolling} from "@react-aria/utils";
|
|
2
3
|
import {useRef as $dXlYe$useRef, useCallback as $dXlYe$useCallback} from "react";
|
|
3
|
-
import {useId as $dXlYe$useId, useEffectEvent as $dXlYe$useEffectEvent, useLayoutEffect as $dXlYe$useLayoutEffect} from "@react-aria/utils";
|
|
4
4
|
import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
5
5
|
|
|
6
6
|
/*
|
|
@@ -18,7 +18,7 @@ import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
21
|
-
let { parentMenuRef: parentMenuRef, submenuRef: submenuRef, type: type = 'menu', isDisabled: isDisabled, delay: delay = 200 } = props;
|
|
21
|
+
let { parentMenuRef: parentMenuRef, submenuRef: submenuRef, type: type = 'menu', isDisabled: isDisabled, delay: delay = 200, shouldUseVirtualFocus: shouldUseVirtualFocus } = props;
|
|
22
22
|
let submenuTriggerId = (0, $dXlYe$useId)();
|
|
23
23
|
let overlayId = (0, $dXlYe$useId)();
|
|
24
24
|
let { direction: direction } = (0, $dXlYe$useLocale)();
|
|
@@ -47,26 +47,34 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
47
47
|
cancelOpenTimeout
|
|
48
48
|
]);
|
|
49
49
|
let submenuKeyDown = (e)=>{
|
|
50
|
+
// If focus is not within the menu, assume virtual focus is being used.
|
|
51
|
+
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
52
|
+
if (!e.currentTarget.contains(document.activeElement)) return;
|
|
50
53
|
switch(e.key){
|
|
51
54
|
case 'ArrowLeft':
|
|
52
55
|
if (direction === 'ltr' && e.currentTarget.contains(e.target)) {
|
|
53
|
-
|
|
56
|
+
e.preventDefault();
|
|
54
57
|
e.stopPropagation();
|
|
55
58
|
onSubmenuClose();
|
|
56
|
-
(
|
|
59
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
57
60
|
}
|
|
58
61
|
break;
|
|
59
62
|
case 'ArrowRight':
|
|
60
63
|
if (direction === 'rtl' && e.currentTarget.contains(e.target)) {
|
|
61
|
-
|
|
64
|
+
e.preventDefault();
|
|
62
65
|
e.stopPropagation();
|
|
63
66
|
onSubmenuClose();
|
|
64
|
-
(
|
|
67
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
65
68
|
}
|
|
66
69
|
break;
|
|
67
70
|
case 'Escape':
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
var _submenuRef_current;
|
|
72
|
+
// TODO: can remove this when we fix collection event leaks
|
|
73
|
+
if ((_submenuRef_current = submenuRef.current) === null || _submenuRef_current === void 0 ? void 0 : _submenuRef_current.contains(e.target)) {
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
onSubmenuClose();
|
|
76
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
77
|
+
}
|
|
70
78
|
break;
|
|
71
79
|
}
|
|
72
80
|
};
|
|
@@ -86,8 +94,9 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
86
94
|
case 'ArrowRight':
|
|
87
95
|
if (!isDisabled) {
|
|
88
96
|
if (direction === 'ltr') {
|
|
97
|
+
e.preventDefault();
|
|
89
98
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
90
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) submenuRef.current
|
|
99
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
91
100
|
} else if (state.isOpen) onSubmenuClose();
|
|
92
101
|
else e.continuePropagation();
|
|
93
102
|
}
|
|
@@ -95,15 +104,13 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
95
104
|
case 'ArrowLeft':
|
|
96
105
|
if (!isDisabled) {
|
|
97
106
|
if (direction === 'rtl') {
|
|
107
|
+
e.preventDefault();
|
|
98
108
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
99
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) submenuRef.current
|
|
109
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
100
110
|
} else if (state.isOpen) onSubmenuClose();
|
|
101
111
|
else e.continuePropagation();
|
|
102
112
|
}
|
|
103
113
|
break;
|
|
104
|
-
case 'Escape':
|
|
105
|
-
state.closeAll();
|
|
106
|
-
break;
|
|
107
114
|
default:
|
|
108
115
|
e.continuePropagation();
|
|
109
116
|
break;
|
|
@@ -157,7 +164,6 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
157
164
|
submenuProps: submenuProps,
|
|
158
165
|
popoverProps: {
|
|
159
166
|
isNonModal: true,
|
|
160
|
-
disableFocusManagement: true,
|
|
161
167
|
shouldCloseOnInteractOutside: shouldCloseOnInteractOutside
|
|
162
168
|
}
|
|
163
169
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {useSafelyMouseToSubmenu as $d275435c250248f8$export$85ec83e04c95f50a} from "./useSafelyMouseToSubmenu.module.js";
|
|
2
|
+
import {useId as $dXlYe$useId, useEffectEvent as $dXlYe$useEffectEvent, useLayoutEffect as $dXlYe$useLayoutEffect, focusWithoutScrolling as $dXlYe$focusWithoutScrolling} from "@react-aria/utils";
|
|
2
3
|
import {useRef as $dXlYe$useRef, useCallback as $dXlYe$useCallback} from "react";
|
|
3
|
-
import {useId as $dXlYe$useId, useEffectEvent as $dXlYe$useEffectEvent, useLayoutEffect as $dXlYe$useLayoutEffect} from "@react-aria/utils";
|
|
4
4
|
import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
5
5
|
|
|
6
6
|
/*
|
|
@@ -18,7 +18,7 @@ import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
21
|
-
let { parentMenuRef: parentMenuRef, submenuRef: submenuRef, type: type = 'menu', isDisabled: isDisabled, delay: delay = 200 } = props;
|
|
21
|
+
let { parentMenuRef: parentMenuRef, submenuRef: submenuRef, type: type = 'menu', isDisabled: isDisabled, delay: delay = 200, shouldUseVirtualFocus: shouldUseVirtualFocus } = props;
|
|
22
22
|
let submenuTriggerId = (0, $dXlYe$useId)();
|
|
23
23
|
let overlayId = (0, $dXlYe$useId)();
|
|
24
24
|
let { direction: direction } = (0, $dXlYe$useLocale)();
|
|
@@ -47,26 +47,34 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
47
47
|
cancelOpenTimeout
|
|
48
48
|
]);
|
|
49
49
|
let submenuKeyDown = (e)=>{
|
|
50
|
+
// If focus is not within the menu, assume virtual focus is being used.
|
|
51
|
+
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
52
|
+
if (!e.currentTarget.contains(document.activeElement)) return;
|
|
50
53
|
switch(e.key){
|
|
51
54
|
case 'ArrowLeft':
|
|
52
55
|
if (direction === 'ltr' && e.currentTarget.contains(e.target)) {
|
|
53
|
-
|
|
56
|
+
e.preventDefault();
|
|
54
57
|
e.stopPropagation();
|
|
55
58
|
onSubmenuClose();
|
|
56
|
-
(
|
|
59
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
57
60
|
}
|
|
58
61
|
break;
|
|
59
62
|
case 'ArrowRight':
|
|
60
63
|
if (direction === 'rtl' && e.currentTarget.contains(e.target)) {
|
|
61
|
-
|
|
64
|
+
e.preventDefault();
|
|
62
65
|
e.stopPropagation();
|
|
63
66
|
onSubmenuClose();
|
|
64
|
-
(
|
|
67
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
65
68
|
}
|
|
66
69
|
break;
|
|
67
70
|
case 'Escape':
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
var _submenuRef_current;
|
|
72
|
+
// TODO: can remove this when we fix collection event leaks
|
|
73
|
+
if ((_submenuRef_current = submenuRef.current) === null || _submenuRef_current === void 0 ? void 0 : _submenuRef_current.contains(e.target)) {
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
onSubmenuClose();
|
|
76
|
+
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
77
|
+
}
|
|
70
78
|
break;
|
|
71
79
|
}
|
|
72
80
|
};
|
|
@@ -86,8 +94,9 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
86
94
|
case 'ArrowRight':
|
|
87
95
|
if (!isDisabled) {
|
|
88
96
|
if (direction === 'ltr') {
|
|
97
|
+
e.preventDefault();
|
|
89
98
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
90
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) submenuRef.current
|
|
99
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
91
100
|
} else if (state.isOpen) onSubmenuClose();
|
|
92
101
|
else e.continuePropagation();
|
|
93
102
|
}
|
|
@@ -95,15 +104,13 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
95
104
|
case 'ArrowLeft':
|
|
96
105
|
if (!isDisabled) {
|
|
97
106
|
if (direction === 'rtl') {
|
|
107
|
+
e.preventDefault();
|
|
98
108
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
99
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) submenuRef.current
|
|
109
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && document.activeElement === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
100
110
|
} else if (state.isOpen) onSubmenuClose();
|
|
101
111
|
else e.continuePropagation();
|
|
102
112
|
}
|
|
103
113
|
break;
|
|
104
|
-
case 'Escape':
|
|
105
|
-
state.closeAll();
|
|
106
|
-
break;
|
|
107
114
|
default:
|
|
108
115
|
e.continuePropagation();
|
|
109
116
|
break;
|
|
@@ -157,7 +164,6 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
157
164
|
submenuProps: submenuProps,
|
|
158
165
|
popoverProps: {
|
|
159
166
|
isNonModal: true,
|
|
160
|
-
disableFocusManagement: true,
|
|
161
167
|
shouldCloseOnInteractOutside: shouldCloseOnInteractOutside
|
|
162
168
|
}
|
|
163
169
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSubmenuTrigger.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaMenuItemProps} from './useMenuItem';\nimport {AriaMenuOptions} from './useMenu';\nimport type {AriaPopoverProps, OverlayProps} from '@react-aria/overlays';\nimport {FocusableElement, FocusStrategy, KeyboardEvent, Node, PressEvent, RefObject} from '@react-types/shared';\nimport type {SubmenuTriggerState} from '@react-stately/menu';\nimport {useCallback, useRef} from 'react';\nimport {useEffectEvent, useId, useLayoutEffect} from '@react-aria/utils';\nimport {useLocale} from '@react-aria/i18n';\nimport {useSafelyMouseToSubmenu} from './useSafelyMouseToSubmenu';\n\nexport interface AriaSubmenuTriggerProps {\n /**\n * An object representing the submenu trigger menu item. Contains all the relevant information that makes up the menu item.\n * @deprecated\n */\n node?: Node<unknown>,\n /** Whether the submenu trigger is disabled. */\n isDisabled?: boolean,\n /** The type of the contents that the submenu trigger opens. */\n type?: 'dialog' | 'menu',\n /** Ref of the menu that contains the submenu trigger. */\n parentMenuRef: RefObject<HTMLElement | null>,\n /** Ref of the submenu opened by the submenu trigger. */\n submenuRef: RefObject<HTMLElement | null>,\n /**\n * The delay time in milliseconds for the submenu to appear after hovering over the trigger.\n * @default 200\n */\n delay?: number\n}\n\ninterface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {\n /** Whether the submenu trigger is in an expanded state. */\n isOpen: boolean\n}\n\ninterface SubmenuProps<T> extends AriaMenuOptions<T> {\n /** The level of the submenu. */\n submenuLevel: number\n}\n\nexport interface SubmenuTriggerAria<T> {\n /** Props for the submenu trigger menu item. */\n submenuTriggerProps: SubmenuTriggerProps,\n /** Props for the submenu controlled by the submenu trigger menu item. */\n submenuProps: SubmenuProps<T>,\n /** Props for the submenu's popover container. */\n popoverProps: Pick<AriaPopoverProps, 'isNonModal' | 'shouldCloseOnInteractOutside'> & Pick<OverlayProps, 'disableFocusManagement'>\n}\n\n/**\n * Provides the behavior and accessibility implementation for a submenu trigger and its associated submenu.\n * @param props - Props for the submenu trigger and refs attach to its submenu and parent menu.\n * @param state - State for the submenu trigger.\n * @param ref - Ref to the submenu trigger element.\n */\nexport function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: SubmenuTriggerState, ref: RefObject<FocusableElement | null>): SubmenuTriggerAria<T> {\n let {parentMenuRef, submenuRef, type = 'menu', isDisabled, delay = 200} = props;\n let submenuTriggerId = useId();\n let overlayId = useId();\n let {direction} = useLocale();\n let openTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let cancelOpenTimeout = useCallback(() => {\n if (openTimeout.current) {\n clearTimeout(openTimeout.current);\n openTimeout.current = undefined;\n }\n }, [openTimeout]);\n\n let onSubmenuOpen = useEffectEvent((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n });\n\n let onSubmenuClose = useEffectEvent(() => {\n cancelOpenTimeout();\n state.close();\n });\n\n useLayoutEffect(() => {\n return () => {\n cancelOpenTimeout();\n };\n }, [cancelOpenTimeout]);\n\n let submenuKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n ref.current?.focus();\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n ref.current?.focus();\n }\n break;\n case 'Escape':\n e.stopPropagation();\n state.closeAll();\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n submenuRef.current.focus();\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n submenuRef.current.focus();\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n case 'Escape':\n state.closeAll();\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n let onBlur = (e) => {\n if (state.isOpen && parentMenuRef.current?.contains(e.relatedTarget)) {\n onSubmenuClose();\n }\n };\n\n let shouldCloseOnInteractOutside = (target) => {\n if (target !== ref.current) {\n return true;\n }\n\n return false;\n };\n\n useSafelyMouseToSubmenu({menuRef: parentMenuRef, submenuRef, isOpen: state.isOpen, isDisabled: isDisabled});\n\n return {\n submenuTriggerProps: {\n id: submenuTriggerId,\n 'aria-controls': state.isOpen ? overlayId : undefined,\n 'aria-haspopup': !isDisabled ? type : undefined,\n 'aria-expanded': state.isOpen ? 'true' : 'false',\n onPressStart,\n onPress,\n onHoverChange,\n onKeyDown: submenuTriggerKeyDown,\n onBlur,\n isOpen: state.isOpen\n },\n submenuProps,\n popoverProps: {\n isNonModal: true,\n disableFocusManagement: true,\n shouldCloseOnInteractOutside\n }\n };\n}\n"],"names":[],"version":3,"file":"useSubmenuTrigger.module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSubmenuTrigger.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaMenuItemProps} from './useMenuItem';\nimport {AriaMenuOptions} from './useMenu';\nimport type {AriaPopoverProps, OverlayProps} from '@react-aria/overlays';\nimport {FocusableElement, FocusStrategy, KeyboardEvent, Node, PressEvent, RefObject} from '@react-types/shared';\nimport {focusWithoutScrolling, useEffectEvent, useId, useLayoutEffect} from '@react-aria/utils';\nimport type {SubmenuTriggerState} from '@react-stately/menu';\nimport {useCallback, useRef} from 'react';\nimport {useLocale} from '@react-aria/i18n';\nimport {useSafelyMouseToSubmenu} from './useSafelyMouseToSubmenu';\n\nexport interface AriaSubmenuTriggerProps {\n /**\n * An object representing the submenu trigger menu item. Contains all the relevant information that makes up the menu item.\n * @deprecated\n */\n node?: Node<unknown>,\n /** Whether the submenu trigger is disabled. */\n isDisabled?: boolean,\n /** The type of the contents that the submenu trigger opens. */\n type?: 'dialog' | 'menu',\n /** Ref of the menu that contains the submenu trigger. */\n parentMenuRef: RefObject<HTMLElement | null>,\n /** Ref of the submenu opened by the submenu trigger. */\n submenuRef: RefObject<HTMLElement | null>,\n /**\n * The delay time in milliseconds for the submenu to appear after hovering over the trigger.\n * @default 200\n */\n delay?: number,\n /** Whether the submenu trigger uses virtual focus. */\n shouldUseVirtualFocus?: boolean\n}\n\ninterface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {\n /** Whether the submenu trigger is in an expanded state. */\n isOpen: boolean\n}\n\ninterface SubmenuProps<T> extends AriaMenuOptions<T> {\n /** The level of the submenu. */\n submenuLevel: number\n}\n\nexport interface SubmenuTriggerAria<T> {\n /** Props for the submenu trigger menu item. */\n submenuTriggerProps: SubmenuTriggerProps,\n /** Props for the submenu controlled by the submenu trigger menu item. */\n submenuProps: SubmenuProps<T>,\n /** Props for the submenu's popover container. */\n popoverProps: Pick<AriaPopoverProps, 'isNonModal' | 'shouldCloseOnInteractOutside'> & Pick<OverlayProps, 'disableFocusManagement'>\n}\n\n/**\n * Provides the behavior and accessibility implementation for a submenu trigger and its associated submenu.\n * @param props - Props for the submenu trigger and refs attach to its submenu and parent menu.\n * @param state - State for the submenu trigger.\n * @param ref - Ref to the submenu trigger element.\n */\nexport function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: SubmenuTriggerState, ref: RefObject<FocusableElement | null>): SubmenuTriggerAria<T> {\n let {parentMenuRef, submenuRef, type = 'menu', isDisabled, delay = 200, shouldUseVirtualFocus} = props;\n let submenuTriggerId = useId();\n let overlayId = useId();\n let {direction} = useLocale();\n let openTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let cancelOpenTimeout = useCallback(() => {\n if (openTimeout.current) {\n clearTimeout(openTimeout.current);\n openTimeout.current = undefined;\n }\n }, [openTimeout]);\n\n let onSubmenuOpen = useEffectEvent((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n });\n\n let onSubmenuClose = useEffectEvent(() => {\n cancelOpenTimeout();\n state.close();\n });\n\n useLayoutEffect(() => {\n return () => {\n cancelOpenTimeout();\n };\n }, [cancelOpenTimeout]);\n\n let submenuKeyDown = (e: KeyboardEvent) => {\n // If focus is not within the menu, assume virtual focus is being used.\n // This means some other input element is also within the popover, so we shouldn't close the menu.\n if (!e.currentTarget.contains(document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'Escape':\n // TODO: can remove this when we fix collection event leaks\n if (submenuRef.current?.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n let onBlur = (e) => {\n if (state.isOpen && (parentMenuRef.current?.contains(e.relatedTarget))) {\n onSubmenuClose();\n }\n };\n\n let shouldCloseOnInteractOutside = (target) => {\n if (target !== ref.current) {\n return true;\n }\n\n return false;\n };\n\n useSafelyMouseToSubmenu({menuRef: parentMenuRef, submenuRef, isOpen: state.isOpen, isDisabled: isDisabled});\n\n return {\n submenuTriggerProps: {\n id: submenuTriggerId,\n 'aria-controls': state.isOpen ? overlayId : undefined,\n 'aria-haspopup': !isDisabled ? type : undefined,\n 'aria-expanded': state.isOpen ? 'true' : 'false',\n onPressStart,\n onPress,\n onHoverChange,\n onKeyDown: submenuTriggerKeyDown,\n onBlur,\n isOpen: state.isOpen\n },\n submenuProps,\n popoverProps: {\n isNonModal: true,\n shouldCloseOnInteractOutside\n }\n };\n}\n"],"names":[],"version":3,"file":"useSubmenuTrigger.module.js.map"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
function $parcel$export(e, n, v, s) {
|
|
3
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
$parcel$export(module.exports, "menuData", () => $815e346b11b84016$export$6f49b4016bfc8d56);
|
|
7
|
+
/*
|
|
8
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
9
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
11
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
14
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
15
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
16
|
+
* governing permissions and limitations under the License.
|
|
17
|
+
*/ const $815e346b11b84016$export$6f49b4016bfc8d56 = new WeakMap();
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=utils.main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;;;;AAAA;;;;;;;;;;CAUC,GAWM,MAAM,4CAAW,IAAI","sources":["packages/@react-aria/menu/src/utils.ts"],"sourcesContent":["/*\n * Copyright 2024 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {Key} from '@react-types/shared';\nimport {TreeState} from '@react-stately/tree';\n\ninterface MenuData {\n onClose?: () => void,\n onAction?: (key: Key) => void,\n shouldUseVirtualFocus?: boolean\n}\n\nexport const menuData = new WeakMap<TreeState<unknown>, MenuData>();\n"],"names":[],"version":3,"file":"utils.main.js.map"}
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/ const $fc79756100351201$export$6f49b4016bfc8d56 = new WeakMap();
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export {$fc79756100351201$export$6f49b4016bfc8d56 as menuData};
|
|
15
|
+
//# sourceMappingURL=utils.module.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/ const $fc79756100351201$export$6f49b4016bfc8d56 = new WeakMap();
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export {$fc79756100351201$export$6f49b4016bfc8d56 as menuData};
|
|
15
|
+
//# sourceMappingURL=utils.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"AAAA;;;;;;;;;;CAUC,GAWM,MAAM,4CAAW,IAAI","sources":["packages/@react-aria/menu/src/utils.ts"],"sourcesContent":["/*\n * Copyright 2024 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {Key} from '@react-types/shared';\nimport {TreeState} from '@react-stately/tree';\n\ninterface MenuData {\n onClose?: () => void,\n onAction?: (key: Key) => void,\n shouldUseVirtualFocus?: boolean\n}\n\nexport const menuData = new WeakMap<TreeState<unknown>, MenuData>();\n"],"names":[],"version":3,"file":"utils.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/menu",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.18.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,19 +22,19 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-aria/focus": "^3.
|
|
26
|
-
"@react-aria/i18n": "^3.12.
|
|
27
|
-
"@react-aria/interactions": "^3.
|
|
28
|
-
"@react-aria/overlays": "^3.
|
|
29
|
-
"@react-aria/selection": "^3.
|
|
30
|
-
"@react-aria/utils": "^3.
|
|
31
|
-
"@react-stately/collections": "^3.12.
|
|
32
|
-
"@react-stately/menu": "^3.9.
|
|
33
|
-
"@react-stately/selection": "^3.
|
|
34
|
-
"@react-stately/tree": "^3.8.
|
|
35
|
-
"@react-types/button": "^3.
|
|
36
|
-
"@react-types/menu": "^3.9.
|
|
37
|
-
"@react-types/shared": "^3.
|
|
25
|
+
"@react-aria/focus": "^3.20.0",
|
|
26
|
+
"@react-aria/i18n": "^3.12.6",
|
|
27
|
+
"@react-aria/interactions": "^3.24.0",
|
|
28
|
+
"@react-aria/overlays": "^3.26.0",
|
|
29
|
+
"@react-aria/selection": "^3.23.0",
|
|
30
|
+
"@react-aria/utils": "^3.28.0",
|
|
31
|
+
"@react-stately/collections": "^3.12.2",
|
|
32
|
+
"@react-stately/menu": "^3.9.2",
|
|
33
|
+
"@react-stately/selection": "^3.20.0",
|
|
34
|
+
"@react-stately/tree": "^3.8.8",
|
|
35
|
+
"@react-types/button": "^3.11.0",
|
|
36
|
+
"@react-types/menu": "^3.9.15",
|
|
37
|
+
"@react-types/shared": "^3.28.0",
|
|
38
38
|
"@swc/helpers": "^0.5.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "4d3c72c94eea2d72eb3a0e7d56000c6ef7e39726"
|
|
48
48
|
}
|
package/src/useMenu.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {AriaMenuProps} from '@react-types/menu';
|
|
14
|
-
import {DOMAttributes,
|
|
14
|
+
import {DOMAttributes, KeyboardDelegate, KeyboardEvents, RefObject} from '@react-types/shared';
|
|
15
15
|
import {filterDOMProps, mergeProps} from '@react-aria/utils';
|
|
16
|
+
import {menuData} from './utils';
|
|
16
17
|
import {TreeState} from '@react-stately/tree';
|
|
17
18
|
import {useSelectableList} from '@react-aria/selection';
|
|
18
19
|
|
|
@@ -24,21 +25,17 @@ export interface MenuAria {
|
|
|
24
25
|
export interface AriaMenuOptions<T> extends Omit<AriaMenuProps<T>, 'children'>, KeyboardEvents {
|
|
25
26
|
/** Whether the menu uses virtual scrolling. */
|
|
26
27
|
isVirtualized?: boolean,
|
|
27
|
-
|
|
28
28
|
/**
|
|
29
29
|
* An optional keyboard delegate implementation for type to select,
|
|
30
30
|
* to override the default.
|
|
31
31
|
*/
|
|
32
|
-
keyboardDelegate?: KeyboardDelegate
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
onAction?: (key: Key) => void
|
|
32
|
+
keyboardDelegate?: KeyboardDelegate,
|
|
33
|
+
/**
|
|
34
|
+
* Whether the menu items should use virtual focus instead of being focused directly.
|
|
35
|
+
*/
|
|
36
|
+
shouldUseVirtualFocus?: boolean
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
export const menuData = new WeakMap<TreeState<unknown>, MenuData>();
|
|
41
|
-
|
|
42
39
|
/**
|
|
43
40
|
* Provides the behavior and accessibility implementation for a menu component.
|
|
44
41
|
* A menu displays a list of actions or options that a user can choose.
|
|
@@ -70,7 +67,8 @@ export function useMenu<T>(props: AriaMenuOptions<T>, state: TreeState<T>, ref:
|
|
|
70
67
|
|
|
71
68
|
menuData.set(state, {
|
|
72
69
|
onClose: props.onClose,
|
|
73
|
-
onAction: props.onAction
|
|
70
|
+
onAction: props.onAction,
|
|
71
|
+
shouldUseVirtualFocus: props.shouldUseVirtualFocus
|
|
74
72
|
});
|
|
75
73
|
|
|
76
74
|
return {
|
|
@@ -79,7 +77,7 @@ export function useMenu<T>(props: AriaMenuOptions<T>, state: TreeState<T>, ref:
|
|
|
79
77
|
...listProps,
|
|
80
78
|
onKeyDown: (e) => {
|
|
81
79
|
// don't clear the menu selected keys if the user is presses escape since escape closes the menu
|
|
82
|
-
if (e.key !== 'Escape') {
|
|
80
|
+
if (e.key !== 'Escape' || props.shouldUseVirtualFocus) {
|
|
83
81
|
listProps.onKeyDown?.(e);
|
|
84
82
|
}
|
|
85
83
|
}
|
package/src/useMenuItem.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key
|
|
|
14
14
|
import {filterDOMProps, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';
|
|
15
15
|
import {getItemCount} from '@react-stately/collections';
|
|
16
16
|
import {isFocusVisible, useFocus, useHover, useKeyboard, usePress} from '@react-aria/interactions';
|
|
17
|
-
import {menuData} from './
|
|
17
|
+
import {menuData} from './utils';
|
|
18
18
|
import {SelectionManager} from '@react-stately/selection';
|
|
19
19
|
import {TreeState} from '@react-stately/tree';
|
|
20
20
|
import {useSelectableItem} from '@react-aria/selection';
|
|
@@ -34,6 +34,8 @@ export interface MenuItemAria {
|
|
|
34
34
|
|
|
35
35
|
/** Whether the item is currently focused. */
|
|
36
36
|
isFocused: boolean,
|
|
37
|
+
/** Whether the item is keyboard focused. */
|
|
38
|
+
isFocusVisible: boolean,
|
|
37
39
|
/** Whether the item is currently selected. */
|
|
38
40
|
isSelected: boolean,
|
|
39
41
|
/** Whether the item is currently in a pressed state. */
|
|
@@ -110,7 +112,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
110
112
|
'aria-haspopup': hasPopup,
|
|
111
113
|
onPressStart: pressStartProp,
|
|
112
114
|
onPressUp: pressUpProp,
|
|
113
|
-
onPress,
|
|
115
|
+
onPress: pressProp,
|
|
114
116
|
onPressChange,
|
|
115
117
|
onPressEnd,
|
|
116
118
|
onHoverStart: hoverStartProp,
|
|
@@ -196,21 +198,36 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
196
198
|
pressStartProp?.(e);
|
|
197
199
|
};
|
|
198
200
|
|
|
201
|
+
let maybeClose = () => {
|
|
202
|
+
// Pressing a menu item should close by default in single selection mode but not multiple
|
|
203
|
+
// selection mode, except if overridden by the closeOnSelect prop.
|
|
204
|
+
if (!isTrigger && onClose && (closeOnSelect ?? (selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key)))) {
|
|
205
|
+
onClose();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
199
209
|
let onPressUp = (e: PressEvent) => {
|
|
200
|
-
|
|
210
|
+
// If interacting with mouse, allow the user to mouse down on the trigger button,
|
|
211
|
+
// drag, and release over an item (matching native behavior).
|
|
212
|
+
if (e.pointerType === 'mouse') {
|
|
201
213
|
performAction(e);
|
|
202
|
-
|
|
203
|
-
// Pressing a menu item should close by default in single selection mode but not multiple
|
|
204
|
-
// selection mode, except if overridden by the closeOnSelect prop.
|
|
205
|
-
if (!isTrigger && onClose && (closeOnSelect ?? (selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key)))) {
|
|
206
|
-
onClose();
|
|
207
|
-
}
|
|
214
|
+
maybeClose();
|
|
208
215
|
}
|
|
209
216
|
|
|
210
217
|
pressUpProp?.(e);
|
|
211
218
|
};
|
|
212
219
|
|
|
220
|
+
let onPress = (e: PressEvent) => {
|
|
221
|
+
if (e.pointerType !== 'keyboard' && e.pointerType !== 'mouse') {
|
|
222
|
+
performAction(e);
|
|
223
|
+
maybeClose();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
pressProp?.(e);
|
|
227
|
+
};
|
|
228
|
+
|
|
213
229
|
let {itemProps, isFocused} = useSelectableItem({
|
|
230
|
+
id,
|
|
214
231
|
selectionManager: selectionManager,
|
|
215
232
|
key,
|
|
216
233
|
ref,
|
|
@@ -220,7 +237,8 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
220
237
|
// because we handle it ourselves. The behavior of menus
|
|
221
238
|
// is slightly different from other collections because
|
|
222
239
|
// actions are performed on key down rather than key up.
|
|
223
|
-
linkBehavior: 'none'
|
|
240
|
+
linkBehavior: 'none',
|
|
241
|
+
shouldUseVirtualFocus: data.shouldUseVirtualFocus
|
|
224
242
|
});
|
|
225
243
|
|
|
226
244
|
let {pressProps, isPressed} = usePress({
|
|
@@ -235,7 +253,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
235
253
|
isDisabled,
|
|
236
254
|
onHoverStart(e) {
|
|
237
255
|
// Hovering over an already expanded sub dialog trigger should keep focus in the dialog.
|
|
238
|
-
if (!isFocusVisible() && !(isTriggerExpanded && hasPopup
|
|
256
|
+
if (!isFocusVisible() && !(isTriggerExpanded && hasPopup)) {
|
|
239
257
|
selectionManager.setFocused(true);
|
|
240
258
|
selectionManager.setFocusedKey(key);
|
|
241
259
|
}
|
|
@@ -286,9 +304,21 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
286
304
|
return {
|
|
287
305
|
menuItemProps: {
|
|
288
306
|
...ariaProps,
|
|
289
|
-
...mergeProps(
|
|
307
|
+
...mergeProps(
|
|
308
|
+
domProps,
|
|
309
|
+
linkProps,
|
|
310
|
+
isTrigger
|
|
311
|
+
? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}
|
|
312
|
+
: itemProps,
|
|
313
|
+
pressProps,
|
|
314
|
+
hoverProps,
|
|
315
|
+
keyboardProps,
|
|
316
|
+
focusProps,
|
|
317
|
+
// Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.
|
|
318
|
+
data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined
|
|
319
|
+
),
|
|
290
320
|
// If a submenu is expanded, set the tabIndex to -1 so that shift tabbing goes out of the menu instead of the parent menu item.
|
|
291
|
-
tabIndex: itemProps.tabIndex != null && isTriggerExpanded ? -1 : itemProps.tabIndex
|
|
321
|
+
tabIndex: itemProps.tabIndex != null && isTriggerExpanded && !data.shouldUseVirtualFocus ? -1 : itemProps.tabIndex
|
|
292
322
|
},
|
|
293
323
|
labelProps: {
|
|
294
324
|
id: labelId
|
|
@@ -300,6 +330,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
300
330
|
id: keyboardId
|
|
301
331
|
},
|
|
302
332
|
isFocused,
|
|
333
|
+
isFocusVisible: isFocused && selectionManager.isFocused && isFocusVisible() && !isTriggerExpanded,
|
|
303
334
|
isSelected,
|
|
304
335
|
isPressed,
|
|
305
336
|
isDisabled
|
package/src/useMenuTrigger.ts
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
|
|
13
13
|
import {AriaButtonProps} from '@react-types/button';
|
|
14
14
|
import {AriaMenuOptions} from './useMenu';
|
|
15
|
+
import {FocusableElement, RefObject} from '@react-types/shared';
|
|
16
|
+
import {focusWithoutScrolling, useId} from '@react-aria/utils';
|
|
15
17
|
// @ts-ignore
|
|
16
18
|
import intlMessages from '../intl/*.json';
|
|
17
19
|
import {MenuTriggerState} from '@react-stately/menu';
|
|
18
20
|
import {MenuTriggerType} from '@react-types/menu';
|
|
19
|
-
import {
|
|
20
|
-
import {useId} from '@react-aria/utils';
|
|
21
|
+
import {PressProps, useLongPress} from '@react-aria/interactions';
|
|
21
22
|
import {useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
22
|
-
import {useLongPress} from '@react-aria/interactions';
|
|
23
23
|
import {useOverlayTrigger} from '@react-aria/overlays';
|
|
24
24
|
|
|
25
25
|
export interface AriaMenuTriggerProps {
|
|
@@ -108,10 +108,14 @@ export function useMenuTrigger<T>(props: AriaMenuTriggerProps, state: MenuTrigge
|
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
let pressProps = {
|
|
111
|
+
let pressProps: PressProps = {
|
|
112
|
+
preventFocusOnPress: true,
|
|
112
113
|
onPressStart(e) {
|
|
113
114
|
// For consistency with native, open the menu on mouse/key down, but touch up.
|
|
114
115
|
if (e.pointerType !== 'touch' && e.pointerType !== 'keyboard' && !isDisabled) {
|
|
116
|
+
// Ensure trigger has focus before opening the menu so it can be restored by FocusScope on close.
|
|
117
|
+
focusWithoutScrolling(e.target as FocusableElement);
|
|
118
|
+
|
|
115
119
|
// If opened with a screen reader, auto focus the first item.
|
|
116
120
|
// Otherwise, the menu itself will be focused.
|
|
117
121
|
state.open(e.pointerType === 'virtual' ? 'first' : null);
|