Switch to rendering svg icons rather than masking them (#31550)

* Switch to rendering svg icons rather than masking them in SpacePanel

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

* Fix badly rendered icon in JoinRuleDropdown

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

* Fix badly rendered icon in RoomPreviewCard

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

* Fix badly rendered icon in Space menus

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

* Fix badly rendered icon in ThreadPanel

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

* Update snapshots

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

* Update screenshot

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

* Remove unused icon underfill

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

* Update screenshot

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

* Add test

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

* Add missing snapshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2025-12-16 13:56:36 +00:00
committed by GitHub
parent 773662e018
commit 7e3a6d9c42
24 changed files with 645 additions and 319 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -79,6 +79,7 @@
@import "./structures/_SearchBox.pcss";
@import "./structures/_SpaceHierarchy.pcss";
@import "./structures/_SpacePanel.pcss";
@import "./structures/_SpacePillButton.pcss";
@import "./structures/_SpaceRoomView.pcss";
@import "./structures/_SplashPage.pcss";
@import "./structures/_TabbedView.pcss";
@@ -381,7 +382,6 @@
@import "./views/spaces/_SpaceBasicSettings.pcss";
@import "./views/spaces/_SpaceChildrenPicker.pcss";
@import "./views/spaces/_SpaceCreateMenu.pcss";
@import "./views/spaces/_SpacePublicShare.pcss";
@import "./views/terms/_InlineTermsAgreement.pcss";
@import "./views/toasts/_AnalyticsToast.pcss";
@import "./views/toasts/_IncomingCallToast.pcss";

View File

@@ -44,29 +44,23 @@ Please see LICENSE files in the repository root for full details.
top: 19px; /* v-align with avatar */
right: -8px;
&::before {
content: "";
position: absolute;
width: inherit;
svg {
height: inherit;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background-color: $background;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
transform: rotate(270deg);
width: inherit;
display: inline-block;
color: $background;
/* Slight alignment tweak to center the asset */
margin-left: 1px;
}
&:not(.expanded) {
opacity: 0;
&::before {
mask-position: center 1px;
}
}
&.expanded::before {
transform: rotate(90deg);
&.expanded svg {
transform: rotate(180deg);
/* Slight alignment tweak to center the asset */
margin-left: -1px;
}
}
@@ -103,7 +97,6 @@ Please see LICENSE files in the repository root for full details.
& > .mx_SpaceButton > .mx_SpaceButton_toggleCollapse {
padding: 0 10px;
margin: 0 -10px;
transform: rotate(-90deg);
}
& > .mx_SpaceTreeLevel {
@@ -166,109 +159,67 @@ Please see LICENSE files in the repository root for full details.
}
.mx_SpaceButton_toggleCollapse {
width: var(--gutterSize);
padding: 10px 0;
min-width: var(--gutterSize);
height: 20px;
mask-position: center;
mask-size: 20px;
mask-repeat: no-repeat;
background-color: $tertiary-content;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
width: var(--gutterSize);
flex-shrink: 0;
padding: 10px 0;
svg {
width: 20px;
height: inherit;
display: inline-block;
color: $tertiary-content;
/* Re-align with parent */
margin-left: -3px;
}
}
.mx_SpaceButton_icon {
width: var(--height-topLevel);
min-width: var(--height-topLevel);
height: var(--height-topLevel);
/* Calculate height excluding padding to allow svg to inherit */
width: calc(var(--height-topLevel) - 14px);
height: calc(var(--height-topLevel) - 14px);
flex-shrink: 0;
border-radius: 8px;
position: relative;
&::before {
position: absolute;
content: "";
width: var(--height-topLevel);
height: var(--height-topLevel);
top: 0;
left: 0;
mask-position: center;
mask-repeat: no-repeat;
mask-size: 18px;
}
}
&.mx_SpaceButton_home,
&.mx_SpaceButton_favourites,
&.mx_SpaceButton_people,
&.mx_SpaceButton_orphans,
&.mx_SpaceButton_videoRooms {
.mx_SpaceButton_icon {
background-color: $panel-actions;
&::before {
background-color: $secondary-content;
}
}
}
&.mx_SpaceButton_withIcon .mx_SpaceButton_icon {
padding: 7px;
background-color: $panel-actions;
}
&.mx_SpaceButton_home .mx_SpaceButton_icon::before {
mask-image: url("@vector-im/compound-design-tokens/icons/home-solid.svg");
}
&.mx_SpaceButton_favourites .mx_SpaceButton_icon::before {
mask-image: url("@vector-im/compound-design-tokens/icons/favourite-solid.svg");
}
&.mx_SpaceButton_people .mx_SpaceButton_icon::before {
mask-image: url("@vector-im/compound-design-tokens/icons/user-profile-solid.svg");
}
&.mx_SpaceButton_orphans .mx_SpaceButton_icon::before {
mask-image: url("@vector-im/compound-design-tokens/icons/room.svg");
}
&.mx_SpaceButton_videoRooms .mx_SpaceButton_icon::before {
mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg");
svg {
width: inherit;
height: inherit;
display: block;
color: $secondary-content;
}
}
&.mx_SpaceButton_new .mx_SpaceButton_icon {
&::before {
background-color: $primary-content;
mask-image: url("@vector-im/compound-design-tokens/icons/plus.svg");
background-color: unset;
svg {
color: $primary-content;
transition: all 0.2s ease-in-out; /* TODO transition */
}
}
&.mx_SpaceButton_newCancel .mx_SpaceButton_icon::before {
&.mx_SpaceButton_newCancel .mx_SpaceButton_icon svg {
transform: rotate(45deg);
}
.mx_SpaceButton_menuButton {
width: 20px;
min-width: 20px; /* yay flex */
height: 20px;
width: 16px;
height: 16px;
padding: var(--cpd-space-0-5x);
flex-shrink: 0;
margin-top: auto;
margin-bottom: auto;
display: none;
position: absolute;
right: 4px;
&::before {
top: 3px;
left: 2px;
content: "";
width: 16px;
height: 16px;
position: absolute;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
mask-image: url("@vector-im/compound-design-tokens/icons/overflow-horizontal.svg");
background: $primary-content;
svg {
width: inherit;
height: inherit;
display: block;
color: $primary-content;
}
}
}
@@ -341,18 +292,6 @@ Please see LICENSE files in the repository root for full details.
padding: 0 0 16px 0;
scrollbar-gutter: stable;
& > .mx_SpaceButton {
height: var(--height-topLevel);
&.mx_SpaceButton_active::before {
height: var(--height-topLevel);
}
}
& > ul {
padding-left: 0;
}
&.mx_IndicatorScrollbar_topOverflow {
mask-image: linear-gradient(to bottom, transparent, black 16px);
}

View File

@@ -0,0 +1,48 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
.mx_SpacePillButton {
position: relative;
padding: 16px 32px 16px 72px;
width: 432px;
box-sizing: border-box;
border-radius: 8px;
border: 1px solid $input-border-color;
font-size: $font-17px;
font-weight: var(--cpd-font-weight-semibold);
margin: 20px 0;
> div {
margin-top: 4px;
font-weight: normal;
font-size: $font-15px;
color: $secondary-content;
}
svg {
position: absolute;
content: "";
width: 28px;
height: 28px;
top: 50%;
transform: translateY(-50%);
left: 22px;
color: $tertiary-content;
}
&:hover {
border-color: var(--cpd-color-bg-action-primary-rest);
svg {
color: var(--cpd-color-icon-primary);
}
> span {
color: $primary-content;
}
}
}

View File

@@ -6,51 +6,6 @@ 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.
*/
@define-mixin SpacePillButton {
position: relative;
padding: 16px 32px 16px 72px;
width: 432px;
box-sizing: border-box;
border-radius: 8px;
border: 1px solid $input-border-color;
font-size: $font-17px;
font-weight: var(--cpd-font-weight-semibold);
margin: 20px 0;
> div {
margin-top: 4px;
font-weight: normal;
font-size: $font-15px;
color: $secondary-content;
}
&::before {
position: absolute;
content: "";
width: 28px;
height: 28px;
top: 50%;
transform: translateY(-50%);
left: 22px;
mask-position: center;
mask-repeat: no-repeat;
mask-size: 28px;
background-color: $tertiary-content;
}
&:hover {
border-color: var(--cpd-color-bg-action-primary-rest);
&::before {
background-color: var(--cpd-color-icon-primary);
}
> span {
color: $primary-content;
}
}
}
.mx_SpaceRoomView {
--innerWidth: 428px;
@@ -242,20 +197,6 @@ Please see LICENSE files in the repository root for full details.
}
}
.mx_SpaceRoomView_privateScope {
> .mx_AccessibleButton {
@mixin SpacePillButton;
}
.mx_SpaceRoomView_privateScope_justMeButton::before {
mask-image: url("@vector-im/compound-design-tokens/icons/user-profile-solid.svg");
}
.mx_SpaceRoomView_privateScope_meAndMyTeammatesButton::before {
mask-image: url("@vector-im/compound-design-tokens/icons/group.svg");
}
}
.mx_SpaceRoomView_inviteTeammates {
.mx_SpaceRoomView_inviteTeammates_buttons {
color: $secondary-content;

View File

@@ -47,16 +47,12 @@ Please see LICENSE files in the repository root for full details.
background: $quinary-content;
}
&::before {
svg {
margin-left: 2px;
content: "";
width: 20px;
height: 20px;
background: currentColor;
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
mask-size: 100%;
mask-repeat: no-repeat;
float: right;
width: 20px;
display: inline-block;
vertical-align: bottom;
}
}
}
@@ -181,25 +177,24 @@ Please see LICENSE files in the repository root for full details.
}
&[aria-checked="true"] {
:first-child {
span:first-child {
margin-left: -20px;
}
:first-child::before {
content: "";
svg {
width: 12px;
height: 12px;
margin-right: 8px;
mask-image: url("@vector-im/compound-design-tokens/icons/check.svg");
mask-size: 100%;
mask-repeat: no-repeat;
background-color: $primary-content;
color: $primary-content;
display: inline-block;
vertical-align: middle;
position: absolute;
top: 14px;
left: 10px;
}
}
:last-child {
span:last-child {
color: $secondary-content;
}
}

View File

@@ -833,7 +833,6 @@ $left-gutter: 64px;
background-repeat: no-repeat;
background-size: contain;
&::before,
&::after {
content: "";
display: block;
@@ -844,10 +843,6 @@ $left-gutter: 64px;
mask-size: contain;
}
&::before {
mask-size: 80%;
}
&.mx_EventTile_e2eIcon_warning::after {
mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg");
background-color: $e2e-warning-color; /* red */

View File

@@ -22,20 +22,13 @@ Please see LICENSE files in the repository root for full details.
line-height: $font-24px;
color: $primary-content;
margin-top: $spacing-24;
position: relative;
padding-left: calc(20px + $spacing-8);
&::before {
content: "";
position: absolute;
height: $font-24px;
width: 20px;
left: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
mask-image: url("@vector-im/compound-design-tokens/icons/info-solid.svg");
background-color: $secondary-content;
svg {
height: 1em;
width: 1em;
margin-right: $spacing-8;
color: $secondary-content;
vertical-align: -2px;
}
}
@@ -63,25 +56,19 @@ Please see LICENSE files in the repository root for full details.
align-items: center;
.mx_RoomPreviewCard_video {
width: 50px;
height: 50px;
width: 22px;
height: 22px;
padding: 14px;
border-radius: calc((50px + 2 * 3px) / 2);
background-color: $accent;
border: 3px solid $system;
position: relative;
left: calc(-50px / 4 - 3px);
&::before {
content: "";
background-color: $button-primary-fg-color;
position: absolute;
width: 50px;
height: 50px;
mask-size: 22px;
mask-position: center;
mask-repeat: no-repeat;
mask-image: url("@vector-im/compound-design-tokens/icons/video-call-solid.svg");
svg {
width: inherit;
height: inherit;
color: $button-primary-fg-color;
}
}

View File

@@ -34,18 +34,6 @@ Please see LICENSE files in the repository root for full details.
}
}
.mx_SpaceCreateMenuType {
@mixin SpacePillButton;
}
.mx_SpaceCreateMenuType_public::before {
mask-image: url("@vector-im/compound-design-tokens/icons/public.svg");
}
.mx_SpaceCreateMenuType_private::before {
mask-image: url("@vector-im/compound-design-tokens/icons/lock-solid.svg");
}
.mx_SpaceCreateMenu_back {
width: 28px;
height: 28px;

View File

@@ -1,21 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
.mx_SpacePublicShare {
.mx_AccessibleButton {
@mixin SpacePillButton;
&.mx_SpacePublicShare_shareButton::before {
mask-image: url("@vector-im/compound-design-tokens/icons/link.svg");
}
&.mx_SpacePublicShare_inviteButton::before {
mask-image: url("$(res)/img/element-icons/room/invite.svg");
}
}
}

View File

@@ -0,0 +1,27 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX } from "react";
import AccessibleButton from "../views/elements/AccessibleButton";
const SpacePillButton: React.FC<{
title: string;
icon: JSX.Element;
description: string;
onClick(): void;
}> = ({ title, icon, description, onClick }) => {
return (
<AccessibleButton className="mx_SpacePillButton" onClick={onClick}>
{icon}
{title}
<div>{description}</div>
</AccessibleButton>
);
};
export default SpacePillButton;

View File

@@ -10,7 +10,12 @@ import { EventType, RoomType, JoinRule, Preset, type Room, RoomEvent } from "mat
import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
import React, { type JSX, useCallback, useContext, useRef, useState } from "react";
import { PlusIcon, RoomIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import {
GroupIcon,
PlusIcon,
RoomIcon,
UserProfileSolidIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import createRoom, { type IOpts } from "../../createRoom";
@@ -68,6 +73,7 @@ import RightPanel from "./RightPanel";
import SpaceHierarchy, { showRoom } from "./SpaceHierarchy";
import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
import { Icon as HashVideoIcon } from "../../../res/img/element-icons/roomlist/hash-video.svg";
import SpacePillButton from "./SpacePillButton.tsx";
interface IProps {
space: Room;
@@ -455,24 +461,22 @@ const SpaceSetupPrivateScope: React.FC<{
})}
</div>
<AccessibleButton
className="mx_SpaceRoomView_privateScope_justMeButton"
<SpacePillButton
icon={<UserProfileSolidIcon />}
title={_t("create_space|personal_space")}
description={_t("create_space|personal_space_description")}
onClick={() => {
onFinished(false);
}}
>
{_t("create_space|personal_space")}
<div>{_t("create_space|personal_space_description")}</div>
</AccessibleButton>
<AccessibleButton
className="mx_SpaceRoomView_privateScope_meAndMyTeammatesButton"
/>
<SpacePillButton
icon={<GroupIcon />}
title={_t("create_space|private_space")}
description={_t("create_space|private_space_description")}
onClick={() => {
onFinished(true);
}}
>
{_t("create_space|private_space")}
<div>{_t("create_space|private_space_description")}</div>
</AccessibleButton>
/>
</div>
);
};

View File

@@ -10,7 +10,7 @@ import React, { useContext, useEffect, useRef, useState } from "react";
import { type EventTimelineSet, type Room, Thread } from "matrix-js-sdk/src/matrix";
import { IconButton, Tooltip } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import ThreadsIcon from "@vector-im/compound-design-tokens/assets/web/icons/threads";
import { ThreadsIcon, CheckIcon, ChevronDownIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { Icon as MarkAllThreadsReadIcon } from "../../../res/img/element-icons/check-all.svg";
import BaseCard from "../views/right_panel/BaseCard";
@@ -57,6 +57,7 @@ export const ThreadPanelHeaderFilterOptionItem: React.FC<
> = ({ label, description, onClick, isSelected }) => {
return (
<MenuItemRadio active={isSelected} className="mx_ThreadPanel_Header_FilterOptionItem" onClick={onClick}>
{isSelected ? <CheckIcon /> : null}
<span>{label}</span>
<span>{description}</span>
</MenuItemRadio>
@@ -145,6 +146,7 @@ export const ThreadPanelHeader: React.FC<{
}}
>
{`${_t("threads|show_thread_filter")} ${value?.label}`}
<ChevronDownIcon />
</ContextMenuButton>
{contextMenu}
</div>

View File

@@ -57,7 +57,7 @@ const JoinRuleDropdown: React.FC<IProps> = ({
options.unshift(
(
<div key={JoinRule.Knock} className="mx_JoinRuleDropdown_knock">
<AskToJoinIcon className="mx_Icon mx_Icon_16 mx_JoinRuleDropdown_icon" />
<AskToJoinIcon />
{labelKnock}
</div>
) as ReactElement & { key: string },

View File

@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type JSX, type FC, useContext, useState } from "react";
import { type Room, JoinRule } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { InfoSolidIcon, VideoCallSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import defaultDispatcher from "../../../dispatcher/dispatcher";
@@ -152,7 +153,9 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
avatarRow = (
<>
<RoomAvatar room={room} size="50px" viewAvatarOnClick />
<div className="mx_RoomPreviewCard_video" />
<div className="mx_RoomPreviewCard_video">
<VideoCallSolidIcon />
</div>
<BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} />
</>
);
@@ -174,6 +177,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
{room.getJoinRule() === "public" && <RoomFacePile room={room} />}
{cannotJoin ? (
<div className="mx_RoomPreviewCard_notice">
<InfoSolidIcon />
{_t("room|join_failed_needs_invite", { roomName: room.name })}
</div>
) : null}

View File

@@ -18,7 +18,6 @@ import React, {
type ReactNode,
useEffect,
} from "react";
import classNames from "classnames";
import {
RoomType,
HistoryVisibility,
@@ -28,6 +27,7 @@ import {
type ICreateRoomOpts,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { LockSolidIcon, PublicIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import ContextMenu, { ChevronFace } from "../../structures/ContextMenu";
@@ -47,6 +47,7 @@ import { Filter } from "../dialogs/spotlight/Filter";
import { type OpenSpotlightPayload } from "../../../dispatcher/payloads/OpenSpotlightPayload.ts";
import { useSettingValue } from "../../../hooks/useSettings.ts";
import { UIFeature } from "../../../settings/UIFeature.ts";
import SpacePillButton from "../../structures/SpacePillButton.tsx";
export const createSpace = async (
client: MatrixClient,
@@ -86,20 +87,6 @@ export const createSpace = async (
});
};
const SpaceCreateMenuType: React.FC<{
title: string;
description: string;
className: string;
onClick(): void;
}> = ({ title, description, className, onClick }) => {
return (
<AccessibleButton className={classNames("mx_SpaceCreateMenuType", className)} onClick={onClick}>
{title}
<div>{description}</div>
</AccessibleButton>
);
};
const spaceNameValidator = withValidation({
rules: [
{
@@ -285,16 +272,16 @@ const SpaceCreateMenu: React.FC<{
<h2>{_t("create_space|label")}</h2>
<p>{_t("create_space|explainer")}</p>
<SpaceCreateMenuType
<SpacePillButton
icon={<PublicIcon />}
title={_t("common|public")}
description={_t("create_space|public_description")}
className="mx_SpaceCreateMenuType_public"
onClick={() => setVisibility(Visibility.Public)}
/>
<SpaceCreateMenuType
<SpacePillButton
icon={<LockSolidIcon />}
title={_t("common|private")}
description={_t("create_space|private_description")}
className="mx_SpaceCreateMenuType_private"
onClick={() => setVisibility(Visibility.Private)}
/>

View File

@@ -22,6 +22,15 @@ import React, {
import { DragDropContext, Draggable, Droppable, type DroppableProvidedProps } from "react-beautiful-dnd";
import classNames from "classnames";
import { type Room } from "matrix-js-sdk/src/matrix";
import {
FavouriteSolidIcon,
HomeSolidIcon,
RoomIcon,
VideoCallSolidIcon,
UserProfileSolidIcon,
PlusIcon,
ChevronRightIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import { useContextMenu } from "../../structures/ContextMenu";
@@ -114,6 +123,7 @@ export const HomeButtonContextMenu: React.FC<ComponentProps<typeof SpaceContextM
interface IMetaSpaceButtonProps extends ComponentProps<typeof SpaceButton> {
selected: boolean;
isPanelCollapsed: boolean;
icon: JSX.Element;
}
type MetaSpaceButtonProps = Pick<IMetaSpaceButtonProps, "selected" | "isPanelCollapsed">;
@@ -152,7 +162,6 @@ const HomeButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollapsed
return (
<MetaSpaceButton
spaceKey={MetaSpace.Home}
className="mx_SpaceButton_home"
selected={selected}
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Home, allRoomsInHome)}
@@ -160,6 +169,7 @@ const HomeButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollapsed
ContextMenuComponent={HomeButtonContextMenu}
contextMenuTooltip={_t("common|options")}
size="32px"
icon={<HomeSolidIcon />}
/>
);
};
@@ -168,12 +178,12 @@ const FavouritesButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCol
return (
<MetaSpaceButton
spaceKey={MetaSpace.Favourites}
className="mx_SpaceButton_favourites"
selected={selected}
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Favourites)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Favourites)}
size="32px"
icon={<FavouriteSolidIcon />}
/>
);
};
@@ -182,12 +192,12 @@ const PeopleButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollaps
return (
<MetaSpaceButton
spaceKey={MetaSpace.People}
className="mx_SpaceButton_people"
selected={selected}
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.People)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.People)}
size="32px"
icon={<UserProfileSolidIcon />}
/>
);
};
@@ -196,12 +206,12 @@ const OrphansButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollap
return (
<MetaSpaceButton
spaceKey={MetaSpace.Orphans}
className="mx_SpaceButton_orphans"
selected={selected}
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Orphans)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Orphans)}
size="32px"
icon={<RoomIcon />}
/>
);
};
@@ -210,12 +220,12 @@ const VideoRoomsButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCol
return (
<MetaSpaceButton
spaceKey={MetaSpace.VideoRooms}
className="mx_SpaceButton_videoRooms"
selected={selected}
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.VideoRooms)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.VideoRooms)}
size="32px"
icon={<VideoCallSolidIcon />}
/>
);
};
@@ -262,6 +272,7 @@ const CreateSpaceButton: React.FC<Pick<IInnerSpacePanelProps, "isPanelCollapsed"
isNarrow={isPanelCollapsed}
innerRef={handle}
size="32px"
icon={<PlusIcon />}
/>
{contextMenu}
@@ -449,7 +460,9 @@ const SpacePanel: React.FC = () => {
className="mx_SpacePanel_Tooltip_KeyboardShortcut"
/>
}
/>
>
<ChevronRightIcon />
</AccessibleButton>
</UserMenu>
<Droppable droppableId="top-level-spaces">
{(provided, snapshot) => (

View File

@@ -9,15 +9,17 @@ Please see LICENSE files in the repository root for full details.
import React, { useState } from "react";
import { type Room } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils";
import { LinkIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import { copyPlaintext } from "../../../utils/strings";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { showRoomInviteDialog } from "../../../RoomInvite";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
import { Icon as InviteIcon } from "../../../../res/img/element-icons/room/invite.svg";
import SpacePillButton from "../../structures/SpacePillButton.tsx";
interface IProps {
space: Room;
@@ -29,8 +31,10 @@ const SpacePublicShare: React.FC<IProps> = ({ space, onFinished }) => {
return (
<div className="mx_SpacePublicShare">
<AccessibleButton
className="mx_SpacePublicShare_shareButton"
<SpacePillButton
icon={<LinkIcon />}
title={_t("space|invite_link")}
description={copiedText}
onClick={async (): Promise<void> => {
const permalinkCreator = new RoomPermalinkCreator(space);
permalinkCreator.load();
@@ -43,22 +47,18 @@ const SpacePublicShare: React.FC<IProps> = ({ space, onFinished }) => {
setCopiedText(_t("action|click_to_copy"));
}
}}
>
{_t("space|invite_link")}
<div>{copiedText}</div>
</AccessibleButton>
/>
{space.canInvite(MatrixClientPeg.safeGet().getSafeUserId()) &&
shouldShowComponent(UIComponent.InviteUsers) ? (
<AccessibleButton
className="mx_SpacePublicShare_inviteButton"
<SpacePillButton
icon={<InviteIcon />}
title={_t("space|invite")}
description={_t("space|invite_description")}
onClick={() => {
if (onFinished) onFinished();
showRoomInviteDialog(space.roomId);
}}
>
{_t("space|invite")}
<div>{_t("space|invite_description")}</div>
</AccessibleButton>
/>
) : null}
</div>
);

View File

@@ -20,6 +20,11 @@ import classNames from "classnames";
import { type Room, RoomEvent } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { type DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
import {
ChevronDownIcon,
ChevronRightIcon,
OverflowHorizontalIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import RoomAvatar from "../avatars/RoomAvatar";
import SpaceStore from "../../../stores/spaces/SpaceStore";
@@ -169,7 +174,9 @@ export const SpaceButton = <T extends keyof HTMLElementTagNameMap>({
onClick={openMenu}
title={contextMenuTooltip}
isExpanded={menuDisplayed}
/>
>
<OverflowHorizontalIcon />
</ContextMenuTooltipButton>
)}
{contextMenu}
@@ -349,7 +356,9 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
onClick={this.toggleCollapse}
tabIndex={-1}
aria-label={collapsed ? _t("action|expand") : _t("action|collapse")}
/>
>
{collapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}
</AccessibleButton>
) : null;
// eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@@ -34,6 +34,17 @@ exports[`ThreadPanel Header expect that All filter for ThreadPanelHeader properl
tabindex="0"
>
Show: All threads
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div>
</div>
</DocumentFragment>
@@ -73,6 +84,17 @@ exports[`ThreadPanel Header expect that My filter for ThreadPanelHeader properly
tabindex="0"
>
Show: My threads
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div>
</div>
</DocumentFragment>
@@ -85,6 +107,17 @@ exports[`ThreadPanel Header expect that ThreadPanelHeader has the correct option
role="menuitemradio"
tabindex="0"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
<span>
All threads
</span>

View File

@@ -8,13 +8,14 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { fireEvent, getByTestId, render } from "jest-matrix-react";
import { mocked } from "jest-mock";
import { mkRoom, stubClient } from "../../../../test-utils";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions";
import { SpaceButton } from "../../../../../src/components/views/spaces/SpaceTreeLevel";
import { SpaceItem, SpaceButton } from "../../../../../src/components/views/spaces/SpaceTreeLevel";
import { MetaSpace, type SpaceKey } from "../../../../../src/stores/spaces";
import SpaceStore from "../../../../../src/stores/spaces/SpaceStore";
import { StaticNotificationState } from "../../../../../src/stores/notifications/StaticNotificationState";
@@ -26,6 +27,8 @@ jest.mock("../../../../../src/stores/spaces/SpaceStore", () => {
class MockSpaceStore extends EventEmitter {
activeSpace: SpaceKey = "!space1";
setActiveSpace = jest.fn();
getChildSpaces = jest.fn();
getNotificationState = jest.fn();
}
return { instance: new MockSpaceStore() };
@@ -127,3 +130,28 @@ describe("SpaceButton", () => {
});
});
});
describe("SpaceItem", () => {
const cli = stubClient();
const space = mkRoom(cli, "!1:example.org");
space.name = "Root Space";
const subspace = mkRoom(cli, "!2:example.org");
subspace.name = "Subspace";
it("should render a space with subspaces", () => {
mocked(SpaceStore.instance.getChildSpaces).mockImplementation((spaceId) =>
spaceId === space.roomId ? [subspace] : [],
);
const { asFragment, queryByText, getByLabelText } = render(<SpaceItem space={space} activeSpaces={[]} />);
expect(queryByText("Root Space")).toBeVisible();
expect(queryByText("Subspace")).toBeNull();
expect(asFragment()).toMatchSnapshot();
fireEvent.click(getByLabelText("Expand"));
expect(queryByText("Root Space")).toBeVisible();
expect(queryByText("Subspace")).toBeVisible();
expect(asFragment()).toMatchSnapshot();
});
});

View File

@@ -41,7 +41,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
class="mx_AccessibleButton mx_SpacePanel_toggleCollapse"
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.7 17.3a.95.95 0 0 1-.275-.7q0-.425.275-.7l3.9-3.9-3.9-3.9a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l4.6 4.6q.15.15.213.325.062.175.062.375t-.062.375a.9.9 0 0 1-.213.325l-4.6 4.6a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275"
/>
</svg>
</div>
</div>
<ul
aria-label="Spaces"
@@ -58,7 +70,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="Home"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_home mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button"
tabindex="0"
>
@@ -73,7 +85,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12.971 3.54 7 3.889A2 2 0 0 1 21 9.177V19a2 2 0 0 1-2 2h-4v-9H9v9H5a2 2 0 0 1-2-2V9.177a2 2 0 0 1 1.029-1.748l7-3.89a2 2 0 0 1 1.942 0"
/>
</svg>
</div>
</div>
</div>
<div
@@ -83,7 +107,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
class="mx_AccessibleButton mx_SpaceButton_menuButton"
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>
</div>
</li>
@@ -94,7 +130,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="Favourites"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_favourites mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button"
tabindex="-1"
>
@@ -109,7 +145,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m12.897 2.817 2.336 4.733 5.223.76a1 1 0 0 1 .555 1.705L17.23 13.7l.892 5.202a1 1 0 0 1-1.45 1.054L12 17.5l-4.672 2.456a1 1 0 0 1-1.451-1.054l.892-5.202-3.78-3.685a1 1 0 0 1 .555-1.706l5.223-.759 2.336-4.733a1 1 0 0 1 1.794 0"
/>
</svg>
</div>
</div>
</div>
</div>
@@ -122,7 +170,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="People"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_people mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button"
tabindex="-1"
>
@@ -137,7 +185,22 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 15q-1.65 0-2.825-1.175T8 11t1.175-2.825T12 7t2.825 1.175T16 11t-1.175 2.825T12 15"
/>
<path
d="M19.528 18.583A9.96 9.96 0 0 0 22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 2.52.933 4.824 2.472 6.583A9.98 9.98 0 0 0 12 22a9.98 9.98 0 0 0 7.528-3.417M8.75 16.388q-1.373.332-2.709.95a8 8 0 1 1 11.918 0 14.7 14.7 0 0 0-2.709-.95A13.8 13.8 0 0 0 12 16q-1.65 0-3.25.387"
/>
</svg>
</div>
</div>
</div>
</div>
@@ -150,7 +213,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="Other rooms"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_orphans mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button"
tabindex="-1"
>
@@ -165,7 +228,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m8.566 17-.944 4.094q-.086.406-.372.656t-.687.25q-.543 0-.887-.469a1.18 1.18 0 0 1-.2-1.031l.801-3.5H3.158q-.572 0-.916-.484a1.27 1.27 0 0 1-.2-1.078 1.12 1.12 0 0 1 1.116-.938H6.85l1.145-5h-3.12q-.57 0-.915-.484a1.27 1.27 0 0 1-.2-1.078A1.12 1.12 0 0 1 4.875 7h3.691l.945-4.094q.085-.406.372-.656.286-.25.686-.25.544 0 .887.469.345.468.2 1.031l-.8 3.5h4.578l.944-4.094q.085-.406.372-.656.286-.25.687-.25.543 0 .887.469t.2 1.031L17.723 7h3.119q.573 0 .916.484.343.485.2 1.079a1.12 1.12 0 0 1-1.116.937H17.15l-1.145 5h3.12q.57 0 .915.484.343.485.2 1.079a1.12 1.12 0 0 1-1.116.937h-3.691l-.944 4.094q-.087.406-.373.656t-.686.25q-.544 0-.887-.469a1.18 1.18 0 0 1-.2-1.031l.8-3.5zm.573-2.5h4.578l1.144-5h-4.578z"
/>
</svg>
</div>
</div>
</div>
</div>
@@ -178,7 +253,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="Conferences"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_videoRooms mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_narrow mx_SpaceButton_withIcon"
role="button"
tabindex="-1"
>
@@ -193,7 +268,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<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>
</div>
</div>
</div>
@@ -206,7 +293,7 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
aria-label="Create a space"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_new mx_SpaceButton_narrow"
class="mx_AccessibleButton mx_SpaceButton mx_SpaceButton_new mx_SpaceButton_narrow mx_SpaceButton_withIcon"
data-testid="create-space-button"
role="button"
tabindex="-1"
@@ -222,7 +309,19 @@ exports[`<SpacePanel /> should show all activated MetaSpaces in the correct orde
>
<div
class="mx_SpaceButton_icon"
/>
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11 13H6a.97.97 0 0 1-.713-.287A.97.97 0 0 1 5 12q0-.424.287-.713A.97.97 0 0 1 6 11h5V6q0-.424.287-.713A.97.97 0 0 1 12 5q.424 0 .713.287Q13 5.576 13 6v5h5q.424 0 .712.287.288.288.288.713 0 .424-.288.713A.97.97 0 0 1 18 13h-5v5q0 .424-.287.712A.97.97 0 0 1 12 19a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 18z"
/>
</svg>
</div>
</div>
</div>
</div>

View File

@@ -47,3 +47,251 @@ exports[`SpaceButton metaspace should render notificationState if one is provide
</div>
</DocumentFragment>
`;
exports[`SpaceItem should render a space with subspaces 1`] = `
<DocumentFragment>
<li
aria-expanded="false"
aria-selected="false"
class="mx_SpaceItem collapsed hasSubSpaces"
role="treeitem"
>
<div
aria-label="Root Space"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
aria-label="Expand"
class="mx_AccessibleButton mx_SpaceButton_toggleCollapse"
role="button"
tabindex="-1"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.7 17.3a.95.95 0 0 1-.275-.7q0-.425.275-.7l3.9-3.9-3.9-3.9a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l4.6 4.6q.15.15.213.325.062.175.062.375t-.062.375a.9.9 0 0 1-.213.325l-4.6 4.6a.95.95 0 0 1-.7.275.95.95 0 0 1-.7-.275"
/>
</svg>
</div>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 32px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="32px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="32px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Root Space
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
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>
</div>
</li>
</DocumentFragment>
`;
exports[`SpaceItem should render a space with subspaces 2`] = `
<DocumentFragment>
<li
aria-expanded="true"
aria-selected="false"
class="mx_SpaceItem hasSubSpaces"
role="treeitem"
>
<div
aria-label="Root Space"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
aria-label="Collapse"
class="mx_AccessibleButton mx_SpaceButton_toggleCollapse"
role="button"
tabindex="-1"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 32px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="32px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="32px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Root Space
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
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>
</div>
<ul
class="mx_SpaceTreeLevel"
role="group"
>
<li
aria-selected="false"
class="mx_SpaceItem"
role="treeitem"
>
<div
aria-label="Subspace"
class="mx_AccessibleButton mx_SpaceButton"
role="button"
tabindex="-1"
>
<div
class="mx_SpaceButton_selectionWrapper"
>
<div
class="mx_SpaceButton_avatarWrapper"
>
<span
aria-label="Avatar"
class="_avatar_zysgz_8 mx_BaseAvatar"
data-color="4"
data-testid="avatar-img"
data-type="round"
style="--cpd-avatar-size: 24px;"
>
<img
alt=""
class="_image_zysgz_43"
data-type="round"
height="24px"
loading="lazy"
referrerpolicy="no-referrer"
src="http://this.is.a.url/avatar.url/room.png"
width="24px"
/>
</span>
</div>
<span
class="mx_SpaceButton_name"
>
Subspace
</span>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Space options"
class="mx_AccessibleButton mx_SpaceButton_menuButton"
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>
</div>
</li>
</ul>
</li>
</DocumentFragment>
`;