@react-aria/menu 3.19.4 → 3.20.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 +6 -5
- package/dist/useMenuItem.main.js.map +1 -1
- package/dist/useMenuItem.mjs +7 -6
- package/dist/useMenuItem.module.js +7 -6
- package/dist/useMenuItem.module.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.main.js +2 -2
- package/dist/useSafelyMouseToSubmenu.main.js.map +1 -1
- package/dist/useSafelyMouseToSubmenu.mjs +2 -2
- package/dist/useSafelyMouseToSubmenu.module.js +2 -2
- package/dist/useSafelyMouseToSubmenu.module.js.map +1 -1
- package/dist/useSubmenuTrigger.main.js +5 -7
- package/dist/useSubmenuTrigger.main.js.map +1 -1
- package/dist/useSubmenuTrigger.mjs +6 -8
- package/dist/useSubmenuTrigger.module.js +6 -8
- package/dist/useSubmenuTrigger.module.js.map +1 -1
- package/package.json +15 -15
- package/src/useMenuItem.ts +14 -8
- package/src/useSafelyMouseToSubmenu.ts +2 -2
- package/src/useSubmenuTrigger.ts +6 -6
package/dist/types.d.ts
CHANGED
|
@@ -93,9 +93,11 @@ export interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, K
|
|
|
93
93
|
onClose?: () => void;
|
|
94
94
|
/**
|
|
95
95
|
* Whether the menu should close when the menu item is selected.
|
|
96
|
-
* @
|
|
96
|
+
* @deprecated - use shouldCloseOnSelect instead.
|
|
97
97
|
*/
|
|
98
98
|
closeOnSelect?: boolean;
|
|
99
|
+
/** Whether the menu should close when the menu item is selected. */
|
|
100
|
+
shouldCloseOnSelect?: boolean;
|
|
99
101
|
/** Whether the menu item is contained in a virtual scrolling menu. */
|
|
100
102
|
isVirtualized?: boolean;
|
|
101
103
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;ACmBA;IACE,kCAAkC;IAClC,SAAS,EAAE,aAAa,CAAA;CACzB;AAED,iCAAiC,CAAC,CAAE,SAAQ,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,cAAc;IAC5F,+CAA+C;IAC/C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAED;;;;;GAKG;AACH,wBAAwB,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,WAAW,GAAG,IAAI,CAAC,GAAG,QAAQ,CAyCvH;AC7DD;IACE,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,eAAe,CAAA;CAC1B;AAED,iCAAiC,CAAC;IAChC,0CAA0C;IAC1C,gBAAgB,EAAE,eAAe,CAAC;IAElC,0BAA0B;IAC1B,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAA;CAC9B;AAED;;;;;GAKG;AACH,+BAA+B,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,OAAO,GAAG,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAC,CA4G1I;ACrID;IACE,uCAAuC;IACvC,aAAa,EAAE,aAAa,CAAC;IAE7B,4DAA4D;IAC5D,UAAU,EAAE,aAAa,CAAC;IAE1B,2EAA2E;IAC3E,gBAAgB,EAAE,aAAa,CAAC;IAEhC,4EAA4E;IAC5E,qBAAqB,EAAE,aAAa,CAAC;IAErC,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,4CAA4C;IAC5C,cAAc,EAAE,OAAO,CAAC;IACxB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAC;IACpB,wDAAwD;IACxD,SAAS,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,kCAAmC,SAAQ,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW;IACxG;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,wCAAwC;IACxC,GAAG,EAAE,GAAG,CAAC;IAET;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,sEAAsE;IACtE,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAE9B,yCAAyC;IACzC,eAAe,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAEpC,gFAAgF;IAChF,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAE7C,0GAA0G;IAC1G,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED;;;;;GAKG;AACH,4BAA4B,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,gBAAgB,GAAG,IAAI,CAAC,GAAG,YAAY,
|
|
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
|
@@ -28,7 +28,7 @@ $parcel$export(module.exports, "useMenuItem", () => $38191ed02615ec07$export$9d3
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
31
|
-
let { id: id, key: key, closeOnSelect: closeOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
31
|
+
let { id: id, key: key, closeOnSelect: closeOnSelect, shouldCloseOnSelect: shouldCloseOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
32
32
|
let isTrigger = !!hasPopup;
|
|
33
33
|
let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';
|
|
34
34
|
var _props_isDisabled;
|
|
@@ -100,7 +100,8 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
100
100
|
performAction();
|
|
101
101
|
(0, $byVdR$reactariautils.handleLinkClick)(e, router, item.props.href, item === null || item === void 0 ? void 0 : item.props.routerOptions);
|
|
102
102
|
let shouldClose = ((_interaction_current = interaction.current) === null || _interaction_current === void 0 ? void 0 : _interaction_current.pointerType) === 'keyboard' ? ((_interaction_current1 = interaction.current) === null || _interaction_current1 === void 0 ? void 0 : _interaction_current1.key) === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key) : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);
|
|
103
|
-
|
|
103
|
+
var _ref;
|
|
104
|
+
shouldClose = (_ref = shouldCloseOnSelect !== null && shouldCloseOnSelect !== void 0 ? shouldCloseOnSelect : closeOnSelect) !== null && _ref !== void 0 ? _ref : shouldClose;
|
|
104
105
|
if (onClose && !isTrigger && shouldClose) onClose();
|
|
105
106
|
interaction.current = null;
|
|
106
107
|
};
|
|
@@ -171,11 +172,11 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
171
172
|
},
|
|
172
173
|
onKeyUp: onKeyUp
|
|
173
174
|
});
|
|
174
|
-
let {
|
|
175
|
+
let { focusableProps: focusableProps } = (0, $byVdR$reactariainteractions.useFocusable)({
|
|
175
176
|
onBlur: onBlur,
|
|
176
177
|
onFocus: onFocus,
|
|
177
178
|
onFocusChange: onFocusChange
|
|
178
|
-
});
|
|
179
|
+
}, ref);
|
|
179
180
|
let domProps = (0, $byVdR$reactariautils.filterDOMProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
180
181
|
delete domProps.id;
|
|
181
182
|
let linkProps = (0, $byVdR$reactariautils.useLinkProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
@@ -186,7 +187,7 @@ function $38191ed02615ec07$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
186
187
|
onFocus: itemProps.onFocus,
|
|
187
188
|
'data-collection': itemProps['data-collection'],
|
|
188
189
|
'data-key': itemProps['data-key']
|
|
189
|
-
} : itemProps, pressProps, hoverProps, keyboardProps,
|
|
190
|
+
} : itemProps, pressProps, hoverProps, keyboardProps, focusableProps, // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.
|
|
190
191
|
data.shouldUseVirtualFocus || isTrigger ? {
|
|
191
192
|
onMouseDown: (e)=>e.preventDefault()
|
|
192
193
|
} : undefined, isDisabled ? undefined : {
|
|
@@ -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, useFocus, 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 * @default true\n */\n closeOnSelect?: 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 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 shouldClose = closeOnSelect ?? shouldClose;\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 {focusProps} = useFocus({onBlur, onFocus, onFocusChange});\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 focusProps,\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, 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"}
|
package/dist/useMenuItem.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {menuData as $fc79756100351201$export$6f49b4016bfc8d56} from "./utils.mjs";
|
|
2
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";
|
|
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,
|
|
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";
|
|
5
5
|
import {useRef as $7Kjv5$useRef} from "react";
|
|
6
6
|
import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selection";
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selecti
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
25
|
-
let { id: id, key: key, closeOnSelect: closeOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
25
|
+
let { id: id, key: key, closeOnSelect: closeOnSelect, shouldCloseOnSelect: shouldCloseOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
26
26
|
let isTrigger = !!hasPopup;
|
|
27
27
|
let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';
|
|
28
28
|
var _props_isDisabled;
|
|
@@ -94,7 +94,8 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
94
94
|
performAction();
|
|
95
95
|
(0, $7Kjv5$handleLinkClick)(e, router, item.props.href, item === null || item === void 0 ? void 0 : item.props.routerOptions);
|
|
96
96
|
let shouldClose = ((_interaction_current = interaction.current) === null || _interaction_current === void 0 ? void 0 : _interaction_current.pointerType) === 'keyboard' ? ((_interaction_current1 = interaction.current) === null || _interaction_current1 === void 0 ? void 0 : _interaction_current1.key) === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key) : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);
|
|
97
|
-
|
|
97
|
+
var _ref;
|
|
98
|
+
shouldClose = (_ref = shouldCloseOnSelect !== null && shouldCloseOnSelect !== void 0 ? shouldCloseOnSelect : closeOnSelect) !== null && _ref !== void 0 ? _ref : shouldClose;
|
|
98
99
|
if (onClose && !isTrigger && shouldClose) onClose();
|
|
99
100
|
interaction.current = null;
|
|
100
101
|
};
|
|
@@ -165,11 +166,11 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
165
166
|
},
|
|
166
167
|
onKeyUp: onKeyUp
|
|
167
168
|
});
|
|
168
|
-
let {
|
|
169
|
+
let { focusableProps: focusableProps } = (0, $7Kjv5$useFocusable)({
|
|
169
170
|
onBlur: onBlur,
|
|
170
171
|
onFocus: onFocus,
|
|
171
172
|
onFocusChange: onFocusChange
|
|
172
|
-
});
|
|
173
|
+
}, ref);
|
|
173
174
|
let domProps = (0, $7Kjv5$filterDOMProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
174
175
|
delete domProps.id;
|
|
175
176
|
let linkProps = (0, $7Kjv5$useLinkProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
@@ -180,7 +181,7 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
180
181
|
onFocus: itemProps.onFocus,
|
|
181
182
|
'data-collection': itemProps['data-collection'],
|
|
182
183
|
'data-key': itemProps['data-key']
|
|
183
|
-
} : itemProps, pressProps, hoverProps, keyboardProps,
|
|
184
|
+
} : itemProps, pressProps, hoverProps, keyboardProps, focusableProps, // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.
|
|
184
185
|
data.shouldUseVirtualFocus || isTrigger ? {
|
|
185
186
|
onMouseDown: (e)=>e.preventDefault()
|
|
186
187
|
} : undefined, isDisabled ? undefined : {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {menuData as $fc79756100351201$export$6f49b4016bfc8d56} from "./utils.module.js";
|
|
2
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";
|
|
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,
|
|
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";
|
|
5
5
|
import {useRef as $7Kjv5$useRef} from "react";
|
|
6
6
|
import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selection";
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ import {useSelectableItem as $7Kjv5$useSelectableItem} from "@react-aria/selecti
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
25
|
-
let { id: id, key: key, closeOnSelect: closeOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
25
|
+
let { id: id, key: key, closeOnSelect: closeOnSelect, shouldCloseOnSelect: shouldCloseOnSelect, isVirtualized: isVirtualized, 'aria-haspopup': hasPopup, onPressStart: onPressStart, onPressUp: pressUpProp, onPress: onPress, onPressChange: pressChangeProp, onPressEnd: onPressEnd, onClick: onClickProp, onHoverStart: hoverStartProp, onHoverChange: onHoverChange, onHoverEnd: onHoverEnd, onKeyDown: onKeyDown, onKeyUp: onKeyUp, onFocus: onFocus, onFocusChange: onFocusChange, onBlur: onBlur, selectionManager: selectionManager = state.selectionManager } = props;
|
|
26
26
|
let isTrigger = !!hasPopup;
|
|
27
27
|
let isTriggerExpanded = isTrigger && props['aria-expanded'] === 'true';
|
|
28
28
|
var _props_isDisabled;
|
|
@@ -94,7 +94,8 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
94
94
|
performAction();
|
|
95
95
|
(0, $7Kjv5$handleLinkClick)(e, router, item.props.href, item === null || item === void 0 ? void 0 : item.props.routerOptions);
|
|
96
96
|
let shouldClose = ((_interaction_current = interaction.current) === null || _interaction_current === void 0 ? void 0 : _interaction_current.pointerType) === 'keyboard' ? ((_interaction_current1 = interaction.current) === null || _interaction_current1 === void 0 ? void 0 : _interaction_current1.key) === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key) : selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);
|
|
97
|
-
|
|
97
|
+
var _ref;
|
|
98
|
+
shouldClose = (_ref = shouldCloseOnSelect !== null && shouldCloseOnSelect !== void 0 ? shouldCloseOnSelect : closeOnSelect) !== null && _ref !== void 0 ? _ref : shouldClose;
|
|
98
99
|
if (onClose && !isTrigger && shouldClose) onClose();
|
|
99
100
|
interaction.current = null;
|
|
100
101
|
};
|
|
@@ -165,11 +166,11 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
165
166
|
},
|
|
166
167
|
onKeyUp: onKeyUp
|
|
167
168
|
});
|
|
168
|
-
let {
|
|
169
|
+
let { focusableProps: focusableProps } = (0, $7Kjv5$useFocusable)({
|
|
169
170
|
onBlur: onBlur,
|
|
170
171
|
onFocus: onFocus,
|
|
171
172
|
onFocusChange: onFocusChange
|
|
172
|
-
});
|
|
173
|
+
}, ref);
|
|
173
174
|
let domProps = (0, $7Kjv5$filterDOMProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
174
175
|
delete domProps.id;
|
|
175
176
|
let linkProps = (0, $7Kjv5$useLinkProps)(item === null || item === void 0 ? void 0 : item.props);
|
|
@@ -180,7 +181,7 @@ function $a2e5df62f93c7633$export$9d32628fc2aea7da(props, state, ref) {
|
|
|
180
181
|
onFocus: itemProps.onFocus,
|
|
181
182
|
'data-collection': itemProps['data-collection'],
|
|
182
183
|
'data-key': itemProps['data-key']
|
|
183
|
-
} : itemProps, pressProps, hoverProps, keyboardProps,
|
|
184
|
+
} : itemProps, pressProps, hoverProps, keyboardProps, focusableProps, // Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.
|
|
184
185
|
data.shouldUseVirtualFocus || isTrigger ? {
|
|
185
186
|
onMouseDown: (e)=>e.preventDefault()
|
|
186
187
|
} : undefined, isDisabled ? undefined : {
|
|
@@ -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, useFocus, 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 * @default true\n */\n closeOnSelect?: 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 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 shouldClose = closeOnSelect ?? shouldClose;\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 {focusProps} = useFocus({onBlur, onFocus, onFocusChange});\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 focusProps,\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, 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,5 +1,5 @@
|
|
|
1
|
-
var $g3RPq$react = require("react");
|
|
2
1
|
var $g3RPq$reactariautils = require("@react-aria/utils");
|
|
2
|
+
var $g3RPq$react = require("react");
|
|
3
3
|
var $g3RPq$reactariainteractions = require("@react-aria/interactions");
|
|
4
4
|
|
|
5
5
|
|
|
@@ -111,7 +111,7 @@ function $62347d8c4183e713$export$85ec83e04c95f50a(options) {
|
|
|
111
111
|
// Fire a pointerover event to trigger the menu to close.
|
|
112
112
|
// Wait until pointer-events:none is no longer applied
|
|
113
113
|
let target = document.elementFromPoint(mouseX, mouseY);
|
|
114
|
-
if (target &&
|
|
114
|
+
if (target && (0, $g3RPq$reactariautils.nodeContains)(menu, target)) target.dispatchEvent(new PointerEvent('pointerover', {
|
|
115
115
|
bubbles: true,
|
|
116
116
|
cancelable: true
|
|
117
117
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\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 && menu.contains(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: 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,5 +1,5 @@
|
|
|
1
|
+
import {useResizeObserver as $fUfeP$useResizeObserver, useEffectEvent as $fUfeP$useEffectEvent, useLayoutEffect as $fUfeP$useLayoutEffect, nodeContains as $fUfeP$nodeContains} from "@react-aria/utils";
|
|
1
2
|
import {useRef as $fUfeP$useRef, useState as $fUfeP$useState, useEffect as $fUfeP$useEffect} from "react";
|
|
2
|
-
import {useResizeObserver as $fUfeP$useResizeObserver, useEffectEvent as $fUfeP$useEffectEvent, useLayoutEffect as $fUfeP$useLayoutEffect} from "@react-aria/utils";
|
|
3
3
|
import {useInteractionModality as $fUfeP$useInteractionModality} from "@react-aria/interactions";
|
|
4
4
|
|
|
5
5
|
|
|
@@ -105,7 +105,7 @@ function $d275435c250248f8$export$85ec83e04c95f50a(options) {
|
|
|
105
105
|
// Fire a pointerover event to trigger the menu to close.
|
|
106
106
|
// Wait until pointer-events:none is no longer applied
|
|
107
107
|
let target = document.elementFromPoint(mouseX, mouseY);
|
|
108
|
-
if (target && menu
|
|
108
|
+
if (target && (0, $fUfeP$nodeContains)(menu, target)) target.dispatchEvent(new PointerEvent('pointerover', {
|
|
109
109
|
bubbles: true,
|
|
110
110
|
cancelable: true
|
|
111
111
|
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import {useResizeObserver as $fUfeP$useResizeObserver, useEffectEvent as $fUfeP$useEffectEvent, useLayoutEffect as $fUfeP$useLayoutEffect, nodeContains as $fUfeP$nodeContains} from "@react-aria/utils";
|
|
1
2
|
import {useRef as $fUfeP$useRef, useState as $fUfeP$useState, useEffect as $fUfeP$useEffect} from "react";
|
|
2
|
-
import {useResizeObserver as $fUfeP$useResizeObserver, useEffectEvent as $fUfeP$useEffectEvent, useLayoutEffect as $fUfeP$useLayoutEffect} from "@react-aria/utils";
|
|
3
3
|
import {useInteractionModality as $fUfeP$useInteractionModality} from "@react-aria/interactions";
|
|
4
4
|
|
|
5
5
|
|
|
@@ -105,7 +105,7 @@ function $d275435c250248f8$export$85ec83e04c95f50a(options) {
|
|
|
105
105
|
// Fire a pointerover event to trigger the menu to close.
|
|
106
106
|
// Wait until pointer-events:none is no longer applied
|
|
107
107
|
let target = document.elementFromPoint(mouseX, mouseY);
|
|
108
|
-
if (target && menu
|
|
108
|
+
if (target && (0, $fUfeP$nodeContains)(menu, target)) target.dispatchEvent(new PointerEvent('pointerover', {
|
|
109
109
|
bubbles: true,
|
|
110
110
|
cancelable: true
|
|
111
111
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/menu/src/useSafelyMouseToSubmenu.ts"],"sourcesContent":["\nimport {RefObject} from '@react-types/shared';\nimport {useEffect, useRef, useState} from 'react';\nimport {useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';\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 && menu.contains(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: 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"}
|
|
@@ -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 (!e.currentTarget
|
|
64
|
+
if (!(0, $23MMN$reactariautils.nodeContains)(e.currentTarget, document.activeElement)) return;
|
|
65
65
|
switch(e.key){
|
|
66
66
|
case 'ArrowLeft':
|
|
67
|
-
if (direction === 'ltr' && e.currentTarget
|
|
67
|
+
if (direction === 'ltr' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget, e.target)) {
|
|
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' && e.currentTarget
|
|
75
|
+
if (direction === 'rtl' && (0, $23MMN$reactariautils.nodeContains)(e.currentTarget, e.target)) {
|
|
76
76
|
e.preventDefault();
|
|
77
77
|
e.stopPropagation();
|
|
78
78
|
onSubmenuClose();
|
|
@@ -80,9 +80,8 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
80
80
|
}
|
|
81
81
|
break;
|
|
82
82
|
case 'Escape':
|
|
83
|
-
var _submenuRef_current;
|
|
84
83
|
// TODO: can remove this when we fix collection event leaks
|
|
85
|
-
if ((
|
|
84
|
+
if ((0, $23MMN$reactariautils.nodeContains)(submenuRef.current, e.target)) {
|
|
86
85
|
e.stopPropagation();
|
|
87
86
|
onSubmenuClose();
|
|
88
87
|
if (!shouldUseVirtualFocus && ref.current) (0, $23MMN$reactariautils.focusWithoutScrolling)(ref.current);
|
|
@@ -147,10 +146,9 @@ function $5f4753043c9f6cdf$export$7138b0d059a6e743(props, state, ref) {
|
|
|
147
146
|
}
|
|
148
147
|
};
|
|
149
148
|
(0, $23MMN$reactariautils.useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
150
|
-
var _parentMenuRef_current;
|
|
151
149
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
152
150
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
153
|
-
if (state.isOpen && ((
|
|
151
|
+
if (state.isOpen && (0, $23MMN$reactariautils.nodeContains)(parentMenuRef.current, e.target) && e.target !== ref.current) onSubmenuClose();
|
|
154
152
|
});
|
|
155
153
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
156
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, 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 (!e.currentTarget.contains(document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'Escape':\n // TODO: can remove this when we fix collection event leaks\n if (submenuRef.current?.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n 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 && (parentMenuRef.current?.contains(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, 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,5 +1,5 @@
|
|
|
1
1
|
import {useSafelyMouseToSubmenu as $d275435c250248f8$export$85ec83e04c95f50a} from "./useSafelyMouseToSubmenu.mjs";
|
|
2
|
-
import {useId as $dXlYe$useId, useLayoutEffect as $dXlYe$useLayoutEffect, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
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";
|
|
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 (!e.currentTarget
|
|
58
|
+
if (!(0, $dXlYe$nodeContains)(e.currentTarget, document.activeElement)) return;
|
|
59
59
|
switch(e.key){
|
|
60
60
|
case 'ArrowLeft':
|
|
61
|
-
if (direction === 'ltr' && e.currentTarget
|
|
61
|
+
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, e.target)) {
|
|
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' && e.currentTarget
|
|
69
|
+
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, e.target)) {
|
|
70
70
|
e.preventDefault();
|
|
71
71
|
e.stopPropagation();
|
|
72
72
|
onSubmenuClose();
|
|
@@ -74,9 +74,8 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
74
74
|
}
|
|
75
75
|
break;
|
|
76
76
|
case 'Escape':
|
|
77
|
-
var _submenuRef_current;
|
|
78
77
|
// TODO: can remove this when we fix collection event leaks
|
|
79
|
-
if ((
|
|
78
|
+
if ((0, $dXlYe$nodeContains)(submenuRef.current, e.target)) {
|
|
80
79
|
e.stopPropagation();
|
|
81
80
|
onSubmenuClose();
|
|
82
81
|
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
@@ -141,10 +140,9 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
141
140
|
}
|
|
142
141
|
};
|
|
143
142
|
(0, $dXlYe$useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
144
|
-
var _parentMenuRef_current;
|
|
145
143
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
146
144
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
147
|
-
if (state.isOpen && ((
|
|
145
|
+
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, e.target) && e.target !== ref.current) onSubmenuClose();
|
|
148
146
|
});
|
|
149
147
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
150
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, focusWithoutScrolling as $dXlYe$focusWithoutScrolling, useEvent as $dXlYe$useEvent} from "@react-aria/utils";
|
|
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";
|
|
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 (!e.currentTarget
|
|
58
|
+
if (!(0, $dXlYe$nodeContains)(e.currentTarget, document.activeElement)) return;
|
|
59
59
|
switch(e.key){
|
|
60
60
|
case 'ArrowLeft':
|
|
61
|
-
if (direction === 'ltr' && e.currentTarget
|
|
61
|
+
if (direction === 'ltr' && (0, $dXlYe$nodeContains)(e.currentTarget, e.target)) {
|
|
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' && e.currentTarget
|
|
69
|
+
if (direction === 'rtl' && (0, $dXlYe$nodeContains)(e.currentTarget, e.target)) {
|
|
70
70
|
e.preventDefault();
|
|
71
71
|
e.stopPropagation();
|
|
72
72
|
onSubmenuClose();
|
|
@@ -74,9 +74,8 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
74
74
|
}
|
|
75
75
|
break;
|
|
76
76
|
case 'Escape':
|
|
77
|
-
var _submenuRef_current;
|
|
78
77
|
// TODO: can remove this when we fix collection event leaks
|
|
79
|
-
if ((
|
|
78
|
+
if ((0, $dXlYe$nodeContains)(submenuRef.current, e.target)) {
|
|
80
79
|
e.stopPropagation();
|
|
81
80
|
onSubmenuClose();
|
|
82
81
|
if (!shouldUseVirtualFocus && ref.current) (0, $dXlYe$focusWithoutScrolling)(ref.current);
|
|
@@ -141,10 +140,9 @@ function $0065b146e7192841$export$7138b0d059a6e743(props, state, ref) {
|
|
|
141
140
|
}
|
|
142
141
|
};
|
|
143
142
|
(0, $dXlYe$useEvent)(parentMenuRef, 'focusin', (e)=>{
|
|
144
|
-
var _parentMenuRef_current;
|
|
145
143
|
// If we detect focus moved to a different item in the same menu that the currently open submenu trigger is in
|
|
146
144
|
// then close the submenu. This is for a case where the user hovers a root menu item when multiple submenus are open
|
|
147
|
-
if (state.isOpen && ((
|
|
145
|
+
if (state.isOpen && (0, $dXlYe$nodeContains)(parentMenuRef.current, e.target) && e.target !== ref.current) onSubmenuClose();
|
|
148
146
|
});
|
|
149
147
|
let shouldCloseOnInteractOutside = (target)=>{
|
|
150
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, 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 (!e.currentTarget.contains(document.activeElement)) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n if (direction === 'ltr' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'ArrowRight':\n if (direction === 'rtl' && e.currentTarget.contains(e.target as Element)) {\n e.preventDefault();\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n case 'Escape':\n // TODO: can remove this when we fix collection event leaks\n if (submenuRef.current?.contains(e.target as Element)) {\n e.stopPropagation();\n onSubmenuClose();\n if (!shouldUseVirtualFocus && ref.current) {\n focusWithoutScrolling(ref.current);\n }\n }\n break;\n }\n };\n\n let submenuProps = {\n id: overlayId,\n 'aria-labelledby': submenuTriggerId,\n submenuLevel: state.submenuLevel,\n ...(type === 'menu' && {\n onClose: state.closeAll,\n autoFocus: state.focusStrategy ?? undefined,\n onKeyDown: submenuKeyDown\n })\n };\n\n let submenuTriggerKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowRight':\n if (!isDisabled) {\n if (direction === 'ltr') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n\n break;\n case 'ArrowLeft':\n if (!isDisabled) {\n if (direction === 'rtl') {\n e.preventDefault();\n if (!state.isOpen) {\n onSubmenuOpen('first');\n }\n\n if (type === 'menu' && !!submenuRef?.current && document.activeElement === ref?.current) {\n focusWithoutScrolling(submenuRef.current);\n }\n } else if (state.isOpen) {\n onSubmenuClose();\n } else {\n e.continuePropagation();\n }\n }\n break;\n default:\n e.continuePropagation();\n break;\n }\n };\n\n let onPressStart = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'virtual' || e.pointerType === 'keyboard')) {\n // If opened with a screen reader or keyboard, auto focus the first submenu item.\n onSubmenuOpen('first');\n }\n };\n\n let onPress = (e: PressEvent) => {\n if (!isDisabled && (e.pointerType === 'touch' || e.pointerType === 'mouse')) {\n // For touch or on a desktop device with a small screen open on press up to possible problems with\n // press up happening on the newly opened tray items\n onSubmenuOpen();\n }\n };\n\n let onHoverChange = (isHovered) => {\n if (!isDisabled) {\n if (isHovered && !state.isOpen) {\n if (!openTimeout.current) {\n openTimeout.current = setTimeout(() => {\n onSubmenuOpen();\n }, delay);\n }\n } else if (!isHovered) {\n cancelOpenTimeout();\n }\n }\n };\n\n 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 && (parentMenuRef.current?.contains(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":"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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/menu",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.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.
|
|
32
|
-
"@react-aria/overlays": "^3.31.
|
|
33
|
-
"@react-aria/selection": "^3.27.
|
|
34
|
-
"@react-aria/utils": "^3.
|
|
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.
|
|
40
|
-
"@react-types/menu": "^3.10.
|
|
41
|
-
"@react-types/shared": "^3.
|
|
29
|
+
"@react-aria/focus": "^3.21.4",
|
|
30
|
+
"@react-aria/i18n": "^3.12.15",
|
|
31
|
+
"@react-aria/interactions": "^3.27.0",
|
|
32
|
+
"@react-aria/overlays": "^3.31.1",
|
|
33
|
+
"@react-aria/selection": "^3.27.1",
|
|
34
|
+
"@react-aria/utils": "^3.33.0",
|
|
35
|
+
"@react-stately/collections": "^3.12.9",
|
|
36
|
+
"@react-stately/menu": "^3.9.10",
|
|
37
|
+
"@react-stately/selection": "^3.20.8",
|
|
38
|
+
"@react-stately/tree": "^3.9.5",
|
|
39
|
+
"@react-types/button": "^3.15.0",
|
|
40
|
+
"@react-types/menu": "^3.10.6",
|
|
41
|
+
"@react-types/shared": "^3.33.0",
|
|
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": "66e51757606b43a89ed02c574ca24517323a2ab9"
|
|
52
52
|
}
|
package/src/useMenuItem.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import {DOMAttributes, DOMProps, FocusableElement, FocusEvents, HoverEvents, Key, KeyboardEvents, PressEvent, PressEvents, RefObject} from '@react-types/shared';
|
|
14
14
|
import {filterDOMProps, handleLinkClick, mergeProps, useLinkProps, useRouter, useSlotId} from '@react-aria/utils';
|
|
15
15
|
import {getItemCount} from '@react-stately/collections';
|
|
16
|
-
import {isFocusVisible,
|
|
16
|
+
import {isFocusVisible, 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';
|
|
@@ -72,10 +72,13 @@ export interface AriaMenuItemProps extends DOMProps, PressEvents, HoverEvents, K
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Whether the menu should close when the menu item is selected.
|
|
75
|
-
* @
|
|
75
|
+
* @deprecated - use shouldCloseOnSelect instead.
|
|
76
76
|
*/
|
|
77
77
|
closeOnSelect?: boolean,
|
|
78
78
|
|
|
79
|
+
/** Whether the menu should close when the menu item is selected. */
|
|
80
|
+
shouldCloseOnSelect?: boolean,
|
|
81
|
+
|
|
79
82
|
/** Whether the menu item is contained in a virtual scrolling menu. */
|
|
80
83
|
isVirtualized?: boolean,
|
|
81
84
|
|
|
@@ -109,6 +112,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
109
112
|
id,
|
|
110
113
|
key,
|
|
111
114
|
closeOnSelect,
|
|
115
|
+
shouldCloseOnSelect,
|
|
112
116
|
isVirtualized,
|
|
113
117
|
'aria-haspopup': hasPopup,
|
|
114
118
|
onPressStart,
|
|
@@ -221,8 +225,10 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
221
225
|
? interaction.current?.key === 'Enter' || selectionManager.selectionMode === 'none' || selectionManager.isLink(key)
|
|
222
226
|
// Close except if multi-select is enabled.
|
|
223
227
|
: selectionManager.selectionMode !== 'multiple' || selectionManager.isLink(key);
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
shouldClose = shouldCloseOnSelect ?? closeOnSelect ?? shouldClose;
|
|
231
|
+
|
|
226
232
|
if (onClose && !isTrigger && shouldClose) {
|
|
227
233
|
onClose();
|
|
228
234
|
}
|
|
@@ -301,7 +307,7 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
301
307
|
onKeyUp
|
|
302
308
|
});
|
|
303
309
|
|
|
304
|
-
let {
|
|
310
|
+
let {focusableProps} = useFocusable({onBlur, onFocus, onFocusChange}, ref);
|
|
305
311
|
let domProps = filterDOMProps(item?.props);
|
|
306
312
|
delete domProps.id;
|
|
307
313
|
let linkProps = useLinkProps(item?.props);
|
|
@@ -312,13 +318,13 @@ export function useMenuItem<T>(props: AriaMenuItemProps, state: TreeState<T>, re
|
|
|
312
318
|
...mergeProps(
|
|
313
319
|
domProps,
|
|
314
320
|
linkProps,
|
|
315
|
-
isTrigger
|
|
316
|
-
? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}
|
|
321
|
+
isTrigger
|
|
322
|
+
? {onFocus: itemProps.onFocus, 'data-collection': itemProps['data-collection'], 'data-key': itemProps['data-key']}
|
|
317
323
|
: itemProps,
|
|
318
324
|
pressProps,
|
|
319
325
|
hoverProps,
|
|
320
326
|
keyboardProps,
|
|
321
|
-
|
|
327
|
+
focusableProps,
|
|
322
328
|
// Prevent DOM focus from moving on mouse down when using virtual focus or this is a submenu/subdialog trigger.
|
|
323
329
|
data.shouldUseVirtualFocus || isTrigger ? {onMouseDown: e => e.preventDefault()} : undefined,
|
|
324
330
|
isDisabled ? undefined : {onClick}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
+
import {nodeContains, useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';
|
|
2
3
|
import {RefObject} from '@react-types/shared';
|
|
3
4
|
import {useEffect, useRef, useState} from 'react';
|
|
4
|
-
import {useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils';
|
|
5
5
|
import {useInteractionModality} from '@react-aria/interactions';
|
|
6
6
|
|
|
7
7
|
interface SafelyMouseToSubmenuOptions {
|
|
@@ -148,7 +148,7 @@ export function useSafelyMouseToSubmenu(options: SafelyMouseToSubmenuOptions): v
|
|
|
148
148
|
// Fire a pointerover event to trigger the menu to close.
|
|
149
149
|
// Wait until pointer-events:none is no longer applied
|
|
150
150
|
let target = document.elementFromPoint(mouseX, mouseY);
|
|
151
|
-
if (target && menu
|
|
151
|
+
if (target && nodeContains(menu, target)) {
|
|
152
152
|
target.dispatchEvent(new PointerEvent('pointerover', {bubbles: true, cancelable: true}));
|
|
153
153
|
}
|
|
154
154
|
}, 100);
|
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, useEvent, useId, useLayoutEffect} from '@react-aria/utils';
|
|
17
|
+
import {focusWithoutScrolling, 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';
|
|
@@ -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 (!e.currentTarget
|
|
103
|
+
if (!nodeContains(e.currentTarget, document.activeElement)) {
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
switch (e.key) {
|
|
108
108
|
case 'ArrowLeft':
|
|
109
|
-
if (direction === 'ltr' && e.currentTarget
|
|
109
|
+
if (direction === 'ltr' && nodeContains(e.currentTarget, e.target 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' && e.currentTarget
|
|
119
|
+
if (direction === 'rtl' && nodeContains(e.currentTarget, e.target 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 (submenuRef.current
|
|
130
|
+
if (nodeContains(submenuRef.current, e.target as Element)) {
|
|
131
131
|
e.stopPropagation();
|
|
132
132
|
onSubmenuClose();
|
|
133
133
|
if (!shouldUseVirtualFocus && ref.current) {
|
|
@@ -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 && (parentMenuRef.current
|
|
229
|
+
if (state.isOpen && (nodeContains(parentMenuRef.current, e.target as HTMLElement) && e.target !== ref.current)) {
|
|
230
230
|
onSubmenuClose();
|
|
231
231
|
}
|
|
232
232
|
});
|