Room list: fix room options remaining on room item after mouse leaving (#31414)

* refactor(room list): remove extra component button and `setMenuOpen` callback

* fix(room list): replace js focus and hover handling by CSS to fix focus decoration

Closes https://github.com/element-hq/element-web/issues/31365

* test(room list): update jest test

* refactor(room list): remove irrelevant comment

* test(room list): update screenshots
This commit is contained in:
Florian Duros
2025-12-04 12:23:13 +01:00
committed by GitHub
parent 2ab9d345b4
commit 1a7023779c
14 changed files with 1316 additions and 751 deletions

View File

@@ -56,8 +56,8 @@ describe("<RoomListItemMenuView />", () => {
room = mkRoom(matrixClient, "room1");
});
function renderMenu(setMenuOpen = jest.fn()) {
return render(<RoomListItemMenuView room={room} setMenuOpen={setMenuOpen} />);
function renderMenu() {
return render(<RoomListItemMenuView room={room} />);
}
it("should render the more options menu", () => {
@@ -84,18 +84,6 @@ describe("<RoomListItemMenuView />", () => {
expect(screen.queryByRole("button", { name: "Notification options" })).toBeNull();
});
it.each([["More Options"], ["Notification options"]])(
"should call setMenuOpen when the menu is opened for %s menu",
async (label) => {
const user = userEvent.setup();
const setMenuOpen = jest.fn();
renderMenu(setMenuOpen);
await user.click(screen.getByRole("button", { name: label }));
expect(setMenuOpen).toHaveBeenCalledWith(true);
},
);
it("should display all the buttons and have the actions linked for the more options menu", async () => {
const user = userEvent.setup();
renderMenu();

View File

@@ -102,41 +102,6 @@ describe("<RoomListItemView />", () => {
expect(defaultValue.openRoom).toHaveBeenCalled();
});
test("should hover decoration if hovered", async () => {
mocked(useRoomListItemViewModel).mockReturnValue({ ...defaultValue, showHoverMenu: true });
const user = userEvent.setup();
renderRoomListItem();
const listItem = screen.getByRole("option", { name: `Open room ${room.name}` });
expect(screen.queryByRole("button", { name: "More Options" })).toBeNull();
await user.hover(listItem);
await waitFor(() => expect(screen.getByRole("button", { name: "More Options" })).toBeInTheDocument());
});
test("should hover decoration if focused", async () => {
const { rerender } = renderRoomListItem({
isFocused: true,
});
const listItem = screen.getByRole("option", { name: `Open room ${room.name}` });
expect(listItem).toHaveClass("_flex_4dswl_9 mx_RoomListItemView mx_RoomListItemView_hover");
rerender(
<RoomListItemView
room={room}
isSelected={false}
isFocused={false}
onFocus={jest.fn()}
roomIndex={0}
roomCount={1}
/>,
);
await waitFor(() => expect(listItem).not.toHaveClass("flex mx_RoomListItemView mx_RoomListItemView_hover"));
});
test("should be selected if isSelected=true", async () => {
const { asFragment } = renderRoomListItem({
isSelected: true,

View File

@@ -38,43 +38,41 @@ exports[`<RoomListItemMenuView /> should render the more options menu 1`] = `
</svg>
</div>
</button>
<div>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Notification options"
aria-labelledby="_r_9_"
class="_icon-button_1pz9o_8"
data-kind="primary"
data-state="closed"
id="radix-_r_7_"
role="button"
style="--cpd-icon-button-size: 24px;"
tabindex="0"
type="button"
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Notification options"
aria-labelledby="_r_9_"
class="_icon-button_1pz9o_8"
data-kind="primary"
data-state="closed"
id="radix-_r_7_"
role="button"
style="--cpd-icon-button-size: 24px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m4.917 2.083 17 17a1 1 0 0 1-1.414 1.414L19.006 19H4.414c-.89 0-1.337-1.077-.707-1.707L5 16v-6s0-2.034 1.096-3.91L3.504 3.498a1 1 0 0 1 1.414-1.414M19 13.35 9.136 3.484C9.93 3.181 10.874 3 12 3c7 0 7 7 7 7z"
/>
<path
d="M10 20h4a2 2 0 0 1-4 0"
/>
</svg>
</div>
</button>
</div>
<path
d="m4.917 2.083 17 17a1 1 0 0 1-1.414 1.414L19.006 19H4.414c-.89 0-1.337-1.077-.707-1.707L5 16v-6s0-2.034 1.096-3.91L3.504 3.498a1 1 0 0 1 1.414-1.414M19 13.35 9.136 3.484C9.93 3.181 10.874 3 12 3c7 0 7 7 7 7z"
/>
<path
d="M10 20h4a2 2 0 0 1-4 0"
/>
</svg>
</div>
</button>
</div>
</DocumentFragment>
`;
@@ -117,43 +115,41 @@ exports[`<RoomListItemMenuView /> should render the notification options menu 1`
</svg>
</div>
</button>
<div>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Notification options"
aria-labelledby="_r_p_"
class="_icon-button_1pz9o_8"
data-kind="primary"
data-state="closed"
id="radix-_r_n_"
role="button"
style="--cpd-icon-button-size: 24px;"
tabindex="0"
type="button"
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Notification options"
aria-labelledby="_r_p_"
class="_icon-button_1pz9o_8"
data-kind="primary"
data-state="closed"
id="radix-_r_n_"
role="button"
style="--cpd-icon-button-size: 24px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
>
<div
class="_indicator-icon_147l5_17"
style="--cpd-icon-button-size: 100%;"
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m4.917 2.083 17 17a1 1 0 0 1-1.414 1.414L19.006 19H4.414c-.89 0-1.337-1.077-.707-1.707L5 16v-6s0-2.034 1.096-3.91L3.504 3.498a1 1 0 0 1 1.414-1.414M19 13.35 9.136 3.484C9.93 3.181 10.874 3 12 3c7 0 7 7 7 7z"
/>
<path
d="M10 20h4a2 2 0 0 1-4 0"
/>
</svg>
</div>
</button>
</div>
<path
d="m4.917 2.083 17 17a1 1 0 0 1-1.414 1.414L19.006 19H4.414c-.89 0-1.337-1.077-.707-1.707L5 16v-6s0-2.034 1.096-3.91L3.504 3.498a1 1 0 0 1 1.414-1.414M19 13.35 9.136 3.484C9.93 3.181 10.874 3 12 3c7 0 7 7 7 7z"
/>
<path
d="M10 20h4a2 2 0 0 1-4 0"
/>
</svg>
</div>
</button>
</div>
</DocumentFragment>
`;

View File

@@ -99,7 +99,7 @@ exports[`<RoomListItemView /> should display notification decoration 1`] = `
</div>
<div
aria-hidden="true"
class="_flex_4dswl_9"
class="_flex_4dswl_9 mx_RoomListItemView_notificationDecoration"
data-testid="notification-decoration"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: center; --mx-flex-gap: var(--cpd-space-1x); --mx-flex-wrap: nowrap;"
>