@@ -13,9 +13,11 @@ import {useId} from '../hooks/useId'
1313import type { MandateProps } from '../utils/types'
1414import type { ForwardRefComponent as PolymorphicForwardRefComponent } from '../utils/polymorphic'
1515import { Tooltip } from '../TooltipV2/Tooltip'
16+ import styles from './ActionMenu.module.css'
17+ import { useResponsiveValue , type ResponsiveValue } from '../hooks/useResponsiveValue'
1618
1719export type MenuCloseHandler = (
18- gesture : 'anchor-click' | 'click-outside' | 'escape' | 'tab' | 'item-select' | 'arrow-left' ,
20+ gesture : 'anchor-click' | 'click-outside' | 'escape' | 'tab' | 'item-select' | 'arrow-left' | 'close' ,
1921) => void
2022
2123export type MenuContextProps = Pick <
@@ -79,18 +81,21 @@ const Menu: React.FC<React.PropsWithChildren<ActionMenuProps>> = ({
7981
8082 const [ combinedOpenState , setCombinedOpenState ] = useProvidedStateOrCreate ( open , onOpenChange , false )
8183 const onOpen = React . useCallback ( ( ) => setCombinedOpenState ( true ) , [ setCombinedOpenState ] )
84+ const isNarrow = useResponsiveValue ( { narrow : true } , false )
8285 const onClose : MenuCloseHandler = React . useCallback (
8386 gesture => {
87+ if ( isNarrow && open && gesture === 'tab' ) {
88+ return
89+ }
8490 setCombinedOpenState ( false )
85-
8691 // Close the parent stack when an item is selected or the user tabs out of the menu entirely
8792 switch ( gesture ) {
8893 case 'tab' :
8994 case 'item-select' :
9095 parentMenuContext . onClose ?.( gesture )
9196 }
9297 } ,
93- [ setCombinedOpenState , parentMenuContext ] ,
98+ [ setCombinedOpenState , parentMenuContext , open , isNarrow ] ,
9499 )
95100
96101 const menuButtonChild = React . Children . toArray ( children ) . find (
@@ -229,8 +234,13 @@ const MenuButton = React.forwardRef(({...props}, anchorRef) => {
229234 )
230235} ) as PolymorphicForwardRefComponent < 'button' , ActionMenuButtonProps >
231236
237+ const defaultVariant : ResponsiveValue < 'anchored' , 'anchored' | 'fullscreen' > = {
238+ regular : 'anchored' ,
239+ narrow : 'anchored' ,
240+ }
241+
232242type MenuOverlayProps = Partial < OverlayProps > &
233- Pick < AnchoredOverlayProps , 'align' | 'side' > & {
243+ Pick < AnchoredOverlayProps , 'align' | 'side' | 'variant' > & {
234244 /**
235245 * Recommended: `ActionList`
236246 */
@@ -243,6 +253,7 @@ const Overlay: React.FC<React.PropsWithChildren<MenuOverlayProps>> = ({
243253 side,
244254 onPositionChange,
245255 'aria-labelledby' : ariaLabelledby ,
256+ variant = defaultVariant ,
246257 ...overlayProps
247258} ) => {
248259 // we typecast anchorRef as required instead of optional
@@ -259,6 +270,10 @@ const Overlay: React.FC<React.PropsWithChildren<MenuOverlayProps>> = ({
259270
260271 const containerRef = React . useRef < HTMLDivElement > ( null )
261272 useMenuKeyboardNavigation ( open , onClose , containerRef , anchorRef , isSubmenu )
273+ const isNarrow = useResponsiveValue ( { narrow : true } , false )
274+ const responsiveVariant = useResponsiveValue ( variant , { regular : 'anchored' , narrow : 'anchored' } )
275+
276+ const isNarrowFullscreen = ! ! isNarrow && variant . narrow === 'fullscreen'
262277
263278 // If the menu anchor is an icon button, we need to label the menu by tooltip that also labelled the anchor.
264279 const [ anchorAriaLabelledby , setAnchorAriaLabelledby ] = useState < null | string > ( null )
@@ -284,10 +299,11 @@ const Overlay: React.FC<React.PropsWithChildren<MenuOverlayProps>> = ({
284299 align = { align }
285300 side = { side ?? ( isSubmenu ? 'outside-right' : 'outside-bottom' ) }
286301 overlayProps = { overlayProps }
287- focusZoneSettings = { { focusOutBehavior : 'wrap' } }
302+ focusZoneSettings = { isNarrowFullscreen ? { disabled : true } : { focusOutBehavior : 'wrap' } }
288303 onPositionChange = { onPositionChange }
304+ variant = { variant }
289305 >
290- < div ref = { containerRef } >
306+ < div ref = { containerRef } className = { styles . ActionMenuContainer } data-variant = { responsiveVariant } >
291307 < ActionListContainerContext . Provider
292308 value = { {
293309 container : 'ActionMenu' ,
@@ -296,7 +312,7 @@ const Overlay: React.FC<React.PropsWithChildren<MenuOverlayProps>> = ({
296312 listLabelledBy : ariaLabelledby || anchorAriaLabelledby || anchorId ,
297313 selectionAttribute : 'aria-checked' , // Should this be here?
298314 afterSelect : ( ) => onClose ?.( 'item-select' ) ,
299- enableFocusZone : false , // AnchoredOverlay takes care of focus zone
315+ enableFocusZone : isNarrowFullscreen , // AnchoredOverlay takes care of focus zone. We only want to enable this if menu is narrow fullscreen.
300316 } }
301317 >
302318 { children }
0 commit comments