diff --git a/package.json b/package.json index 29ef96753c..ba656afa87 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/playwright/e2e/audio-player/audio-player.spec.ts b/playwright/e2e/audio-player/audio-player.spec.ts index 01b0f23bb4..d6f730b23b 100644 --- a/playwright/e2e/audio-player/audio-player.spec.ts +++ b/playwright/e2e/audio-player/audio-player.spec.ts @@ -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 diff --git a/playwright/e2e/crypto/backups-mas.spec.ts b/playwright/e2e/crypto/backups-mas.spec.ts index f048bc6a2b..521ec109d9 100644 --- a/playwright/e2e/crypto/backups-mas.spec.ts +++ b/playwright/e2e/crypto/backups-mas.spec.ts @@ -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); diff --git a/playwright/e2e/messages/messages.spec.ts b/playwright/e2e/messages/messages.spec.ts index a5ea38482c..04763e1079 100644 --- a/playwright/e2e/messages/messages.spec.ts +++ b/playwright/e2e/messages/messages.spec.ts @@ -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 { + await expect(msgTile.getByRole("status")).toHaveAccessibleName("Your message was sent"); +} + async function sendMessage(page: Page, message: string): Promise { 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; } diff --git a/playwright/e2e/right-panel/file-panel.spec.ts b/playwright/e2e/right-panel/file-panel.spec.ts index 5549b2d315..69e17eeef1 100644 --- a/playwright/e2e/right-panel/file-panel.spec.ts +++ b/playwright/e2e/right-panel/file-panel.spec.ts @@ -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", () => { diff --git a/playwright/e2e/threads/threads.spec.ts b/playwright/e2e/threads/threads.spec.ts index 5ffc2003b8..e9e40dc4b4 100644 --- a/playwright/e2e/threads/threads.spec.ts +++ b/playwright/e2e/threads/threads.spec.ts @@ -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 }); diff --git a/playwright/e2e/timeline/timeline.spec.ts b/playwright/e2e/timeline/timeline.spec.ts index 806e7e9038..b9df009df9 100644 --- a/playwright/e2e/timeline/timeline.spec.ts +++ b/playwright/e2e/timeline/timeline.spec.ts @@ -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, diff --git a/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png b/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png index 94efd93b7e..a911341579 100644 Binary files a/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png and b/playwright/snapshots/user-menu/user-menu.spec.ts/user-menu-linux.png differ diff --git a/res/css/views/dialogs/_ForwardDialog.pcss b/res/css/views/dialogs/_ForwardDialog.pcss index 2e5b190487..b155bd1f4a 100644 --- a/res/css/views/dialogs/_ForwardDialog.pcss +++ b/res/css/views/dialogs/_ForwardDialog.pcss @@ -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; - } } } } diff --git a/res/css/views/dialogs/_RoomSettingsDialog.pcss b/res/css/views/dialogs/_RoomSettingsDialog.pcss index bc64e9543b..9967adca50 100644 --- a/res/css/views/dialogs/_RoomSettingsDialog.pcss +++ b/res/css/views/dialogs/_RoomSettingsDialog.pcss @@ -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; -} diff --git a/res/css/views/messages/_LegacyCallEvent.pcss b/res/css/views/messages/_LegacyCallEvent.pcss index 48fb197575..b7a69d1f34 100644 --- a/res/css/views/messages/_LegacyCallEvent.pcss +++ b/res/css/views/messages/_LegacyCallEvent.pcss @@ -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, diff --git a/res/css/views/rooms/_EventTile.pcss b/res/css/views/rooms/_EventTile.pcss index 155d520edf..6ec7a87fb9 100644 --- a/res/css/views/rooms/_EventTile.pcss +++ b/res/css/views/rooms/_EventTile.pcss @@ -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 { diff --git a/res/css/views/rooms/_RoomSublist.pcss b/res/css/views/rooms/_RoomSublist.pcss index b6aa7e8ecd..aca8109f50 100644 --- a/res/css/views/rooms/_RoomSublist.pcss +++ b/res/css/views/rooms/_RoomSublist.pcss @@ -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, diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.pcss b/res/css/views/rooms/_VoiceRecordComposerTile.pcss index 1715a8efe5..9c54538673 100644 --- a/res/css/views/rooms/_VoiceRecordComposerTile.pcss +++ b/res/css/views/rooms/_VoiceRecordComposerTile.pcss @@ -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; } } diff --git a/res/css/views/toasts/_IncomingLegacyCallToast.pcss b/res/css/views/toasts/_IncomingLegacyCallToast.pcss index 667dd110d1..2d0dae1888 100644 --- a/res/css/views/toasts/_IncomingLegacyCallToast.pcss +++ b/res/css/views/toasts/_IncomingLegacyCallToast.pcss @@ -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"); - } } diff --git a/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss b/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss index 023f941e71..c4ad182fea 100644 --- a/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss +++ b/res/css/views/voip/LegacyCallView/_LegacyCallViewButtons.pcss @@ -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 */ diff --git a/res/img/element-icons/roomlist/dark-light-mode.svg b/res/img/element-icons/roomlist/dark-light-mode.svg deleted file mode 100644 index a6a6464b5c..0000000000 --- a/res/img/element-icons/roomlist/dark-light-mode.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index d077b3da1b..6f9b768588 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -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 { : _t("user_menu|switch_theme_dark") } > - + {topSection} diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 6b4f737fa0..19c84bc108 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -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> = ({ room, type, content, matrixClient: className = "mx_ForwardList_sending"; disabled = true; title = _t("forward|sending"); - icon =
; + icon = ; } else if (sendState === SendState.Sent) { className = "mx_ForwardList_sent"; disabled = true; title = _t("forward|sent"); - icon =
; + icon = ; } else { className = "mx_ForwardList_sendFailed"; disabled = true; diff --git a/src/components/views/messages/LegacyCallEvent.tsx b/src/components/views/messages/LegacyCallEvent.tsx index f43953fb6e..7996a2a8a6 100644 --- a/src/components/views/messages/LegacyCallEvent.tsx +++ b/src/components/views/messages/LegacyCallEvent.tsx @@ -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 } private renderSilenceIcon(): JSX.Element { - const silenceClass = classNames({ - mx_LegacyCallEvent_iconButton: true, - mx_LegacyCallEvent_unSilence: this.state.silenced, - mx_LegacyCallEvent_silence: !this.state.silenced, - }); - return ( + > + {this.state.silenced ? : } + ); } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index af7b0daa53..4355eacad9 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -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 let msgOption: JSX.Element | undefined; if (this.shouldShowSentReceipt || this.shouldShowSendingReceipt) { - msgOption = ; + msgOption = ; } else if (this.props.showReadReceipts) { msgOption = ( { } 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 = ; - } - - let label = _t("timeline|send_state_sending"); + let icon: JSX.Element | undefined; + let label: string | undefined; if (messageState === "encrypting") { + icon = ; label = _t("timeline|send_state_encrypting"); } else if (isSent) { + icon = ; label = _t("timeline|send_state_sent"); } else if (isFailed) { + icon = ; label = _t("timeline|send_state_failed"); + } else { + icon = ; + label = _t("timeline|send_state_sending"); } return ( @@ -1593,9 +1596,7 @@ function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
- - {nonCssBadge} - + {icon}
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 53c2f6782d..ed3b13701c 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -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 { className={showMoreBtnClasses} aria-label={label} > - - {/* set by CSS masking */} - + {showMoreText} ); @@ -781,9 +780,7 @@ export default class RoomSublist extends React.Component { className={showMoreBtnClasses} aria-label={label} > - - {/* set by CSS masking */} - + {showLessText} ); diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx index ab69536578..17b5664e81 100644 --- a/src/components/views/rooms/VoiceRecordComposerTile.tsx +++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx @@ -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 + > + + ); if (this.state.recorder && !this.state.recorder?.isRecording) { stopBtn = null; diff --git a/src/components/views/settings/AvatarSetting.tsx b/src/components/views/settings/AvatarSetting.tsx index 2c8dac96d7..1c27efa75c 100644 --- a/src/components/views/settings/AvatarSetting.tsx +++ b/src/components/views/settings/AvatarSetting.tsx @@ -175,7 +175,7 @@ const AvatarSetting: React.FC = ({ * to the menu component, hence the empty onClick. */ onClick={() => {}} - className="mx_AvatarSetting_avatarPlaceholder mx_AvatarSetting_avatarDisplay" + className="mx_AvatarSetting_avatarDisplay" disabled={disabled} > , "title" | "element"> & { state: boolean; onLabel?: string; + onIcon: JSX.Element; offLabel?: string; + offIcon: JSX.Element; forceHide?: boolean; onHover?: (hovering: boolean) => void; ref?: Ref; @@ -49,7 +65,9 @@ const LegacyCallViewToggleButton: FC = ({ state: isOn, className, onLabel, + onIcon, offLabel, + offIcon, forceHide, onHover, ref, @@ -71,6 +89,7 @@ const LegacyCallViewToggleButton: FC = ({ onTooltipOpenChange={onHover} {...props} > + {isOn ? onIcon : offIcon} {children} ); @@ -84,10 +103,6 @@ const LegacyCallViewDropdownButton: React.FC = ({ state, d const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu(); 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 = ({ state, d {...props} > } + offIcon={} onHover={(hovering) => setHoveringDropdown(hovering)} state={state} /> @@ -267,19 +284,23 @@ export default class LegacyCallViewButtons extends React.Component + > + + )} } offLabel={_t("voip|enable_microphone")} + offIcon={} onClick={this.props.handlers.onMicMuteClick} deviceKinds={[MediaDeviceKindEnum.AudioInput, MediaDeviceKindEnum.AudioOutput]} /> @@ -288,7 +309,9 @@ export default class LegacyCallViewButtons extends React.Component} offLabel={_t("voip|enable_camera")} + offIcon={} onClick={this.props.handlers.onVidMuteClick} deviceKinds={[MediaDeviceKindEnum.VideoInput]} /> @@ -298,7 +321,9 @@ export default class LegacyCallViewButtons extends React.Component} offLabel={_t("voip|start_screenshare")} + offIcon={} onClick={this.props.handlers.onScreenshareClick} /> )} @@ -307,26 +332,32 @@ export default class LegacyCallViewButtons extends React.Component} offLabel={_t("voip|show_sidebar_button")} + offIcon={} onClick={this.props.handlers.onToggleSidebarClick} /> )} {this.props.buttonsVisibility.contextMenu && ( + > + + )} + > + +
); } diff --git a/src/toasts/IncomingLegacyCallToast.tsx b/src/toasts/IncomingLegacyCallToast.tsx index 18c3f9f506..4f976ced9f 100644 --- a/src/toasts/IncomingLegacyCallToast.tsx +++ b/src/toasts/IncomingLegacyCallToast.tsx @@ -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 @@ -130,11 +127,13 @@ export default class IncomingLegacyCallToast extends React.Component
+ > + {this.state.silenced ? : } + ); } diff --git a/test/unit-tests/components/structures/MessagePanel-test.tsx b/test/unit-tests/components/structures/MessagePanel-test.tsx index 71234bea3b..cef5310920 100644 --- a/test/unit-tests/components/structures/MessagePanel-test.tsx +++ b/test/unit-tests/components/structures/MessagePanel-test.tsx @@ -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(); }); }); diff --git a/test/unit-tests/components/views/rooms/EventTile-test.tsx b/test/unit-tests/components/views/rooms/EventTile-test.tsx index bae1719058..47d9031435 100644 --- a/test/unit-tests/components/views/rooms/EventTile-test.tsx +++ b/test/unit-tests/components/views/rooms/EventTile-test.tsx @@ -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); + }); }); diff --git a/test/unit-tests/components/views/voip/LegacyCallView/__snapshots__/LegacyCallViewButtons-test.tsx.snap b/test/unit-tests/components/views/voip/LegacyCallView/__snapshots__/LegacyCallViewButtons-test.tsx.snap index a470199a8f..5fa4a9fa46 100644 --- a/test/unit-tests/components/views/voip/LegacyCallView/__snapshots__/LegacyCallViewButtons-test.tsx.snap +++ b/test/unit-tests/components/views/voip/LegacyCallView/__snapshots__/LegacyCallViewButtons-test.tsx.snap @@ -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" - /> + > + + + +
+ + + +
+ > + + + +
+ + +
+ > + + + +
+ > + + + +
+ > + + + +
+ > + + + +
`; diff --git a/test/unit-tests/toasts/__snapshots__/IncomingLegacyCallToast-test.tsx.snap b/test/unit-tests/toasts/__snapshots__/IncomingLegacyCallToast-test.tsx.snap index 03c4f2e3b1..2113c95133 100644 --- a/test/unit-tests/toasts/__snapshots__/IncomingLegacyCallToast-test.tsx.snap +++ b/test/unit-tests/toasts/__snapshots__/IncomingLegacyCallToast-test.tsx.snap @@ -4,27 +4,66 @@ exports[` renders disabled silenced button when call
+> + + + +
`; exports[` renders sound on button when call is silenced 1`] = `
+> + + + +
`; exports[` renders when silence button when call is not silenced 1`] = `
+> + + + + +
`; diff --git a/yarn.lock b/yarn.lock index 5ac93db2e9..d74b6c2f15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"