1
1
import * as React from 'react'
2
- import { withStyles } from '@material-ui/styles'
3
- import Menu from 'material-ui-popup-state/HoverMenu'
2
+ import { makeStyles } from '@material-ui/styles'
3
+ import HoverMenu from 'material-ui-popup-state/HoverMenu'
4
4
import MenuItem from '@material-ui/core/MenuItem'
5
5
import ChevronRight from '@material-ui/icons/ChevronRight'
6
6
import Button from '@material-ui/core/Button'
@@ -10,91 +10,123 @@ import {
10
10
bindMenu ,
11
11
} from 'material-ui-popup-state/hooks'
12
12
13
- const ParentPopupState = React . createContext ( null )
13
+ const useCascadingMenuStyles = makeStyles ( ( theme ) => ( {
14
+ submenu : {
15
+ marginTop : theme . spacing ( - 1 ) ,
16
+ } ,
17
+ title : {
18
+ flexGrow : 1 ,
19
+ } ,
20
+ moreArrow : {
21
+ marginRight : theme . spacing ( - 1 ) ,
22
+ } ,
23
+ } ) )
24
+
25
+ const CascadingContext = React . createContext ( {
26
+ parentPopupState : null ,
27
+ rootPopupState : null ,
28
+ } )
29
+
30
+ function CascadingMenuItem ( { onClick, ...props } ) {
31
+ const { rootPopupState } = React . useContext ( CascadingContext )
32
+ if ( ! rootPopupState ) throw new Error ( 'must be used inside a CascadingMenu' )
33
+ const handleClick = React . useCallback (
34
+ ( event ) => {
35
+ rootPopupState . close ( event )
36
+ if ( onClick ) onClick ( event )
37
+ } ,
38
+ [ rootPopupState , onClick ]
39
+ )
40
+
41
+ return < MenuItem { ...props } onClick = { handleClick } />
42
+ }
43
+
44
+ function CascadingSubmenu ( { title, popupId, ...props } ) {
45
+ const classes = useCascadingMenuStyles ( )
46
+ const { parentPopupState } = React . useContext ( CascadingContext )
47
+ const popupState = usePopupState ( {
48
+ popupId,
49
+ variant : 'popover' ,
50
+ parentPopupState,
51
+ disableAutoFocus : true ,
52
+ } )
53
+ return (
54
+ < React . Fragment >
55
+ < MenuItem { ...bindHover ( popupState ) } >
56
+ < span className = { classes . title } > { title } </ span >
57
+ < ChevronRight className = { classes . moreArrow } />
58
+ </ MenuItem >
59
+ < CascadingMenu
60
+ { ...props }
61
+ classes = { { ...props . classes , paper : classes . submenu } }
62
+ anchorOrigin = { { vertical : 'top' , horizontal : 'right' } }
63
+ transformOrigin = { { vertical : 'top' , horizontal : 'left' } }
64
+ popupState = { popupState }
65
+ />
66
+ </ React . Fragment >
67
+ )
68
+ }
69
+
70
+ function CascadingMenu ( { popupState, ...props } ) {
71
+ const { rootPopupState } = React . useContext ( CascadingContext )
72
+ const context = React . useMemo (
73
+ ( ) => ( {
74
+ rootPopupState : rootPopupState || popupState ,
75
+ parentPopupState : popupState ,
76
+ } ) ,
77
+ [ rootPopupState , popupState ]
78
+ )
79
+
80
+ return (
81
+ < CascadingContext . Provider value = { context } >
82
+ < HoverMenu { ...props } { ...bindMenu ( popupState ) } />
83
+ </ CascadingContext . Provider >
84
+ )
85
+ }
14
86
15
87
const CascadingHoverMenus = ( ) => {
16
88
const popupState = usePopupState ( {
17
89
popupId : 'demoMenu' ,
18
90
variant : 'popover' ,
19
- deferOpenClose : true ,
91
+ disableAutoFocus : true ,
20
92
} )
21
93
return (
22
94
< div style = { { height : 600 } } >
23
95
< Button variant = "contained" { ...bindHover ( popupState ) } >
24
96
Hover to open Menu
25
97
</ Button >
26
- < ParentPopupState . Provider value = { popupState } >
27
- < Menu
28
- { ...bindMenu ( popupState ) }
29
- anchorOrigin = { { vertical : 'bottom' , horizontal : 'left' } }
30
- transformOrigin = { { vertical : 'top' , horizontal : 'left' } }
98
+ < CascadingMenu
99
+ popupState = { popupState }
100
+ anchorOrigin = { { vertical : 'bottom' , horizontal : 'left' } }
101
+ transformOrigin = { { vertical : 'top' , horizontal : 'left' } }
102
+ >
103
+ < CascadingMenuItem > Tea</ CascadingMenuItem >
104
+ < CascadingMenuItem > Cake</ CascadingMenuItem >
105
+ < CascadingMenuItem > Death</ CascadingMenuItem >
106
+ < CascadingSubmenu
107
+ popupId = "moreChoicesCascadingMenu"
108
+ title = "More Choices"
31
109
>
32
- < MenuItem onClick = { popupState . close } > Tea</ MenuItem >
33
- < MenuItem onClick = { popupState . close } > Cake</ MenuItem >
34
- < MenuItem onClick = { popupState . close } > Death</ MenuItem >
35
- < Submenu popupId = "moreChoicesMenu" title = "More Choices" >
36
- < MenuItem onClick = { popupState . close } > Cheesecake</ MenuItem >
37
- < MenuItem onClick = { popupState . close } > Cheesedeath</ MenuItem >
38
- < Submenu popupId = "evenMoreChoicesMenu" title = "Even More Choices" >
39
- < MenuItem onClick = { popupState . close } > Cake (the band)</ MenuItem >
40
- < MenuItem onClick = { popupState . close } > Death Metal</ MenuItem >
41
- </ Submenu >
42
- < Submenu popupId = "moreBenignChoices" title = "More Benign Choices" >
43
- < MenuItem onClick = { popupState . close } > Salad</ MenuItem >
44
- < MenuItem onClick = { popupState . close } > Lobotomy</ MenuItem >
45
- </ Submenu >
46
- </ Submenu >
47
- </ Menu >
48
- </ ParentPopupState . Provider >
110
+ < CascadingMenuItem > Cheesecake</ CascadingMenuItem >
111
+ < CascadingMenuItem > Cheesedeath</ CascadingMenuItem >
112
+ < CascadingSubmenu
113
+ popupId = "evenMoreChoicesCascadingMenu"
114
+ title = "Even More Choices"
115
+ >
116
+ < CascadingMenuItem > Cake (the band)</ CascadingMenuItem >
117
+ < CascadingMenuItem > Death Metal</ CascadingMenuItem >
118
+ </ CascadingSubmenu >
119
+ < CascadingSubmenu
120
+ popupId = "moreBenignChoices"
121
+ title = "More Benign Choices"
122
+ >
123
+ < CascadingMenuItem > Salad</ CascadingMenuItem >
124
+ < CascadingMenuItem > Lobotomy</ CascadingMenuItem >
125
+ </ CascadingSubmenu >
126
+ </ CascadingSubmenu >
127
+ </ CascadingMenu >
49
128
</ div >
50
129
)
51
130
}
52
131
53
132
export default CascadingHoverMenus
54
-
55
- const submenuStyles = ( theme ) => ( {
56
- menu : {
57
- marginTop : theme . spacing ( - 1 ) ,
58
- } ,
59
- title : {
60
- flexGrow : 1 ,
61
- } ,
62
- moreArrow : {
63
- marginRight : theme . spacing ( - 1 ) ,
64
- } ,
65
- } )
66
-
67
- const Submenu = withStyles ( submenuStyles ) (
68
- // Unfortunately, MUI <Menu> injects refs into its children, which causes a
69
- // warning in some cases unless we use forwardRef here.
70
- React . forwardRef ( ( { classes, title, popupId, children, ...props } , ref ) => {
71
- const parentPopupState = React . useContext ( ParentPopupState )
72
- const popupState = usePopupState ( {
73
- popupId,
74
- variant : 'popover' ,
75
- parentPopupState,
76
- deferOpenClose : true ,
77
- } )
78
- return (
79
- < ParentPopupState . Provider value = { popupState } >
80
- < MenuItem
81
- { ...bindHover ( popupState ) }
82
- selected = { popupState . isOpen }
83
- ref = { ref }
84
- >
85
- < span className = { classes . title } > { title } </ span >
86
- < ChevronRight className = { classes . moreArrow } />
87
- </ MenuItem >
88
- < Menu
89
- { ...bindMenu ( popupState ) }
90
- classes = { { paper : classes . menu } }
91
- anchorOrigin = { { vertical : 'top' , horizontal : 'right' } }
92
- transformOrigin = { { vertical : 'top' , horizontal : 'left' } }
93
- { ...props }
94
- >
95
- { children }
96
- </ Menu >
97
- </ ParentPopupState . Provider >
98
- )
99
- } )
100
- )
0 commit comments