@@ -158,8 +158,61 @@ export class FeatherGridContextMenu extends GridContextMenu {
158158 throw 'unreachable' ;
159159 }
160160
161+ // Get the current height of the main viewport.
162+ const px = window . pageXOffset ;
163+ const py = window . pageYOffset ;
164+ const cw = document . documentElement . clientWidth ;
165+ const ch = document . documentElement . clientHeight ;
166+ const bodyh = document . documentElement . scrollHeight ;
167+ var style = window . getComputedStyle ( document . body ) ;
168+ const extraspaceX = parseFloat ( style . marginLeft ) + parseFloat ( style . paddingLeft ) + parseFloat ( style . borderLeftWidth ) ;
169+ const extraspaceY = parseFloat ( style . marginTop ) + parseFloat ( style . paddingTop ) + parseFloat ( style . borderTopWidth ) ;
170+
161171 // Open context menu at location of the click event
162- this . _menu . open ( hit . x , hit . y ) ;
172+ this . _menu . open ( hit . x , 0 ) ; //Using 0 so it's at least at the bottom
173+ //of the parent div and not a mile down
174+
175+ // Now that it's open, move it to the correct position.
176+ // Lumino won't allow a negative y-coordinate, but we
177+ // need it to be negative with absolute positioning. This
178+ // position-reposition thing isn't ideal, since there's a
179+ // split-second that the menu is not where it ought to be,
180+ // but in practice this is usually going to be so brief a
181+ // moment that nobody will notice; it's functionally a
182+ // performance hit in a spot where people likely won't notice
183+ // a performance hit.
184+
185+ // We're going to do the full coordinate recalculation,
186+ // since the conditions below are part of the Lumino
187+ // menu's positioning math for a reason. They show up in
188+ // ipydatagrid's InteractiveFilterDialog positioning math
189+ // as well.
190+
191+ let node = this . _menu . node ;
192+ let { width, height } = node . getBoundingClientRect ( ) ;
193+
194+ let hitx = hit . x ;
195+ let hity = hit . y ;
196+
197+ // Adjust the X position of the menu to fit on-screen.
198+ if ( hitx + width > px + cw ) {
199+ hitx = px + cw - width ;
200+ }
201+
202+ // Adjust the Y position of the menu to fit on-screen.
203+ if ( hity + height > py + ch ) {
204+ if ( hity > py + ch ) {
205+ hity = py + ch - height ;
206+ } else {
207+ hity = hity - height ;
208+ }
209+ }
210+
211+ hitx = hitx - extraspaceX ;
212+ hity = hity - bodyh + extraspaceY ;
213+
214+ // Update the position of the menu to the computed position.
215+ this . _menu . node . style . transform = `translate(${ Math . max ( 0 , hitx ) } px, ${ hity } px` ;
163216 }
164217}
165218
0 commit comments