Skip to content

Commit

Permalink
fix boundaries check when repositioning menu #163
Browse files Browse the repository at this point in the history
  • Loading branch information
fkhadra committed Nov 3, 2022
1 parent 6243e05 commit 9f06550
Showing 1 changed file with 25 additions and 31 deletions.
56 changes: 25 additions & 31 deletions src/components/Menu.tsx
Expand Up @@ -150,30 +150,24 @@ export const Menu: React.FC<MenuProps> = ({
}
}, [state.visible, menuController, refTracker]);

// compute menu position
useEffect(() => {
if (state.visible) {
const { innerWidth: windowWidth, innerHeight: windowHeight } = window;
const {
offsetWidth: menuWidth,
offsetHeight: menuHeight,
} = nodeRef.current!;
let { x, y } = state;

if (x + menuWidth > windowWidth) {
x -= x + menuWidth - windowWidth;
}
function checkBoundaries(x: number, y: number) {
if (nodeRef.current) {
const { innerWidth, innerHeight } = window;
const { offsetWidth, offsetHeight } = nodeRef.current;

if (y + menuHeight > windowHeight) {
y -= y + menuHeight - windowHeight;
}
if (x + offsetWidth > innerWidth) x -= x + offsetWidth - innerWidth;

setState({
x,
y,
});
if (y + offsetHeight > innerHeight) y -= y + offsetHeight - innerHeight;
}

return { x, y };
}

// when the menu is transitioning from not visible to visible,
// the nodeRef is attached to the dom element this let us check the boundaries
useEffect(() => {
if (state.visible) setState(checkBoundaries(state.x, state.y));

// state.visible and state{x,y} are updated together
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.visible]);
Expand Down Expand Up @@ -223,10 +217,10 @@ export const Menu: React.FC<MenuProps> = ({

function show({ event, props, position }: ContextMenuParams) {
event.stopPropagation();
const { x, y } = position || getMousePosition(event);
const p = position || getMousePosition(event);
// check boundaries when the menu is already visible and just moving position
const { x, y } = checkBoundaries(p.x, p.y);

// prevent react from batching the state update
// if the menu is already visible we have to recompute bounding rect based on position
flushSync(() => {
setState({
visible: true,
Expand All @@ -239,18 +233,18 @@ export const Menu: React.FC<MenuProps> = ({
});
}

function hide(event?: Event) {
// Safari trigger a click event when you ctrl + trackpad
// Firefox: trigger a click event when right click occur
const e = event as KeyboardEvent & MouseEvent;
function hide(e?: Event) {
type SafariEvent = KeyboardEvent & MouseEvent;

if (
typeof e !== 'undefined' &&
(e.button === 2 || e.ctrlKey === true) &&
e != null &&
// Safari trigger a click event when you ctrl + trackpad
((e as SafariEvent).button === 2 ||
(e as SafariEvent).ctrlKey === true) &&
// Firefox trigger a click event when right click occur
e.type !== 'contextmenu'
) {
)
return;
}

hasExitAnimation(animation)
? setState(state => ({ willLeave: state.visible }))
Expand Down

0 comments on commit 9f06550

Please sign in to comment.