Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.

Commit 34d1875

Browse files
authored
Open room settings on room header avatar click (#88)
* Open room settings on room header avatar click Signed-off-by: Michael Telatynski <[email protected]> * Fix nested interactive elements aria fail Signed-off-by: Michael Telatynski <[email protected]> * Update things for a11y and update snapshots Signed-off-by: Michael Telatynski <[email protected]> * Fix tests Signed-off-by: Michael Telatynski <[email protected]> * Iterate tests Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]>
1 parent 3f67819 commit 34d1875

File tree

12 files changed

+103
-58
lines changed

12 files changed

+103
-58
lines changed

playwright/e2e/room/room-header.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ test.describe("Room Header", () => {
4545
await expect(header.getByRole("button", { name: "Threads" })).toBeVisible();
4646
await expect(header.getByRole("button", { name: "Notifications" })).toBeVisible();
4747

48-
// Assert that there are six buttons in total
49-
await expect(header.getByRole("button")).toHaveCount(7);
48+
// Assert that there are eight buttons in total
49+
await expect(header.getByRole("button")).toHaveCount(8);
5050

5151
await expect(header).toMatchScreenshot("room-header.png");
5252
});
@@ -119,7 +119,7 @@ test.describe("Room Header", () => {
119119
await expect(header.getByRole("button", { name: "Notifications" })).toBeVisible();
120120

121121
// Assert that there is not a button except those buttons
122-
await expect(header.getByRole("button")).toHaveCount(6);
122+
await expect(header.getByRole("button")).toHaveCount(7);
123123

124124
await expect(header).toMatchScreenshot("room-header-video-room.png");
125125
});

playwright/element-web-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ export const expect = baseExpect.extend({
345345

346346
if (!options?.showTooltips) {
347347
css += `
348+
[role="tooltip"],
348349
.mx_Tooltip_visible {
349350
visibility: hidden !important;
350351
}
Loading
Loading
Loading

res/css/views/rooms/_RoomHeader.pcss

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
99
.mx_RoomHeader {
1010
height: 64px;
1111
box-sizing: border-box;
12-
padding: 0 var(--cpd-space-3x);
12+
padding: 0 var(--cpd-space-3x) 0 calc(var(--cpd-space-3x) + var(--cpd-space-1-5x));
1313
border-bottom: 1px solid $separator;
1414
background-color: $background;
1515
transition: all 0.2s ease;
@@ -31,6 +31,8 @@ Please see LICENSE files in the repository root for full details.
3131
cursor: pointer;
3232
gap: var(--cpd-space-3x);
3333
text-align: left;
34+
height: 100%;
35+
padding: 0;
3436
}
3537

3638
.mx_RoomHeader_info {

src/components/views/avatars/BaseAvatar.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
99
Please see LICENSE files in the repository root for full details.
1010
*/
1111

12-
import React, { forwardRef, useCallback, useContext, useEffect, useState } from "react";
12+
import React, { AriaRole, forwardRef, useCallback, useContext, useEffect, useState } from "react";
1313
import classNames from "classnames";
1414
import { ClientEvent, SyncState } from "matrix-js-sdk/src/matrix";
1515
import { Avatar } from "@vector-im/compound-web";
@@ -33,6 +33,7 @@ interface IProps {
3333
className?: string;
3434
tabIndex?: number;
3535
altText?: string;
36+
role?: AriaRole;
3637
}
3738

3839
const calculateUrls = (url?: string | null, urls?: string[], lowBandwidth = false): string[] => {

src/components/views/rooms/RoomHeader.tsx

+20-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ import WithPresenceIndicator, { useDmMember } from "../avatars/WithPresenceIndic
5050
import { IOOBData } from "../../../stores/ThreepidInviteStore";
5151
import RoomContext from "../../../contexts/RoomContext";
5252
import { MainSplitContentType } from "../../structures/RoomView";
53+
import defaultDispatcher from "../../../dispatcher/dispatcher.ts";
54+
import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog.tsx";
5355

5456
export default function RoomHeader({
5557
room,
@@ -229,18 +231,33 @@ export default function RoomHeader({
229231
roomContext.mainSplitContentType === MainSplitContentType.MaximisedWidget ||
230232
roomContext.mainSplitContentType === MainSplitContentType.Call;
231233

234+
const onAvatarClick = (): void => {
235+
defaultDispatcher.dispatch({
236+
action: "open_room_settings",
237+
initial_tab_id: RoomSettingsTab.General,
238+
});
239+
};
240+
232241
return (
233242
<>
234243
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
244+
<WithPresenceIndicator room={room} size="8px">
245+
{/* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */}
246+
<RoomAvatar
247+
room={room}
248+
size="40px"
249+
oobData={oobData}
250+
onClick={onAvatarClick}
251+
tabIndex={-1}
252+
aria-label={_t("room|header_avatar_open_settings_label")}
253+
/>
254+
</WithPresenceIndicator>
235255
<button
236256
aria-label={_t("right_panel|room_summary_card|title")}
237257
tabIndex={0}
238258
onClick={() => RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomSummary)}
239259
className="mx_RoomHeader_infoWrapper"
240260
>
241-
<WithPresenceIndicator room={room} size="8px">
242-
<RoomAvatar room={room} size="40px" oobData={oobData} />
243-
</WithPresenceIndicator>
244261
<Box flex="1" className="mx_RoomHeader_info">
245262
<BodyText
246263
as="div"

src/i18n/strings/en_EN.json

+1
Original file line numberDiff line numberDiff line change
@@ -1983,6 +1983,7 @@
19831983
"video_call_ec_layout_spotlight": "Spotlight",
19841984
"video_room_view_chat_button": "View chat timeline"
19851985
},
1986+
"header_avatar_open_settings_label": "Open room settings",
19861987
"header_face_pile_tooltip": "People",
19871988
"header_untrusted_label": "Untrusted",
19881989
"inaccessible": "This room or space is not accessible at this time.",

test/components/structures/__snapshots__/RoomView-test.tsx.snap

+52-40
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,24 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1
99
class="mx_Flex mx_RoomHeader light-panel"
1010
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
1111
>
12+
<button
13+
aria-label="Open room settings"
14+
aria-live="off"
15+
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
16+
data-color="3"
17+
data-testid="avatar-img"
18+
data-type="round"
19+
role="button"
20+
style="--cpd-avatar-size: 40px;"
21+
tabindex="-1"
22+
>
23+
u
24+
</button>
1225
<button
1326
aria-label="Room info"
1427
class="mx_RoomHeader_infoWrapper"
1528
tabindex="0"
1629
>
17-
<span
18-
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
19-
data-color="3"
20-
data-testid="avatar-img"
21-
data-type="round"
22-
role="presentation"
23-
style="--cpd-avatar-size: 40px;"
24-
>
25-
u
26-
</span>
2730
<div
2831
class="mx_Box mx_RoomHeader_info mx_Box--flex"
2932
style="--mx-box-flex: 1;"
@@ -179,21 +182,24 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
179182
class="mx_Flex mx_RoomHeader light-panel"
180183
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
181184
>
185+
<button
186+
aria-label="Open room settings"
187+
aria-live="off"
188+
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
189+
data-color="3"
190+
data-testid="avatar-img"
191+
data-type="round"
192+
role="button"
193+
style="--cpd-avatar-size: 40px;"
194+
tabindex="-1"
195+
>
196+
u
197+
</button>
182198
<button
183199
aria-label="Room info"
184200
class="mx_RoomHeader_infoWrapper"
185201
tabindex="0"
186202
>
187-
<span
188-
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
189-
data-color="3"
190-
data-testid="avatar-img"
191-
data-type="round"
192-
role="presentation"
193-
style="--cpd-avatar-size: 40px;"
194-
>
195-
u
196-
</span>
197203
<div
198204
class="mx_Box mx_RoomHeader_info mx_Box--flex"
199205
style="--mx-box-flex: 1;"
@@ -434,21 +440,24 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
434440
class="mx_Flex mx_RoomHeader light-panel"
435441
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
436442
>
443+
<button
444+
aria-label="Open room settings"
445+
aria-live="off"
446+
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
447+
data-color="3"
448+
data-testid="avatar-img"
449+
data-type="round"
450+
role="button"
451+
style="--cpd-avatar-size: 40px;"
452+
tabindex="-1"
453+
>
454+
u
455+
</button>
437456
<button
438457
aria-label="Room info"
439458
class="mx_RoomHeader_infoWrapper"
440459
tabindex="0"
441460
>
442-
<span
443-
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
444-
data-color="3"
445-
data-testid="avatar-img"
446-
data-type="round"
447-
role="presentation"
448-
style="--cpd-avatar-size: 40px;"
449-
>
450-
u
451-
</span>
452461
<div
453462
class="mx_Box mx_RoomHeader_info mx_Box--flex"
454463
style="--mx-box-flex: 1;"
@@ -766,21 +775,24 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
766775
class="mx_Flex mx_RoomHeader light-panel"
767776
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
768777
>
778+
<button
779+
aria-label="Open room settings"
780+
aria-live="off"
781+
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
782+
data-color="3"
783+
data-testid="avatar-img"
784+
data-type="round"
785+
role="button"
786+
style="--cpd-avatar-size: 40px;"
787+
tabindex="-1"
788+
>
789+
u
790+
</button>
769791
<button
770792
aria-label="Room info"
771793
class="mx_RoomHeader_infoWrapper"
772794
tabindex="0"
773795
>
774-
<span
775-
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
776-
data-color="3"
777-
data-testid="avatar-img"
778-
data-type="round"
779-
role="presentation"
780-
style="--cpd-avatar-size: 40px;"
781-
>
782-
u
783-
</span>
784796
<div
785797
class="mx_Box mx_RoomHeader_info mx_Box--flex"
786798
style="--mx-box-flex: 1;"

test/components/views/rooms/RoomHeader-test.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,14 @@ describe("RoomHeader", () => {
683683
expect(screen.getByRole("heading", { name: "Asking to join" })).toBeInTheDocument();
684684
});
685685
});
686+
687+
it("should open room settings when clicking the room avatar", async () => {
688+
const { container } = render(<RoomHeader room={room} />, getWrapper());
689+
690+
const dispatcherSpy = jest.spyOn(dispatcher, "dispatch");
691+
fireEvent.click(getByLabelText(container, "Open room settings"));
692+
expect(dispatcherSpy).toHaveBeenCalledWith(expect.objectContaining({ action: "open_room_settings" }));
693+
});
686694
});
687695

688696
/**

test/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap

+13-10
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
66
class="mx_Flex mx_RoomHeader light-panel"
77
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x);"
88
>
9+
<button
10+
aria-label="Open room settings"
11+
aria-live="off"
12+
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
13+
data-color="3"
14+
data-testid="avatar-img"
15+
data-type="round"
16+
role="button"
17+
style="--cpd-avatar-size: 40px;"
18+
tabindex="-1"
19+
>
20+
!
21+
</button>
922
<button
1023
aria-label="Room info"
1124
class="mx_RoomHeader_infoWrapper"
1225
tabindex="0"
1326
>
14-
<span
15-
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
16-
data-color="3"
17-
data-testid="avatar-img"
18-
data-type="round"
19-
role="presentation"
20-
style="--cpd-avatar-size: 40px;"
21-
>
22-
!
23-
</span>
2427
<div
2528
class="mx_Box mx_RoomHeader_info mx_Box--flex"
2629
style="--mx-box-flex: 1;"

0 commit comments

Comments
 (0)