@@ -29,14 +29,14 @@ const GridMenu = ({
2929 top,
3030 left : incomingLeft ,
3131 subMenu,
32- subtractWidthFromLeft ,
32+ parentDimensions ,
3333} : {
3434 menuItems : ( MenuItem | string ) [ ] ;
3535 theme : string ;
3636 top : number ;
37- left : number ;
37+ left ? : number ;
3838 subMenu ?: boolean ;
39- subtractWidthFromLeft ?: boolean ;
39+ parentDimensions ?: { left : number ; width : number } ;
4040} ) => {
4141 const menuRef = useRef < HTMLDivElement > ( undefined ) ;
4242 const [ subMenuItems , setSubMenuItems ] = useState < ( MenuItem | string ) [ ] > ( [ ] ) ;
@@ -45,18 +45,27 @@ const GridMenu = ({
4545 : `ag-menu ag-column-menu ag-ltr ag-popup-child ag-popup-positioned-under ${ theme } ` ;
4646 const [ activeIndex , setActiveIndex ] = useState ( - 1 ) ;
4747
48- const [ offset , setOffset ] = useState ( 0 ) ;
49- const [ left , setLeft ] = useState ( incomingLeft ) ;
48+ const [ left , setLeft ] = useState ( parentDimensions ?. left ?? incomingLeft ) ;
49+ const [ displayed , setDisplayed ] = useState ( false ) ;
5050 useEffect ( ( ) => {
51- const w = menuRef . current . getBoundingClientRect ( ) . width ;
52- const cw = menuRef . current . closest ( "body" ) . clientWidth ;
53- if ( subtractWidthFromLeft ) {
54- setLeft ( incomingLeft - w ) ;
51+ const clientWidth = menuRef . current . closest ( "body" ) . clientWidth ;
52+ const width = menuRef . current . getBoundingClientRect ( ) . width ;
53+
54+ if ( parentDimensions ) {
55+ // First, lets put the child menu to the right
56+ let adjustedLeft = parentDimensions . left + parentDimensions . width ;
57+ // If that's off screen, lets instead place it to the left
58+ if ( adjustedLeft + width > clientWidth ) {
59+ adjustedLeft = parentDimensions . left - width ;
60+ }
61+ setLeft ( adjustedLeft ) ;
62+ setDisplayed ( true ) ;
5563 return ;
5664 }
57- if ( left + w > cw ) {
58- setOffset ( left + w - cw + 15 ) ;
65+ if ( left + width > clientWidth ) {
66+ setLeft ( left - ( left + width - clientWidth + 15 ) ) ;
5967 }
68+ setDisplayed ( true ) ;
6069 } , [ ] ) ;
6170
6271 return (
@@ -66,20 +75,25 @@ const GridMenu = ({
6675 menuItems = { subMenuItems }
6776 theme = { theme }
6877 top = { top }
69- left = {
70- offset === 0
71- ? left + menuRef . current . getBoundingClientRect ( ) . width
72- : left - offset
73- }
74- subtractWidthFromLeft = { offset !== 0 }
78+ parentDimensions = { {
79+ left,
80+ width : menuRef . current . getBoundingClientRect ( ) . width ,
81+ } }
7582 subMenu
7683 />
7784 ) }
78- < div className = "ag-theme-sas ag-popup" >
85+ < div
86+ className = "ag-theme-sas ag-popup"
87+ // We rely on the menu being displayed _first_ before being able to
88+ // calculate it's correct left position. This prevents actually showing the
89+ // menu to the user until we've figured that out. This prevents flashes of the
90+ // menu in the wrong position.
91+ style = { { visibility : displayed ? "visible" : "hidden" } }
92+ >
7993 < div
8094 className = { className }
8195 role = "presentation"
82- style = { { top, left : left - offset } }
96+ style = { { top, left } }
8397 ref = { menuRef }
8498 >
8599 < div className = "ag-menu-list ag-focus-managed" role = "menu" >
0 commit comments