Skip to content

Commit 308d78c

Browse files
committed
fix(context-menu): render menu inline and use viewport coordinates
Signed-off-by: Lars Heinemann <lhein.smx@gmail.com>
1 parent a128910 commit 308d78c

4 files changed

Lines changed: 79 additions & 8 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { ReactNode } from 'react';
2+
import { act, fireEvent, render, screen } from '@testing-library/react';
3+
4+
import { WithContextMenuProps, withContextMenu } from './withContextMenu';
5+
6+
let capturedReference: unknown;
7+
8+
jest.mock('../components/contextmenu/ContextMenu', () => ({
9+
__esModule: true,
10+
default: ({ children, reference }: { children: ReactNode; reference: unknown }) => {
11+
capturedReference = reference;
12+
return <div data-testid="context-menu">{children}</div>;
13+
}
14+
}));
15+
16+
const WrappedComponent = ({ onContextMenu }: WithContextMenuProps) => (
17+
<div data-testid="wrapped-node" onContextMenu={onContextMenu}>
18+
Wrapped node
19+
</div>
20+
);
21+
22+
describe('withContextMenu', () => {
23+
beforeEach(() => {
24+
capturedReference = undefined;
25+
});
26+
27+
it('should use viewport coordinates for point-based context menus', async () => {
28+
const ComponentWithContextMenu = withContextMenu(() => [<div key="action">Action</div>])(WrappedComponent);
29+
30+
render(<ComponentWithContextMenu />);
31+
32+
await act(async () => {
33+
fireEvent.contextMenu(screen.getByTestId('wrapped-node'), {
34+
clientX: 120,
35+
clientY: 140,
36+
pageX: 420,
37+
pageY: 540
38+
});
39+
});
40+
41+
expect(await screen.findByTestId('context-menu')).toBeInTheDocument();
42+
expect(capturedReference).toEqual({ x: 120, y: 140 });
43+
});
44+
});

packages/module/src/behavior/withContextMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export const withContextMenu =
3131
setReference(
3232
atPoint
3333
? {
34-
x: e.pageX,
35-
y: e.pageY
34+
x: e.clientX,
35+
y: e.clientY
3636
}
3737
: e.currentTarget
3838
);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ReactNode } from 'react';
2+
import { fireEvent, render, screen } from '@testing-library/react';
3+
4+
import ContextMenu from './ContextMenu';
5+
import { ContextMenuItem } from './index';
6+
7+
jest.mock('../popper/Popper', () => ({
8+
__esModule: true,
9+
default: ({ children }: { children: ReactNode }) => <div data-testid="mock-popper">{children}</div>
10+
}));
11+
12+
describe('ContextMenu', () => {
13+
it('should render menu items inside the topology popper and close on select', () => {
14+
const onRequestClose = jest.fn();
15+
16+
render(
17+
<ContextMenu reference={{ x: 120, y: 140 }} onRequestClose={onRequestClose}>
18+
<ContextMenuItem>First</ContextMenuItem>
19+
</ContextMenu>
20+
);
21+
22+
expect(screen.getByTestId('mock-popper')).toBeInTheDocument();
23+
24+
const menuItem = screen.getByRole('menuitem', { name: 'First' });
25+
fireEvent.click(menuItem);
26+
27+
expect(onRequestClose).toHaveBeenCalledTimes(1);
28+
});
29+
});

packages/module/src/components/contextmenu/ContextMenu.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useCallback, useEffect } from 'react';
2-
import { Dropdown } from '@patternfly/react-core';
2+
import { Menu, MenuContent } from '@patternfly/react-core';
33
import { css } from '@patternfly/react-styles';
44
import topologyStyles from '../../css/topology-components';
55
// FIXME fully qualified due to the effect of long build times on storybook
@@ -35,14 +35,12 @@ const ContextMenu: React.FunctionComponent<ContextMenuProps> = ({
3535

3636
return (
3737
<Popper {...other} closeOnEsc closeOnOutsideClick open={isOpen} onRequestClose={handleOnRequestClose}>
38-
<Dropdown
38+
<Menu
3939
onSelect={handleOnRequestClose}
40-
toggle={() => <></>}
4140
className={css(topologyStyles.topologyContextMenuCDropdownMenu)}
42-
popperProps={{ appendTo: 'inline' }}
4341
>
44-
{children}
45-
</Dropdown>
42+
<MenuContent>{children}</MenuContent>
43+
</Menu>
4644
</Popper>
4745
);
4846
};

0 commit comments

Comments
 (0)