Skip to content

Commit 755abca

Browse files
author
qmorozov
committed
Fix duplicate context menu on right-click in room list item menus
1 parent c31444b commit 755abca

File tree

3 files changed

+100
-72
lines changed

3 files changed

+100
-72
lines changed

src/components/views/rooms/RoomListPanel/RoomListItemMenuView.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,24 @@ function MoreOptionsMenu({ vm, setMenuOpen }: MoreOptionsMenuProps): JSX.Element
7272
const [open, setOpen] = useState(false);
7373

7474
return (
75-
<Menu
76-
open={open}
77-
onOpenChange={(isOpen) => {
78-
setOpen(isOpen);
79-
setMenuOpen(isOpen);
80-
}}
81-
title={_t("room_list|room|more_options")}
82-
showTitle={false}
83-
align="start"
84-
trigger={<MoreOptionsButton size="24px" />}
75+
<div
76+
// Prevent context menu from opening when right-clicking on the menu content
77+
onContextMenu={(e) => e.stopPropagation()}
8578
>
86-
<MoreOptionContent vm={vm} />
87-
</Menu>
79+
<Menu
80+
open={open}
81+
onOpenChange={(isOpen) => {
82+
setOpen(isOpen);
83+
setMenuOpen(isOpen);
84+
}}
85+
title={_t("room_list|room|more_options")}
86+
showTitle={false}
87+
align="start"
88+
trigger={<MoreOptionsButton size="24px" />}
89+
>
90+
<MoreOptionContent vm={vm} />
91+
</Menu>
92+
</div>
8893
);
8994
}
9095

@@ -202,6 +207,8 @@ function NotificationMenu({ vm, setMenuOpen }: NotificationMenuProps): JSX.Eleme
202207
<div
203208
// We don't want keyboard navigation events to bubble up to the ListView changing the focused item
204209
onKeyDown={(e) => e.stopPropagation()}
210+
// Prevent context menu from opening when right-clicking on the menu content
211+
onContextMenu={(e) => e.stopPropagation()}
205212
>
206213
<Menu
207214
open={open}

test/unit-tests/components/views/rooms/RoomListPanel/RoomListItemMenuView-test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,21 @@ describe("<RoomListItemMenuView />", () => {
153153
await user.click(screen.getByRole("menuitem", { name: "Mute room" }));
154154
expect(defaultValue.setRoomNotifState).toHaveBeenCalledWith(RoomNotifState.Mute);
155155
});
156+
157+
it("should prevent context menu event bubbling when right-clicking on open menu", async () => {
158+
const user = userEvent.setup();
159+
const { container } = renderMenu();
160+
161+
await user.click(screen.getByRole("button", { name: "More Options" }));
162+
const menuItem = await screen.findByRole("menuitem", { name: "Mark as read" });
163+
164+
const contextMenuHandler = jest.fn();
165+
container.addEventListener("contextmenu", contextMenuHandler);
166+
167+
const contextMenuEvent = new MouseEvent("contextmenu", { bubbles: true, cancelable: true });
168+
menuItem.dispatchEvent(contextMenuEvent);
169+
170+
expect(contextMenuHandler).not.toHaveBeenCalled();
171+
container.removeEventListener("contextmenu", contextMenuHandler);
172+
});
156173
});

test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListItemMenuView-test.tsx.snap

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,40 @@ exports[`<RoomListItemMenuView /> should render the more options menu 1`] = `
66
class="flex mx_RoomListItemMenuView"
77
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-1x); --mx-flex-wrap: nowrap;"
88
>
9-
<button
10-
aria-disabled="false"
11-
aria-expanded="false"
12-
aria-haspopup="menu"
13-
aria-label="More Options"
14-
aria-labelledby="«r2»"
15-
class="_icon-button_1pz9o_8"
16-
data-kind="primary"
17-
data-state="closed"
18-
id="radix-«r0»"
19-
role="button"
20-
style="--cpd-icon-button-size: 24px;"
21-
tabindex="0"
22-
type="button"
23-
>
24-
<div
25-
class="_indicator-icon_zr2a0_17"
26-
style="--cpd-icon-button-size: 100%;"
9+
<div>
10+
<button
11+
aria-disabled="false"
12+
aria-expanded="false"
13+
aria-haspopup="menu"
14+
aria-label="More Options"
15+
aria-labelledby="«r2»"
16+
class="_icon-button_1pz9o_8"
17+
data-kind="primary"
18+
data-state="closed"
19+
id="radix-«r0»"
20+
role="button"
21+
style="--cpd-icon-button-size: 24px;"
22+
tabindex="0"
23+
type="button"
2724
>
28-
<svg
29-
fill="currentColor"
30-
height="1em"
31-
viewBox="0 0 24 24"
32-
width="1em"
33-
xmlns="http://www.w3.org/2000/svg"
25+
<div
26+
class="_indicator-icon_zr2a0_17"
27+
style="--cpd-icon-button-size: 100%;"
3428
>
35-
<path
36-
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
37-
/>
38-
</svg>
39-
</div>
40-
</button>
29+
<svg
30+
fill="currentColor"
31+
height="1em"
32+
viewBox="0 0 24 24"
33+
width="1em"
34+
xmlns="http://www.w3.org/2000/svg"
35+
>
36+
<path
37+
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
38+
/>
39+
</svg>
40+
</div>
41+
</button>
42+
</div>
4143
<div>
4244
<button
4345
aria-disabled="false"
@@ -85,38 +87,40 @@ exports[`<RoomListItemMenuView /> should render the notification options menu 1`
8587
class="flex mx_RoomListItemMenuView"
8688
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-1x); --mx-flex-wrap: nowrap;"
8789
>
88-
<button
89-
aria-disabled="false"
90-
aria-expanded="false"
91-
aria-haspopup="menu"
92-
aria-label="More Options"
93-
aria-labelledby="«ri»"
94-
class="_icon-button_1pz9o_8"
95-
data-kind="primary"
96-
data-state="closed"
97-
id="radix-«rg»"
98-
role="button"
99-
style="--cpd-icon-button-size: 24px;"
100-
tabindex="0"
101-
type="button"
102-
>
103-
<div
104-
class="_indicator-icon_zr2a0_17"
105-
style="--cpd-icon-button-size: 100%;"
90+
<div>
91+
<button
92+
aria-disabled="false"
93+
aria-expanded="false"
94+
aria-haspopup="menu"
95+
aria-label="More Options"
96+
aria-labelledby="«ri»"
97+
class="_icon-button_1pz9o_8"
98+
data-kind="primary"
99+
data-state="closed"
100+
id="radix-«rg»"
101+
role="button"
102+
style="--cpd-icon-button-size: 24px;"
103+
tabindex="0"
104+
type="button"
106105
>
107-
<svg
108-
fill="currentColor"
109-
height="1em"
110-
viewBox="0 0 24 24"
111-
width="1em"
112-
xmlns="http://www.w3.org/2000/svg"
106+
<div
107+
class="_indicator-icon_zr2a0_17"
108+
style="--cpd-icon-button-size: 100%;"
113109
>
114-
<path
115-
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
116-
/>
117-
</svg>
118-
</div>
119-
</button>
110+
<svg
111+
fill="currentColor"
112+
height="1em"
113+
viewBox="0 0 24 24"
114+
width="1em"
115+
xmlns="http://www.w3.org/2000/svg"
116+
>
117+
<path
118+
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
119+
/>
120+
</svg>
121+
</div>
122+
</button>
123+
</div>
120124
<div>
121125
<button
122126
aria-disabled="false"

0 commit comments

Comments
 (0)