Update the way we render icons for accessibility (#31731)

* Switch to Compound icons to replace old icons

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Apply same treatment to missed icons

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove duplicated icon

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update icon

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in ImageView

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in ExtensionsCard

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in LegacyRoomListHeader

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in ImageSizePanel

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in LegacyRoomList

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove icon from CreateSecretStorageDialog title

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in LiveContentSummary

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in RoomCallBanner

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in NonUrgentEchoFailureToast

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in LegacyCallViewHeader

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Switch from css masks to rendering svg in CallEvent

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Delint

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update screenshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Replace dark-light-mode.svg with Compound

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Draw stop icon using svg rather than square mask

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Replace masks in RoomSublist with SVG icons

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Replace masks with SVG icons in LegacyCall views

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Replace masks with SVG icons in EventTile

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Replace masks with SVG icons in ForwardDialog

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove redundant css style

The `::before` has no content so is never rendered

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* delint

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update playwright tests & screenshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshot

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove snapshot as it causes issues

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Delint

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* More tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2026-01-16 11:21:57 +00:00 committed by GitHub
parent 28464b4d12
commit 466f60ead5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 347 additions and 281 deletions

View File

@ -92,7 +92,7 @@
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^10.0.0",
"@types/png-chunks-extract": "^1.0.2",
"@vector-im/compound-design-tokens": "6.6.0",
"@vector-im/compound-design-tokens": "6.8.0",
"@vector-im/compound-web": "^8.3.4",
"@vector-im/matrix-wysiwyg": "2.40.0",
"@zxcvbn-ts/core": "^3.0.4",

View File

@ -36,7 +36,9 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
// Wait until the file is sent
await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
"Your message was sent",
);
// wait for the tile to finish loading
await expect(
page

View File

@ -106,8 +106,8 @@ test.describe("Key backup reset from elsewhere", () => {
// Should be the message we sent plus the room creation event
await expect(page.locator(".mx_EventTile")).toHaveCount(2);
await expect(
page.locator(".mx_RoomView_MessageList > .mx_EventTile_last .mx_EventTile_receiptSent"),
).toBeVisible();
page.locator(".mx_RoomView_MessageList > .mx_EventTile_last").getByRole("status"),
).toHaveAccessibleName("Your message was sent");
// Wait for it to try uploading the key
await page.clock.fastForward(20000);

View File

@ -12,12 +12,16 @@ import { type Locator, type Page } from "@playwright/test";
import { test, expect } from "../../element-web-test";
async function waitForMessageSentStatus(msgTile: Locator): Promise<void> {
await expect(msgTile.getByRole("status")).toHaveAccessibleName("Your message was sent");
}
async function sendMessage(page: Page, message: string): Promise<Locator> {
await page.getByRole("textbox", { name: "Send an unencrypted message…" }).fill(message);
await page.getByRole("button", { name: "Send message" }).click();
const msgTile = page.locator(".mx_EventTile_last");
await msgTile.locator(".mx_EventTile_receiptSent").waitFor();
await waitForMessageSentStatus(msgTile);
return msgTile;
}
@ -31,7 +35,7 @@ async function sendMultilineMessages(page: Page, messages: string[]) {
await page.getByRole("button", { name: "Send message" }).click();
const msgTile = page.locator(".mx_EventTile_last");
await msgTile.locator(".mx_EventTile_receiptSent").waitFor();
await waitForMessageSentStatus(msgTile);
return msgTile;
}
@ -44,7 +48,7 @@ async function replyMessage(page: Page, message: Locator, replyMessage: string):
await page.getByRole("button", { name: "Send message" }).click();
const msgTile = page.locator(".mx_EventTile_last");
await msgTile.locator(".mx_EventTile_receiptSent").waitFor();
await waitForMessageSentStatus(msgTile);
return msgTile;
}

View File

@ -23,7 +23,9 @@ async function uploadFile(page: Page, file: string) {
// Wait until the file is sent
await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
"Your message was sent",
);
}
test.describe("FilePanel", () => {

View File

@ -410,7 +410,9 @@ test.describe("Threads", () => {
await textbox.fill("Please come here");
await textbox.press("Enter");
// Wait until the reply is sent
await expect(locator.locator(".mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible();
await expect(locator.locator(".mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
"Your message was sent",
);
// Take a snapshot of reply to the shared location
await page.addStyleTag({ content: css });

View File

@ -385,8 +385,8 @@ test.describe("Timeline", () => {
// Make sure the second message was sent
await expect(
page.locator(".mx_RoomView_MessageList > .mx_EventTile_last .mx_EventTile_receiptSent"),
).toBeVisible();
page.locator(".mx_RoomView_MessageList > .mx_EventTile_last").getByRole("status"),
).toHaveAccessibleName("Your message was sent");
// 1. Alignment of collapsed GELS (generic event list summary) and messages
// Check inline start spacing of collapsed GELS
@ -468,8 +468,8 @@ test.describe("Timeline", () => {
page.locator(".mx_GenericEventListSummary .mx_EventTile_last .mx_RedactedBody"),
).toBeVisible();
await expect(
page.locator(".mx_GenericEventListSummary .mx_EventTile_last .mx_EventTile_receiptSent"),
).toBeVisible();
page.locator(".mx_GenericEventListSummary .mx_EventTile_last").getByRole("status"),
).toHaveAccessibleName("Your message was sent");
// Record alignment of expanded GELS and placeholder of deleted message on messagePanel
await expect(page.locator(".mx_MainSplit")).toMatchScreenshot(
"expanded-gels-redaction-placeholder.png",
@ -502,8 +502,8 @@ test.describe("Timeline", () => {
await expect(page.locator(".mx_EventTile_emote .mx_EventTile_avatar")).toHaveCSS("margin-left", "99px");
// Make sure emote was sent
await expect(
page.locator(".mx_EventTile_last.mx_EventTile_emote .mx_EventTile_receiptSent"),
).toBeVisible();
page.locator(".mx_EventTile_last.mx_EventTile_emote").getByRole("status"),
).toHaveAccessibleName("Your message was sent");
// Record alignment of expanded GELS, placeholder of deleted message, and emote
await expect(page.locator(".mx_MainSplit")).toMatchScreenshot("expanded-gels-emote-irc-layout.png", {
// Exclude timestamp from snapshot of mx_MainSplit
@ -772,7 +772,9 @@ test.describe("Timeline", () => {
// Wait until the file is sent
await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible();
await expect(page.locator(".mx_EventTile.mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
"Your message was sent",
);
// Assert that the file size is displayed in kibibytes (1024 bytes), not kilobytes (1000 bytes)
// See: https://github.com/vector-im/element-web/issues/24866
@ -1151,7 +1153,9 @@ test.describe("Timeline", () => {
// Assert that 'reply2' was sent
await expect(page.locator(".mx_RoomView_body .mx_EventTile_last").getByText(reply2)).toBeVisible();
await expect(page.locator(".mx_EventTile_last .mx_EventTile_receiptSent")).toBeVisible();
await expect(page.locator(".mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
"Your message was sent",
);
// Exclude timestamp and read marker from snapshot
const screenshotOptions = {
@ -1301,7 +1305,7 @@ test.describe("Timeline", () => {
await expect(page.locator(".mx_NewRoomIntro .mx_BaseAvatar")).toBeVisible();
const lastEventTileIrc = page.locator(".mx_EventTile_last[data-layout='irc']");
await expect(lastEventTileIrc.locator(".mx_MTextBody").first()).toBeVisible();
await expect(lastEventTileIrc.locator(".mx_EventTile_receiptSent")).toBeVisible(); // rendered at the bottom of EventTile
await expect(lastEventTileIrc.getByRole("status")).toHaveAccessibleName("Your message was sent"); // rendered at the bottom of EventTile
// Take a snapshot in IRC layout
await expect(page.locator(".mx_ScrollPanel")).toMatchScreenshot(
"long-strings-with-reply-irc-layout.png",
@ -1314,7 +1318,7 @@ test.describe("Timeline", () => {
await expect(page.locator(".mx_NewRoomIntro .mx_BaseAvatar")).toBeVisible();
const lastEventTileGroup = page.locator(".mx_EventTile_last[data-layout='group']");
await expect(lastEventTileGroup.locator(".mx_MTextBody").first()).toBeVisible();
await expect(lastEventTileGroup.locator(".mx_EventTile_receiptSent")).toBeVisible();
await expect(lastEventTileGroup.getByRole("status")).toHaveAccessibleName("Your message was sent");
await expect(page.locator(".mx_ScrollPanel")).toMatchScreenshot(
"long-strings-with-reply-modern-layout.png",
screenshotOptions,
@ -1326,7 +1330,7 @@ test.describe("Timeline", () => {
await expect(page.locator(".mx_NewRoomIntro .mx_BaseAvatar")).toBeVisible();
const lastEventTileBubble = page.locator(".mx_EventTile_last[data-layout='bubble']");
await expect(lastEventTileBubble.locator(".mx_MTextBody").first()).toBeVisible();
await expect(lastEventTileBubble.locator(".mx_EventTile_receiptSent")).toBeVisible();
await expect(lastEventTileBubble.getByRole("status")).toHaveAccessibleName("Your message was sent");
await expect(page.locator(".mx_ScrollPanel")).toMatchScreenshot(
"long-strings-with-reply-bubble-layout.png",
screenshotOptions,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -134,35 +134,17 @@ Please see LICENSE files in the repository root for full details.
visibility: hidden;
}
.mx_ForwardList_sendIcon,
.mx_NotificationBadge {
& > svg {
position: absolute;
width: 14px;
height: 14px;
color: $accent;
}
.mx_NotificationBadge {
/* Match the failed to send indicator's color with the disabled button */
background-color: $button-danger-disabled-fg-color;
}
&.mx_ForwardList_sending .mx_ForwardList_sendIcon {
background-color: $accent;
mask-image: url("@vector-im/compound-design-tokens/icons/circle.svg");
mask-position: center;
mask-repeat: no-repeat;
mask-size: 14px;
width: 14px;
height: 14px;
}
&.mx_ForwardList_sent .mx_ForwardList_sendIcon {
background-color: $accent;
mask-image: url("@vector-im/compound-design-tokens/icons/check-circle.svg");
mask-position: center;
mask-repeat: no-repeat;
mask-size: 14px;
width: 14px;
height: 14px;
}
}
}
}

View File

@ -13,11 +13,3 @@ Please see LICENSE files in the repository root for full details.
margin: 0 auto;
padding-right: 80px;
}
/* show a different AvatarSetting placeholder for RoomProfileSettings which is basically a clone of ProfileSettings */
.mx_RoomSettingsDialog .mx_AvatarSetting_avatar .mx_AvatarSetting_avatarPlaceholder::before {
mask: url("@vector-im/compound-design-tokens/icons/image.svg");
mask-repeat: no-repeat;
mask-size: 36px;
mask-position: center;
}

View File

@ -30,26 +30,13 @@ Please see LICENSE files in the repository root for full details.
.mx_LegacyCallEvent_iconButton {
display: inline-flex;
&::before {
content: "";
svg {
height: 16px;
width: 16px;
background-color: $secondary-content;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
color: $secondary-content;
}
}
.mx_LegacyCallEvent_silence::before {
mask-image: url("@vector-im/compound-design-tokens/icons/volume-on-solid.svg");
}
.mx_LegacyCallEvent_unSilence::before {
mask-image: url("@vector-im/compound-design-tokens/icons/volume-off-solid.svg");
}
&.mx_LegacyCallEvent_voice {
.mx_LegacyCallEvent_type_icon::before,
.mx_LegacyCallEvent_content_button_callBack span::before,

View File

@ -38,34 +38,11 @@ $left-gutter: 64px;
text-align: start;
}
.mx_EventTile_receiptSent,
.mx_EventTile_receiptSending {
position: relative;
.mx_ReadReceiptGroup_container svg {
display: inline-block;
width: 16px;
height: 16px;
&::before {
background-color: var(--cpd-color-icon-tertiary);
mask-repeat: no-repeat;
mask-position: center;
mask-size: 16px;
width: 16px;
height: 16px;
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
}
}
.mx_EventTile_receiptSent::before {
mask-image: url("@vector-im/compound-design-tokens/icons/check-circle.svg");
}
.mx_EventTile_receiptSending::before {
mask-image: url("@vector-im/compound-design-tokens/icons/circle.svg");
color: var(--cpd-color-icon-tertiary);
}
.mx_EventTile_content {

View File

@ -246,21 +246,9 @@ Please see LICENSE files in the repository root for full details.
height: 18px;
margin-left: 12px;
margin-right: 16px;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $tertiary-content;
color: $tertiary-content;
left: -1px; /* adjust for image position */
}
.mx_RoomSublist_showMoreButtonChevron,
.mx_RoomSublist_showLessButtonChevron {
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
}
.mx_RoomSublist_showLessButtonChevron {
transform: rotate(180deg);
}
}
&.mx_RoomSublist_hasMenuOpen,

View File

@ -7,23 +7,18 @@ Please see LICENSE files in the repository root for full details.
*/
.mx_VoiceRecordComposerTile_stop {
/* 28px plus a 2px border makes this a 32px square (as intended) */
width: 28px;
height: 28px;
/* 20px + 4px padding + 2px border makes this a 32px square (as intended) */
width: 20px;
height: 20px;
padding: var(--cpd-space-1x);
border: 2px solid $voice-record-stop-border-color;
border-radius: 32px;
margin-right: 2px; /* between us and the waveform component */
position: relative;
&::after {
content: "";
width: 14px;
height: 14px;
position: absolute;
top: 7px;
left: 7px;
border-radius: 2px;
background-color: $voice-record-stop-symbol-color;
svg {
width: inherit;
height: inherit;
color: $voice-record-stop-symbol-color;
}
}

View File

@ -114,23 +114,10 @@ Please see LICENSE files in the repository root for full details.
height: 20px;
width: 20px;
&::before {
content: "";
svg {
height: inherit;
width: inherit;
background-color: $tertiary-content;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
color: $tertiary-content;
}
}
.mx_IncomingLegacyCallToast_silence::before {
mask-image: url("@vector-im/compound-design-tokens/icons/volume-on-solid.svg");
}
.mx_IncomingLegacyCallToast_unSilence::before {
mask-image: url("@vector-im/compound-design-tokens/icons/volume-off-solid.svg");
}
}

View File

@ -44,15 +44,10 @@ Please see LICENSE files in the repository root for full details.
box-shadow: 0px 4px 4px 0px #00000026; /* Same on both themes */
&::before {
content: "";
svg {
display: inline-block;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
background-color: $call-view-button-on-foreground;
color: $call-view-button-on-foreground;
height: 24px;
width: 24px;
@ -66,103 +61,60 @@ Please see LICENSE files in the repository root for full details.
right: 0;
bottom: 0;
&::before {
svg {
width: 16px;
height: 16px;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-up.svg");
}
}
&.mx_LegacyCallViewButtons_dropdownButton_collapsed::before {
transform: rotate(180deg);
}
&.mx_LegacyCallViewButtons_button_mic svg {
height: 20px;
width: 20px;
}
/* State buttons */
&.mx_LegacyCallViewButtons_button_on {
background-color: $call-view-button-on-background;
&::before {
background-color: $call-view-button-on-foreground;
}
&.mx_LegacyCallViewButtons_button_mic::before {
height: 20px;
mask-image: url("@vector-im/compound-design-tokens/icons/mic-on-solid.svg");
width: 20px;
}
&.mx_LegacyCallViewButtons_button_vid::before {
mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg");
svg {
color: $call-view-button-on-foreground;
}
&.mx_LegacyCallViewButtons_button_screensharing {
background-color: $accent;
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/share-screen-solid.svg");
background-color: white; /* Same on both themes */
svg {
color: white; /* Same on both themes */
}
}
&.mx_LegacyCallViewButtons_button_sidebar::before {
mask-image: url("@vector-im/compound-design-tokens/icons/list-view.svg");
}
}
&.mx_LegacyCallViewButtons_button_off {
background-color: $call-view-button-off-background;
&::before {
background-color: $call-view-button-off-foreground;
}
&.mx_LegacyCallViewButtons_button_mic::before {
height: 20px;
mask-image: url("@vector-im/compound-design-tokens/icons/mic-off-solid.svg");
width: 20px;
}
&.mx_LegacyCallViewButtons_button_vid::before {
mask-image: url("@vector-im/compound-design-tokens/icons/video-call-off-solid.svg");
}
&.mx_LegacyCallViewButtons_button_screensharing {
background-color: $call-view-button-on-background;
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/share-screen-solid.svg");
background-color: $call-view-button-on-foreground;
}
svg {
color: $call-view-button-off-foreground;
}
&.mx_LegacyCallViewButtons_button_screensharing,
&.mx_LegacyCallViewButtons_button_sidebar {
background-color: $call-view-button-on-background;
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/spotlight-view.svg");
background-color: $call-view-button-on-foreground;
svg {
color: $call-view-button-on-foreground;
}
}
}
/* State buttons */
/* Stateless buttons */
&.mx_LegacyCallViewButtons_dialpad::before {
mask-image: url("@vector-im/compound-design-tokens/icons/dial-pad.svg");
}
&.mx_LegacyCallViewButtons_button_hangup {
background-color: $alert;
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/end-call.svg");
background-color: white; /* Same on both themes */
svg {
color: white; /* Same on both themes */
}
}
&.mx_LegacyCallViewButtons_button_more::before {
mask-image: url("@vector-im/compound-design-tokens/icons/overflow-horizontal.svg");
}
/* Stateless buttons */
/* Invisible state */

View File

@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 9C15 12.3137 12.3137 15 9 15V13C11.2091 13 13 11.2091 13 9C13 6.79086 11.2091 5 9 5V3C12.3137 3 15 5.68629 15 9ZM9 5C6.79086 5 5 6.79086 5 9C5 11.2091 6.79086 13 9 13V5ZM17 9C17 13.4183 13.4183 17 9 17C4.58172 17 1 13.4183 1 9C1 4.58172 4.58172 1 9 1C13.4183 1 17 4.58172 17 9Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 450 B

View File

@ -16,6 +16,7 @@ import {
SettingsSolidIcon,
LeaveIcon,
NotificationsSolidIcon,
ThemeIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import { MatrixClientPeg } from "../../MatrixClientPeg";
@ -51,7 +52,6 @@ import PosthogTrackers from "../../PosthogTrackers";
import { type ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload";
import { SDKContext } from "../../contexts/SDKContext";
import { shouldShowFeedback } from "../../utils/Feedback";
import { Icon as DarkLightModeSvg } from "../../../res/img/element-icons/roomlist/dark-light-mode.svg";
interface IProps {
isPanelCollapsed: boolean;
@ -407,7 +407,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
: _t("user_menu|switch_theme_dark")
}
>
<DarkLightModeSvg width="16px" height="16px" />
<ThemeIcon width="16px" height="16px" />
</RovingAccessibleButton>
</div>
{topSection}

View File

@ -23,6 +23,7 @@ import {
type TimelineEvents,
} from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { CheckCircleIcon, CircleIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher";
@ -127,12 +128,12 @@ const Entry: React.FC<IEntryProps<any>> = ({ room, type, content, matrixClient:
className = "mx_ForwardList_sending";
disabled = true;
title = _t("forward|sending");
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
icon = <CircleIcon aria-label={title} />;
} else if (sendState === SendState.Sent) {
className = "mx_ForwardList_sent";
disabled = true;
title = _t("forward|sent");
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
icon = <CheckCircleIcon aria-label={title} />;
} else {
className = "mx_ForwardList_sendFailed";
disabled = true;

View File

@ -11,6 +11,7 @@ import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
import { CallErrorCode, CallState } from "matrix-js-sdk/src/webrtc/call";
import classNames from "classnames";
import { Clock } from "@element-hq/web-shared-components";
import { VolumeOffSolidIcon, VolumeOnSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import MemberAvatar from "../avatars/MemberAvatar";
@ -99,18 +100,14 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
}
private renderSilenceIcon(): JSX.Element {
const silenceClass = classNames({
mx_LegacyCallEvent_iconButton: true,
mx_LegacyCallEvent_unSilence: this.state.silenced,
mx_LegacyCallEvent_silence: !this.state.silenced,
});
return (
<AccessibleButton
className={silenceClass}
className="mx_LegacyCallEvent_iconButton"
onClick={this.props.callEventGrouper.toggleSilenced}
title={this.state.silenced ? _t("voip|unsilence") : _t("voip|silence")}
/>
>
{this.state.silenced ? <VolumeOffSolidIcon /> : <VolumeOnSolidIcon />}
</AccessibleButton>
);
}

View File

@ -35,7 +35,12 @@ import {
} from "matrix-js-sdk/src/crypto-api";
import { Tooltip } from "@vector-im/compound-web";
import { uniqueId } from "lodash";
import { ErrorSolidIcon, InfoIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import {
CircleIcon,
ErrorSolidIcon,
InfoIcon,
CheckCircleIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import ReplyChain from "../elements/ReplyChain";
import { _t } from "../../../languageHandler";
@ -175,7 +180,7 @@ export interface EventTileProps {
// the status of this event - ie, mxEvent.status. Denormalised to here so
// that we can tell when it changes.
eventSendStatus?: string;
eventSendStatus?: EventStatus;
forExport?: boolean;
@ -1187,7 +1192,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
let msgOption: JSX.Element | undefined;
if (this.shouldShowSentReceipt || this.shouldShowSendingReceipt) {
msgOption = <SentReceipt messageState={this.props.mxEvent.getAssociatedStatus()} />;
msgOption = <SentReceipt messageState={this.props.eventSendStatus} />;
} else if (this.props.showReadReceipts) {
msgOption = (
<ReadReceiptGroup
@ -1563,29 +1568,27 @@ class E2ePadlock extends React.Component<IE2ePadlockProps> {
}
interface ISentReceiptProps {
messageState: EventStatus | null;
messageState: EventStatus | undefined;
}
function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
const isSent = !messageState || messageState === "sent";
const isFailed = messageState === "not_sent";
const receiptClasses = classNames({
mx_EventTile_receiptSent: isSent,
mx_EventTile_receiptSending: !isSent && !isFailed,
});
let nonCssBadge: JSX.Element | undefined;
if (isFailed) {
nonCssBadge = <NotificationBadge notification={StaticNotificationState.RED_EXCLAMATION} />;
}
let label = _t("timeline|send_state_sending");
let icon: JSX.Element | undefined;
let label: string | undefined;
if (messageState === "encrypting") {
icon = <CircleIcon />;
label = _t("timeline|send_state_encrypting");
} else if (isSent) {
icon = <CheckCircleIcon />;
label = _t("timeline|send_state_sent");
} else if (isFailed) {
icon = <NotificationBadge notification={StaticNotificationState.RED_EXCLAMATION} />;
label = _t("timeline|send_state_failed");
} else {
icon = <CircleIcon />;
label = _t("timeline|send_state_sending");
}
return (
@ -1593,9 +1596,7 @@ function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
<div className="mx_ReadReceiptGroup">
<Tooltip label={label} placement="top-end">
<div className="mx_ReadReceiptGroup_button" role="status">
<span className="mx_ReadReceiptGroup_container">
<span className={receiptClasses}>{nonCssBadge}</span>
</span>
<span className="mx_ReadReceiptGroup_container">{icon}</span>
</div>
</Tooltip>
</div>

View File

@ -16,6 +16,7 @@ import React, { type JSX, type ComponentType, createRef, type ReactComponentElem
import {
ChevronDownIcon,
ChevronRightIcon,
ChevronUpIcon,
OverflowHorizontalIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
@ -763,9 +764,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
className={showMoreBtnClasses}
aria-label={label}
>
<span className="mx_RoomSublist_showMoreButtonChevron mx_RoomSublist_showNButtonChevron">
{/* set by CSS masking */}
</span>
<ChevronDownIcon className="mx_RoomSublist_showNButtonChevron" />
{showMoreText}
</RovingAccessibleButton>
);
@ -781,9 +780,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
className={showMoreBtnClasses}
aria-label={label}
>
<span className="mx_RoomSublist_showLessButtonChevron mx_RoomSublist_showNButtonChevron">
{/* set by CSS masking */}
</span>
<ChevronUpIcon className="mx_RoomSublist_showNButtonChevron" />
{showLessText}
</RovingAccessibleButton>
);

View File

@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type ReactNode } from "react";
import { type Room, type IEventRelation, type MatrixEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { DeleteIcon, StopSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import { RecordingState } from "../../../audio/VoiceRecording";
@ -262,7 +262,9 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
className="mx_VoiceRecordComposerTile_stop"
onClick={this.onRecordStartEndClick}
title={tooltip}
/>
>
<StopSolidIcon />
</AccessibleButton>
);
if (this.state.recorder && !this.state.recorder?.isRecording) {
stopBtn = null;

View File

@ -175,7 +175,7 @@ const AvatarSetting: React.FC<IProps> = ({
* to the menu component, hence the empty onClick.
*/
onClick={() => {}}
className="mx_AvatarSetting_avatarPlaceholder mx_AvatarSetting_avatarDisplay"
className="mx_AvatarSetting_avatarDisplay"
disabled={disabled}
>
<BaseAvatar

View File

@ -8,9 +8,23 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import React, { createRef, useState, type Ref, type FC } from "react";
import React, { createRef, useState, type Ref, type FC, type JSX } from "react";
import classNames from "classnames";
import { type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import {
ChevronDownIcon,
ChevronUpIcon,
DialPadIcon,
EndCallIcon,
ListViewIcon,
MicOffSolidIcon,
MicOnSolidIcon,
OverflowHorizontalIcon,
ShareScreenSolidIcon,
SpotlightViewIcon,
VideoCallOffSolidIcon,
VideoCallSolidIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import LegacyCallContextMenu from "../../context_menus/LegacyCallContextMenu";
import DialpadContextMenu from "../../context_menus/DialpadContextMenu";
@ -38,7 +52,9 @@ const CONTROLS_HIDE_DELAY = 2000;
type ButtonProps = Omit<AccessibleButtonProps<"div">, "title" | "element"> & {
state: boolean;
onLabel?: string;
onIcon: JSX.Element;
offLabel?: string;
offIcon: JSX.Element;
forceHide?: boolean;
onHover?: (hovering: boolean) => void;
ref?: Ref<HTMLElement>;
@ -49,7 +65,9 @@ const LegacyCallViewToggleButton: FC<ButtonProps> = ({
state: isOn,
className,
onLabel,
onIcon,
offLabel,
offIcon,
forceHide,
onHover,
ref,
@ -71,6 +89,7 @@ const LegacyCallViewToggleButton: FC<ButtonProps> = ({
onTooltipOpenChange={onHover}
{...props}
>
{isOn ? onIcon : offIcon}
{children}
</AccessibleButton>
);
@ -84,10 +103,6 @@ const LegacyCallViewDropdownButton: React.FC<IDropdownButtonProps> = ({ state, d
const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
const [hoveringDropdown, setHoveringDropdown] = useState(false);
const classes = classNames("mx_LegacyCallViewButtons_button", "mx_LegacyCallViewButtons_dropdownButton", {
mx_LegacyCallViewButtons_dropdownButton_collapsed: !menuDisplayed,
});
const onClick = (event: ButtonEvent): void => {
event.stopPropagation();
openMenu();
@ -101,8 +116,10 @@ const LegacyCallViewDropdownButton: React.FC<IDropdownButtonProps> = ({ state, d
{...props}
>
<LegacyCallViewToggleButton
className={classes}
className="mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton"
onClick={onClick}
onIcon={<ChevronUpIcon />}
offIcon={<ChevronDownIcon />}
onHover={(hovering) => setHoveringDropdown(hovering)}
state={state}
/>
@ -267,19 +284,23 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
{this.props.buttonsVisibility.dialpad && (
<ContextMenuTooltipButton
className="mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dialpad"
className="mx_LegacyCallViewButtons_button"
ref={this.dialpadButton}
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
title={_t("voip|dialpad")}
placement="top"
/>
>
<DialPadIcon />
</ContextMenuTooltipButton>
)}
<LegacyCallViewDropdownButton
state={!this.props.buttonsState.micMuted}
className="mx_LegacyCallViewButtons_button_mic"
onLabel={_t("voip|disable_microphone")}
onIcon={<MicOnSolidIcon />}
offLabel={_t("voip|enable_microphone")}
offIcon={<MicOffSolidIcon />}
onClick={this.props.handlers.onMicMuteClick}
deviceKinds={[MediaDeviceKindEnum.AudioInput, MediaDeviceKindEnum.AudioOutput]}
/>
@ -288,7 +309,9 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
state={!this.props.buttonsState.vidMuted}
className="mx_LegacyCallViewButtons_button_vid"
onLabel={_t("voip|disable_camera")}
onIcon={<VideoCallSolidIcon />}
offLabel={_t("voip|enable_camera")}
offIcon={<VideoCallOffSolidIcon />}
onClick={this.props.handlers.onVidMuteClick}
deviceKinds={[MediaDeviceKindEnum.VideoInput]}
/>
@ -298,7 +321,9 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
state={this.props.buttonsState.screensharing}
className="mx_LegacyCallViewButtons_button_screensharing"
onLabel={_t("voip|stop_screenshare")}
onIcon={<ShareScreenSolidIcon />}
offLabel={_t("voip|start_screenshare")}
offIcon={<ShareScreenSolidIcon />}
onClick={this.props.handlers.onScreenshareClick}
/>
)}
@ -307,26 +332,32 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
state={this.props.buttonsState.sidebarShown}
className="mx_LegacyCallViewButtons_button_sidebar"
onLabel={_t("voip|hide_sidebar_button")}
onIcon={<ListViewIcon />}
offLabel={_t("voip|show_sidebar_button")}
offIcon={<SpotlightViewIcon />}
onClick={this.props.handlers.onToggleSidebarClick}
/>
)}
{this.props.buttonsVisibility.contextMenu && (
<ContextMenuTooltipButton
className="mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_more"
className="mx_LegacyCallViewButtons_button"
onClick={this.onMoreClick}
ref={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
title={_t("voip|more_button")}
placement="top"
/>
>
<OverflowHorizontalIcon />
</ContextMenuTooltipButton>
)}
<AccessibleButton
className="mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_hangup"
onClick={this.props.handlers.onHangupClick}
title={_t("voip|hangup")}
placement="top"
/>
>
<EndCallIcon />
</AccessibleButton>
</div>
);
}

View File

@ -12,6 +12,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { CallType, type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import classNames from "classnames";
import { VolumeOffSolidIcon, VolumeOnSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../LegacyCallHandler";
import { MatrixClientPeg } from "../MatrixClientPeg";
@ -98,10 +99,6 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
mx_IncomingLegacyCallToast_content_voice: isVoice,
mx_IncomingLegacyCallToast_content_video: !isVoice,
});
const silenceClass = classNames("mx_IncomingLegacyCallToast_iconButton", {
mx_IncomingLegacyCallToast_unSilence: this.state.silenced,
mx_IncomingLegacyCallToast_silence: !this.state.silenced,
});
return (
<React.Fragment>
@ -130,11 +127,13 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
</div>
</div>
<AccessibleButton
className={silenceClass}
className="mx_IncomingLegacyCallToast_iconButton"
disabled={callForcedSilent}
onClick={this.onSilenceClick}
title={silenceButtonTooltip}
/>
>
{this.state.silenced ? <VolumeOffSolidIcon /> : <VolumeOnSolidIcon />}
</AccessibleButton>
</React.Fragment>
);
}

View File

@ -11,7 +11,7 @@ import React from "react";
import { EventEmitter } from "events";
import { type MatrixEvent, Room, RoomMember, type Thread, ReceiptType } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { render } from "jest-matrix-react";
import { render, within } from "jest-matrix-react";
import MessagePanel, { shouldFormContinuation } from "../../../../src/components/structures/MessagePanel";
import SettingsStore from "../../../../src/settings/SettingsStore";
@ -794,8 +794,8 @@ describe("MessagePanel", function () {
const tiles = container.getElementsByClassName("mx_EventTile");
expect(tiles.length).toEqual(2);
expect(tiles[0].querySelector(".mx_EventTile_receiptSent")).toBeTruthy();
expect(tiles[1].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
expect(within(tiles[0] as HTMLElement).queryByRole("status")).toHaveAccessibleName("Your message was sent");
expect(within(tiles[1] as HTMLElement).queryByRole("status")).not.toBeInTheDocument();
});
it("should set lastSuccessful=false on non-last event if last event has a receipt from someone else", () => {
@ -830,8 +830,8 @@ describe("MessagePanel", function () {
const tiles = container.getElementsByClassName("mx_EventTile");
expect(tiles.length).toEqual(2);
expect(tiles[0].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
expect(tiles[1].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
expect(within(tiles[0] as HTMLElement).queryByRole("status")).not.toBeInTheDocument();
expect(within(tiles[1] as HTMLElement).queryByRole("status")).not.toBeInTheDocument();
});
});

View File

@ -10,6 +10,7 @@ import React from "react";
import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
import { mocked } from "jest-mock";
import {
EventStatus,
EventType,
type IEventDecryptionResult,
type MatrixClient,
@ -614,4 +615,20 @@ describe("EventTile", () => {
// The event tile should now show the not encrypted status
await waitFor(() => expect(screen.getByText("Not encrypted")).toBeInTheDocument());
});
it.each([
[EventStatus.NOT_SENT, "Failed to send"],
[EventStatus.SENDING, "Sending your message…"],
[EventStatus.ENCRYPTING, "Encrypting your message…"],
])("should display %s status icon", (eventSendStatus, text) => {
const ownEvent = mkMessage({
room: room.roomId,
user: client.getSafeUserId(),
msg: "Hello world!",
event: true,
});
const { getByRole } = getComponent({ mxEvent: ownEvent, eventSendStatus });
expect(getByRole("status")).toHaveAccessibleName(text);
});
});

View File

@ -9,21 +9,59 @@ exports[`LegacyCallViewButtons should render the buttons 1`] = `
aria-expanded="false"
aria-haspopup="true"
aria-label="Dialpad"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dialpad"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 18.6c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M6.6 2.4c-.99 0-1.8.81-1.8 1.8S5.61 6 6.6 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M17.4 6c.99 0 1.8-.81 1.8-1.8s-.81-1.8-1.8-1.8-1.8.81-1.8 1.8.81 1.8 1.8 1.8M12 13.2c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m-5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8S11.01 6 12 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8"
/>
</svg>
</div>
<div
aria-label="Mute microphone"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_mic mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 6a4 4 0 1 1 8 0v6a4 4 0 0 1-8 0z"
/>
<path
d="M5 11a1 1 0 0 1 1 1 6 6 0 0 0 12 0 1 1 0 1 1 2 0 8 8 0 0 1-7 7.938V21a1 1 0 1 1-2 0v-1.062A8 8 0 0 1 4 12a1 1 0 0 1 1-1"
/>
</svg>
<div
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_dropdownButton_collapsed mx_LegacyCallViewButtons_button_on"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12 10.775-3.9 3.9a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275.95.95 0 0 1-.275-.7q0-.425.275-.7l4.6-4.6q.15-.15.325-.212Q11.8 8.4 12 8.4t.375.063a.9.9 0 0 1 .325.212l4.6 4.6a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275z"
/>
</svg>
</div>
</div>
<div
aria-label="Turn off camera"
@ -31,38 +69,111 @@ exports[`LegacyCallViewButtons should render the buttons 1`] = `
role="button"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
/>
</svg>
<div
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_dropdownButton_collapsed mx_LegacyCallViewButtons_button_on"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12 10.775-3.9 3.9a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275.95.95 0 0 1-.275-.7q0-.425.275-.7l4.6-4.6q.15-.15.325-.212Q11.8 8.4 12 8.4t.375.063a.9.9 0 0 1 .325.212l4.6 4.6a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275z"
/>
</svg>
</div>
</div>
<div
aria-label="Start sharing your screen"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_screensharing mx_LegacyCallViewButtons_button_off"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.288 20.713Q1.575 21 2 21h20q.424 0 .712-.288A.97.97 0 0 0 23 20a.97.97 0 0 0-.288-.712A.97.97 0 0 0 22 19H2a.97.97 0 0 0-.712.288A.97.97 0 0 0 1 20q0 .424.288.712m1.3-3.299A1.93 1.93 0 0 1 2 16V5q0-.824.587-1.412A1.93 1.93 0 0 1 4 3h16q.824 0 1.413.587Q22 4.176 22 5v11q0 .824-.587 1.413A1.93 1.93 0 0 1 20 18H4q-.824 0-1.412-.587m10.12-10.12a1 1 0 0 0-1.415 0l-2.5 2.5a1 1 0 0 0 1.414 1.414l.793-.793V13a1 1 0 1 0 2 0v-2.586l.793.793a1 1 0 0 0 1.414-1.414z"
/>
</svg>
</div>
<div
aria-label="Show sidebar"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_sidebar mx_LegacyCallViewButtons_button_off"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M20 6H4v12h16zM4 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"
fill-rule="evenodd"
/>
</svg>
</div>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="More"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_more"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
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"
/>
</svg>
</div>
<div
aria-label="Hangup"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_hangup"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m2.765 16.02-2.47-2.416A1.02 1.02 0 0 1 0 12.852q0-.456.295-.751a15.6 15.6 0 0 1 5.316-3.786A15.9 15.9 0 0 1 12 7q3.355 0 6.39 1.329a16 16 0 0 1 5.315 3.772q.295.294.295.751t-.295.752l-2.47 2.416a1.047 1.047 0 0 1-1.396.108l-3.114-2.363a1.1 1.1 0 0 1-.322-.376 1.1 1.1 0 0 1-.108-.483v-2.27a13.6 13.6 0 0 0-2.12-.524C13.459 9.996 12 9.937 12 9.937s-1.459.059-2.174.175q-1.074.174-2.121.523v2.271q0 .268-.108.483a1.1 1.1 0 0 1-.322.376l-3.114 2.363a1.047 1.047 0 0 1-1.396-.107"
/>
</svg>
</div>
</div>
</div>
`;

View File

@ -4,27 +4,66 @@ exports[`<IncomingLegacyCallToast /> renders disabled silenced button when call
<div
aria-disabled="true"
aria-label="Notifications silenced"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton mx_IncomingLegacyCallToast_unSilence mx_AccessibleButton_disabled"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton mx_AccessibleButton_disabled"
disabled=""
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3.5 3.5a1 1 0 1 0-1.414 1.414L5.172 8H5a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h2l3.293 3.293c.63.63 1.707.184 1.707-.707v-3.758l7.086 7.086A1 1 0 0 0 20.5 20.5l-2.136-2.136.003-.003-1.414-1.414-.003.003-1.414-1.414.003-.003-1.415-1.415-.002.003L12 12v-.006L7.503 7.497 7.5 7.5zm11.496 8.662 1.661 1.66c.222-.564.343-1.18.343-1.822 0-1.38-.56-2.632-1.464-3.536a1 1 0 1 0-1.414 1.414 3 3 0 0 1 .874 2.284m3.164 3.165 1.462 1.46A8.96 8.96 0 0 0 21 12a8.98 8.98 0 0 0-2.636-6.364A1 1 0 0 0 16.95 7.05 6.98 6.98 0 0 1 19 12a7 7 0 0 1-.84 3.326M8.917 6.083 12 9.166V5.414c0-.89-1.077-1.337-1.707-.707z"
/>
</svg>
</div>
`;
exports[`<IncomingLegacyCallToast /> renders sound on button when call is silenced 1`] = `
<div
aria-label="Sound on"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton mx_IncomingLegacyCallToast_unSilence"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3.5 3.5a1 1 0 1 0-1.414 1.414L5.172 8H5a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h2l3.293 3.293c.63.63 1.707.184 1.707-.707v-3.758l7.086 7.086A1 1 0 0 0 20.5 20.5l-2.136-2.136.003-.003-1.414-1.414-.003.003-1.414-1.414.003-.003-1.415-1.415-.002.003L12 12v-.006L7.503 7.497 7.5 7.5zm11.496 8.662 1.661 1.66c.222-.564.343-1.18.343-1.822 0-1.38-.56-2.632-1.464-3.536a1 1 0 1 0-1.414 1.414 3 3 0 0 1 .874 2.284m3.164 3.165 1.462 1.46A8.96 8.96 0 0 0 21 12a8.98 8.98 0 0 0-2.636-6.364A1 1 0 0 0 16.95 7.05 6.98 6.98 0 0 1 19 12a7 7 0 0 1-.84 3.326M8.917 6.083 12 9.166V5.414c0-.89-1.077-1.337-1.707-.707z"
/>
</svg>
</div>
`;
exports[`<IncomingLegacyCallToast /> renders when silence button when call is not silenced 1`] = `
<div
aria-label="Silence call"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton mx_IncomingLegacyCallToast_silence"
class="mx_AccessibleButton mx_IncomingLegacyCallToast_iconButton"
role="button"
tabindex="0"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3 14v-4a2 2 0 0 1 2-2h2l3.293-3.293c.63-.63 1.707-.184 1.707.707v13.172c0 .89-1.077 1.337-1.707.707L7 16H5a2 2 0 0 1-2-2m11.122-5.536a1 1 0 0 1 1.414 0A5 5 0 0 1 17 12c0 1.38-.56 2.632-1.464 3.536a1 1 0 0 1-1.415-1.415 3 3 0 0 0 .88-2.121c0-.829-.335-1.577-.88-2.121a1 1 0 0 1 0-1.415"
/>
<path
d="M16.95 5.636a1 1 0 0 1 1.414 0A8.98 8.98 0 0 1 21 12a8.98 8.98 0 0 1-2.636 6.364 1 1 0 0 1-1.414-1.414A6.98 6.98 0 0 0 19 12a6.98 6.98 0 0 0-2.05-4.95 1 1 0 0 1 0-1.414"
/>
</svg>
</div>
`;

View File

@ -4160,10 +4160,10 @@
resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777"
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
"@vector-im/compound-design-tokens@6.6.0":
version "6.6.0"
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-6.6.0.tgz#deac29620caa4c3c6e6669e1392acf40c5ca8eed"
integrity sha512-IqHldApA5nG3US8bsbH/W2cHx2a7lOF7sOE1HQRAUxLP1B3yfIo8sgw1u6g2kvj8DM4sFIZoKcQ3Lvwym+AsYw==
"@vector-im/compound-design-tokens@6.8.0":
version "6.8.0"
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-6.8.0.tgz#3711df7b22a065c4d49dedbd8b83241c73a619f9"
integrity sha512-RDJjnFg9yxkbSYqiAG5Nv4enD5h8Oq89su0izZIvuKRzBxLWkV2/+JoDM94zkjI4aDLYff3gwWMviqAxJKi+Lw==
"@vector-im/compound-design-tokens@^6.4.3":
version "6.5.0"