@@ -12,6 +12,7 @@ import React, {
1212 useMemo ,
1313 ReactNode ,
1414 useState ,
15+ useId ,
1516} from 'react' ;
1617import classnames from 'classnames' ;
1718import { Icon } from './Icon' ;
@@ -68,6 +69,18 @@ export const DropdownMenuHandlerContext = createContext<DropdownMenuHandler>(
6869 { }
6970) ;
7071
72+ type OpenSubmenuContext = {
73+ openSubmenuKeys : {
74+ [ key : string ] : { isOpen : boolean ; level : number } | undefined ;
75+ } ;
76+ handleSubmenuOpen : ( key : string , level : number ) => void ;
77+ } ;
78+
79+ export const OpenSubmenuContext = createContext < OpenSubmenuContext > ( {
80+ openSubmenuKeys : { } ,
81+ handleSubmenuOpen : ( ) => { } ,
82+ } ) ;
83+
7184/**
7285 *
7386 */
@@ -82,6 +95,7 @@ export type DropdownMenuItemProps = {
8295 onClick ?: ( e : React . SyntheticEvent ) => void ;
8396 submenu ?: ReactNode ;
8497 submenuItems ?: Array < { key : string | number } & DropdownMenuItemProps > ;
98+ level ?: number ;
8599} & Omit < AnchorHTMLAttributes < HTMLAnchorElement > , 'onClick' > ;
86100
87101/**
@@ -104,13 +118,18 @@ export const DropdownMenuItem: FC<DropdownMenuItemProps> = (props) => {
104118 submenu : submenu_ ,
105119 submenuItems,
106120 children,
121+ level = 0 ,
107122 ...rprops
108123 } = props ;
109124
110125 const { onMenuSelect, onMenuBlur, onMenuFocus } = useContext (
111126 DropdownMenuHandlerContext
112127 ) ;
113128
129+ const { openSubmenuKeys, handleSubmenuOpen } = useContext ( OpenSubmenuContext ) ;
130+
131+ const submenuKey = useId ( ) ;
132+
114133 const onKeyDown = useEventCallback ( ( e : KeyboardEvent < HTMLAnchorElement > ) => {
115134 if ( e . keyCode === 13 || e . keyCode === 32 ) {
116135 // return or space
@@ -163,7 +182,7 @@ export const DropdownMenuItem: FC<DropdownMenuItemProps> = (props) => {
163182 const onMenuItemClick = useEventCallback (
164183 ( e : SyntheticEvent < HTMLAnchorElement > ) => {
165184 if ( submenu ) {
166- setSubmenuExpanded ( ( expanded ) => ! expanded ) ;
185+ handleSubmenuOpen ( submenuKey , level + 1 ) ;
167186 return ;
168187 }
169188 onClick ?.( e ) ;
@@ -192,11 +211,12 @@ export const DropdownMenuItem: FC<DropdownMenuItemProps> = (props) => {
192211 ( submenuItems ? (
193212 < DropdownSubmenu label = { label } >
194213 { submenuItems ?. map ( ( { key, ...itemProps } ) => (
195- < DropdownMenuItem key = { key } { ...itemProps } />
214+ < DropdownMenuItem key = { key } level = { level + 1 } { ...itemProps } />
196215 ) ) }
197216 </ DropdownSubmenu >
198217 ) : undefined ) ;
199- const [ submenuExpanded , setSubmenuExpanded ] = useState ( false ) ;
218+
219+ const submenuExpanded = openSubmenuKeys [ submenuKey ] ?. isOpen ?? false ;
200220
201221 const menuItemClass = classnames (
202222 'slds-dropdown__item' ,
@@ -340,6 +360,24 @@ const DropdownMenuInner: FC<DropdownMenuProps & AutoAlignInjectedProps> = (
340360 } ) ,
341361 [ onBlur , onFocus , onMenuSelect ]
342362 ) ;
363+
364+ const [ openSubmenuKeys , setOpenSubmenuKeys ] = useState < {
365+ [ key : string ] : { isOpen : boolean ; level : number } ;
366+ } > ( { } ) ;
367+
368+ const handleSubmenuOpen = ( key : string , level : number ) => {
369+ setOpenSubmenuKeys ( ( prevState ) => {
370+ const newState = { ...prevState } ;
371+ Object . keys ( newState ) . forEach ( ( submenuKey ) => {
372+ if ( newState [ submenuKey ] . level >= level && key !== submenuKey ) {
373+ newState [ submenuKey ] . isOpen = false ;
374+ }
375+ } ) ;
376+ newState [ key ] = { isOpen : ! newState [ key ] ?. isOpen , level } ;
377+ return newState ;
378+ } ) ;
379+ } ;
380+
343381 return (
344382 < div
345383 className = { dropdownClassNames }
@@ -354,7 +392,11 @@ const DropdownMenuInner: FC<DropdownMenuProps & AutoAlignInjectedProps> = (
354392 { header ? < MenuHeader > { header } </ MenuHeader > : null }
355393 < ul className = 'slds-dropdown__list' role = 'menu' >
356394 < DropdownMenuHandlerContext . Provider value = { handlers } >
357- { children }
395+ < OpenSubmenuContext . Provider
396+ value = { { openSubmenuKeys, handleSubmenuOpen } }
397+ >
398+ { children }
399+ </ OpenSubmenuContext . Provider >
358400 </ DropdownMenuHandlerContext . Provider >
359401 </ ul >
360402 </ div >
0 commit comments