@@ -58,11 +58,44 @@ class ContextMenuRoot extends Component<
5858 openMenu : React . RefObject < ContextMenu > ;
5959
6060 handleContextMenu ( e : MouseEvent ) : void {
61- if ( ! ContextActionUtils . isContextActionEvent ( e ) ) {
61+ if ( ! this . container . current ) {
6262 return ;
6363 }
6464
65- if ( ! this . container . current ) {
65+ const parentRect = this . container . current . getBoundingClientRect ( ) ;
66+ const top = e . clientY - parentRect . top ;
67+ const left = e . clientX - parentRect . left ;
68+ const { actions } = this . state ;
69+
70+ // Context menu is open and user clicked on the context-root blocking layer
71+ // Mac and Linux appear to trigger contextmenu events on mousedown vs. mouseup on Windows
72+ // Mouseup on Windows triggers blur before contextmenu which effectively does what this path does
73+ if ( actions != null && e . target === this . container . current ) {
74+ // re-emit right clicks that hit the context-root blocking layer
75+ // while we already have a custom context menu open
76+ e . preventDefault ( ) ;
77+
78+ // Set actions to null removes the menu
79+ // That allows a new menu to be opened on a different element so initial position is set properly
80+ // Otherwise the instance of this menu may be reused
81+ // A new contextmenu event is triggered on the element at the location the user clicked on the blocking layer
82+ this . setState ( { actions : null } , ( ) => {
83+ const element = document . elementFromPoint ( left , top ) ; // x y
84+
85+ const mouseEvent = new MouseEvent ( 'contextmenu' , {
86+ clientX : e . clientX ,
87+ clientY : e . clientY ,
88+ bubbles : true ,
89+ cancelable : true ,
90+ } ) ;
91+
92+ element ?. dispatchEvent ( mouseEvent ) ;
93+ } ) ;
94+ return ;
95+ }
96+
97+ if ( ! ContextActionUtils . isContextActionEvent ( e ) ) {
98+ // Open native menu if no custom context actions
6699 return ;
67100 }
68101
@@ -73,38 +106,8 @@ class ContextMenuRoot extends Component<
73106
74107 const contextActions = ContextActionUtils . getMenuItems ( e . contextActions ) ;
75108
76- const parentRect = this . container . current . getBoundingClientRect ( ) ;
77- const top = e . clientY - parentRect . top ;
78- const left = e . clientX - parentRect . left ;
79-
80109 if ( contextActions . length === 0 ) {
81- // This code path seems to only exist for Chrome on Mac
82- // Mac appears to trigger contextmenu events on mousedown vs. mouseup on Windows
83- // Mouseup on Windows triggers blur before contextmenu which effectively does what this path does
84- if ( e . target === this . container . current ) {
85- // re-emit right clicks that hit the context-root blocking layer
86- e . preventDefault ( ) ;
87-
88- // Set actions to null removes the menu
89- // That allows a new menu to be opened on a different element so initial position is set properly
90- // Otherwise the instance of this menu may be reused
91- // A new contextmenu event is triggered on the element at the location the user clicked on the blocking layer
92- this . setState ( { actions : null } , ( ) => {
93- const element = document . elementFromPoint ( left , top ) ; // x y
94-
95- const mouseEvent = new MouseEvent ( 'contextmenu' , {
96- clientX : e . clientX ,
97- clientY : e . clientY ,
98- bubbles : true ,
99- cancelable : true ,
100- } ) ;
101-
102- element ?. dispatchEvent ( mouseEvent ) ;
103- } ) ;
104- return ;
105- }
106-
107- // target was a menu item
110+ // No actions after filtering. Use native menu
108111 return ;
109112 }
110113
0 commit comments