Add secondary filters to the new room list (#29818)

* Secondary filters

* Update snapshots

* Fix imports

* Update screenshots

* Add unit test

* Imports

* Prettier

* Add playwright test
This commit is contained in:
David Baker
2025-04-30 10:12:56 +01:00
committed by GitHub
parent cd05838bf6
commit 4f4f391959
15 changed files with 616 additions and 13 deletions

View File

@@ -6,7 +6,7 @@
*/
import { expect, test } from "../../../element-web-test";
import type { Page } from "@playwright/test";
import type { Locator, Page } from "@playwright/test";
test.describe("Room list filters and sort", () => {
test.use({
@@ -18,10 +18,14 @@ test.describe("Room list filters and sort", () => {
labsFlags: ["feature_new_room_list"],
});
function getPrimaryFilters(page: Page) {
function getPrimaryFilters(page: Page): Locator {
return page.getByRole("listbox", { name: "Room list filters" });
}
function getSecondaryFilters(page: Page): Locator {
return page.getByRole("button", { name: "Filter" });
}
/**
* Get the room list
* @param page
@@ -106,6 +110,11 @@ test.describe("Room list filters and sort", () => {
await app.client.evaluate(async (client, favouriteId) => {
await client.setRoomTag(favouriteId, "m.favourite", { order: 0.5 });
}, favouriteId);
const lowPrioId = await app.client.createRoom({ name: "Low prio room" });
await app.client.evaluate(async (client, id) => {
await client.setRoomTag(id, "m.lowpriority", { order: 0.5 });
}, lowPrioId);
});
test("should filter the list (with primary filters)", { tag: "@screenshot" }, async ({ page, app, user }) => {
@@ -137,7 +146,19 @@ test.describe("Room list filters and sort", () => {
await expect(roomList.getByRole("gridcell", { name: "unread room" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "empty room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(3);
expect(await roomList.locator("role=gridcell").count()).toBe(4);
});
test("should filter the list (with secondary filters)", { tag: "@screenshot" }, async ({ page, app, user }) => {
const roomList = getRoomList(page);
const secondaryFilters = getSecondaryFilters(page);
await secondaryFilters.click();
await expect(page.getByRole("menu", { name: "Filter" })).toMatchScreenshot("filter-menu.png");
await page.getByRole("menuitem", { name: "Low priority" }).click();
await expect(roomList.getByRole("gridcell", { name: "Low prio room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
});
test(

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
import React, { type Ref, type JSX, useState } from "react";
import {
ArrowDownIcon,
ChatIcon,
ChatNewIcon,
CheckIcon,
FilterIcon,
MentionIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../../languageHandler";
import { type RoomListViewState } from "../../../viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../viewmodels/roomlist/useFilteredRooms";
import { textForSecondaryFilter } from "./textForFilter";
interface MenuTriggerProps extends React.ComponentProps<typeof IconButton> {
ref?: Ref<HTMLButtonElement>;
}
const MenuTrigger = ({ ref, ...props }: MenuTriggerProps): JSX.Element => (
<Tooltip label={_t("room_list|filter")}>
<IconButton size="28px" aria-label={_t("room_list|filter")} {...props} ref={ref}>
<FilterIcon />
</IconButton>
</Tooltip>
);
interface FilterOptionProps {
/**
* The filter to display
*/
filter: SecondaryFilters;
/**
* True if the filter is selected
*/
selected: boolean;
/**
* The function to call when the filter is selected
*/
onSelect: (filter: SecondaryFilters) => void;
}
function iconForFilter(filter: SecondaryFilters, size: string): JSX.Element {
switch (filter) {
case SecondaryFilters.AllActivity:
return <ChatIcon width={size} height={size} />;
case SecondaryFilters.MentionsOnly:
return <MentionIcon width={size} height={size} />;
case SecondaryFilters.InvitesOnly:
return <ChatNewIcon width={size} height={size} />;
case SecondaryFilters.LowPriority:
return <ArrowDownIcon width={size} height={size} />;
}
}
function FilterOption({ filter, selected, onSelect }: FilterOptionProps): JSX.Element {
const checkComponent = <CheckIcon width="24px" height="24px" color="var(--cpd-color-icon-primary)" />;
return (
<MenuItem
aria-selected={selected}
hideChevron={true}
Icon={iconForFilter(filter, "20px")}
label={textForSecondaryFilter(filter)}
onSelect={() => {
onSelect(filter);
}}
>
{selected && checkComponent}
</MenuItem>
);
}
interface Props {
/**
* The view model for the room list view
*/
vm: RoomListViewState;
}
export function RoomListFilterMenu({ vm }: Props): JSX.Element {
const [open, setOpen] = useState(false);
return (
<Menu
open={open}
onOpenChange={setOpen}
title={_t("room_list|filter")}
showTitle={true}
align="start"
trigger={<MenuTrigger />}
>
{[
SecondaryFilters.AllActivity,
SecondaryFilters.MentionsOnly,
SecondaryFilters.InvitesOnly,
SecondaryFilters.LowPriority,
].map((filter) => (
<FilterOption
key={filter}
filter={filter}
selected={vm.activeSecondaryFilter === filter}
onSelect={(selectedFilter) => {
vm.activateSecondaryFilter(selectedFilter);
setOpen(false);
}}
/>
))}
</Menu>
);
}

View File

@@ -11,6 +11,8 @@ import type { RoomListViewState } from "../../../viewmodels/roomlist/RoomListVie
import { Flex } from "../../../utils/Flex";
import { _t } from "../../../../languageHandler";
import { RoomListOptionsMenu } from "./RoomListOptionsMenu";
import { RoomListFilterMenu } from "./RoomListFilterMenu";
import { textForSecondaryFilter } from "./textForFilter";
interface Props {
/**
@@ -23,13 +25,17 @@ interface Props {
* The secondary filters for the room list (eg. mentions only / invites only).
*/
export function RoomListSecondaryFilters({ vm }: Props): JSX.Element {
const activeFilterText = textForSecondaryFilter(vm.activeSecondaryFilter);
return (
<Flex
aria-label={_t("room_list|secondary_filters")}
className="mx_RoomListSecondaryFilters"
align="center"
gap="8px"
gap="4px"
>
<RoomListFilterMenu vm={vm} />
{activeFilterText}
<RoomListOptionsMenu vm={vm} />
</Flex>
);

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { _t } from "../../../../languageHandler";
import { SecondaryFilters } from "../../../viewmodels/roomlist/useFilteredRooms";
/**
* Gives the human readable text name for a secondary filter.
* @param filter The filter in question
* @returns The translated, human readable name for the filter
*/
export function textForSecondaryFilter(filter: SecondaryFilters): string {
switch (filter) {
case SecondaryFilters.AllActivity:
return _t("room_list|secondary_filter|all_activity");
case SecondaryFilters.MentionsOnly:
return _t("room_list|secondary_filter|mentions_only");
case SecondaryFilters.InvitesOnly:
return _t("room_list|secondary_filter|invites_only");
case SecondaryFilters.LowPriority:
return _t("room_list|secondary_filter|low_priority");
default:
throw new Error("Unknown filter");
}
}

View File

@@ -2121,6 +2121,7 @@
"failed_add_tag": "Failed to add tag %(tagName)s to room",
"failed_remove_tag": "Failed to remove tag %(tagName)s from room",
"failed_set_dm_tag": "Failed to set direct message tag",
"filter": "Filter",
"filters": {
"favourite": "Favourites",
"people": "People",
@@ -2154,6 +2155,12 @@
"open_room": "Open room %(roomName)s"
},
"room_options": "Room Options",
"secondary_filter": {
"all_activity": "All activity",
"invites_only": "Invites only",
"low_priority": "Low priority",
"mentions_only": "Mentions only"
},
"secondary_filters": "Secondary filters",
"show_less": "Show less",
"show_message_previews": "Show message previews",

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { render, type RenderOptions, screen } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { TooltipProvider } from "@vector-im/compound-web";
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { SortOption } from "../../../../../../src/components/viewmodels/roomlist/useSorter";
import { RoomListFilterMenu } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListFilterMenu";
function getRenderOptions(): RenderOptions {
return {
wrapper: ({ children }) => <TooltipProvider>{children}</TooltipProvider>,
};
}
describe("<RoomListFilterMenu />", () => {
let vm: RoomListViewState;
beforeEach(() => {
vm = {
rooms: [],
canCreateRoom: true,
createRoom: jest.fn(),
createChatRoom: jest.fn(),
primaryFilters: [],
activateSecondaryFilter: () => {},
activeSecondaryFilter: SecondaryFilters.AllActivity,
sort: jest.fn(),
activeSortOption: SortOption.Activity,
shouldShowMessagePreview: false,
toggleMessagePreview: jest.fn(),
activeIndex: undefined,
};
});
it("should render room list filter menu button", async () => {
const { asFragment } = render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
expect(screen.getByRole("button", { name: "Filter" })).toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
});
it("opens the menu on click", async () => {
const userevent = userEvent.setup();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
expect(screen.getByRole("menu", { name: "Filter" })).toBeInTheDocument();
});
it("shows 'All activity' checked if selected", async () => {
const userevent = userEvent.setup();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "All activity" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Invites only' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.InvitesOnly;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Invites only" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Low priority' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.LowPriority;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Low priority" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Mentions only' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.MentionsOnly;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Mentions only" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("activates filter when item clicked", async () => {
const userevent = userEvent.setup();
vm.activateSecondaryFilter = jest.fn();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
await userevent.click(screen.getByRole("menuitem", { name: "Invites only" }));
expect(vm.activateSecondaryFilter).toHaveBeenCalledWith(SecondaryFilters.InvitesOnly);
});
});

View File

@@ -0,0 +1,208 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RoomListFilterMenu /> should render room list filter menu button 1`] = `
<DocumentFragment>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Filter"
aria-labelledby="«r2»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«r0»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_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"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
</DocumentFragment>
`;
exports[`<RoomListFilterMenu /> shows 'All activity' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m1.5 21.25 1.45-4.95a10.2 10.2 0 0 1-.712-2.1A10.2 10.2 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22q-1.125 0-2.2-.238a10.2 10.2 0 0 1-2.1-.712L2.75 22.5a.94.94 0 0 1-1-.25.94.94 0 0 1-.25-1m2.45-1.2 3.2-.95a1 1 0 0 1 .275-.062q.15-.013.275-.013.225 0 .438.038.212.036.412.137a7.4 7.4 0 0 0 1.675.6Q11.1 20 12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12q0 .9.2 1.775t.6 1.675q.176.325.188.688t-.088.712z"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
All activity
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Invites only' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 6h-2a.97.97 0 0 1-.712-.287A.97.97 0 0 1 16 5q0-.424.288-.713A.97.97 0 0 1 17 4h2V2q0-.424.288-.712A.97.97 0 0 1 20 1q.424 0 .712.288Q21 1.575 21 2v2h2q.424 0 .712.287Q24 4.576 24 5t-.288.713A.97.97 0 0 1 23 6h-2v2q0 .424-.288.713A.97.97 0 0 1 20 9a.97.97 0 0 1-.712-.287A.97.97 0 0 1 19 8z"
/>
<path
d="M22 17v-6.341A6 6 0 0 1 20 11v6H6a2 2 0 0 0-1.414.586L4 18.172V5h10c0-.701.12-1.374.341-2H4a2 2 0 0 0-2 2v15.586c0 .89 1.077 1.337 1.707.707L6 19h14a2 2 0 0 0 2-2"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Invites only
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Low priority' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4.5a1 1 0 0 1 1 1v10.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-6 6a1 1 0 0 1-1.414 0l-6-6a1 1 0 1 1 1.414-1.414L11 16.086V5.5a1 1 0 0 1 1-1"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Low priority
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Mentions only' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4a8 8 0 1 0 0 16 1 1 0 1 1 0 2C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10v1.5a3.5 3.5 0 0 1-6.396 1.966A5 5 0 1 1 17 12v1.5a1.5 1.5 0 0 0 3 0V12a8 8 0 0 0-8-8m3 8a3 3 0 1 0-6 0 3 3 0 0 0 6 0"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Mentions only
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;

View File

@@ -116,17 +116,49 @@ exports[`<RoomListPanel /> should not render the RoomListSearch component when U
<div
aria-label="Secondary filters"
class="mx_Flex mx_RoomListSecondaryFilters"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 8px; --mx-flex-wrap: nowrap;"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 4px; --mx-flex-wrap: nowrap;"
>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Filter"
aria-labelledby="«rk»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«ri»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_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"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
All activity
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-labelledby="«rc»"
aria-labelledby="«rr»"
class="_icon-button_m2erp_8 mx_RoomListSecondaryFilters_roomOptionsButton"
data-state="closed"
id="radix-«ra»"
id="radix-«rp»"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
@@ -374,18 +406,50 @@ exports[`<RoomListPanel /> should render the RoomListSearch component when UICom
<div
aria-label="Secondary filters"
class="mx_Flex mx_RoomListSecondaryFilters"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 8px; --mx-flex-wrap: nowrap;"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 4px; --mx-flex-wrap: nowrap;"
>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-label="Filter"
aria-labelledby="«r4»"
class="_icon-button_m2erp_8 mx_RoomListSecondaryFilters_roomOptionsButton"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«r2»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_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"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
All activity
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-labelledby="«rb»"
class="_icon-button_m2erp_8 mx_RoomListSecondaryFilters_roomOptionsButton"
data-state="closed"
id="radix-«r9»"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
type="button"

View File

@@ -5,18 +5,50 @@ exports[`<RoomListSecondaryFilters /> should render 'room options' button 1`] =
<div
aria-label="Secondary filters"
class="mx_Flex mx_RoomListSecondaryFilters"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 8px; --mx-flex-wrap: nowrap;"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 4px; --mx-flex-wrap: nowrap;"
>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-label="Filter"
aria-labelledby="«r2»"
class="_icon-button_m2erp_8 mx_RoomListSecondaryFilters_roomOptionsButton"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«r0»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_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"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
All activity
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-labelledby="«r9»"
class="_icon-button_m2erp_8 mx_RoomListSecondaryFilters_roomOptionsButton"
data-state="closed"
id="radix-«r7»"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
type="button"