@react-aria/menu 3.20.0 → 3.21.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 +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/useMenuItem.main.js +11 -3
- package/dist/useMenuItem.main.js.map +1 -1
- package/dist/useMenuItem.mjs +13 -5
- package/dist/useMenuItem.module.js +13 -5
- package/dist/useMenuItem.module.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.main.js +1 -1
- package/dist/useSafelyMouseToSubmenu.main.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.mjs +1 -1
- package/dist/useSafelyMouseToSubmenu.module.js +1 -1
- package/dist/useSafelyMouseToSubmenu.module.js.map +1 -1
- package/dist/useSubmenuTrigger.main.js +7 -7
- package/dist/useSubmenuTrigger.main.js.map +1 -1
- package/dist/useSubmenuTrigger.mjs +8 -8
- package/dist/useSubmenuTrigger.module.js +8 -8
- package/dist/useSubmenuTrigger.module.js.map +1 -1
- package/package.json +15 -15
- package/src/useMenuItem.ts +19 -7
- package/src/useSafelyMouseToSubmenu.ts +1 -1
- package/src/useSubmenuTrigger.ts +9 -9
package/dist/types.d.ts
CHANGED
|
@@ -111,6 +111,8 @@ export interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, K
|
|
|
111
111
|
'aria-expanded'?: boolean | 'true' | 'false';
|
|
112
112
|
/** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */
|
|
113
113
|
'aria-controls'?: string;
|
|
114
|
+
/** Identifies the element(s) that describe the menu item. */
|
|
115
|
+
'aria-describedby'?: string;
|
|
114
116
|
/** Override of the selection manager. By default, `state.selectionManager` is used. */
|
|
115
117
|
selectionManager?: SelectionManager;
|
|
116
118
|
}
|
|
@@ -163,7 +165,7 @@ export interface AriaSubmenuTriggerProps {
|
|
|
163
165
|
/** Whether the submenu trigger uses virtual focus. */
|
|
164
166
|
shouldUseVirtualFocus?: boolean;
|
|
165
167
|
}
|
|
166
|
-
interface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {
|
|
168
|
+
interface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key' | 'onAction'> {
|
|
167
169
|
/** Whether the submenu trigger is in an expanded state. */
|
|
168
170
|
isOpen: boolean;
|
|
169
171
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/packages/@react-aria/menu/src/utils.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useMenu.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useMenuTrigger.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useMenuItem.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useMenuSection.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/useSubmenuTrigger.ts","packages/@react-aria/menu/src/packages/@react-aria/menu/src/index.ts","packages/@react-aria/menu/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 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\nexport {useMenuTrigger} from './useMenuTrigger';\nexport {useMenu} from './useMenu';\nexport {useMenuItem} from './useMenuItem';\nexport {useMenuSection} from './useMenuSection';\nexport {useSubmenuTrigger} from './useSubmenuTrigger';\n\nexport type {AriaMenuProps} from '@react-types/menu';\nexport type {AriaMenuTriggerProps, MenuTriggerAria} from './useMenuTrigger';\nexport type {AriaMenuOptions, MenuAria} from './useMenu';\nexport type {AriaMenuItemProps, MenuItemAria} from './useMenuItem';\nexport type {AriaMenuSectionProps, MenuSectionAria} from './useMenuSection';\nexport type {AriaSubmenuTriggerProps, SubmenuTriggerAria} from './useSubmenuTrigger';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/dist/useMenuItem.main.js
CHANGED
|
@@ -65,6 +65,7 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
65
65
|
'aria-label': props['aria-label'],
|
|
66
66
|
'aria-labelledby': labelId,
|
|
67
67
|
'aria-describedby': [
|
|
68
|
+
props['aria-describedby'],
|
|
68
69
|
descriptionId,
|
|
69
70
|
keyboardId
|
|
70
71
|
].filter(Boolean).join(' ') || undefined,
|
|
@@ -74,7 +75,8 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
74
75
|
};
|
|
75
76
|
if (selectionManager.selectionMode !== 'none' && !isTrigger) ariaProps['aria-checked'] = isSelected;
|
|
76
77
|
if (isVirtualized) {
|
|
77
|
-
|
|
78
|
+
let index = Number(item === null || item === void 0 ? void 0 : item.index);
|
|
79
|
+
ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;
|
|
78
80
|
ariaProps['aria-setsize'] = (0, $byVdR$reactstatelycollections.getItemCount)(state.collection);
|
|
79
81
|
}
|
|
80
82
|
let isPressedRef = (0, $byVdR$react.useRef)(false);
|
|
@@ -154,7 +156,10 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
154
156
|
pointerType: 'keyboard',
|
|
155
157
|
key: ' '
|
|
156
158
|
};
|
|
157
|
-
e.
|
|
159
|
+
(0, $byVdR$reactariautils.getEventTarget)(e).click();
|
|
160
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
161
|
+
// to the newly opened submenu's first item.
|
|
162
|
+
(0, $byVdR$reactariainteractions.setInteractionModality)('keyboard');
|
|
158
163
|
break;
|
|
159
164
|
case 'Enter':
|
|
160
165
|
interaction.current = {
|
|
@@ -162,7 +167,10 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
162
167
|
key: 'Enter'
|
|
163
168
|
};
|
|
164
169
|
// Trigger click unless this is a link. Links trigger click natively.
|
|
165
|
-
if (e.
|
|
170
|
+
if ((0, $byVdR$reactariautils.getEventTarget)(e).tagName !== 'A') (0, $byVdR$reactariautils.getEventTarget)(e).click();
|
|
171
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
172
|
+
// to the newly opened submenu's first item.
|
|
173
|
+
(0, $byVdR$reactariainteractions.setInteractionModality)('keyboard');
|
|
166
174
|
break;
|
|
167
175
|
default:
|
|
168
176
|
if (!isTrigger) e.continuePropagation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useMenuItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';\nimport {filterDOMProps, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';\nimport {getItemCount} from '@react-stately/collections';\nimport {isFocusVisible, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';\nimport {menuData} from './utils';\nimport {MouseEvent, useRef} from 'react';\nimport {SelectionManager} from '@react-stately/selection';\nimport {TreeState} from '@react-stately/tree';\nimport {useSelectableItem} from '@react-aria/selection';\n\nexport interface MenuItemAria {\n /** Props for the menu item element. */\n menuItemProps: DOMAttributes,\n\n /** Props for the main text element inside the menu item. */\n labelProps: DOMAttributes,\n\n /** Props for the description text element inside the menu item, if any. */\n descriptionProps: DOMAttributes,\n\n /** Props for the keyboard shortcut text element inside the item, if any. */\n keyboardShortcutProps: DOMAttributes,\n\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /** Whether the item is keyboard focused. */\n isFocusVisible: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is disabled. */\n isDisabled: boolean\n}\n\nexport interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, KeyboardEvents, FocusEvents {\n /**\n * Whether the menu item is disabled.\n * @deprecated - pass disabledKeys to useTreeState instead.\n */\n isDisabled?: boolean,\n\n /**\n * Whether the menu item is selected.\n * @deprecated - pass selectedKeys to useTreeState instead.\n */\n isSelected?: boolean,\n\n /** A screen reader only label for the menu item. */\n 'aria-label'?: string,\n\n /** The unique key for the menu item. */\n key: Key,\n\n /**\n * Handler that is called when the menu should close after selecting an item.\n * @deprecated - pass to the menu instead.\n */\n onClose?: () => void,\n\n /**\n * Whether the menu should close when the menu item is selected.\n * @deprecated - use shouldCloseOnSelect instead.\n */\n closeOnSelect?: boolean,\n\n /** Whether the menu should close when the menu item is selected. */\n shouldCloseOnSelect?: boolean,\n\n /** Whether the menu item is contained in a virtual scrolling menu. */\n isVirtualized?: boolean,\n\n /**\n * Handler that is called when the user activates the item.\n * @deprecated - pass to the menu instead.\n */\n onAction?: (key: Key) => void,\n\n /** What kind of popup the item opens. */\n 'aria-haspopup'?: 'menu' | 'dialog',\n\n /** Indicates whether the menu item's popup element is expanded or collapsed. */\n 'aria-expanded'?: boolean | 'true' | 'false',\n\n /** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */\n 'aria-controls'?: string,\n\n /** Override of the selection manager. By default, `state.selectionManager` is used. */\n selectionManager?: SelectionManager\n}\n\n/**\n * Provides the behavior and accessibility implementation for an item in a menu.\n * See `useMenu` for more details about menus.\n * @param props - Props for the item.\n * @param state - State for the menu, as returned by `useTreeState`.\n */\nexport function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, ref: RefObject<FocusableElement | null>): MenuItemAria {\n let {\n id,\n key,\n closeOnSelect,\n shouldCloseOnSelect,\n isVirtualized,\n 'aria-haspopup': hasPopup,\n onPressStart,\n onPressUp: pressUpProp,\n onPress,\n onPressChange: pressChangeProp,\n onPressEnd,\n onClick: onClickProp,\n onHoverStart: hoverStartProp,\n onHoverChange,\n onHoverEnd,\n onKeyDown,\n onKeyUp,\n onFocus,\n onFocusChange,\n onBlur,\n selectionManager = state.selectionManager\n } = props;\n\n let isTrigger = !!hasPopup;\n let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';\n let isDisabled = props.isDisabled ?? selectionManager.isDisabled(key);\n let isSelected = props.isSelected ?? selectionManager.isSelected(key);\n let data = menuData.get(state)!;\n let item = state.collection.getItem(key);\n let onClose = props.onClose || data.onClose;\n let router = useRouter();\n let performAction = () => {\n if (isTrigger) {\n return;\n }\n\n if (item?.props?.onAction) {\n item.props.onAction();\n } else if (props.onAction) {\n props.onAction(key);\n }\n\n if (data.onAction) {\n // Must reassign to variable otherwise `this` binding gets messed up. Something to do with WeakMap.\n let onAction = data.onAction;\n onAction(key);\n }\n };\n\n let role = 'menuitem';\n if (!isTrigger) {\n if (selectionManager.selectionMode === 'single') {\n role = 'menuitemradio';\n } else if (selectionManager.selectionMode === 'multiple') {\n role = 'menuitemcheckbox';\n }\n }\n\n let labelId = useSlotId();\n let descriptionId = useSlotId();\n let keyboardId = useSlotId();\n\n let ariaProps = {\n id,\n 'aria-disabled': isDisabled || undefined,\n role,\n 'aria-label': props['aria-label'],\n 'aria-labelledby': labelId,\n 'aria-describedby': [descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,\n 'aria-controls': props['aria-controls'],\n 'aria-haspopup': hasPopup,\n 'aria-expanded': props['aria-expanded']\n };\n\n if (selectionManager.selectionMode !== 'none' && !isTrigger) {\n ariaProps['aria-checked'] = isSelected;\n }\n\n if (isVirtualized) {\n ariaProps['aria-posinset'] = item?.index;\n ariaProps['aria-setsize'] = getItemCount(state.collection);\n }\n\n let isPressedRef = useRef(false);\n let onPressChange = (isPressed: boolean) => {\n pressChangeProp?.(isPressed);\n isPressedRef.current = isPressed;\n };\n\n let interaction = useRef<{pointerType: string, key?: string} | null>(null);\n let onPressUp = (e: PressEvent) => {\n if (e.pointerType !== 'keyboard') {\n interaction.current = {pointerType: e.pointerType};\n }\n\n // If interacting with mouse, allow the user to mouse down on the trigger button,\n // drag, and release over an item (matching native behavior).\n if (e.pointerType === 'mouse') {\n if (!isPressedRef.current) {\n (e.target as HTMLElement).click();\n }\n }\n\n pressUpProp?.(e);\n };\n\n let onClick = (e: MouseEvent<FocusableElement>) => {\n onClickProp?.(e);\n performAction();\n handleLinkClick(e, router, item!.props.href, item?.props.routerOptions);\n\n let shouldClose = interaction.current?.pointerType === 'keyboard'\n // Always close when pressing Enter key, or if item is not selectable.\n ? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)\n // Close except if multi-select is enabled.\n : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);\n\n\n shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;\n\n if (onClose && !isTrigger && shouldClose) {\n onClose();\n }\n\n interaction.current = null;\n };\n\n let {itemProps, isFocused} = useSelectableItem({\n id,\n selectionManager: selectionManager,\n key,\n ref,\n shouldSelectOnPressUp: true,\n allowsDifferentPressOrigin: true,\n // Disable all handling of links in useSelectable item\n // because we handle it ourselves. The behavior of menus\n // is slightly different from other collections because\n // actions are performed on key down rather than key up.\n linkBehavior: 'none',\n shouldUseVirtualFocus: data.shouldUseVirtualFocus\n });\n\n let {pressProps, isPressed} = usePress({\n onPressStart,\n onPress,\n onPressUp,\n onPressChange,\n onPressEnd,\n isDisabled\n });\n let {hoverProps} = useHover({\n isDisabled,\n onHoverStart(e) {\n // Hovering over an already expanded sub dialog trigger should keep focus in the dialog.\n if (!isFocusVisible() && !(isTriggerExpanded && hasPopup)) {\n selectionManager.setFocused(true);\n selectionManager.setFocusedKey(key);\n }\n hoverStartProp?.(e);\n },\n onHoverChange,\n onHoverEnd\n });\n\n let {keyboardProps} = useKeyboard({\n onKeyDown: (e) => {\n // Ignore repeating events, which may have started on the menu trigger before moving\n // focus to the menu item. We want to wait for a second complete key press sequence.\n if (e.repeat) {\n e.continuePropagation();\n return;\n }\n\n switch (e.key) {\n case ' ':\n interaction.current = {pointerType: 'keyboard', key: ' '};\n (e.target as HTMLElement).click();\n break;\n case 'Enter':\n interaction.current = {pointerType: 'keyboard', key: 'Enter'};\n\n // Trigger click unless this is a link. Links trigger click natively.\n if ((e.target as HTMLElement).tagName !== 'A') {\n (e.target as HTMLElement).click();\n }\n break;\n default:\n if (!isTrigger) {\n e.continuePropagation();\n }\n\n onKeyDown?.(e);\n break;\n }\n },\n onKeyUp\n });\n\n let {focusableProps} = useFocusable({onBlur, onFocus, onFocusChange}, ref);\n let domProps = filterDOMProps(item?.props);\n delete domProps.id;\n let linkProps = useLinkProps(item?.props);\n\n return {\n menuItemProps: {\n ...ariaProps,\n ...mergeProps(\n domProps,\n linkProps,\n isTrigger\n ? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}\n : itemProps,\n pressProps,\n hoverProps,\n keyboardProps,\n focusableProps,\n // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.\n data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined,\n isDisabled ? undefined : {onClick}\n ),\n // 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.\n tabIndex: itemProps.tabIndex != null && isTriggerExpanded && !data.shouldUseVirtualFocus ? -1 : itemProps.tabIndex\n },\n labelProps: {\n id: labelId\n },\n descriptionProps: {\n id: descriptionId\n },\n keyboardShortcutProps: {\n id: keyboardId\n },\n isFocused,\n isFocusVisible: isFocused && selectionManager.isFocused && isFocusVisible() && !isTriggerExpanded,\n isSelected,\n isPressed,\n isDisabled\n };\n}\n"],"names":[],"version":3,"file":"useMenuItem.main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useMenuItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';\nimport {filterDOMProps, getEventTarget, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';\nimport {getItemCount} from '@react-stately/collections';\nimport {isFocusVisible, setInteractionModality, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';\nimport {menuData} from './utils';\nimport {MouseEvent, useRef} from 'react';\nimport {SelectionManager} from '@react-stately/selection';\nimport {TreeState} from '@react-stately/tree';\nimport {useSelectableItem} from '@react-aria/selection';\n\nexport interface MenuItemAria {\n /** Props for the menu item element. */\n menuItemProps: DOMAttributes,\n\n /** Props for the main text element inside the menu item. */\n labelProps: DOMAttributes,\n\n /** Props for the description text element inside the menu item, if any. */\n descriptionProps: DOMAttributes,\n\n /** Props for the keyboard shortcut text element inside the item, if any. */\n keyboardShortcutProps: DOMAttributes,\n\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /** Whether the item is keyboard focused. */\n isFocusVisible: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is disabled. */\n isDisabled: boolean\n}\n\nexport interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, KeyboardEvents, FocusEvents {\n /**\n * Whether the menu item is disabled.\n * @deprecated - pass disabledKeys to useTreeState instead.\n */\n isDisabled?: boolean,\n\n /**\n * Whether the menu item is selected.\n * @deprecated - pass selectedKeys to useTreeState instead.\n */\n isSelected?: boolean,\n\n /** A screen reader only label for the menu item. */\n 'aria-label'?: string,\n\n /** The unique key for the menu item. */\n key: Key,\n\n /**\n * Handler that is called when the menu should close after selecting an item.\n * @deprecated - pass to the menu instead.\n */\n onClose?: () => void,\n\n /**\n * Whether the menu should close when the menu item is selected.\n * @deprecated - use shouldCloseOnSelect instead.\n */\n closeOnSelect?: boolean,\n\n /** Whether the menu should close when the menu item is selected. */\n shouldCloseOnSelect?: boolean,\n\n /** Whether the menu item is contained in a virtual scrolling menu. */\n isVirtualized?: boolean,\n\n /**\n * Handler that is called when the user activates the item.\n * @deprecated - pass to the menu instead.\n */\n onAction?: (key: Key) => void,\n\n /** What kind of popup the item opens. */\n 'aria-haspopup'?: 'menu' | 'dialog',\n\n /** Indicates whether the menu item's popup element is expanded or collapsed. */\n 'aria-expanded'?: boolean | 'true' | 'false',\n\n /** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */\n 'aria-controls'?: string,\n\n /** Identifies the element(s) that describe the menu item. */\n 'aria-describedby'?: string,\n\n /** Override of the selection manager. By default, `state.selectionManager` is used. */\n selectionManager?: SelectionManager\n}\n\n/**\n * Provides the behavior and accessibility implementation for an item in a menu.\n * See `useMenu` for more details about menus.\n * @param props - Props for the item.\n * @param state - State for the menu, as returned by `useTreeState`.\n */\nexport function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, ref: RefObject<FocusableElement | null>): MenuItemAria {\n let {\n id,\n key,\n closeOnSelect,\n shouldCloseOnSelect,\n isVirtualized,\n 'aria-haspopup': hasPopup,\n onPressStart,\n onPressUp: pressUpProp,\n onPress,\n onPressChange: pressChangeProp,\n onPressEnd,\n onClick: onClickProp,\n onHoverStart: hoverStartProp,\n onHoverChange,\n onHoverEnd,\n onKeyDown,\n onKeyUp,\n onFocus,\n onFocusChange,\n onBlur,\n selectionManager = state.selectionManager\n } = props;\n\n let isTrigger = !!hasPopup;\n let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';\n let isDisabled = props.isDisabled ?? selectionManager.isDisabled(key);\n let isSelected = props.isSelected ?? selectionManager.isSelected(key);\n let data = menuData.get(state)!;\n let item = state.collection.getItem(key);\n let onClose = props.onClose || data.onClose;\n let router = useRouter();\n let performAction = () => {\n if (isTrigger) {\n return;\n }\n\n if (item?.props?.onAction) {\n item.props.onAction();\n } else if (props.onAction) {\n props.onAction(key);\n }\n\n if (data.onAction) {\n // Must reassign to variable otherwise `this` binding gets messed up. Something to do with WeakMap.\n let onAction = data.onAction;\n onAction(key);\n }\n };\n\n let role = 'menuitem';\n if (!isTrigger) {\n if (selectionManager.selectionMode === 'single') {\n role = 'menuitemradio';\n } else if (selectionManager.selectionMode === 'multiple') {\n role = 'menuitemcheckbox';\n }\n }\n\n let labelId = useSlotId();\n let descriptionId = useSlotId();\n let keyboardId = useSlotId();\n\n let ariaProps = {\n id,\n 'aria-disabled': isDisabled || undefined,\n role,\n 'aria-label': props['aria-label'],\n 'aria-labelledby': labelId,\n 'aria-describedby': [props['aria-describedby'], descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,\n 'aria-controls': props['aria-controls'],\n 'aria-haspopup': hasPopup,\n 'aria-expanded': props['aria-expanded']\n };\n\n if (selectionManager.selectionMode !== 'none' && !isTrigger) {\n ariaProps['aria-checked'] = isSelected;\n }\n\n if (isVirtualized) {\n let index = Number(item?.index);\n ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;\n ariaProps['aria-setsize'] = getItemCount(state.collection);\n }\n\n let isPressedRef = useRef(false);\n let onPressChange = (isPressed: boolean) => {\n pressChangeProp?.(isPressed);\n isPressedRef.current = isPressed;\n };\n\n let interaction = useRef<{pointerType: string, key?: string} | null>(null);\n let onPressUp = (e: PressEvent) => {\n if (e.pointerType !== 'keyboard') {\n interaction.current = {pointerType: e.pointerType};\n }\n\n // If interacting with mouse, allow the user to mouse down on the trigger button,\n // drag, and release over an item (matching native behavior).\n if (e.pointerType === 'mouse') {\n if (!isPressedRef.current) {\n (e.target as HTMLElement).click();\n }\n }\n\n pressUpProp?.(e);\n };\n\n let onClick = (e: MouseEvent<FocusableElement>) => {\n onClickProp?.(e);\n performAction();\n handleLinkClick(e, router, item!.props.href, item?.props.routerOptions);\n\n let shouldClose = interaction.current?.pointerType === 'keyboard'\n // Always close when pressing Enter key, or if item is not selectable.\n ? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)\n // Close except if multi-select is enabled.\n : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);\n\n\n shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;\n\n if (onClose && !isTrigger && shouldClose) {\n onClose();\n }\n\n interaction.current = null;\n };\n\n let {itemProps, isFocused} = useSelectableItem({\n id,\n selectionManager: selectionManager,\n key,\n ref,\n shouldSelectOnPressUp: true,\n allowsDifferentPressOrigin: true,\n // Disable all handling of links in useSelectable item\n // because we handle it ourselves. The behavior of menus\n // is slightly different from other collections because\n // actions are performed on key down rather than key up.\n linkBehavior: 'none',\n shouldUseVirtualFocus: data.shouldUseVirtualFocus\n });\n\n let {pressProps, isPressed} = usePress({\n onPressStart,\n onPress,\n onPressUp,\n onPressChange,\n onPressEnd,\n isDisabled\n });\n let {hoverProps} = useHover({\n isDisabled,\n onHoverStart(e) {\n // Hovering over an already expanded sub dialog trigger should keep focus in the dialog.\n if (!isFocusVisible() && !(isTriggerExpanded && hasPopup)) {\n selectionManager.setFocused(true);\n selectionManager.setFocusedKey(key);\n }\n hoverStartProp?.(e);\n },\n onHoverChange,\n onHoverEnd\n });\n\n let {keyboardProps} = useKeyboard({\n onKeyDown: (e) => {\n // Ignore repeating events, which may have started on the menu trigger before moving\n // focus to the menu item. We want to wait for a second complete key press sequence.\n if (e.repeat) {\n e.continuePropagation();\n return;\n }\n\n switch (e.key) {\n case ' ':\n interaction.current = {pointerType: 'keyboard', key: ' '};\n (getEventTarget(e) as HTMLElement).click();\n\n // click above sets modality to \"virtual\", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus\n // to the newly opened submenu's first item.\n setInteractionModality('keyboard');\n break;\n case 'Enter':\n interaction.current = {pointerType: 'keyboard', key: 'Enter'};\n\n // Trigger click unless this is a link. Links trigger click natively.\n if ((getEventTarget(e) as HTMLElement).tagName !== 'A') {\n (getEventTarget(e) as HTMLElement).click();\n }\n\n // click above sets modality to \"virtual\", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus\n // to the newly opened submenu's first item.\n setInteractionModality('keyboard');\n break;\n default:\n if (!isTrigger) {\n e.continuePropagation();\n }\n\n onKeyDown?.(e);\n break;\n }\n },\n onKeyUp\n });\n\n let {focusableProps} = useFocusable({onBlur, onFocus, onFocusChange}, ref);\n let domProps = filterDOMProps(item?.props);\n delete domProps.id;\n let linkProps = useLinkProps(item?.props);\n\n return {\n menuItemProps: {\n ...ariaProps,\n ...mergeProps(\n domProps,\n linkProps,\n isTrigger\n ? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}\n : itemProps,\n pressProps,\n hoverProps,\n keyboardProps,\n focusableProps,\n // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.\n data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined,\n isDisabled ? undefined : {onClick}\n ),\n // 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.\n tabIndex: itemProps.tabIndex != null && isTriggerExpanded && !data.shouldUseVirtualFocus ? -1 : itemProps.tabIndex\n },\n labelProps: {\n id: labelId\n },\n descriptionProps: {\n id: descriptionId\n },\n keyboardShortcutProps: {\n id: keyboardId\n },\n isFocused,\n isFocusVisible: isFocused && selectionManager.isFocused && isFocusVisible() && !isTriggerExpanded,\n isSelected,\n isPressed,\n isDisabled\n };\n}\n"],"names":[],"version":3,"file":"useMenuItem.main.js.map"}
|
package/dist/useMenuItem.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {menuData as $fc79756100351201$export$6f49b4016bfc8d56} from "./utils.mjs";
|
|
2
|
-
import {useRouter as $7Kjv5$useRouter, useSlotId as $7Kjv5$useSlotId, handleLinkClick as $7Kjv5$handleLinkClick, filterDOMProps as $7Kjv5$filterDOMProps, useLinkProps as $7Kjv5$useLinkProps, mergeProps as $7Kjv5$mergeProps} from "@react-aria/utils";
|
|
2
|
+
import {useRouter as $7Kjv5$useRouter, useSlotId as $7Kjv5$useSlotId, handleLinkClick as $7Kjv5$handleLinkClick, getEventTarget as $7Kjv5$getEventTarget, filterDOMProps as $7Kjv5$filterDOMProps, useLinkProps as $7Kjv5$useLinkProps, mergeProps as $7Kjv5$mergeProps} from "@react-aria/utils";
|
|
3
3
|
import {getItemCount as $7Kjv5$getItemCount} from "@react-stately/collections";
|
|
4
|
-
import {usePress as $7Kjv5$usePress, useHover as $7Kjv5$useHover, isFocusVisible as $7Kjv5$isFocusVisible, useKeyboard as $7Kjv5$useKeyboard, useFocusable as $7Kjv5$useFocusable} from "@react-aria/interactions";
|
|
4
|
+
import {usePress as $7Kjv5$usePress, useHover as $7Kjv5$useHover, isFocusVisible as $7Kjv5$isFocusVisible, useKeyboard as $7Kjv5$useKeyboard, setInteractionModality as $7Kjv5$setInteractionModality, useFocusable as $7Kjv5$useFocusable} from "@react-aria/interactions";
|
|
5
5
|
import {useRef as $7Kjv5$useRef} from "react";
|
|
6
6
|
import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selection";
|
|
7
7
|
|
|
@@ -59,6 +59,7 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
59
59
|
'aria-label': props['aria-label'],
|
|
60
60
|
'aria-labelledby': labelId,
|
|
61
61
|
'aria-describedby': [
|
|
62
|
+
props['aria-describedby'],
|
|
62
63
|
descriptionId,
|
|
63
64
|
keyboardId
|
|
64
65
|
].filter(Boolean).join(' ') || undefined,
|
|
@@ -68,7 +69,8 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
68
69
|
};
|
|
69
70
|
if (selectionManager.selectionMode !== 'none' && !isTrigger) ariaProps['aria-checked'] = isSelected;
|
|
70
71
|
if (isVirtualized) {
|
|
71
|
-
|
|
72
|
+
let index = Number(item === null || item === void 0 ? void 0 : item.index);
|
|
73
|
+
ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;
|
|
72
74
|
ariaProps['aria-setsize'] = (0, $7Kjv5$getItemCount)(state.collection);
|
|
73
75
|
}
|
|
74
76
|
let isPressedRef = (0, $7Kjv5$useRef)(false);
|
|
@@ -148,7 +150,10 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
148
150
|
pointerType: 'keyboard',
|
|
149
151
|
key: ' '
|
|
150
152
|
};
|
|
151
|
-
e.
|
|
153
|
+
(0, $7Kjv5$getEventTarget)(e).click();
|
|
154
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
155
|
+
// to the newly opened submenu's first item.
|
|
156
|
+
(0, $7Kjv5$setInteractionModality)('keyboard');
|
|
152
157
|
break;
|
|
153
158
|
case 'Enter':
|
|
154
159
|
interaction.current = {
|
|
@@ -156,7 +161,10 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
156
161
|
key: 'Enter'
|
|
157
162
|
};
|
|
158
163
|
// Trigger click unless this is a link. Links trigger click natively.
|
|
159
|
-
if (e.
|
|
164
|
+
if ((0, $7Kjv5$getEventTarget)(e).tagName !== 'A') (0, $7Kjv5$getEventTarget)(e).click();
|
|
165
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
166
|
+
// to the newly opened submenu's first item.
|
|
167
|
+
(0, $7Kjv5$setInteractionModality)('keyboard');
|
|
160
168
|
break;
|
|
161
169
|
default:
|
|
162
170
|
if (!isTrigger) e.continuePropagation();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {menuData as $fc79756100351201$export$6f49b4016bfc8d56} from "./utils.module.js";
|
|
2
|
-
import {useRouter as $7Kjv5$useRouter, useSlotId as $7Kjv5$useSlotId, handleLinkClick as $7Kjv5$handleLinkClick, filterDOMProps as $7Kjv5$filterDOMProps, useLinkProps as $7Kjv5$useLinkProps, mergeProps as $7Kjv5$mergeProps} from "@react-aria/utils";
|
|
2
|
+
import {useRouter as $7Kjv5$useRouter, useSlotId as $7Kjv5$useSlotId, handleLinkClick as $7Kjv5$handleLinkClick, getEventTarget as $7Kjv5$getEventTarget, filterDOMProps as $7Kjv5$filterDOMProps, useLinkProps as $7Kjv5$useLinkProps, mergeProps as $7Kjv5$mergeProps} from "@react-aria/utils";
|
|
3
3
|
import {getItemCount as $7Kjv5$getItemCount} from "@react-stately/collections";
|
|
4
|
-
import {usePress as $7Kjv5$usePress, useHover as $7Kjv5$useHover, isFocusVisible as $7Kjv5$isFocusVisible, useKeyboard as $7Kjv5$useKeyboard, useFocusable as $7Kjv5$useFocusable} from "@react-aria/interactions";
|
|
4
|
+
import {usePress as $7Kjv5$usePress, useHover as $7Kjv5$useHover, isFocusVisible as $7Kjv5$isFocusVisible, useKeyboard as $7Kjv5$useKeyboard, setInteractionModality as $7Kjv5$setInteractionModality, useFocusable as $7Kjv5$useFocusable} from "@react-aria/interactions";
|
|
5
5
|
import {useRef as $7Kjv5$useRef} from "react";
|
|
6
6
|
import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selection";
|
|
7
7
|
|
|
@@ -59,6 +59,7 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
59
59
|
'aria-label': props['aria-label'],
|
|
60
60
|
'aria-labelledby': labelId,
|
|
61
61
|
'aria-describedby': [
|
|
62
|
+
props['aria-describedby'],
|
|
62
63
|
descriptionId,
|
|
63
64
|
keyboardId
|
|
64
65
|
].filter(Boolean).join(' ') || undefined,
|
|
@@ -68,7 +69,8 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
68
69
|
};
|
|
69
70
|
if (selectionManager.selectionMode !== 'none' && !isTrigger) ariaProps['aria-checked'] = isSelected;
|
|
70
71
|
if (isVirtualized) {
|
|
71
|
-
|
|
72
|
+
let index = Number(item === null || item === void 0 ? void 0 : item.index);
|
|
73
|
+
ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;
|
|
72
74
|
ariaProps['aria-setsize'] = (0, $7Kjv5$getItemCount)(state.collection);
|
|
73
75
|
}
|
|
74
76
|
let isPressedRef = (0, $7Kjv5$useRef)(false);
|
|
@@ -148,7 +150,10 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
148
150
|
pointerType: 'keyboard',
|
|
149
151
|
key: ' '
|
|
150
152
|
};
|
|
151
|
-
e.
|
|
153
|
+
(0, $7Kjv5$getEventTarget)(e).click();
|
|
154
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
155
|
+
// to the newly opened submenu's first item.
|
|
156
|
+
(0, $7Kjv5$setInteractionModality)('keyboard');
|
|
152
157
|
break;
|
|
153
158
|
case 'Enter':
|
|
154
159
|
interaction.current = {
|
|
@@ -156,7 +161,10 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
156
161
|
key: 'Enter'
|
|
157
162
|
};
|
|
158
163
|
// Trigger click unless this is a link. Links trigger click natively.
|
|
159
|
-
if (e.
|
|
164
|
+
if ((0, $7Kjv5$getEventTarget)(e).tagName !== 'A') (0, $7Kjv5$getEventTarget)(e).click();
|
|
165
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
166
|
+
// to the newly opened submenu's first item.
|
|
167
|
+
(0, $7Kjv5$setInteractionModality)('keyboard');
|
|
160
168
|
break;
|
|
161
169
|
default:
|
|
162
170
|
if (!isTrigger) e.continuePropagation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useMenuItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';\nimport {filterDOMProps, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';\nimport {getItemCount} from '@react-stately/collections';\nimport {isFocusVisible, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';\nimport {menuData} from './utils';\nimport {MouseEvent, useRef} from 'react';\nimport {SelectionManager} from '@react-stately/selection';\nimport {TreeState} from '@react-stately/tree';\nimport {useSelectableItem} from '@react-aria/selection';\n\nexport interface MenuItemAria {\n /** Props for the menu item element. */\n menuItemProps: DOMAttributes,\n\n /** Props for the main text element inside the menu item. */\n labelProps: DOMAttributes,\n\n /** Props for the description text element inside the menu item, if any. */\n descriptionProps: DOMAttributes,\n\n /** Props for the keyboard shortcut text element inside the item, if any. */\n keyboardShortcutProps: DOMAttributes,\n\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /** Whether the item is keyboard focused. */\n isFocusVisible: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is disabled. */\n isDisabled: boolean\n}\n\nexport interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, KeyboardEvents, FocusEvents {\n /**\n * Whether the menu item is disabled.\n * @deprecated - pass disabledKeys to useTreeState instead.\n */\n isDisabled?: boolean,\n\n /**\n * Whether the menu item is selected.\n * @deprecated - pass selectedKeys to useTreeState instead.\n */\n isSelected?: boolean,\n\n /** A screen reader only label for the menu item. */\n 'aria-label'?: string,\n\n /** The unique key for the menu item. */\n key: Key,\n\n /**\n * Handler that is called when the menu should close after selecting an item.\n * @deprecated - pass to the menu instead.\n */\n onClose?: () => void,\n\n /**\n * Whether the menu should close when the menu item is selected.\n * @deprecated - use shouldCloseOnSelect instead.\n */\n closeOnSelect?: boolean,\n\n /** Whether the menu should close when the menu item is selected. */\n shouldCloseOnSelect?: boolean,\n\n /** Whether the menu item is contained in a virtual scrolling menu. */\n isVirtualized?: boolean,\n\n /**\n * Handler that is called when the user activates the item.\n * @deprecated - pass to the menu instead.\n */\n onAction?: (key: Key) => void,\n\n /** What kind of popup the item opens. */\n 'aria-haspopup'?: 'menu' | 'dialog',\n\n /** Indicates whether the menu item's popup element is expanded or collapsed. */\n 'aria-expanded'?: boolean | 'true' | 'false',\n\n /** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */\n 'aria-controls'?: string,\n\n /** Override of the selection manager. By default, `state.selectionManager` is used. */\n selectionManager?: SelectionManager\n}\n\n/**\n * Provides the behavior and accessibility implementation for an item in a menu.\n * See `useMenu` for more details about menus.\n * @param props - Props for the item.\n * @param state - State for the menu, as returned by `useTreeState`.\n */\nexport function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, ref: RefObject<FocusableElement | null>): MenuItemAria {\n let {\n id,\n key,\n closeOnSelect,\n shouldCloseOnSelect,\n isVirtualized,\n 'aria-haspopup': hasPopup,\n onPressStart,\n onPressUp: pressUpProp,\n onPress,\n onPressChange: pressChangeProp,\n onPressEnd,\n onClick: onClickProp,\n onHoverStart: hoverStartProp,\n onHoverChange,\n onHoverEnd,\n onKeyDown,\n onKeyUp,\n onFocus,\n onFocusChange,\n onBlur,\n selectionManager = state.selectionManager\n } = props;\n\n let isTrigger = !!hasPopup;\n let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';\n let isDisabled = props.isDisabled ?? selectionManager.isDisabled(key);\n let isSelected = props.isSelected ?? selectionManager.isSelected(key);\n let data = menuData.get(state)!;\n let item = state.collection.getItem(key);\n let onClose = props.onClose || data.onClose;\n let router = useRouter();\n let performAction = () => {\n if (isTrigger) {\n return;\n }\n\n if (item?.props?.onAction) {\n item.props.onAction();\n } else if (props.onAction) {\n props.onAction(key);\n }\n\n if (data.onAction) {\n // Must reassign to variable otherwise `this` binding gets messed up. Something to do with WeakMap.\n let onAction = data.onAction;\n onAction(key);\n }\n };\n\n let role = 'menuitem';\n if (!isTrigger) {\n if (selectionManager.selectionMode === 'single') {\n role = 'menuitemradio';\n } else if (selectionManager.selectionMode === 'multiple') {\n role = 'menuitemcheckbox';\n }\n }\n\n let labelId = useSlotId();\n let descriptionId = useSlotId();\n let keyboardId = useSlotId();\n\n let ariaProps = {\n id,\n 'aria-disabled': isDisabled || undefined,\n role,\n 'aria-label': props['aria-label'],\n 'aria-labelledby': labelId,\n 'aria-describedby': [descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,\n 'aria-controls': props['aria-controls'],\n 'aria-haspopup': hasPopup,\n 'aria-expanded': props['aria-expanded']\n };\n\n if (selectionManager.selectionMode !== 'none' && !isTrigger) {\n ariaProps['aria-checked'] = isSelected;\n }\n\n if (isVirtualized) {\n ariaProps['aria-posinset'] = item?.index;\n ariaProps['aria-setsize'] = getItemCount(state.collection);\n }\n\n let isPressedRef = useRef(false);\n let onPressChange = (isPressed: boolean) => {\n pressChangeProp?.(isPressed);\n isPressedRef.current = isPressed;\n };\n\n let interaction = useRef<{pointerType: string, key?: string} | null>(null);\n let onPressUp = (e: PressEvent) => {\n if (e.pointerType !== 'keyboard') {\n interaction.current = {pointerType: e.pointerType};\n }\n\n // If interacting with mouse, allow the user to mouse down on the trigger button,\n // drag, and release over an item (matching native behavior).\n if (e.pointerType === 'mouse') {\n if (!isPressedRef.current) {\n (e.target as HTMLElement).click();\n }\n }\n\n pressUpProp?.(e);\n };\n\n let onClick = (e: MouseEvent<FocusableElement>) => {\n onClickProp?.(e);\n performAction();\n handleLinkClick(e, router, item!.props.href, item?.props.routerOptions);\n\n let shouldClose = interaction.current?.pointerType === 'keyboard'\n // Always close when pressing Enter key, or if item is not selectable.\n ? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)\n // Close except if multi-select is enabled.\n : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);\n\n\n shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;\n\n if (onClose && !isTrigger && shouldClose) {\n onClose();\n }\n\n interaction.current = null;\n };\n\n let {itemProps, isFocused} = useSelectableItem({\n id,\n selectionManager: selectionManager,\n key,\n ref,\n shouldSelectOnPressUp: true,\n allowsDifferentPressOrigin: true,\n // Disable all handling of links in useSelectable item\n // because we handle it ourselves. The behavior of menus\n // is slightly different from other collections because\n // actions are performed on key down rather than key up.\n linkBehavior: 'none',\n shouldUseVirtualFocus: data.shouldUseVirtualFocus\n });\n\n let {pressProps, isPressed} = usePress({\n onPressStart,\n onPress,\n onPressUp,\n onPressChange,\n onPressEnd,\n isDisabled\n });\n let {hoverProps} = useHover({\n isDisabled,\n onHoverStart(e) {\n // Hovering over an already expanded sub dialog trigger should keep focus in the dialog.\n if (!isFocusVisible() && !(isTriggerExpanded && hasPopup)) {\n selectionManager.setFocused(true);\n selectionManager.setFocusedKey(key);\n }\n hoverStartProp?.(e);\n },\n onHoverChange,\n onHoverEnd\n });\n\n let {keyboardProps} = useKeyboard({\n onKeyDown: (e) => {\n // Ignore repeating events, which may have started on the menu trigger before moving\n // focus to the menu item. We want to wait for a second complete key press sequence.\n if (e.repeat) {\n e.continuePropagation();\n return;\n }\n\n switch (e.key) {\n case ' ':\n interaction.current = {pointerType: 'keyboard', key: ' '};\n (e.target as HTMLElement).click();\n break;\n case 'Enter':\n interaction.current = {pointerType: 'keyboard', key: 'Enter'};\n\n // Trigger click unless this is a link. Links trigger click natively.\n if ((e.target as HTMLElement).tagName !== 'A') {\n (e.target as HTMLElement).click();\n }\n break;\n default:\n if (!isTrigger) {\n e.continuePropagation();\n }\n\n onKeyDown?.(e);\n break;\n }\n },\n onKeyUp\n });\n\n let {focusableProps} = useFocusable({onBlur, onFocus, onFocusChange}, ref);\n let domProps = filterDOMProps(item?.props);\n delete domProps.id;\n let linkProps = useLinkProps(item?.props);\n\n return {\n menuItemProps: {\n ...ariaProps,\n ...mergeProps(\n domProps,\n linkProps,\n isTrigger\n ? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}\n : itemProps,\n pressProps,\n hoverProps,\n keyboardProps,\n focusableProps,\n // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.\n data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined,\n isDisabled ? undefined : {onClick}\n ),\n // 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.\n tabIndex: itemProps.tabIndex != null && isTriggerExpanded && !data.shouldUseVirtualFocus ? -1 : itemProps.tabIndex\n },\n labelProps: {\n id: labelId\n },\n descriptionProps: {\n id: descriptionId\n },\n keyboardShortcutProps: {\n id: keyboardId\n },\n isFocused,\n isFocusVisible: isFocused && selectionManager.isFocused && isFocusVisible() && !isTriggerExpanded,\n isSelected,\n isPressed,\n isDisabled\n };\n}\n"],"names":[],"version":3,"file":"useMenuItem.module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useMenuItem.ts"],"sourcesContent":["/*\n * Copyright 2020 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 {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';\nimport {filterDOMProps, getEventTarget, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';\nimport {getItemCount} from '@react-stately/collections';\nimport {isFocusVisible, setInteractionModality, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';\nimport {menuData} from './utils';\nimport {MouseEvent, useRef} from 'react';\nimport {SelectionManager} from '@react-stately/selection';\nimport {TreeState} from '@react-stately/tree';\nimport {useSelectableItem} from '@react-aria/selection';\n\nexport interface MenuItemAria {\n /** Props for the menu item element. */\n menuItemProps: DOMAttributes,\n\n /** Props for the main text element inside the menu item. */\n labelProps: DOMAttributes,\n\n /** Props for the description text element inside the menu item, if any. */\n descriptionProps: DOMAttributes,\n\n /** Props for the keyboard shortcut text element inside the item, if any. */\n keyboardShortcutProps: DOMAttributes,\n\n /** Whether the item is currently focused. */\n isFocused: boolean,\n /** Whether the item is keyboard focused. */\n isFocusVisible: boolean,\n /** Whether the item is currently selected. */\n isSelected: boolean,\n /** Whether the item is currently in a pressed state. */\n isPressed: boolean,\n /** Whether the item is disabled. */\n isDisabled: boolean\n}\n\nexport interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, KeyboardEvents, FocusEvents {\n /**\n * Whether the menu item is disabled.\n * @deprecated - pass disabledKeys to useTreeState instead.\n */\n isDisabled?: boolean,\n\n /**\n * Whether the menu item is selected.\n * @deprecated - pass selectedKeys to useTreeState instead.\n */\n isSelected?: boolean,\n\n /** A screen reader only label for the menu item. */\n 'aria-label'?: string,\n\n /** The unique key for the menu item. */\n key: Key,\n\n /**\n * Handler that is called when the menu should close after selecting an item.\n * @deprecated - pass to the menu instead.\n */\n onClose?: () => void,\n\n /**\n * Whether the menu should close when the menu item is selected.\n * @deprecated - use shouldCloseOnSelect instead.\n */\n closeOnSelect?: boolean,\n\n /** Whether the menu should close when the menu item is selected. */\n shouldCloseOnSelect?: boolean,\n\n /** Whether the menu item is contained in a virtual scrolling menu. */\n isVirtualized?: boolean,\n\n /**\n * Handler that is called when the user activates the item.\n * @deprecated - pass to the menu instead.\n */\n onAction?: (key: Key) => void,\n\n /** What kind of popup the item opens. */\n 'aria-haspopup'?: 'menu' | 'dialog',\n\n /** Indicates whether the menu item's popup element is expanded or collapsed. */\n 'aria-expanded'?: boolean | 'true' | 'false',\n\n /** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */\n 'aria-controls'?: string,\n\n /** Identifies the element(s) that describe the menu item. */\n 'aria-describedby'?: string,\n\n /** Override of the selection manager. By default, `state.selectionManager` is used. */\n selectionManager?: SelectionManager\n}\n\n/**\n * Provides the behavior and accessibility implementation for an item in a menu.\n * See `useMenu` for more details about menus.\n * @param props - Props for the item.\n * @param state - State for the menu, as returned by `useTreeState`.\n */\nexport function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, ref: RefObject<FocusableElement | null>): MenuItemAria {\n let {\n id,\n key,\n closeOnSelect,\n shouldCloseOnSelect,\n isVirtualized,\n 'aria-haspopup': hasPopup,\n onPressStart,\n onPressUp: pressUpProp,\n onPress,\n onPressChange: pressChangeProp,\n onPressEnd,\n onClick: onClickProp,\n onHoverStart: hoverStartProp,\n onHoverChange,\n onHoverEnd,\n onKeyDown,\n onKeyUp,\n onFocus,\n onFocusChange,\n onBlur,\n selectionManager = state.selectionManager\n } = props;\n\n let isTrigger = !!hasPopup;\n let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';\n let isDisabled = props.isDisabled ?? selectionManager.isDisabled(key);\n let isSelected = props.isSelected ?? selectionManager.isSelected(key);\n let data = menuData.get(state)!;\n let item = state.collection.getItem(key);\n let onClose = props.onClose || data.onClose;\n let router = useRouter();\n let performAction = () => {\n if (isTrigger) {\n return;\n }\n\n if (item?.props?.onAction) {\n item.props.onAction();\n } else if (props.onAction) {\n props.onAction(key);\n }\n\n if (data.onAction) {\n // Must reassign to variable otherwise `this` binding gets messed up. Something to do with WeakMap.\n let onAction = data.onAction;\n onAction(key);\n }\n };\n\n let role = 'menuitem';\n if (!isTrigger) {\n if (selectionManager.selectionMode === 'single') {\n role = 'menuitemradio';\n } else if (selectionManager.selectionMode === 'multiple') {\n role = 'menuitemcheckbox';\n }\n }\n\n let labelId = useSlotId();\n let descriptionId = useSlotId();\n let keyboardId = useSlotId();\n\n let ariaProps = {\n id,\n 'aria-disabled': isDisabled || undefined,\n role,\n 'aria-label': props['aria-label'],\n 'aria-labelledby': labelId,\n 'aria-describedby': [props['aria-describedby'], descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,\n 'aria-controls': props['aria-controls'],\n 'aria-haspopup': hasPopup,\n 'aria-expanded': props['aria-expanded']\n };\n\n if (selectionManager.selectionMode !== 'none' && !isTrigger) {\n ariaProps['aria-checked'] = isSelected;\n }\n\n if (isVirtualized) {\n let index = Number(item?.index);\n ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;\n ariaProps['aria-setsize'] = getItemCount(state.collection);\n }\n\n let isPressedRef = useRef(false);\n let onPressChange = (isPressed: boolean) => {\n pressChangeProp?.(isPressed);\n isPressedRef.current = isPressed;\n };\n\n let interaction = useRef<{pointerType: string, key?: string} | null>(null);\n let onPressUp = (e: PressEvent) => {\n if (e.pointerType !== 'keyboard') {\n interaction.current = {pointerType: e.pointerType};\n }\n\n // If interacting with mouse, allow the user to mouse down on the trigger button,\n // drag, and release over an item (matching native behavior).\n if (e.pointerType === 'mouse') {\n if (!isPressedRef.current) {\n (e.target as HTMLElement).click();\n }\n }\n\n pressUpProp?.(e);\n };\n\n let onClick = (e: MouseEvent<FocusableElement>) => {\n onClickProp?.(e);\n performAction();\n handleLinkClick(e, router, item!.props.href, item?.props.routerOptions);\n\n let shouldClose = interaction.current?.pointerType === 'keyboard'\n // Always close when pressing Enter key, or if item is not selectable.\n ? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)\n // Close except if multi-select is enabled.\n : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);\n\n\n shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;\n\n if (onClose && !isTrigger && shouldClose) {\n onClose();\n }\n\n interaction.current = null;\n };\n\n let {itemProps, isFocused} = useSelectableItem({\n id,\n selectionManager: selectionManager,\n key,\n ref,\n shouldSelectOnPressUp: true,\n allowsDifferentPressOrigin: true,\n // Disable all handling of links in useSelectable item\n // because we handle it ourselves. The behavior of menus\n // is slightly different from other collections because\n // actions are performed on key down rather than key up.\n linkBehavior: 'none',\n shouldUseVirtualFocus: data.shouldUseVirtualFocus\n });\n\n let {pressProps, isPressed} = usePress({\n onPressStart,\n onPress,\n onPressUp,\n onPressChange,\n onPressEnd,\n isDisabled\n });\n let {hoverProps} = useHover({\n isDisabled,\n onHoverStart(e) {\n // Hovering over an already expanded sub dialog trigger should keep focus in the dialog.\n if (!isFocusVisible() && !(isTriggerExpanded && hasPopup)) {\n selectionManager.setFocused(true);\n selectionManager.setFocusedKey(key);\n }\n hoverStartProp?.(e);\n },\n onHoverChange,\n onHoverEnd\n });\n\n let {keyboardProps} = useKeyboard({\n onKeyDown: (e) => {\n // Ignore repeating events, which may have started on the menu trigger before moving\n // focus to the menu item. We want to wait for a second complete key press sequence.\n if (e.repeat) {\n e.continuePropagation();\n return;\n }\n\n switch (e.key) {\n case ' ':\n interaction.current = {pointerType: 'keyboard', key: ' '};\n (getEventTarget(e) as HTMLElement).click();\n\n // click above sets modality to \"virtual\", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus\n // to the newly opened submenu's first item.\n setInteractionModality('keyboard');\n break;\n case 'Enter':\n interaction.current = {pointerType: 'keyboard', key: 'Enter'};\n\n // Trigger click unless this is a link. Links trigger click natively.\n if ((getEventTarget(e) as HTMLElement).tagName !== 'A') {\n (getEventTarget(e) as HTMLElement).click();\n }\n\n // click above sets modality to \"virtual\", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus\n // to the newly opened submenu's first item.\n setInteractionModality('keyboard');\n break;\n default:\n if (!isTrigger) {\n e.continuePropagation();\n }\n\n onKeyDown?.(e);\n break;\n }\n },\n onKeyUp\n });\n\n let {focusableProps} = useFocusable({onBlur, onFocus, onFocusChange}, ref);\n let domProps = filterDOMProps(item?.props);\n delete domProps.id;\n let linkProps = useLinkProps(item?.props);\n\n return {\n menuItemProps: {\n ...ariaProps,\n ...mergeProps(\n domProps,\n linkProps,\n isTrigger\n ? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}\n : itemProps,\n pressProps,\n hoverProps,\n keyboardProps,\n focusableProps,\n // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.\n data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined,\n isDisabled ? undefined : {onClick}\n ),\n // 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.\n tabIndex: itemProps.tabIndex != null && isTriggerExpanded && !data.shouldUseVirtualFocus ? -1 : itemProps.tabIndex\n },\n labelProps: {\n id: labelId\n },\n descriptionProps: {\n id: descriptionId\n },\n keyboardShortcutProps: {\n id: keyboardId\n },\n isFocused,\n isFocusVisible: isFocused && selectionManager.isFocused && isFocusVisible() && !isTriggerExpanded,\n isSelected,\n isPressed,\n isDisabled\n };\n}\n"],"names":[],"version":3,"file":"useMenuItem.module.js.map"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {nodeContains, useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useInteractionModality} from '@react-aria/interactions';\n\ninterface SafelyMouseToSubmenuOptions {\n /** Ref for the parent menu. */\n menuRef: RefObject<Element | null>,\n /** Ref for the submenu. */\n submenuRef: RefObject<Element | null>,\n /** Whether the submenu is open. */\n isOpen: boolean,\n /** Whether this feature is disabled. */\n isDisabled?: boolean\n}\n\nconst ALLOWED_INVALID_MOVEMENTS = 2;\nconst THROTTLE_TIME = 50;\nconst TIMEOUT_TIME = 1000;\nconst ANGLE_PADDING = Math.PI / 12; // 15°\n\n/**\n * Allows the user to move their pointer to the submenu without it closing when their mouse leaves the trigger element.\n * Prevents pointer events from going to the underlying menu if the user is moving their pointer towards the sub-menu.\n */\nexport function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): void {\n let {menuRef, submenuRef, isOpen, isDisabled} = options;\n let prevPointerPos = useRef<{x: number, y: number} | undefined>(undefined);\n let submenuRect = useRef<DOMRect | undefined>(undefined);\n let lastProcessedTime = useRef<number>(0);\n let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let autoCloseTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let submenuSide = useRef<'left' | 'right' | undefined>(undefined);\n let movementsTowardsSubmenuCount = useRef<number>(2);\n let [preventPointerEvents, setPreventPointerEvents] = useState(false);\n\n let updateSubmenuRect = () => {\n if (submenuRef.current) {\n submenuRect.current = submenuRef.current.getBoundingClientRect();\n submenuSide.current = undefined;\n }\n };\n useResizeObserver({ref: submenuRef, onResize: updateSubmenuRect});\n\n let reset = () => {\n setPreventPointerEvents(false);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n prevPointerPos.current = undefined;\n };\n\n let modality = useInteractionModality();\n\n // Prevent mouse down over safe triangle. Clicking while pointer-events: none is applied\n // will cause focus to move unexpectedly since it will go to an element behind the menu.\n let onPointerDown = useEffectEvent((e: PointerEvent) => {\n if (preventPointerEvents) {\n e.preventDefault();\n }\n });\n\n useEffect(() => {\n if (preventPointerEvents && menuRef.current) {\n (menuRef.current as HTMLElement).style.pointerEvents = 'none';\n } else {\n (menuRef.current as HTMLElement).style.pointerEvents = '';\n }\n }, [menuRef, preventPointerEvents]);\n\n useLayoutEffect(() => {\n let submenu = submenuRef.current;\n let menu = menuRef.current;\n\n if (isDisabled || !submenu || !isOpen || modality !== 'pointer' || !menu) {\n reset();\n return;\n }\n submenuRect.current = submenu.getBoundingClientRect();\n\n let onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch' || e.pointerType === 'pen') {\n return;\n }\n\n let currentTime = Date.now();\n\n // Throttle\n if (currentTime - lastProcessedTime.current < THROTTLE_TIME) {\n return;\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n\n let {clientX: mouseX, clientY: mouseY} = e;\n\n if (!prevPointerPos.current) {\n prevPointerPos.current = {x: mouseX, y: mouseY};\n return;\n }\n\n if (!submenuRect.current) {\n return;\n }\n\n if (!submenuSide.current) {\n submenuSide.current = mouseX > submenuRect.current.right ? 'left' : 'right';\n }\n\n // Pointer is outside of parent menu\n if (mouseX < menu.getBoundingClientRect().left || mouseX > menu.getBoundingClientRect().right || mouseY < menu.getBoundingClientRect().top || mouseY > menu.getBoundingClientRect().bottom) {\n reset();\n return;\n }\n\n /* Check if pointer is moving towards submenu.\n Uses the 2-argument arctangent (https://en.wikipedia.org/wiki/Atan2) to calculate:\n - angle between previous pointer and top of submenu\n - angle between previous pointer and bottom of submenu\n - angle between previous pointer and current pointer (delta)\n If the pointer delta angle value is between the top and bottom angle values, we know the pointer is moving towards the submenu.\n */\n let prevMouseX = prevPointerPos.current.x;\n let prevMouseY = prevPointerPos.current.y;\n let toSubmenuX = submenuSide.current === 'right' ? submenuRect.current.left - prevMouseX : prevMouseX - submenuRect.current.right;\n let angleTop = Math.atan2(prevMouseY - submenuRect.current.top, toSubmenuX) + ANGLE_PADDING;\n let angleBottom = Math.atan2(prevMouseY - submenuRect.current.bottom, toSubmenuX) - ANGLE_PADDING;\n let anglePointer = Math.atan2(prevMouseY - mouseY, (submenuSide.current === 'left' ? -(mouseX - prevMouseX) : mouseX - prevMouseX));\n let isMovingTowardsSubmenu = anglePointer < angleTop && anglePointer > angleBottom;\n\n movementsTowardsSubmenuCount.current = isMovingTowardsSubmenu ?\n Math.min(movementsTowardsSubmenuCount.current + 1, ALLOWED_INVALID_MOVEMENTS) :\n Math.max(movementsTowardsSubmenuCount.current - 1, 0);\n\n if (movementsTowardsSubmenuCount.current >= ALLOWED_INVALID_MOVEMENTS) {\n setPreventPointerEvents(true);\n } else {\n setPreventPointerEvents(false);\n }\n\n lastProcessedTime.current = currentTime;\n prevPointerPos.current = {x: mouseX, y: mouseY};\n\n // If the pointer is moving towards the submenu, start a timeout to close if no other movements are made after 500ms.\n if (isMovingTowardsSubmenu) {\n timeout.current = setTimeout(() => {\n reset();\n autoCloseTimeout.current = setTimeout(() => {\n // Fire a pointerover event to trigger the menu to close.\n // Wait until pointer-events:none is no longer applied\n let target = document.elementFromPoint(mouseX, mouseY);\n if (target && nodeContains(menu, target)) {\n target.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));\n }\n }, 100);\n }, TIMEOUT_TIME);\n }\n };\n\n window.addEventListener('pointermove', onPointerMove);\n\n // Prevent pointer down over the safe triangle. See above comment.\n // Do not enable in tests, because JSDom doesn't do hit testing.\n if (process.env.NODE_ENV !== 'test') {\n window.addEventListener('pointerdown', onPointerDown, true);\n }\n\n return () => {\n window.removeEventListener('pointermove', onPointerMove);\n if (process.env.NODE_ENV !== 'test') {\n window.removeEventListener('pointerdown', onPointerDown, true);\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n };\n\n }, [isDisabled, isOpen, menuRef, modality, setPreventPointerEvents, submenuRef]);\n}\n"],"names":[],"version":3,"file":"useSafelyMouseToSubmenu.main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {nodeContains, useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useInteractionModality} from '@react-aria/interactions';\n\ninterface SafelyMouseToSubmenuOptions {\n /** Ref for the parent menu. */\n menuRef: RefObject<Element | null>,\n /** Ref for the submenu. */\n submenuRef: RefObject<Element | null>,\n /** Whether the submenu is open. */\n isOpen: boolean,\n /** Whether this feature is disabled. */\n isDisabled?: boolean\n}\n\nconst ALLOWED_INVALID_MOVEMENTS = 2;\nconst THROTTLE_TIME = 50;\nconst TIMEOUT_TIME = 1000;\nconst ANGLE_PADDING = Math.PI / 12; // 15°\n\n/**\n * Allows the user to move their pointer to the submenu without it closing when their mouse leaves the trigger element.\n * Prevents pointer events from going to the underlying menu if the user is moving their pointer towards the sub-menu.\n */\nexport function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): void {\n let {menuRef, submenuRef, isOpen, isDisabled} = options;\n let prevPointerPos = useRef<{x: number, y: number} | undefined>(undefined);\n let submenuRect = useRef<DOMRect | undefined>(undefined);\n let lastProcessedTime = useRef<number>(0);\n let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let autoCloseTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let submenuSide = useRef<'left' | 'right' | undefined>(undefined);\n let movementsTowardsSubmenuCount = useRef<number>(2);\n let [preventPointerEvents, setPreventPointerEvents] = useState(false);\n\n let updateSubmenuRect = () => {\n if (submenuRef.current) {\n submenuRect.current = submenuRef.current.getBoundingClientRect();\n submenuSide.current = undefined;\n }\n };\n useResizeObserver({ref: isOpen ? submenuRef : undefined, onResize: updateSubmenuRect});\n\n let reset = () => {\n setPreventPointerEvents(false);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n prevPointerPos.current = undefined;\n };\n\n let modality = useInteractionModality();\n\n // Prevent mouse down over safe triangle. Clicking while pointer-events: none is applied\n // will cause focus to move unexpectedly since it will go to an element behind the menu.\n let onPointerDown = useEffectEvent((e: PointerEvent) => {\n if (preventPointerEvents) {\n e.preventDefault();\n }\n });\n\n useEffect(() => {\n if (preventPointerEvents && menuRef.current) {\n (menuRef.current as HTMLElement).style.pointerEvents = 'none';\n } else {\n (menuRef.current as HTMLElement).style.pointerEvents = '';\n }\n }, [menuRef, preventPointerEvents]);\n\n useLayoutEffect(() => {\n let submenu = submenuRef.current;\n let menu = menuRef.current;\n\n if (isDisabled || !submenu || !isOpen || modality !== 'pointer' || !menu) {\n reset();\n return;\n }\n submenuRect.current = submenu.getBoundingClientRect();\n\n let onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch' || e.pointerType === 'pen') {\n return;\n }\n\n let currentTime = Date.now();\n\n // Throttle\n if (currentTime - lastProcessedTime.current < THROTTLE_TIME) {\n return;\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n\n let {clientX: mouseX, clientY: mouseY} = e;\n\n if (!prevPointerPos.current) {\n prevPointerPos.current = {x: mouseX, y: mouseY};\n return;\n }\n\n if (!submenuRect.current) {\n return;\n }\n\n if (!submenuSide.current) {\n submenuSide.current = mouseX > submenuRect.current.right ? 'left' : 'right';\n }\n\n // Pointer is outside of parent menu\n if (mouseX < menu.getBoundingClientRect().left || mouseX > menu.getBoundingClientRect().right || mouseY < menu.getBoundingClientRect().top || mouseY > menu.getBoundingClientRect().bottom) {\n reset();\n return;\n }\n\n /* Check if pointer is moving towards submenu.\n Uses the 2-argument arctangent (https://en.wikipedia.org/wiki/Atan2) to calculate:\n - angle between previous pointer and top of submenu\n - angle between previous pointer and bottom of submenu\n - angle between previous pointer and current pointer (delta)\n If the pointer delta angle value is between the top and bottom angle values, we know the pointer is moving towards the submenu.\n */\n let prevMouseX = prevPointerPos.current.x;\n let prevMouseY = prevPointerPos.current.y;\n let toSubmenuX = submenuSide.current === 'right' ? submenuRect.current.left - prevMouseX : prevMouseX - submenuRect.current.right;\n let angleTop = Math.atan2(prevMouseY - submenuRect.current.top, toSubmenuX) + ANGLE_PADDING;\n let angleBottom = Math.atan2(prevMouseY - submenuRect.current.bottom, toSubmenuX) - ANGLE_PADDING;\n let anglePointer = Math.atan2(prevMouseY - mouseY, (submenuSide.current === 'left' ? -(mouseX - prevMouseX) : mouseX - prevMouseX));\n let isMovingTowardsSubmenu = anglePointer < angleTop && anglePointer > angleBottom;\n\n movementsTowardsSubmenuCount.current = isMovingTowardsSubmenu ?\n Math.min(movementsTowardsSubmenuCount.current + 1, ALLOWED_INVALID_MOVEMENTS) :\n Math.max(movementsTowardsSubmenuCount.current - 1, 0);\n\n if (movementsTowardsSubmenuCount.current >= ALLOWED_INVALID_MOVEMENTS) {\n setPreventPointerEvents(true);\n } else {\n setPreventPointerEvents(false);\n }\n\n lastProcessedTime.current = currentTime;\n prevPointerPos.current = {x: mouseX, y: mouseY};\n\n // If the pointer is moving towards the submenu, start a timeout to close if no other movements are made after 500ms.\n if (isMovingTowardsSubmenu) {\n timeout.current = setTimeout(() => {\n reset();\n autoCloseTimeout.current = setTimeout(() => {\n // Fire a pointerover event to trigger the menu to close.\n // Wait until pointer-events:none is no longer applied\n let target = document.elementFromPoint(mouseX, mouseY);\n if (target && nodeContains(menu, target)) {\n target.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));\n }\n }, 100);\n }, TIMEOUT_TIME);\n }\n };\n\n window.addEventListener('pointermove', onPointerMove);\n\n // Prevent pointer down over the safe triangle. See above comment.\n // Do not enable in tests, because JSDom doesn't do hit testing.\n if (process.env.NODE_ENV !== 'test') {\n window.addEventListener('pointerdown', onPointerDown, true);\n }\n\n return () => {\n window.removeEventListener('pointermove', onPointerMove);\n if (process.env.NODE_ENV !== 'test') {\n window.removeEventListener('pointerdown', onPointerDown, true);\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n };\n\n }, [isDisabled, isOpen, menuRef, modality, setPreventPointerEvents, submenuRef]);\n}\n"],"names":[],"version":3,"file":"useSafelyMouseToSubmenu.main.js.map"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {nodeContains, useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useInteractionModality} from '@react-aria/interactions';\n\ninterface SafelyMouseToSubmenuOptions {\n /** Ref for the parent menu. */\n menuRef: RefObject<Element | null>,\n /** Ref for the submenu. */\n submenuRef: RefObject<Element | null>,\n /** Whether the submenu is open. */\n isOpen: boolean,\n /** Whether this feature is disabled. */\n isDisabled?: boolean\n}\n\nconst ALLOWED_INVALID_MOVEMENTS = 2;\nconst THROTTLE_TIME = 50;\nconst TIMEOUT_TIME = 1000;\nconst ANGLE_PADDING = Math.PI / 12; // 15°\n\n/**\n * Allows the user to move their pointer to the submenu without it closing when their mouse leaves the trigger element.\n * Prevents pointer events from going to the underlying menu if the user is moving their pointer towards the sub-menu.\n */\nexport function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): void {\n let {menuRef, submenuRef, isOpen, isDisabled} = options;\n let prevPointerPos = useRef<{x: number, y: number} | undefined>(undefined);\n let submenuRect = useRef<DOMRect | undefined>(undefined);\n let lastProcessedTime = useRef<number>(0);\n let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let autoCloseTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let submenuSide = useRef<'left' | 'right' | undefined>(undefined);\n let movementsTowardsSubmenuCount = useRef<number>(2);\n let [preventPointerEvents, setPreventPointerEvents] = useState(false);\n\n let updateSubmenuRect = () => {\n if (submenuRef.current) {\n submenuRect.current = submenuRef.current.getBoundingClientRect();\n submenuSide.current = undefined;\n }\n };\n useResizeObserver({ref: submenuRef, onResize: updateSubmenuRect});\n\n let reset = () => {\n setPreventPointerEvents(false);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n prevPointerPos.current = undefined;\n };\n\n let modality = useInteractionModality();\n\n // Prevent mouse down over safe triangle. Clicking while pointer-events: none is applied\n // will cause focus to move unexpectedly since it will go to an element behind the menu.\n let onPointerDown = useEffectEvent((e: PointerEvent) => {\n if (preventPointerEvents) {\n e.preventDefault();\n }\n });\n\n useEffect(() => {\n if (preventPointerEvents && menuRef.current) {\n (menuRef.current as HTMLElement).style.pointerEvents = 'none';\n } else {\n (menuRef.current as HTMLElement).style.pointerEvents = '';\n }\n }, [menuRef, preventPointerEvents]);\n\n useLayoutEffect(() => {\n let submenu = submenuRef.current;\n let menu = menuRef.current;\n\n if (isDisabled || !submenu || !isOpen || modality !== 'pointer' || !menu) {\n reset();\n return;\n }\n submenuRect.current = submenu.getBoundingClientRect();\n\n let onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch' || e.pointerType === 'pen') {\n return;\n }\n\n let currentTime = Date.now();\n\n // Throttle\n if (currentTime - lastProcessedTime.current < THROTTLE_TIME) {\n return;\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n\n let {clientX: mouseX, clientY: mouseY} = e;\n\n if (!prevPointerPos.current) {\n prevPointerPos.current = {x: mouseX, y: mouseY};\n return;\n }\n\n if (!submenuRect.current) {\n return;\n }\n\n if (!submenuSide.current) {\n submenuSide.current = mouseX > submenuRect.current.right ? 'left' : 'right';\n }\n\n // Pointer is outside of parent menu\n if (mouseX < menu.getBoundingClientRect().left || mouseX > menu.getBoundingClientRect().right || mouseY < menu.getBoundingClientRect().top || mouseY > menu.getBoundingClientRect().bottom) {\n reset();\n return;\n }\n\n /* Check if pointer is moving towards submenu.\n Uses the 2-argument arctangent (https://en.wikipedia.org/wiki/Atan2) to calculate:\n - angle between previous pointer and top of submenu\n - angle between previous pointer and bottom of submenu\n - angle between previous pointer and current pointer (delta)\n If the pointer delta angle value is between the top and bottom angle values, we know the pointer is moving towards the submenu.\n */\n let prevMouseX = prevPointerPos.current.x;\n let prevMouseY = prevPointerPos.current.y;\n let toSubmenuX = submenuSide.current === 'right' ? submenuRect.current.left - prevMouseX : prevMouseX - submenuRect.current.right;\n let angleTop = Math.atan2(prevMouseY - submenuRect.current.top, toSubmenuX) + ANGLE_PADDING;\n let angleBottom = Math.atan2(prevMouseY - submenuRect.current.bottom, toSubmenuX) - ANGLE_PADDING;\n let anglePointer = Math.atan2(prevMouseY - mouseY, (submenuSide.current === 'left' ? -(mouseX - prevMouseX) : mouseX - prevMouseX));\n let isMovingTowardsSubmenu = anglePointer < angleTop && anglePointer > angleBottom;\n\n movementsTowardsSubmenuCount.current = isMovingTowardsSubmenu ?\n Math.min(movementsTowardsSubmenuCount.current + 1, ALLOWED_INVALID_MOVEMENTS) :\n Math.max(movementsTowardsSubmenuCount.current - 1, 0);\n\n if (movementsTowardsSubmenuCount.current >= ALLOWED_INVALID_MOVEMENTS) {\n setPreventPointerEvents(true);\n } else {\n setPreventPointerEvents(false);\n }\n\n lastProcessedTime.current = currentTime;\n prevPointerPos.current = {x: mouseX, y: mouseY};\n\n // If the pointer is moving towards the submenu, start a timeout to close if no other movements are made after 500ms.\n if (isMovingTowardsSubmenu) {\n timeout.current = setTimeout(() => {\n reset();\n autoCloseTimeout.current = setTimeout(() => {\n // Fire a pointerover event to trigger the menu to close.\n // Wait until pointer-events:none is no longer applied\n let target = document.elementFromPoint(mouseX, mouseY);\n if (target && nodeContains(menu, target)) {\n target.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));\n }\n }, 100);\n }, TIMEOUT_TIME);\n }\n };\n\n window.addEventListener('pointermove', onPointerMove);\n\n // Prevent pointer down over the safe triangle. See above comment.\n // Do not enable in tests, because JSDom doesn't do hit testing.\n if (process.env.NODE_ENV !== 'test') {\n window.addEventListener('pointerdown', onPointerDown, true);\n }\n\n return () => {\n window.removeEventListener('pointermove', onPointerMove);\n if (process.env.NODE_ENV !== 'test') {\n window.removeEventListener('pointerdown', onPointerDown, true);\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n };\n\n }, [isDisabled, isOpen, menuRef, modality, setPreventPointerEvents, submenuRef]);\n}\n"],"names":[],"version":3,"file":"useSafelyMouseToSubmenu.module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {nodeContains, useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useInteractionModality} from '@react-aria/interactions';\n\ninterface SafelyMouseToSubmenuOptions {\n /** Ref for the parent menu. */\n menuRef: RefObject<Element | null>,\n /** Ref for the submenu. */\n submenuRef: RefObject<Element | null>,\n /** Whether the submenu is open. */\n isOpen: boolean,\n /** Whether this feature is disabled. */\n isDisabled?: boolean\n}\n\nconst ALLOWED_INVALID_MOVEMENTS = 2;\nconst THROTTLE_TIME = 50;\nconst TIMEOUT_TIME = 1000;\nconst ANGLE_PADDING = Math.PI / 12; // 15°\n\n/**\n * Allows the user to move their pointer to the submenu without it closing when their mouse leaves the trigger element.\n * Prevents pointer events from going to the underlying menu if the user is moving their pointer towards the sub-menu.\n */\nexport function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): void {\n let {menuRef, submenuRef, isOpen, isDisabled} = options;\n let prevPointerPos = useRef<{x: number, y: number} | undefined>(undefined);\n let submenuRect = useRef<DOMRect | undefined>(undefined);\n let lastProcessedTime = useRef<number>(0);\n let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let autoCloseTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n let submenuSide = useRef<'left' | 'right' | undefined>(undefined);\n let movementsTowardsSubmenuCount = useRef<number>(2);\n let [preventPointerEvents, setPreventPointerEvents] = useState(false);\n\n let updateSubmenuRect = () => {\n if (submenuRef.current) {\n submenuRect.current = submenuRef.current.getBoundingClientRect();\n submenuSide.current = undefined;\n }\n };\n useResizeObserver({ref: isOpen ? submenuRef : undefined, onResize: updateSubmenuRect});\n\n let reset = () => {\n setPreventPointerEvents(false);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n prevPointerPos.current = undefined;\n };\n\n let modality = useInteractionModality();\n\n // Prevent mouse down over safe triangle. Clicking while pointer-events: none is applied\n // will cause focus to move unexpectedly since it will go to an element behind the menu.\n let onPointerDown = useEffectEvent((e: PointerEvent) => {\n if (preventPointerEvents) {\n e.preventDefault();\n }\n });\n\n useEffect(() => {\n if (preventPointerEvents && menuRef.current) {\n (menuRef.current as HTMLElement).style.pointerEvents = 'none';\n } else {\n (menuRef.current as HTMLElement).style.pointerEvents = '';\n }\n }, [menuRef, preventPointerEvents]);\n\n useLayoutEffect(() => {\n let submenu = submenuRef.current;\n let menu = menuRef.current;\n\n if (isDisabled || !submenu || !isOpen || modality !== 'pointer' || !menu) {\n reset();\n return;\n }\n submenuRect.current = submenu.getBoundingClientRect();\n\n let onPointerMove = (e: PointerEvent) => {\n if (e.pointerType === 'touch' || e.pointerType === 'pen') {\n return;\n }\n\n let currentTime = Date.now();\n\n // Throttle\n if (currentTime - lastProcessedTime.current < THROTTLE_TIME) {\n return;\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n\n let {clientX: mouseX, clientY: mouseY} = e;\n\n if (!prevPointerPos.current) {\n prevPointerPos.current = {x: mouseX, y: mouseY};\n return;\n }\n\n if (!submenuRect.current) {\n return;\n }\n\n if (!submenuSide.current) {\n submenuSide.current = mouseX > submenuRect.current.right ? 'left' : 'right';\n }\n\n // Pointer is outside of parent menu\n if (mouseX < menu.getBoundingClientRect().left || mouseX > menu.getBoundingClientRect().right || mouseY < menu.getBoundingClientRect().top || mouseY > menu.getBoundingClientRect().bottom) {\n reset();\n return;\n }\n\n /* Check if pointer is moving towards submenu.\n Uses the 2-argument arctangent (https://en.wikipedia.org/wiki/Atan2) to calculate:\n - angle between previous pointer and top of submenu\n - angle between previous pointer and bottom of submenu\n - angle between previous pointer and current pointer (delta)\n If the pointer delta angle value is between the top and bottom angle values, we know the pointer is moving towards the submenu.\n */\n let prevMouseX = prevPointerPos.current.x;\n let prevMouseY = prevPointerPos.current.y;\n let toSubmenuX = submenuSide.current === 'right' ? submenuRect.current.left - prevMouseX : prevMouseX - submenuRect.current.right;\n let angleTop = Math.atan2(prevMouseY - submenuRect.current.top, toSubmenuX) + ANGLE_PADDING;\n let angleBottom = Math.atan2(prevMouseY - submenuRect.current.bottom, toSubmenuX) - ANGLE_PADDING;\n let anglePointer = Math.atan2(prevMouseY - mouseY, (submenuSide.current === 'left' ? -(mouseX - prevMouseX) : mouseX - prevMouseX));\n let isMovingTowardsSubmenu = anglePointer < angleTop && anglePointer > angleBottom;\n\n movementsTowardsSubmenuCount.current = isMovingTowardsSubmenu ?\n Math.min(movementsTowardsSubmenuCount.current + 1, ALLOWED_INVALID_MOVEMENTS) :\n Math.max(movementsTowardsSubmenuCount.current - 1, 0);\n\n if (movementsTowardsSubmenuCount.current >= ALLOWED_INVALID_MOVEMENTS) {\n setPreventPointerEvents(true);\n } else {\n setPreventPointerEvents(false);\n }\n\n lastProcessedTime.current = currentTime;\n prevPointerPos.current = {x: mouseX, y: mouseY};\n\n // If the pointer is moving towards the submenu, start a timeout to close if no other movements are made after 500ms.\n if (isMovingTowardsSubmenu) {\n timeout.current = setTimeout(() => {\n reset();\n autoCloseTimeout.current = setTimeout(() => {\n // Fire a pointerover event to trigger the menu to close.\n // Wait until pointer-events:none is no longer applied\n let target = document.elementFromPoint(mouseX, mouseY);\n if (target && nodeContains(menu, target)) {\n target.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));\n }\n }, 100);\n }, TIMEOUT_TIME);\n }\n };\n\n window.addEventListener('pointermove', onPointerMove);\n\n // Prevent pointer down over the safe triangle. See above comment.\n // Do not enable in tests, because JSDom doesn't do hit testing.\n if (process.env.NODE_ENV !== 'test') {\n window.addEventListener('pointerdown', onPointerDown, true);\n }\n\n return () => {\n window.removeEventListener('pointermove', onPointerMove);\n if (process.env.NODE_ENV !== 'test') {\n window.removeEventListener('pointerdown', onPointerDown, true);\n }\n clearTimeout(timeout.current);\n clearTimeout(autoCloseTimeout.current);\n movementsTowardsSubmenuCount.current = ALLOWED_INVALID_MOVEMENTS;\n };\n\n }, [isDisabled, isOpen, menuRef, modality, setPreventPointerEvents, submenuRef]);\n}\n"],"names":[],"version":3,"file":"useSafelyMouseToSubmenu.module.js.map"}
|
|
@@ -61,10 +61,10 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
61
61
|
let submenuKeyDown = (e)=>{
|
|
62
62
|
// If focus is not within the menu, assume virtual focus is being used.
|
|
63
63
|
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
64
|
-
if (!(0, $23MMN$reactariautils.
|
|
64
|
+
if (!(0, $23MMN$reactariautils.isFocusWithin)(e.currentTarget)) return;
|
|
65
65
|
switch(e.key){
|
|
66
66
|
case 'ArrowLeft':
|
|
67
|
-
if (direction === 'ltr' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget,
|
|
67
|
+
if (direction === 'ltr' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget, (0, $23MMN$reactariautils.getEventTarget)(e))) {
|
|
68
68
|
e.preventDefault();
|
|
69
69
|
e.stopPropagation();
|
|
70
70
|
onSubmenuClose();
|
|
@@ -72,7 +72,7 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
72
72
|
}
|
|
73
73
|
break;
|
|
74
74
|
case 'ArrowRight':
|
|
75
|
-
if (direction === 'rtl' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget,
|
|
75
|
+
if (direction === 'rtl' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget, (0, $23MMN$reactariautils.getEventTarget)(e))) {
|
|
76
76
|
e.preventDefault();
|
|
77
77
|
e.stopPropagation();
|
|
78
78
|
onSubmenuClose();
|
|
@@ -81,7 +81,7 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
81
81
|
break;
|
|
82
82
|
case 'Escape':
|
|
83
83
|
// TODO: can remove this when we fix collection event leaks
|
|
84
|
-
if ((0, $23MMN$reactariautils.nodeContains)(submenuRef.current,
|
|
84
|
+
if ((0, $23MMN$reactariautils.nodeContains)(submenuRef.current, (0, $23MMN$reactariautils.getEventTarget)(e))) {
|
|
85
85
|
e.stopPropagation();
|
|
86
86
|
onSubmenuClose();
|
|
87
87
|
if (!shouldUseVirtualFocus && ref.current) (0, $23MMN$reactariautils.focusWithoutScrolling)(ref.current);
|
|
@@ -107,7 +107,7 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
107
107
|
if (direction === 'ltr') {
|
|
108
108
|
e.preventDefault();
|
|
109
109
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
110
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
110
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $23MMN$reactariautils.getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $23MMN$reactariautils.focusWithoutScrolling)(submenuRef.current);
|
|
111
111
|
} else if (state.isOpen) onSubmenuClose();
|
|
112
112
|
else e.continuePropagation();
|
|
113
113
|
}
|
|
@@ -117,7 +117,7 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
117
117
|
if (direction === 'rtl') {
|
|
118
118
|
e.preventDefault();
|
|
119
119
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
120
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
120
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $23MMN$reactariautils.getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $23MMN$reactariautils.focusWithoutScrolling)(submenuRef.current);
|
|
121
121
|
} else if (state.isOpen) onSubmenuClose();
|
|
122
122
|
else e.continuePropagation();
|
|
123
123
|
}
|
|
@@ -148,7 +148,7 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
148
148
|
(0, $23MMN$reactariautils.useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
149
149
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
150
150
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
151
|
-
if (state.isOpen && (0, $23MMN$reactariautils.nodeContains)(parentMenuRef.current,
|
|
151
|
+
if (state.isOpen && (0, $23MMN$reactariautils.nodeContains)(parentMenuRef.current, (0, $23MMN$reactariautils.getEventTarget)(e)) && (0, $23MMN$reactariautils.getEventTarget)(e) !== ref.current) onSubmenuClose();
|
|
152
152
|
});
|
|
153
153
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
154
154
|
if (target !== ref.current) return true;
|
|
@@ -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 {focusWithoutScrolling, nodeContains, useEvent, 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 = useCallback((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n }, [state, cancelOpenTimeout]);\n\n let onSubmenuClose = useCallback(() => {\n cancelOpenTimeout();\n state.close();\n }, [state, cancelOpenTimeout]);\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 (!nodeContains(e.currentTarget, document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && nodeContains(e.currentTarget, 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' && nodeContains(e.currentTarget, 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 (nodeContains(submenuRef.current, 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 useEvent(parentMenuRef, 'focusin', (e) => {\n // If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in\n // then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open\n if (state.isOpen && (nodeContains(parentMenuRef.current, e.target as HTMLElement) && e.target !== ref.current)) {\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 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
|
+
{"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, getActiveElement, getEventTarget, isFocusWithin, nodeContains, useEvent, 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' | 'onAction'> {\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 = useCallback((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n }, [state, cancelOpenTimeout]);\n\n let onSubmenuClose = useCallback(() => {\n cancelOpenTimeout();\n state.close();\n }, [state, cancelOpenTimeout]);\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 (!isFocusWithin(e.currentTarget)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && nodeContains(e.currentTarget, getEventTarget(e) 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' && nodeContains(e.currentTarget, getEventTarget(e) 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 (nodeContains(submenuRef.current, getEventTarget(e) 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 && getActiveElement() === 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 && getActiveElement() === 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 useEvent(parentMenuRef, 'focusin', (e) => {\n // If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in\n // then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open\n if (state.isOpen && (nodeContains(parentMenuRef.current, getEventTarget(e) as HTMLElement) && getEventTarget(e) !== ref.current)) {\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 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,5 +1,5 @@
|
|
|
1
1
|
import {useSafelyMouseToSubmenu as $d275435c250248f8$export$85ec83e04c95f50a} from "./useSafelyMouseToSubmenu.mjs";
|
|
2
|
-
import {useId as $dXlYe$useId, useLayoutEffect as $dXlYe$useLayoutEffect, nodeContains as $dXlYe$nodeContains, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
2
|
+
import {useId as $dXlYe$useId, useLayoutEffect as $dXlYe$useLayoutEffect, isFocusWithin as $dXlYe$isFocusWithin, nodeContains as $dXlYe$nodeContains, getEventTarget as $dXlYe$getEventTarget, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, getActiveElement as $dXlYe$getActiveElement, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
3
3
|
import {useRef as $dXlYe$useRef, useCallback as $dXlYe$useCallback} from "react";
|
|
4
4
|
import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
5
5
|
|
|
@@ -55,10 +55,10 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
55
55
|
let submenuKeyDown = (e)=>{
|
|
56
56
|
// If focus is not within the menu, assume virtual focus is being used.
|
|
57
57
|
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
58
|
-
if (!(0, $dXlYe$
|
|
58
|
+
if (!(0, $dXlYe$isFocusWithin)(e.currentTarget)) return;
|
|
59
59
|
switch(e.key){
|
|
60
60
|
case 'ArrowLeft':
|
|
61
|
-
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, e
|
|
61
|
+
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, (0, $dXlYe$getEventTarget)(e))) {
|
|
62
62
|
e.preventDefault();
|
|
63
63
|
e.stopPropagation();
|
|
64
64
|
onSubmenuClose();
|
|
@@ -66,7 +66,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
66
66
|
}
|
|
67
67
|
break;
|
|
68
68
|
case 'ArrowRight':
|
|
69
|
-
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, e
|
|
69
|
+
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, (0, $dXlYe$getEventTarget)(e))) {
|
|
70
70
|
e.preventDefault();
|
|
71
71
|
e.stopPropagation();
|
|
72
72
|
onSubmenuClose();
|
|
@@ -75,7 +75,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
75
75
|
break;
|
|
76
76
|
case 'Escape':
|
|
77
77
|
// TODO: can remove this when we fix collection event leaks
|
|
78
|
-
if ((0, $dXlYe$nodeContains)(submenuRef.current, e
|
|
78
|
+
if ((0, $dXlYe$nodeContains)(submenuRef.current, (0, $dXlYe$getEventTarget)(e))) {
|
|
79
79
|
e.stopPropagation();
|
|
80
80
|
onSubmenuClose();
|
|
81
81
|
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
@@ -101,7 +101,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
101
101
|
if (direction === 'ltr') {
|
|
102
102
|
e.preventDefault();
|
|
103
103
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
104
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
104
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $dXlYe$getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
105
105
|
} else if (state.isOpen) onSubmenuClose();
|
|
106
106
|
else e.continuePropagation();
|
|
107
107
|
}
|
|
@@ -111,7 +111,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
111
111
|
if (direction === 'rtl') {
|
|
112
112
|
e.preventDefault();
|
|
113
113
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
114
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
114
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $dXlYe$getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
115
115
|
} else if (state.isOpen) onSubmenuClose();
|
|
116
116
|
else e.continuePropagation();
|
|
117
117
|
}
|
|
@@ -142,7 +142,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
142
142
|
(0, $dXlYe$useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
143
143
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
144
144
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
145
|
-
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, e
|
|
145
|
+
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, (0, $dXlYe$getEventTarget)(e)) && (0, $dXlYe$getEventTarget)(e) !== ref.current) onSubmenuClose();
|
|
146
146
|
});
|
|
147
147
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
148
148
|
if (target !== ref.current) return true;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {useSafelyMouseToSubmenu as $d275435c250248f8$export$85ec83e04c95f50a} from "./useSafelyMouseToSubmenu.module.js";
|
|
2
|
-
import {useId as $dXlYe$useId, useLayoutEffect as $dXlYe$useLayoutEffect, nodeContains as $dXlYe$nodeContains, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
2
|
+
import {useId as $dXlYe$useId, useLayoutEffect as $dXlYe$useLayoutEffect, isFocusWithin as $dXlYe$isFocusWithin, nodeContains as $dXlYe$nodeContains, getEventTarget as $dXlYe$getEventTarget, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, getActiveElement as $dXlYe$getActiveElement, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
3
3
|
import {useRef as $dXlYe$useRef, useCallback as $dXlYe$useCallback} from "react";
|
|
4
4
|
import {useLocale as $dXlYe$useLocale} from "@react-aria/i18n";
|
|
5
5
|
|
|
@@ -55,10 +55,10 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
55
55
|
let submenuKeyDown = (e)=>{
|
|
56
56
|
// If focus is not within the menu, assume virtual focus is being used.
|
|
57
57
|
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
58
|
-
if (!(0, $dXlYe$
|
|
58
|
+
if (!(0, $dXlYe$isFocusWithin)(e.currentTarget)) return;
|
|
59
59
|
switch(e.key){
|
|
60
60
|
case 'ArrowLeft':
|
|
61
|
-
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, e
|
|
61
|
+
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, (0, $dXlYe$getEventTarget)(e))) {
|
|
62
62
|
e.preventDefault();
|
|
63
63
|
e.stopPropagation();
|
|
64
64
|
onSubmenuClose();
|
|
@@ -66,7 +66,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
66
66
|
}
|
|
67
67
|
break;
|
|
68
68
|
case 'ArrowRight':
|
|
69
|
-
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, e
|
|
69
|
+
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, (0, $dXlYe$getEventTarget)(e))) {
|
|
70
70
|
e.preventDefault();
|
|
71
71
|
e.stopPropagation();
|
|
72
72
|
onSubmenuClose();
|
|
@@ -75,7 +75,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
75
75
|
break;
|
|
76
76
|
case 'Escape':
|
|
77
77
|
// TODO: can remove this when we fix collection event leaks
|
|
78
|
-
if ((0, $dXlYe$nodeContains)(submenuRef.current, e
|
|
78
|
+
if ((0, $dXlYe$nodeContains)(submenuRef.current, (0, $dXlYe$getEventTarget)(e))) {
|
|
79
79
|
e.stopPropagation();
|
|
80
80
|
onSubmenuClose();
|
|
81
81
|
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
@@ -101,7 +101,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
101
101
|
if (direction === 'ltr') {
|
|
102
102
|
e.preventDefault();
|
|
103
103
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
104
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
104
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $dXlYe$getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
105
105
|
} else if (state.isOpen) onSubmenuClose();
|
|
106
106
|
else e.continuePropagation();
|
|
107
107
|
}
|
|
@@ -111,7 +111,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
111
111
|
if (direction === 'rtl') {
|
|
112
112
|
e.preventDefault();
|
|
113
113
|
if (!state.isOpen) onSubmenuOpen('first');
|
|
114
|
-
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) &&
|
|
114
|
+
if (type === 'menu' && !!(submenuRef === null || submenuRef === void 0 ? void 0 : submenuRef.current) && (0, $dXlYe$getActiveElement)() === (ref === null || ref === void 0 ? void 0 : ref.current)) (0, $dXlYe$focusWithoutScrolling)(submenuRef.current);
|
|
115
115
|
} else if (state.isOpen) onSubmenuClose();
|
|
116
116
|
else e.continuePropagation();
|
|
117
117
|
}
|
|
@@ -142,7 +142,7 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
142
142
|
(0, $dXlYe$useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
143
143
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
144
144
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
145
|
-
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, e
|
|
145
|
+
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, (0, $dXlYe$getEventTarget)(e)) && (0, $dXlYe$getEventTarget)(e) !== ref.current) onSubmenuClose();
|
|
146
146
|
});
|
|
147
147
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
148
148
|
if (target !== ref.current) return true;
|
|
@@ -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 {focusWithoutScrolling, nodeContains, useEvent, 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 = useCallback((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n }, [state, cancelOpenTimeout]);\n\n let onSubmenuClose = useCallback(() => {\n cancelOpenTimeout();\n state.close();\n }, [state, cancelOpenTimeout]);\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 (!nodeContains(e.currentTarget, document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && nodeContains(e.currentTarget, 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' && nodeContains(e.currentTarget, 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 (nodeContains(submenuRef.current, 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 useEvent(parentMenuRef, 'focusin', (e) => {\n // If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in\n // then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open\n if (state.isOpen && (nodeContains(parentMenuRef.current, e.target as HTMLElement) && e.target !== ref.current)) {\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 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"}
|
|
1
|
+
{"mappings":";;;;;AAAA;;;;;;;;;;CAUC;;;;AA4DM,SAAS,0CAAqB,KAA8B,EAAE,KAA0B,EAAE,GAAuC;IACtI,IAAI,iBAAC,aAAa,cAAE,UAAU,QAAE,OAAO,oBAAQ,UAAU,SAAE,QAAQ,4BAAK,qBAAqB,EAAC,GAAG;IACjG,IAAI,mBAAmB,CAAA,GAAA,YAAI;IAC3B,IAAI,YAAY,CAAA,GAAA,YAAI;IACpB,IAAI,aAAC,SAAS,EAAC,GAAG,CAAA,GAAA,gBAAQ;IAC1B,IAAI,cAAc,CAAA,GAAA,aAAK,EAA6C;IACpE,IAAI,oBAAoB,CAAA,GAAA,kBAAU,EAAE;QAClC,IAAI,YAAY,OAAO,EAAE;YACvB,aAAa,YAAY,OAAO;YAChC,YAAY,OAAO,GAAG;QACxB;IACF,GAAG;QAAC;KAAY;IAEhB,IAAI,gBAAgB,CAAA,GAAA,kBAAU,EAAE,CAAC;QAC/B;QACA,MAAM,IAAI,CAAC;IACb,GAAG;QAAC;QAAO;KAAkB;IAE7B,IAAI,iBAAiB,CAAA,GAAA,kBAAU,EAAE;QAC/B;QACA,MAAM,KAAK;IACb,GAAG;QAAC;QAAO;KAAkB;IAE7B,CAAA,GAAA,sBAAc,EAAE;QACd,OAAO;YACL;QACF;IACF,GAAG;QAAC;KAAkB;IAEtB,IAAI,iBAAiB,CAAC;QACpB,uEAAuE;QACvE,kGAAkG;QAClG,IAAI,CAAC,CAAA,GAAA,oBAAY,EAAE,EAAE,aAAa,GAChC;QAGF,OAAQ,EAAE,GAAG;YACX,KAAK;gBACH,IAAI,cAAc,SAAS,CAAA,GAAA,mBAAW,EAAE,EAAE,aAAa,EAAE,CAAA,GAAA,qBAAa,EAAE,KAAgB;oBACtF,EAAE,cAAc;oBAChB,EAAE,eAAe;oBACjB;oBACA,IAAI,CAAC,yBAAyB,IAAI,OAAO,EACvC,CAAA,GAAA,4BAAoB,EAAE,IAAI,OAAO;gBAErC;gBACA;YACF,KAAK;gBACH,IAAI,cAAc,SAAS,CAAA,GAAA,mBAAW,EAAE,EAAE,aAAa,EAAE,CAAA,GAAA,qBAAa,EAAE,KAAgB;oBACtF,EAAE,cAAc;oBAChB,EAAE,eAAe;oBACjB;oBACA,IAAI,CAAC,yBAAyB,IAAI,OAAO,EACvC,CAAA,GAAA,4BAAoB,EAAE,IAAI,OAAO;gBAErC;gBACA;YACF,KAAK;gBACH,2DAA2D;gBAC3D,IAAI,CAAA,GAAA,mBAAW,EAAE,WAAW,OAAO,EAAE,CAAA,GAAA,qBAAa,EAAE,KAAgB;oBAClE,EAAE,eAAe;oBACjB;oBACA,IAAI,CAAC,yBAAyB,IAAI,OAAO,EACvC,CAAA,GAAA,4BAAoB,EAAE,IAAI,OAAO;gBAErC;gBACA;QACJ;IACF;QAQe;IANf,IAAI,eAAe;QACjB,IAAI;QACJ,mBAAmB;QACnB,cAAc,MAAM,YAAY;QAChC,GAAI,SAAS,UAAU;YACrB,SAAS,MAAM,QAAQ;YACvB,WAAW,CAAA,uBAAA,MAAM,aAAa,cAAnB,kCAAA,uBAAuB;YAClC,WAAW;QACb,CAAC;IACH;IAEA,IAAI,wBAAwB,CAAC;QAC3B,OAAQ,EAAE,GAAG;YACX,KAAK;gBACH,IAAI,CAAC,YAAY;oBACf,IAAI,cAAc,OAAO;wBACvB,EAAE,cAAc;wBAChB,IAAI,CAAC,MAAM,MAAM,EACf,cAAc;wBAGhB,IAAI,SAAS,UAAU,CAAC,EAAC,uBAAA,iCAAA,WAAY,OAAO,KAAI,CAAA,GAAA,uBAAe,SAAQ,gBAAA,0BAAA,IAAK,OAAO,GACjF,CAAA,GAAA,4BAAoB,EAAE,WAAW,OAAO;oBAE5C,OAAO,IAAI,MAAM,MAAM,EACrB;yBAEA,EAAE,mBAAmB;gBAEzB;gBAEA;YACF,KAAK;gBACH,IAAI,CAAC,YAAY;oBACf,IAAI,cAAc,OAAO;wBACvB,EAAE,cAAc;wBAChB,IAAI,CAAC,MAAM,MAAM,EACf,cAAc;wBAGhB,IAAI,SAAS,UAAU,CAAC,EAAC,uBAAA,iCAAA,WAAY,OAAO,KAAI,CAAA,GAAA,uBAAe,SAAQ,gBAAA,0BAAA,IAAK,OAAO,GACjF,CAAA,GAAA,4BAAoB,EAAE,WAAW,OAAO;oBAE5C,OAAO,IAAI,MAAM,MAAM,EACrB;yBAEA,EAAE,mBAAmB;gBAEzB;gBACA;YACF;gBACE,EAAE,mBAAmB;gBACrB;QACJ;IACF;IAEA,IAAI,eAAe,CAAC;QAClB,IAAI,CAAC,cAAe,CAAA,EAAE,WAAW,KAAK,aAAa,EAAE,WAAW,KAAK,UAAS,GAC5E,iFAAiF;QACjF,cAAc;IAElB;IAEA,IAAI,UAAU,CAAC;QACb,IAAI,CAAC,cAAe,CAAA,EAAE,WAAW,KAAK,WAAW,EAAE,WAAW,KAAK,OAAM,GACvE,kGAAkG;QAClG,oDAAoD;QACpD;IAEJ;IAEA,IAAI,gBAAgB,CAAC;QACnB,IAAI,CAAC,YAAY;YACf,IAAI,aAAa,CAAC,MAAM,MAAM,EAC5B;gBAAA,IAAI,CAAC,YAAY,OAAO,EACtB,YAAY,OAAO,GAAG,WAAW;oBAC/B;gBACF,GAAG;YACL,OACK,IAAI,CAAC,WACV;QAEJ;IACF;IAEA,CAAA,GAAA,eAAO,EAAE,eAAe,WAAW,CAAC;QAClC,8GAA8G;QAC9G,oHAAoH;QACpH,IAAI,MAAM,MAAM,IAAK,CAAA,GAAA,mBAAW,EAAE,cAAc,OAAO,EAAE,CAAA,GAAA,qBAAa,EAAE,OAAsB,CAAA,GAAA,qBAAa,EAAE,OAAO,IAAI,OAAO,EAC7H;IAEJ;IAEA,IAAI,+BAA+B,CAAC;QAClC,IAAI,WAAW,IAAI,OAAO,EACxB,OAAO;QAGT,OAAO;IACT;IAEA,CAAA,GAAA,yCAAsB,EAAE;QAAC,SAAS;oBAAe;QAAY,QAAQ,MAAM,MAAM;QAAE,YAAY;IAAU;IAEzG,OAAO;QACL,qBAAqB;YACnB,IAAI;YACJ,iBAAiB,MAAM,MAAM,GAAG,YAAY;YAC5C,iBAAiB,CAAC,aAAa,OAAO;YACtC,iBAAiB,MAAM,MAAM,GAAG,SAAS;0BACzC;qBACA;2BACA;YACA,WAAW;YACX,QAAQ,MAAM,MAAM;QACtB;sBACA;QACA,cAAc;YACZ,YAAY;0CACZ;QACF;IACF;AACF","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, getActiveElement, getEventTarget, isFocusWithin, nodeContains, useEvent, 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' | 'onAction'> {\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 = useCallback((focusStrategy?: FocusStrategy) => {\n cancelOpenTimeout();\n state.open(focusStrategy);\n }, [state, cancelOpenTimeout]);\n\n let onSubmenuClose = useCallback(() => {\n cancelOpenTimeout();\n state.close();\n }, [state, cancelOpenTimeout]);\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 (!isFocusWithin(e.currentTarget)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && nodeContains(e.currentTarget, getEventTarget(e) 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' && nodeContains(e.currentTarget, getEventTarget(e) 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 (nodeContains(submenuRef.current, getEventTarget(e) 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 && getActiveElement() === 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 && getActiveElement() === 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 useEvent(parentMenuRef, 'focusin', (e) => {\n // If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in\n // then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open\n if (state.isOpen && (nodeContains(parentMenuRef.current, getEventTarget(e) as HTMLElement) && getEventTarget(e) !== ref.current)) {\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 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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/menu",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.21.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
"url": "https://github.com/adobe/react-spectrum"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@react-aria/focus": "^3.21.
|
|
30
|
-
"@react-aria/i18n": "^3.12.
|
|
31
|
-
"@react-aria/interactions": "^3.27.
|
|
32
|
-
"@react-aria/overlays": "^3.31.
|
|
33
|
-
"@react-aria/selection": "^3.27.
|
|
34
|
-
"@react-aria/utils": "^3.33.
|
|
35
|
-
"@react-stately/collections": "^3.12.
|
|
36
|
-
"@react-stately/menu": "^3.9.
|
|
37
|
-
"@react-stately/selection": "^3.20.
|
|
38
|
-
"@react-stately/tree": "^3.9.
|
|
39
|
-
"@react-types/button": "^3.15.
|
|
40
|
-
"@react-types/menu": "^3.10.
|
|
41
|
-
"@react-types/shared": "^3.33.
|
|
29
|
+
"@react-aria/focus": "^3.21.5",
|
|
30
|
+
"@react-aria/i18n": "^3.12.16",
|
|
31
|
+
"@react-aria/interactions": "^3.27.1",
|
|
32
|
+
"@react-aria/overlays": "^3.31.2",
|
|
33
|
+
"@react-aria/selection": "^3.27.2",
|
|
34
|
+
"@react-aria/utils": "^3.33.1",
|
|
35
|
+
"@react-stately/collections": "^3.12.10",
|
|
36
|
+
"@react-stately/menu": "^3.9.11",
|
|
37
|
+
"@react-stately/selection": "^3.20.9",
|
|
38
|
+
"@react-stately/tree": "^3.9.6",
|
|
39
|
+
"@react-types/button": "^3.15.1",
|
|
40
|
+
"@react-types/menu": "^3.10.7",
|
|
41
|
+
"@react-types/shared": "^3.33.1",
|
|
42
42
|
"@swc/helpers": "^0.5.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "8df187370053aa35f553cb388ad670f65e1ab371"
|
|
52
52
|
}
|
package/src/useMenuItem.ts
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';
|
|
14
|
-
import {filterDOMProps, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';
|
|
14
|
+
import {filterDOMProps, getEventTarget, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';
|
|
15
15
|
import {getItemCount} from '@react-stately/collections';
|
|
16
|
-
import {isFocusVisible, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';
|
|
16
|
+
import {isFocusVisible, setInteractionModality, useFocusable, useHover, useKeyboard, usePress} from '@react-aria/interactions';
|
|
17
17
|
import {menuData} from './utils';
|
|
18
18
|
import {MouseEvent, useRef} from 'react';
|
|
19
19
|
import {SelectionManager} from '@react-stately/selection';
|
|
@@ -97,6 +97,9 @@ export interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, K
|
|
|
97
97
|
/** Identifies the menu item's popup element whose contents or presence is controlled by the menu item. */
|
|
98
98
|
'aria-controls'?: string,
|
|
99
99
|
|
|
100
|
+
/** Identifies the element(s) that describe the menu item. */
|
|
101
|
+
'aria-describedby'?: string,
|
|
102
|
+
|
|
100
103
|
/** Override of the selection manager. By default, `state.selectionManager` is used. */
|
|
101
104
|
selectionManager?: SelectionManager
|
|
102
105
|
}
|
|
@@ -177,7 +180,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
177
180
|
role,
|
|
178
181
|
'aria-label': props['aria-label'],
|
|
179
182
|
'aria-labelledby': labelId,
|
|
180
|
-
'aria-describedby': [descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,
|
|
183
|
+
'aria-describedby': [props['aria-describedby'], descriptionId, keyboardId].filter(Boolean).join(' ') || undefined,
|
|
181
184
|
'aria-controls': props['aria-controls'],
|
|
182
185
|
'aria-haspopup': hasPopup,
|
|
183
186
|
'aria-expanded': props['aria-expanded']
|
|
@@ -188,7 +191,8 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
if (isVirtualized) {
|
|
191
|
-
|
|
194
|
+
let index = Number(item?.index);
|
|
195
|
+
ariaProps['aria-posinset'] = Number.isNaN(index) ? undefined : index + 1;
|
|
192
196
|
ariaProps['aria-setsize'] = getItemCount(state.collection);
|
|
193
197
|
}
|
|
194
198
|
|
|
@@ -285,15 +289,23 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
285
289
|
switch (e.key) {
|
|
286
290
|
case ' ':
|
|
287
291
|
interaction.current = {pointerType: 'keyboard', key: ' '};
|
|
288
|
-
(e
|
|
292
|
+
(getEventTarget(e) as HTMLElement).click();
|
|
293
|
+
|
|
294
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
295
|
+
// to the newly opened submenu's first item.
|
|
296
|
+
setInteractionModality('keyboard');
|
|
289
297
|
break;
|
|
290
298
|
case 'Enter':
|
|
291
299
|
interaction.current = {pointerType: 'keyboard', key: 'Enter'};
|
|
292
300
|
|
|
293
301
|
// Trigger click unless this is a link. Links trigger click natively.
|
|
294
|
-
if ((e
|
|
295
|
-
(e
|
|
302
|
+
if ((getEventTarget(e) as HTMLElement).tagName !== 'A') {
|
|
303
|
+
(getEventTarget(e) as HTMLElement).click();
|
|
296
304
|
}
|
|
305
|
+
|
|
306
|
+
// click above sets modality to "virtual", need to set interaction modality back to 'keyboard' so focusSafely calls properly move focus
|
|
307
|
+
// to the newly opened submenu's first item.
|
|
308
|
+
setInteractionModality('keyboard');
|
|
297
309
|
break;
|
|
298
310
|
default:
|
|
299
311
|
if (!isTrigger) {
|
|
@@ -41,7 +41,7 @@ export function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): v
|
|
|
41
41
|
submenuSide.current = undefined;
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
-
useResizeObserver({ref: submenuRef, onResize: updateSubmenuRect});
|
|
44
|
+
useResizeObserver({ref: isOpen ? submenuRef : undefined, onResize: updateSubmenuRect});
|
|
45
45
|
|
|
46
46
|
let reset = () => {
|
|
47
47
|
setPreventPointerEvents(false);
|
package/src/useSubmenuTrigger.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {AriaMenuItemProps} from './useMenuItem';
|
|
|
14
14
|
import {AriaMenuOptions} from './useMenu';
|
|
15
15
|
import type {AriaPopoverProps, OverlayProps} from '@react-aria/overlays';
|
|
16
16
|
import {FocusableElement, FocusStrategy, KeyboardEvent, Node, PressEvent, RefObject} from '@react-types/shared';
|
|
17
|
-
import {focusWithoutScrolling, nodeContains, useEvent, useId, useLayoutEffect} from '@react-aria/utils';
|
|
17
|
+
import {focusWithoutScrolling, getActiveElement, getEventTarget, isFocusWithin, nodeContains, useEvent, useId, useLayoutEffect} from '@react-aria/utils';
|
|
18
18
|
import type {SubmenuTriggerState} from '@react-stately/menu';
|
|
19
19
|
import {useCallback, useRef} from 'react';
|
|
20
20
|
import {useLocale} from '@react-aria/i18n';
|
|
@@ -43,7 +43,7 @@ export interface AriaSubmenuTriggerProps {
|
|
|
43
43
|
shouldUseVirtualFocus?: boolean
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
interface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key'> {
|
|
46
|
+
interface SubmenuTriggerProps extends Omit<AriaMenuItemProps, 'key' | 'onAction'> {
|
|
47
47
|
/** Whether the submenu trigger is in an expanded state. */
|
|
48
48
|
isOpen: boolean
|
|
49
49
|
}
|
|
@@ -100,13 +100,13 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
100
100
|
let submenuKeyDown = (e: KeyboardEvent) => {
|
|
101
101
|
// If focus is not within the menu, assume virtual focus is being used.
|
|
102
102
|
// This means some other input element is also within the popover, so we shouldn't close the menu.
|
|
103
|
-
if (!
|
|
103
|
+
if (!isFocusWithin(e.currentTarget)) {
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
switch (e.key) {
|
|
108
108
|
case 'ArrowLeft':
|
|
109
|
-
if (direction === 'ltr' && nodeContains(e.currentTarget, e
|
|
109
|
+
if (direction === 'ltr' && nodeContains(e.currentTarget, getEventTarget(e) as Element)) {
|
|
110
110
|
e.preventDefault();
|
|
111
111
|
e.stopPropagation();
|
|
112
112
|
onSubmenuClose();
|
|
@@ -116,7 +116,7 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
116
116
|
}
|
|
117
117
|
break;
|
|
118
118
|
case 'ArrowRight':
|
|
119
|
-
if (direction === 'rtl' && nodeContains(e.currentTarget, e
|
|
119
|
+
if (direction === 'rtl' && nodeContains(e.currentTarget, getEventTarget(e) as Element)) {
|
|
120
120
|
e.preventDefault();
|
|
121
121
|
e.stopPropagation();
|
|
122
122
|
onSubmenuClose();
|
|
@@ -127,7 +127,7 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
127
127
|
break;
|
|
128
128
|
case 'Escape':
|
|
129
129
|
// TODO: can remove this when we fix collection event leaks
|
|
130
|
-
if (nodeContains(submenuRef.current, e
|
|
130
|
+
if (nodeContains(submenuRef.current, getEventTarget(e) as Element)) {
|
|
131
131
|
e.stopPropagation();
|
|
132
132
|
onSubmenuClose();
|
|
133
133
|
if (!shouldUseVirtualFocus && ref.current) {
|
|
@@ -159,7 +159,7 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
159
159
|
onSubmenuOpen('first');
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
if (type === 'menu' && !!submenuRef?.current &&
|
|
162
|
+
if (type === 'menu' && !!submenuRef?.current && getActiveElement() === ref?.current) {
|
|
163
163
|
focusWithoutScrolling(submenuRef.current);
|
|
164
164
|
}
|
|
165
165
|
} else if (state.isOpen) {
|
|
@@ -178,7 +178,7 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
178
178
|
onSubmenuOpen('first');
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
if (type === 'menu' && !!submenuRef?.current &&
|
|
181
|
+
if (type === 'menu' && !!submenuRef?.current && getActiveElement() === ref?.current) {
|
|
182
182
|
focusWithoutScrolling(submenuRef.current);
|
|
183
183
|
}
|
|
184
184
|
} else if (state.isOpen) {
|
|
@@ -226,7 +226,7 @@ export function useSubmenuTrigger<T>(props: AriaSubmenuTriggerProps, state: Subm
|
|
|
226
226
|
useEvent(parentMenuRef, 'focusin', (e) => {
|
|
227
227
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
228
228
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
229
|
-
if (state.isOpen && (nodeContains(parentMenuRef.current, e
|
|
229
|
+
if (state.isOpen && (nodeContains(parentMenuRef.current, getEventTarget(e) as HTMLElement) && getEventTarget(e) !== ref.current)) {
|
|
230
230
|
onSubmenuClose();
|
|
231
231
|
}
|
|
232
232
|
});
|