Update toast styles to match Figma (#12833)

* Warn users on unsupported browsers before they lack features

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

* Update Learn more link

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

* Iterate

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

* Iterate

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

* Update toast styles to match Figma

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

* Remove test code

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

* update tests

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

* Update tests

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

* Update snapshots

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2024-07-30 13:57:15 +01:00 committed by GitHub
parent a1897583b1
commit b0392b8fc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 156 additions and 114 deletions

View file

@ -83,7 +83,7 @@
"@sentry/browser": "^8.0.0", "@sentry/browser": "^8.0.0",
"@testing-library/react-hooks": "^8.0.1", "@testing-library/react-hooks": "^8.0.1",
"@vector-im/compound-design-tokens": "^1.6.1", "@vector-im/compound-design-tokens": "^1.6.1",
"@vector-im/compound-web": "^5.4.0", "@vector-im/compound-web": "^5.5.0",
"@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-en": "^3.0.2", "@zxcvbn-ts/language-en": "^3.0.2",

View file

@ -45,7 +45,7 @@ export class Toasts {
*/ */
public async acceptToast(expectedTitle: string): Promise<void> { public async acceptToast(expectedTitle: string): Promise<void> {
const toast = await this.getToast(expectedTitle); const toast = await this.getToast(expectedTitle);
await toast.locator(".mx_Toast_buttons .mx_AccessibleButton_kind_primary").click(); await toast.locator('.mx_Toast_buttons button[data-kind="primary"]').click();
} }
/** /**
@ -55,6 +55,6 @@ export class Toasts {
*/ */
public async rejectToast(expectedTitle: string): Promise<void> { public async rejectToast(expectedTitle: string): Promise<void> {
const toast = await this.getToast(expectedTitle); const toast = await this.getToast(expectedTitle);
await toast.locator(".mx_Toast_buttons .mx_AccessibleButton_kind_danger_outline").click(); await toast.locator('.mx_Toast_buttons button[data-kind="secondary"]').click();
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -154,6 +154,7 @@ limitations under the License.
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin: 4px 0 11px 0; margin: 4px 0 11px 0;
color: $secondary-content;
font: var(--cpd-font-body-sm-regular); font: var(--cpd-font-body-sm-regular);
a { a {
@ -161,10 +162,6 @@ limitations under the License.
} }
} }
.mx_Toast_detail {
color: $secondary-content;
}
.mx_Toast_deviceID { .mx_Toast_deviceID {
font-size: $font-10px; font-size: $font-10px;
} }

View file

@ -17,6 +17,7 @@ limitations under the License.
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import browserlist from "browserslist"; import browserlist from "browserslist";
import electronToChromium from "electron-to-chromium/versions"; import electronToChromium from "electron-to-chromium/versions";
import PopOutIcon from "@vector-im/compound-design-tokens/assets/web/icons/pop-out";
import { DeviceType, parseUserAgent } from "./utils/device/parseUserAgent"; import { DeviceType, parseUserAgent } from "./utils/device/parseUserAgent";
import ToastStore from "./stores/ToastStore"; import ToastStore from "./stores/ToastStore";
@ -112,10 +113,11 @@ export function checkBrowserSupport(): void {
title: _t("unsupported_browser|title", { brand }), title: _t("unsupported_browser|title", { brand }),
props: { props: {
description: _t("unsupported_browser|description", { brand }), description: _t("unsupported_browser|description", { brand }),
acceptLabel: _t("action|learn_more"), secondaryLabel: _t("action|learn_more"),
onAccept: onLearnMoreClick, SecondaryIcon: PopOutIcon,
rejectLabel: _t("action|dismiss"), onSecondaryClick: onLearnMoreClick,
onReject: onDismissClick, primaryLabel: _t("action|dismiss"),
onPrimaryClick: onDismissClick,
}, },
component: GenericToast, component: GenericToast,
priority: 40, priority: 40,

View file

@ -1390,8 +1390,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
title: userNotice.title, title: userNotice.title,
props: { props: {
description: <Linkify>{userNotice.description}</Linkify>, description: <Linkify>{userNotice.description}</Linkify>,
acceptLabel: _t("action|ok"), primaryLabel: _t("action|ok"),
onAccept: () => { onPrimaryClick: () => {
ToastStore.sharedInstance().dismissToast(key); ToastStore.sharedInstance().dismissToast(key);
localStorage.setItem(key, "1"); localStorage.setItem(key, "1");
}, },

View file

@ -16,6 +16,7 @@ limitations under the License.
import * as React from "react"; import * as React from "react";
import classNames from "classnames"; import classNames from "classnames";
import { Text } from "@vector-im/compound-web";
import ToastStore, { IToast } from "../../stores/ToastStore"; import ToastStore, { IToast } from "../../stores/ToastStore";
@ -78,7 +79,9 @@ export default class ToastContainer extends React.Component<{}, IState> {
if (title) { if (title) {
titleElement = ( titleElement = (
<div className="mx_Toast_title"> <div className="mx_Toast_title">
<h2>{title}</h2> <Text size="lg" weight="semibold" as="h2">
{title}
</Text>
<span className="mx_Toast_title_countIndicator">{countIndicator}</span> <span className="mx_Toast_title_countIndicator">{countIndicator}</span>
</div> </div>
); );

View file

@ -31,9 +31,9 @@ const SECOND = 1000;
const GenericExpiringToast: React.FC<IProps> = ({ const GenericExpiringToast: React.FC<IProps> = ({
description, description,
acceptLabel, primaryLabel,
dismissLabel, dismissLabel,
onAccept, onPrimaryClick,
onDismiss, onDismiss,
toastKey, toastKey,
numSeconds, numSeconds,
@ -52,10 +52,10 @@ const GenericExpiringToast: React.FC<IProps> = ({
return ( return (
<GenericToast <GenericToast
description={description} description={description}
acceptLabel={acceptLabel} primaryLabel={primaryLabel}
onAccept={onAccept} onPrimaryClick={onPrimaryClick}
rejectLabel={rejectLabel} secondaryLabel={rejectLabel}
onReject={onReject} onSecondaryClick={onReject}
/> />
); );
}; };

View file

@ -14,31 +14,37 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ReactNode } from "react"; import React, { ComponentType, ReactNode } from "react";
import { Button } from "@vector-im/compound-web";
import AccessibleButton from "../elements/AccessibleButton";
import { XOR } from "../../../@types/common"; import { XOR } from "../../../@types/common";
export interface IProps { export interface IProps {
description: ReactNode; description: ReactNode;
detail?: ReactNode; detail?: ReactNode;
acceptLabel: string; primaryLabel: string;
PrimaryIcon?: ComponentType<React.SVGAttributes<SVGElement>>;
onAccept(): void; onPrimaryClick(): void;
} }
interface IPropsExtended extends IProps { interface IPropsExtended extends IProps {
rejectLabel: string; secondaryLabel: string;
onReject(): void; SecondaryIcon?: ComponentType<React.SVGAttributes<SVGElement>>;
destructive?: "primary" | "secondary";
onSecondaryClick(): void;
} }
const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({ const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({
description, description,
detail, detail,
acceptLabel, primaryLabel,
rejectLabel, PrimaryIcon,
onAccept, secondaryLabel,
onReject, SecondaryIcon,
destructive,
onPrimaryClick,
onSecondaryClick,
}) => { }) => {
const detailContent = detail ? <div className="mx_Toast_detail">{detail}</div> : null; const detailContent = detail ? <div className="mx_Toast_detail">{detail}</div> : null;
@ -49,14 +55,24 @@ const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({
{detailContent} {detailContent}
</div> </div>
<div className="mx_Toast_buttons" aria-live="off"> <div className="mx_Toast_buttons" aria-live="off">
{onReject && rejectLabel && ( {onSecondaryClick && secondaryLabel && (
<AccessibleButton kind="danger_outline" onClick={onReject}> <Button
{rejectLabel} onClick={onSecondaryClick}
</AccessibleButton> kind={destructive === "secondary" ? "destructive" : "secondary"}
Icon={SecondaryIcon}
size="sm"
>
{secondaryLabel}
</Button>
)} )}
<AccessibleButton onClick={onAccept} kind="primary"> <Button
{acceptLabel} onClick={onPrimaryClick}
</AccessibleButton> kind={destructive === "primary" ? "destructive" : "primary"}
Icon={PrimaryIcon}
size="sm"
>
{primaryLabel}
</Button>
</div> </div>
</div> </div>
); );

View file

@ -185,14 +185,14 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
<GenericToast <GenericToast
description={description} description={description}
detail={detail} detail={detail}
acceptLabel={ primaryLabel={
request.isSelfVerification || !request.roomId request.isSelfVerification || !request.roomId
? _t("encryption|verification|request_toast_accept") ? _t("encryption|verification|request_toast_accept")
: _t("encryption|verification|request_toast_accept_user") : _t("encryption|verification|request_toast_accept_user")
} }
onAccept={this.accept} onPrimaryClick={this.accept}
rejectLabel={declineLabel} secondaryLabel={declineLabel}
onReject={this.cancel} onSecondaryClick={this.cancel}
/> />
); );
} }

View file

@ -114,8 +114,8 @@ async function checkServerVersions(): Promise<void> {
version: MINIMUM_MATRIX_VERSION, version: MINIMUM_MATRIX_VERSION,
brand: SdkConfig.get().brand, brand: SdkConfig.get().brand,
}), }),
acceptLabel: _t("action|ok"), primaryLabel: _t("action|ok"),
onAccept: () => { onPrimaryClick: () => {
ToastStore.sharedInstance().dismissToast(toastKey); ToastStore.sharedInstance().dismissToast(toastKey);
}, },
}, },

View file

@ -87,10 +87,10 @@ export const showToast = (): void => {
// them to opt in again. // them to opt in again.
props = { props = {
description: _t("analytics|consent_migration"), description: _t("analytics|consent_migration"),
acceptLabel: _t("analytics|accept_button"), primaryLabel: _t("analytics|accept_button"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|learn_more"), secondaryLabel: _t("action|learn_more"),
onReject: onLearnMorePreviouslyOptedIn, onSecondaryClick: onLearnMorePreviouslyOptedIn,
}; };
} else if (legacyAnalyticsOptIn === null || legacyAnalyticsOptIn === undefined) { } else if (legacyAnalyticsOptIn === null || legacyAnalyticsOptIn === undefined) {
// The user had no analytics setting previously set, so we just need to prompt to opt-in, rather than // The user had no analytics setting previously set, so we just need to prompt to opt-in, rather than
@ -102,10 +102,10 @@ export const showToast = (): void => {
); );
props = { props = {
description: _t("analytics|learn_more", {}, { LearnMoreLink: learnMoreLink }), description: _t("analytics|learn_more", {}, { LearnMoreLink: learnMoreLink }),
acceptLabel: _t("action|yes"), primaryLabel: _t("action|yes"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|no"), secondaryLabel: _t("action|no"),
onReject, onSecondaryClick: onReject,
}; };
} else { } else {
// false // false

View file

@ -44,10 +44,10 @@ export const showToast = (deviceIds: Set<string>): void => {
icon: "verification_warning", icon: "verification_warning",
props: { props: {
description: _t("encryption|verification|unverified_sessions_toast_description"), description: _t("encryption|verification|unverified_sessions_toast_description"),
acceptLabel: _t("action|review"), primaryLabel: _t("action|review"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("encryption|verification|unverified_sessions_toast_reject"), secondaryLabel: _t("encryption|verification|unverified_sessions_toast_reject"),
onReject, onSecondaryClick: onReject,
}, },
component: GenericToast, component: GenericToast,
priority: 50, priority: 50,

View file

@ -44,10 +44,10 @@ export const showToast = (fromMessageSend: boolean): void => {
: _t("notifications|enable_prompt_toast_title"), : _t("notifications|enable_prompt_toast_title"),
props: { props: {
description: _t("notifications|enable_prompt_toast_description"), description: _t("notifications|enable_prompt_toast_description"),
acceptLabel: _t("action|enable"), primaryLabel: _t("action|enable"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|dismiss"), secondaryLabel: _t("action|dismiss"),
onReject, onSecondaryClick: onReject,
}, },
component: GenericToast, component: GenericToast,
priority: 30, priority: 30,

View file

@ -45,10 +45,10 @@ export const showToast = (): void => {
title: _t("mobile_guide|toast_title"), title: _t("mobile_guide|toast_title"),
props: { props: {
description: _t("mobile_guide|toast_description", { brand }), description: _t("mobile_guide|toast_description", { brand }),
acceptLabel: _t("mobile_guide|toast_accept"), primaryLabel: _t("mobile_guide|toast_accept"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|dismiss"), secondaryLabel: _t("action|dismiss"),
onReject, onSecondaryClick: onReject,
}, },
component: GenericToast, component: GenericToast,
priority: 99, priority: 99,

View file

@ -47,8 +47,8 @@ export const showToast = (
{errorText} {contactText} {errorText} {contactText}
</React.Fragment> </React.Fragment>
), ),
acceptLabel: _t("action|ok"), primaryLabel: _t("action|ok"),
onAccept: () => { onPrimaryClick: () => {
hideToast(); hideToast();
if (onHideToast) onHideToast(); if (onHideToast) onHideToast();
}, },

View file

@ -114,10 +114,11 @@ export const showToast = (kind: Kind): void => {
icon: getIcon(kind), icon: getIcon(kind),
props: { props: {
description: getDescription(kind), description: getDescription(kind),
acceptLabel: getSetupCaption(kind), primaryLabel: getSetupCaption(kind),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("encryption|verification|unverified_sessions_toast_reject"), secondaryLabel: _t("encryption|verification|unverified_sessions_toast_reject"),
onReject, onSecondaryClick: onReject,
destructive: "secondary",
}, },
component: GenericToast, component: GenericToast,
priority: kind === Kind.VERIFY_THIS_SESSION ? 95 : 40, priority: kind === Kind.VERIFY_THIS_SESSION ? 95 : 40,

View file

@ -59,10 +59,11 @@ export const showToast = async (deviceId: string): Promise<void> => {
props: { props: {
description: device.display_name, description: device.display_name,
detail: <DeviceMetaData device={extendedDevice} />, detail: <DeviceMetaData device={extendedDevice} />,
acceptLabel: _t("encryption|verification|unverified_session_toast_accept"), primaryLabel: _t("encryption|verification|unverified_session_toast_accept"),
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|no"), secondaryLabel: _t("action|no"),
onReject, onSecondaryClick: onReject,
destructive: "secondary",
}, },
component: GenericToast, component: GenericToast,
priority: 80, priority: 80,

View file

@ -83,10 +83,10 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st
title: _t("update|toast_title", { brand }), title: _t("update|toast_title", { brand }),
props: { props: {
description: _t("update|toast_description", { brand }), description: _t("update|toast_description", { brand }),
acceptLabel, primaryLabel: acceptLabel,
onAccept, onPrimaryClick: onAccept,
rejectLabel: _t("action|dismiss"), secondaryLabel: _t("action|dismiss"),
onReject, onSecondaryClick: onReject,
}, },
component: GenericToast, component: GenericToast,
priority: 20, priority: 20,

View file

@ -21,11 +21,11 @@ import GenericToast from "../../../../src/components/views/toasts/GenericToast";
const renderGenericToast = (props: Partial<ComponentProps<typeof GenericToast>> = {}): RenderResult => { const renderGenericToast = (props: Partial<ComponentProps<typeof GenericToast>> = {}): RenderResult => {
const propsWithDefaults = { const propsWithDefaults = {
acceptLabel: "Accept", primaryLabel: "Accept",
description: <div>Description</div>, description: <div>Description</div>,
onAccept: () => {}, onPrimaryClick: () => {},
onReject: () => {}, onSecondaryClick: () => {},
rejectLabel: "Reject", secondaryLabel: "Reject",
...props, ...props,
}; };

View file

@ -14,20 +14,24 @@ exports[`GenericToast should render as expected with detail content 1`] = `
aria-live="off" aria-live="off"
class="mx_Toast_buttons" class="mx_Toast_buttons"
> >
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline" class="_button_zt6rp_17"
data-kind="secondary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Reject Reject
</div> </button>
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" class="_button_zt6rp_17"
data-kind="primary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Accept Accept
</div> </button>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>
@ -52,20 +56,24 @@ exports[`GenericToast should render as expected without detail content 1`] = `
aria-live="off" aria-live="off"
class="mx_Toast_buttons" class="mx_Toast_buttons"
> >
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline" class="_button_zt6rp_17"
data-kind="secondary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Reject Reject
</div> </button>
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" class="_button_zt6rp_17"
data-kind="primary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Accept Accept
</div> </button>
</div> </div>
</div> </div>
</DocumentFragment> </DocumentFragment>

View file

@ -12,20 +12,24 @@ exports[`VerificationRequestToast should render a cross-user verification 1`] =
aria-live="off" aria-live="off"
class="mx_Toast_buttons" class="mx_Toast_buttons"
> >
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline" class="_button_zt6rp_17"
data-kind="secondary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Ignore Ignore
</div> </button>
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" class="_button_zt6rp_17"
data-kind="primary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Verify Session Verify Session
</div> </button>
</div> </div>
</div> </div>
</div> </div>
@ -48,20 +52,24 @@ exports[`VerificationRequestToast should render a self-verification 1`] = `
aria-live="off" aria-live="off"
class="mx_Toast_buttons" class="mx_Toast_buttons"
> >
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline" class="_button_zt6rp_17"
data-kind="secondary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Ignore Ignore
</div> </button>
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" class="_button_zt6rp_17"
data-kind="primary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Verify Session Verify Session
</div> </button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -80,7 +80,7 @@ describe("LifecycleStore", () => {
await sleep(0); await sleep(0);
addOrReplaceToast.mock.calls[0][0].props.onAccept(); addOrReplaceToast.mock.calls[0][0].props.onPrimaryClick();
expect(dismissToast).toHaveBeenCalledWith(addOrReplaceToast.mock.calls[0][0].key); expect(dismissToast).toHaveBeenCalledWith(addOrReplaceToast.mock.calls[0][0].key);
}); });

View file

@ -13,7 +13,9 @@ exports[`UnverifiedSessionToast when rendering the toast should render as expect
<div <div
class="mx_Toast_title" class="mx_Toast_title"
> >
<h2> <h2
class="_typography_yh5dq_162 _font-body-lg-semibold_yh5dq_83"
>
New login. Was this you? New login. Was this you?
</h2> </h2>
<span <span
@ -47,20 +49,24 @@ exports[`UnverifiedSessionToast when rendering the toast should render as expect
aria-live="off" aria-live="off"
class="mx_Toast_buttons" class="mx_Toast_buttons"
> >
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline" class="_button_zt6rp_17 _destructive_zt6rp_111"
data-kind="secondary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
No No
</div> </button>
<div <button
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" class="_button_zt6rp_17"
data-kind="primary"
data-size="sm"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Yes, it was me Yes, it was me
</div> </button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -3017,7 +3017,7 @@
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-1.6.1.tgz#3f1bb5b2b9f8aff10144aab19dfa11165c3c927b" resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-1.6.1.tgz#3f1bb5b2b9f8aff10144aab19dfa11165c3c927b"
integrity sha512-u5xG/8AN7QkPPWhugj0ZrQtWsAjuKHzuOoP0s3bbDg7ZkKTE9l5tM29bdOHnSv9mEYKO+KVMMfsl0W1rlaTmAw== integrity sha512-u5xG/8AN7QkPPWhugj0ZrQtWsAjuKHzuOoP0s3bbDg7ZkKTE9l5tM29bdOHnSv9mEYKO+KVMMfsl0W1rlaTmAw==
"@vector-im/compound-web@^5.4.0": "@vector-im/compound-web@^5.5.0":
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-5.5.0.tgz#c646cd8c59aa7e5df527d843ad3b7b7c064d5224" resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-5.5.0.tgz#c646cd8c59aa7e5df527d843ad3b7b7c064d5224"
integrity sha512-Z+QSXOkJE4/LYk9j9FMVE2m5noz3gEA4yRxetjSJyXB5mDpyIJ1OYAweuZJXS3foxqygVDeB82YgTw1JgDtUvg== integrity sha512-Z+QSXOkJE4/LYk9j9FMVE2m5noz3gEA4yRxetjSJyXB5mDpyIJ1OYAweuZJXS3foxqygVDeB82YgTw1JgDtUvg==