Change avatar to use Compound implementation (#11448)

* Move avatar to new compound implementation

* Make space avatars square

* Remove reference to the avatar initial CSS class

* remove references to mx_BaseAvatar_image

* Fixe test suites

* Fix accessbility violations

* Add ConfirmUserActionDialog test

* Fix tests

* Add FacePile test

* Fix items clipping in members list

* Fix user info avatar sizing

* Fix tests
pull/28788/head^2
Germain 2023-08-24 04:48:35 +01:00 committed by GitHub
parent e34920133e
commit 09c5e06d12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 936 additions and 1413 deletions

View File

@ -232,7 +232,7 @@ describe("General user settings tab", () => {
cy.closeDialog();
// Assert the avatar's initial characters are set
cy.get(".mx_UserMenu .mx_BaseAvatar_initial").findByText("A").should("exist"); // Alice
cy.get(".mx_RoomView_wrapper .mx_BaseAvatar_initial").findByText("A").should("exist"); // Alice
cy.get(".mx_UserMenu .mx_BaseAvatar").findByText("A").should("exist"); // Alice
cy.get(".mx_RoomView_wrapper .mx_BaseAvatar").findByText("A").should("exist"); // Alice
});
});

View File

@ -98,7 +98,7 @@ describe("Threads", () => {
// Wait until the both messages are read
cy.get(".mx_ThreadView .mx_EventTile_last[data-layout=group]").within(() => {
cy.get(".mx_EventTile_line .mx_MTextBody").findByText(MessageLong).should("exist");
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar_image").should("be.visible");
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar").should("be.visible");
// Make sure the CSS style for spacing is applied to mx_EventTile_line on group/modern layout
cy.get(".mx_EventTile_line").should("have.css", "padding-inline-start", ThreadViewGroupSpacingStart);
@ -118,7 +118,7 @@ describe("Threads", () => {
cy.get(".mx_EventTile_line .mx_MTextBody").findByText(MessageLong).should("exist");
// Make sure the avatar inside ReadReceiptGroup is visible on the group layout
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar_image").should("be.visible");
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar").should("be.visible");
});
// Enable the bubble layout
@ -127,12 +127,12 @@ describe("Threads", () => {
cy.get(".mx_ThreadView .mx_EventTile[data-layout='bubble'].mx_EventTile_last").within(() => {
// TODO: remove this after fixing the issue of ReadReceiptGroup being hidden on the bubble layout
// See: https://github.com/vector-im/element-web/issues/23569
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar_image").should("exist");
cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar").should("exist");
// Make sure the avatar inside ReadReceiptGroup is visible on bubble layout
// TODO: enable this after fixing the issue of ReadReceiptGroup being hidden on the bubble layout
// See: https://github.com/vector-im/element-web/issues/23569
// cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar_image").should("be.visible");
// cy.get(".mx_ReadReceiptGroup .mx_BaseAvatar").should("be.visible");
});
// Re-enable the group layout

View File

@ -45,7 +45,7 @@ const expectDisplayName = (e: JQuery<HTMLElement>, displayName: string): void =>
const expectAvatar = (e: JQuery<HTMLElement>, avatarUrl: string): void => {
cy.all([cy.window({ log: false }), cy.getClient()]).then(([win, cli]) => {
const size = AVATAR_SIZE * win.devicePixelRatio;
expect(e.find(".mx_BaseAvatar_image").attr("src")).to.equal(
expect(e.find(".mx_BaseAvatar img").attr("src")).to.equal(
// eslint-disable-next-line no-restricted-properties
cli.mxcUrlToHttp(avatarUrl, size, size, AVATAR_RESIZE_METHOD),
);

View File

@ -111,8 +111,4 @@ limitations under the License.
margin-right: 8px;
vertical-align: middle;
}
.mx_BaseAvatar_image {
border-radius: 8px;
}
}

View File

@ -25,16 +25,6 @@ limitations under the License.
text-align: left;
}
.mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_image {
margin-right: -12px;
border: 1px solid $background;
}
.mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_initial {
padding-left: 1px;
padding-top: 1px;
}
.mx_RoomStatusBar_typingIndicatorRemaining {
display: inline-block;
color: #acacac;

View File

@ -108,12 +108,6 @@ limitations under the License.
}
}
.mx_SpaceHierarchy_subspace {
.mx_BaseAvatar_image {
border-radius: 8px;
}
}
.mx_SpaceHierarchy_subspace_toggle {
position: absolute;
left: -1px;

View File

@ -232,10 +232,6 @@ limitations under the License.
transform: rotate(45deg);
}
.mx_BaseAvatar_image {
border-radius: 8px;
}
.mx_SpaceButton_menuButton {
width: 20px;
min-width: 20px; /* yay flex */
@ -269,19 +265,6 @@ limitations under the License.
min-width: 0;
flex-grow: 1;
.mx_BaseAvatar:not(.mx_UserMenu_userAvatar_BaseAvatar) .mx_BaseAvatar_initial {
color: $secondary-content;
border-radius: 8px;
background-color: $panel-actions;
font-size: $font-15px !important; /* override inline style */
font-weight: var(--cpd-font-weight-semibold);
line-height: $font-18px;
& + .mx_BaseAvatar_image {
visibility: hidden;
}
}
.mx_SpaceTreeLevel {
// Indent subspaces
padding-left: 16px;
@ -290,6 +273,7 @@ limitations under the License.
.mx_SpaceButton_avatarWrapper {
position: relative;
line-height: 0;
}
.mx_SpacePanel_badgeContainer {

View File

@ -143,10 +143,6 @@ limitations under the License.
.mx_BaseAvatar {
width: 80px;
.mx_BaseAvatar_image {
border-radius: 12px;
}
}
}

View File

@ -14,57 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_BaseAvatar {
position: relative;
/* In at least Firefox, the case of relative positioned inline elements */
/* (such as mx_BaseAvatar) with absolute positioned children (such as */
/* mx_BaseAvatar_initial) is a dark corner full of spider webs. It will give */
/* different results during full reflow of the page vs. incremental reflow */
/* of small portions. While that's surely a browser bug, we can avoid it by */
/* using `inline-block` instead of the default `inline`. */
/* https://github.com/vector-im/element-web/issues/5594 */
/* https://bugzilla.mozilla.org/show_bug.cgi?id=1535053 */
/* https://bugzilla.mozilla.org/show_bug.cgi?id=255139 */
display: inline-block;
user-select: none;
&.mx_RoomAvatar_isSpaceRoom {
&.mx_BaseAvatar_image,
.mx_BaseAvatar_image {
border-radius: 8px;
}
}
}
.mx_BaseAvatar_initial {
position: absolute;
left: 0;
color: $avatar-initial-color;
text-align: center;
speak: none;
pointer-events: none;
font-weight: normal;
}
.mx_BaseAvatar_image {
object-fit: cover;
aspect-ratio: 1;
border-radius: 125px;
vertical-align: top;
background-color: $background;
}
/* Percy screenshot test specific CSS */
@media only percy {
/* Stick the default room avatar colour, so it doesn't cause a false diff on the screenshot */
.mx_BaseAvatar_initial {
.mx_BaseAvatar {
background-color: var(--percy-color-avatar) !important;
border-radius: 125px;
}
.mx_RoomAvatar_isSpaceRoom .mx_BaseAvatar_initial {
border-radius: 8px;
}
.mx_BaseAvatar_initial + .mx_BaseAvatar_image {
visibility: hidden;
}
}

View File

@ -18,6 +18,7 @@ limitations under the License.
.mx_ExtraTile {
position: relative;
contain: content;
line-height: 1;
&.mx_DecoratedRoomAvatar_cutout .mx_BaseAvatar {
mask-image: url("$(res)/img/element-icons/roomlist/decorated-avatar-mask.svg");
@ -29,9 +30,9 @@ limitations under the License.
.mx_DecoratedRoomAvatar_icon {
position: absolute;
/* the following percentage based sizings are to match the scalable svg mask for the cutout */
bottom: -6.25%;
right: -6.25%;
margin: 12.5%;
bottom: 0;
right: 0;
transform: translate(-25%, -70%);
width: 25%;
height: 25%;
border-radius: 50%;

View File

@ -157,12 +157,6 @@ limitations under the License.
.mx_SubspaceSelector {
display: flex;
.mx_BaseAvatar_image {
border-radius: 8px;
margin: 0;
vertical-align: unset;
}
.mx_BaseAvatar {
display: inline-flex;
margin: auto 16px auto 5px;
@ -228,16 +222,10 @@ limitations under the License.
display: flex;
margin-top: 12px;
.mx_DecoratedRoomAvatar, /* we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling */
.mx_BaseAvatar.mx_RoomAvatar_isSpaceRoom {
.mx_DecoratedRoomAvatar, /* we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling */ {
margin-right: 12px;
}
img.mx_RoomAvatar_isSpaceRoom,
.mx_RoomAvatar_isSpaceRoom img {
border-radius: 8px;
}
.mx_AddExistingToSpace_entry_name {
font-size: $font-15px;
line-height: 30px;

View File

@ -66,11 +66,6 @@ limitations under the License.
flex-grow: 1;
}
img.mx_RoomAvatar_isSpaceRoom,
.mx_RoomAvatar_isSpaceRoom img {
border-radius: 4px;
}
.mx_ManageRestrictedJoinRuleDialog_entry_name {
margin: 0 8px;
font-size: $font-15px;
@ -98,10 +93,6 @@ limitations under the License.
.mx_BaseAvatar {
margin-right: 12px;
}
.mx_BaseAvatar_image {
border-radius: 8px;
}
}
.mx_ManageRestrictedJoinRuleDialog_section_info {

View File

@ -29,14 +29,10 @@ limitations under the License.
margin-right: -8px;
}
.mx_BaseAvatar_image {
.mx_BaseAvatar {
border: 1px solid var(--facepile-background, $background);
}
.mx_BaseAvatar_initial {
margin: 1px; /* to offset the border on the image */
}
.mx_FacePile_more {
position: relative;
border-radius: 100%;

View File

@ -123,11 +123,6 @@ limitations under the License.
text-overflow: ellipsis;
overflow: hidden;
.mx_BaseAvatar_image {
vertical-align: top;
margin-right: 12px;
}
span {
color: $primary-content;
}

View File

@ -95,49 +95,14 @@ limitations under the License.
.mx_UserInfo_avatar_transition {
max-width: 30vh;
aspect-ratio: 1 / 1;
margin: 0 auto;
transition: 0.5s;
.mx_UserInfo_avatar_transition_child {
/* use padding-top instead of height to make this element square,
as the % in padding is a % of the width (including margin,
that's why we had to put the margin to center on a parent div),
and not a % of the parent height. */
padding-top: 100%;
position: relative;
.mx_BaseAvatar,
.mx_BaseAvatar_initial,
.mx_BaseAvatar_image {
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
width: 100% !important;
height: 100% !important;
}
.mx_BaseAvatar {
&.mx_BaseAvatar_image {
cursor: zoom-in;
}
.mx_BaseAvatar_initial {
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
/* override the calculated sizes so that the letter isn't HUGE */
font-size: 6rem !important;
width: 100% !important;
transition: font-size 0.5s;
& + .mx_BaseAvatar_image {
cursor: default;
}
}
}
.mx_BaseAvatar,
.mx_BaseAvatar img {
width: 100%;
height: 100%;
}
}
}
@ -285,14 +250,6 @@ limitations under the License.
max-width: 72px;
margin: 0 auto;
}
.mx_UserInfo_avatar_transition_child {
.mx_BaseAvatar {
.mx_BaseAvatar_initial {
font-size: 40px !important; /* override the other override because here the avatar is smaller */
}
}
}
}
}
}

View File

@ -67,6 +67,7 @@ limitations under the License.
padding-top: 4px;
padding-bottom: 4px;
position: relative;
line-height: 0;
}
.mx_EntityTile_name {

View File

@ -571,6 +571,7 @@ $left-gutter: 64px;
.mx_EventTile_avatar,
.mx_EventTile_e2eIcon {
line-height: 1;
margin: $spacing-block-start 0 $spacing-block-end;
}

View File

@ -163,10 +163,6 @@ limitations under the License.
cursor: pointer;
}
.mx_LegacyRoomHeader_avatar .mx_BaseAvatar_image {
object-fit: cover;
}
.mx_LegacyRoomHeader_button {
cursor: pointer;
flex: 0 0 auto;

View File

@ -96,7 +96,7 @@ limitations under the License.
display: block;
}
.mx_BaseAvatar.mx_BaseAvatar_image {
.mx_BaseAvatar img {
cursor: zoom-in;
}
}

View File

@ -70,13 +70,6 @@ limitations under the License.
display: flex;
align-items: center;
.mx_RoomAvatar_isSpaceRoom {
&.mx_BaseAvatar_image,
.mx_BaseAvatar_image {
border-radius: 12px;
}
}
.mx_RoomPreviewCard_video {
width: 50px;
height: 50px;

View File

@ -31,10 +31,6 @@ limitations under the License.
margin-left: -12px;
}
.mx_WhoIsTypingTile_avatars .mx_BaseAvatar_initial {
padding-top: 1px;
}
.mx_WhoIsTypingTile_avatars .mx_BaseAvatar {
border: 1px solid $background;
border-radius: 40px;

View File

@ -39,11 +39,6 @@ limitations under the License.
color: $secondary-content;
display: inline-block;
img.mx_RoomAvatar_isSpaceRoom,
.mx_RoomAvatar_isSpaceRoom img {
border-radius: 8px;
}
.mx_BaseAvatar {
margin-right: 8px;
}

View File

@ -177,8 +177,7 @@ export function showAnyInviteErrors(
}
name={name!}
idName={user?.userId}
width={36}
height={36}
size="36px"
/>
</div>
<div className="mx_InviteDialog_tile_nameStack">

View File

@ -56,7 +56,7 @@ export default class NotifProvider extends AutocompleteProvider {
suffix: " ",
component: (
<PillCompletion title="@room" description={_t("Notify the whole room")}>
<RoomAvatar width={24} height={24} room={this.room} />
<RoomAvatar size="24px" room={this.room} />
</PillCompletion>
),
range: range!,

View File

@ -122,7 +122,7 @@ export default class RoomProvider extends AutocompleteProvider {
href: makeRoomPermalink(this.room.client, room.displayedAlias),
component: (
<PillCompletion title={room.room.name} description={room.displayedAlias}>
<RoomAvatar width={24} height={24} room={room.room} />
<RoomAvatar size="24px" room={room.room} />
</PillCompletion>
),
range: range!,

View File

@ -135,7 +135,7 @@ export default class UserProvider extends AutocompleteProvider {
href: makeUserPermalink(user.userId),
component: (
<PillCompletion title={displayName} description={description}>
<MemberAvatar member={user} width={24} height={24} />
<MemberAvatar member={user} size="24px" />
</PillCompletion>
),
range: range!,

View File

@ -59,7 +59,7 @@ const getOwnProfile = (
avatarUrl?: string;
} => ({
displayName: OwnProfileStore.instance.displayName || userId,
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE) ?? undefined,
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(parseInt(AVATAR_SIZE, 10)) ?? undefined,
});
const UserWelcomeTop: React.FC = () => {
@ -84,9 +84,7 @@ const UserWelcomeTop: React.FC = () => {
idName={userId}
name={ownProfile.displayName}
url={ownProfile.avatarUrl}
width={AVATAR_SIZE}
height={AVATAR_SIZE}
resizeMethod="crop"
size={AVATAR_SIZE + "px"}
/>
</MiniAvatarUploader>
@ -106,7 +104,7 @@ const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
}
let introSection: JSX.Element;
if (justRegistered || !OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE)) {
if (justRegistered || !OwnProfileStore.instance.getHttpAvatarUrl(parseInt(AVATAR_SIZE, 10))) {
introSection = <UserWelcomeTop />;
} else {
const brandingConfig = SdkConfig.getObject("branding");

View File

@ -194,15 +194,14 @@ const Tile: React.FC<ITileProps> = ({
let avatar: ReactElement;
if (joinedRoom) {
avatar = <RoomAvatar room={joinedRoom} width={20} height={20} />;
avatar = <RoomAvatar room={joinedRoom} size="20px" />;
} else {
avatar = (
<BaseAvatar
name={name}
idName={room.room_id}
url={room.avatar_url ? mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(20) : null}
width={20}
height={20}
size="20px"
/>
);
}

View File

@ -265,7 +265,7 @@ const SpaceLanding: React.FC<{ space: Room }> = ({ space }) => {
return (
<div className="mx_SpaceRoomView_landing">
<div className="mx_SpaceRoomView_landing_header">
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
<RoomAvatar room={space} size="80px" viewAvatarOnClick={true} type="square" />
</div>
<div className="mx_SpaceRoomView_landing_name">
<RoomName room={space}>

View File

@ -458,9 +458,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
idName={userId}
name={displayName}
url={avatarUrl}
width={avatarSize}
height={avatarSize}
resizeMethod="crop"
size={avatarSize + "px"}
className="mx_UserMenu_userAvatar_BaseAvatar"
/>
{liveAvatarAddon}

View File

@ -19,34 +19,29 @@ limitations under the License.
import React, { useCallback, useContext, useEffect, useState } from "react";
import classNames from "classnames";
import { ResizeMethod, ClientEvent } from "matrix-js-sdk/src/matrix";
import { ClientEvent } from "matrix-js-sdk/src/matrix";
import { Avatar } from "@vector-im/compound-web";
import * as AvatarLogic from "../../../Avatar";
import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { ButtonEvent } from "../elements/AccessibleButton";
import RoomContext from "../../../contexts/RoomContext";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { toPx } from "../../../utils/units";
import { _t } from "../../../languageHandler";
interface IProps {
name?: string; // The name (first initial used as default)
idName?: string; // ID for generating hash colours
name?: React.ComponentProps<typeof Avatar>["name"]; // The name (first initial used as default)
idName?: React.ComponentProps<typeof Avatar>["id"]; // ID for generating hash colours
title?: string; // onHover title text
url?: string | null; // highest priority of them all, shortcut to set in urls[0]
urls?: string[]; // [highest_priority, ... , lowest_priority]
width: number;
height: number;
// XXX: resizeMethod not actually used.
resizeMethod?: ResizeMethod;
defaultToInitialLetter?: boolean; // true to add default url
type?: React.ComponentProps<typeof Avatar>["type"];
size: string;
onClick?: (ev: ButtonEvent) => void;
inputRef?: React.RefObject<HTMLImageElement & HTMLSpanElement>;
inputRef?: React.RefObject<HTMLSpanElement>;
className?: string;
tabIndex?: number;
altText?: string;
ariaLabel?: string;
}
const calculateUrls = (url?: string | null, urls?: string[], lowBandwidth = false): string[] => {
@ -107,120 +102,47 @@ const BaseAvatar: React.FC<IProps> = (props) => {
title,
url,
urls,
width = 40,
height = 40,
resizeMethod = "crop", // eslint-disable-line @typescript-eslint/no-unused-vars
defaultToInitialLetter = true,
size = "40px",
onClick,
inputRef,
className,
type = "round",
altText = _t("Avatar"),
ariaLabel = _t("Avatar"),
...otherProps
} = props;
const [imageUrl, onError] = useImageUrl({ url, urls });
if (!imageUrl && defaultToInitialLetter && name) {
const initialLetter = AvatarLogic.getInitialLetter(name);
const textNode = (
<span
className="mx_BaseAvatar_initial"
aria-hidden="true"
style={{
fontSize: toPx(width * 0.65),
width: toPx(width),
lineHeight: toPx(height),
}}
>
{initialLetter}
</span>
);
const imgNode = (
<img
loading="lazy"
className="mx_BaseAvatar_image"
src={AvatarLogic.defaultAvatarUrlForString(idName || name)}
alt=""
title={title}
onError={onError}
style={{
width: toPx(width),
height: toPx(height),
}}
aria-hidden="true"
data-testid="avatar-img"
/>
);
if (onClick) {
return (
<AccessibleButton
aria-label={ariaLabel}
aria-live="off"
{...otherProps}
element="span"
className={classNames("mx_BaseAvatar", className)}
onClick={onClick}
inputRef={inputRef}
>
{textNode}
{imgNode}
</AccessibleButton>
);
} else {
return (
<span
className={classNames("mx_BaseAvatar", className)}
ref={inputRef}
{...otherProps}
role="presentation"
>
{textNode}
{imgNode}
</span>
);
}
}
const extraProps: Partial<React.ComponentProps<typeof Avatar>> = {};
if (onClick) {
return (
<AccessibleButton
className={classNames("mx_BaseAvatar mx_BaseAvatar_image", className)}
element="img"
src={imageUrl}
onClick={onClick}
onError={onError}
style={{
width: toPx(width),
height: toPx(height),
}}
title={title}
alt={altText}
inputRef={inputRef}
data-testid="avatar-img"
{...otherProps}
/>
);
extraProps["aria-live"] = "off";
extraProps["role"] = "button";
} else if (!imageUrl) {
extraProps["role"] = "presentation";
extraProps["aria-label"] = undefined;
} else {
return (
<img
loading="lazy"
className={classNames("mx_BaseAvatar mx_BaseAvatar_image", className)}
src={imageUrl}
onError={onError}
style={{
width: toPx(width),
height: toPx(height),
}}
title={title}
alt=""
ref={inputRef}
data-testid="avatar-img"
{...otherProps}
/>
);
extraProps["role"] = undefined;
}
return (
<Avatar
ref={inputRef}
src={imageUrl}
id={idName ?? ""}
name={name ?? ""}
type={type}
size={size}
className={classNames("mx_BaseAvatar", className)}
aria-label={altText}
onError={onError}
title={title}
onClick={onClick}
{...extraProps}
{...otherProps}
data-testid="avatar-img"
/>
);
};
export default BaseAvatar;

View File

@ -33,7 +33,7 @@ import TooltipTarget from "../elements/TooltipTarget";
interface IProps {
room: Room;
avatarSize: number;
size: string;
displayBadge?: boolean;
forceCount?: boolean;
oobData?: IOOBData;
@ -207,8 +207,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
<div className={classes}>
<RoomAvatar
room={this.props.room}
width={this.props.avatarSize}
height={this.props.avatarSize}
size={this.props.size}
oobData={this.props.oobData}
viewAvatarOnClick={this.props.viewAvatarOnClick}
/>

View File

@ -30,8 +30,7 @@ import { _t } from "../../../languageHandler";
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
member: RoomMember | null;
fallbackUserId?: string;
width: number;
height: number;
size: string;
resizeMethod?: ResizeMethod;
// Whether the onClick of the avatar should be overridden to dispatch `Action.ViewUser`
viewUserOnClick?: boolean;
@ -44,8 +43,7 @@ interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" |
}
export default function MemberAvatar({
width,
height,
size,
resizeMethod = "crop",
viewUserOnClick,
forceHistorical,
@ -68,8 +66,8 @@ export default function MemberAvatar({
if (member?.name) {
if (member.getMxcAvatarUrl()) {
imageUrl = mediaFromMxc(member.getMxcAvatarUrl() ?? "").getThumbnailOfSourceHttp(
width,
height,
parseInt(size, 10),
parseInt(size, 10),
resizeMethod,
);
}
@ -85,9 +83,7 @@ export default function MemberAvatar({
return (
<BaseAvatar
{...props}
width={width}
height={height}
resizeMethod={resizeMethod}
size={size}
name={name ?? ""}
title={hideTitle ? undefined : title}
idName={member?.userId ?? fallbackUserId}
@ -104,7 +100,6 @@ export default function MemberAvatar({
: props.onClick
}
altText={_t("Profile picture")}
ariaLabel={_t("Profile picture")}
/>
);
}

View File

@ -16,7 +16,6 @@ limitations under the License.
import React, { ComponentProps } from "react";
import { Room, RoomStateEvent, MatrixEvent, EventType, RoomType } from "matrix-js-sdk/src/matrix";
import classNames from "classnames";
import BaseAvatar from "./BaseAvatar";
import ImageView from "../elements/ImageView";
@ -47,9 +46,7 @@ interface IState {
export default class RoomAvatar extends React.Component<IProps, IState> {
public static defaultProps = {
width: 36,
height: 36,
resizeMethod: "crop",
size: "36px",
oobData: {},
};
@ -87,9 +84,9 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
let oobAvatar: string | null = null;
if (props.oobData.avatarUrl) {
oobAvatar = mediaFromMxc(props.oobData.avatarUrl).getThumbnailOfSourceHttp(
props.width,
props.height,
props.resizeMethod,
parseInt(props.size, 10),
parseInt(props.size, 10),
"crop",
);
}
@ -102,7 +99,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
private static getRoomAvatarUrl(props: IProps): string | null {
if (!props.room) return null;
return Avatar.avatarUrlForRoom(props.room, props.width, props.height, props.resizeMethod);
return Avatar.avatarUrlForRoom(props.room, parseInt(props.size, 10), parseInt(props.size, 10), "crop");
}
private onRoomAvatarClick = (): void => {
@ -140,9 +137,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
return (
<BaseAvatar
{...otherProps}
className={classNames(className, {
mx_RoomAvatar_isSpaceRoom: (room?.getType() ?? this.props.oobData?.roomType) === RoomType.Space,
})}
type={(room?.getType() ?? this.props.oobData?.roomType) === RoomType.Space ? "square" : "round"}
name={roomName}
idName={this.roomIdName}
urls={this.state.urls}

View File

@ -24,7 +24,7 @@ import BaseAvatar from "./BaseAvatar";
interface SearchResultAvatarProps {
user: Member | RoomMember;
size: number;
size: string;
}
export function SearchResultAvatar({ user, size }: SearchResultAvatarProps): JSX.Element {
@ -46,11 +46,10 @@ export function SearchResultAvatar({ user, size }: SearchResultAvatarProps): JSX
return (
<BaseAvatar
className="mx_SearchResultAvatar"
url={avatarUrl ? mediaFromMxc(avatarUrl).getSquareThumbnailHttp(size) : null}
url={avatarUrl ? mediaFromMxc(avatarUrl).getSquareThumbnailHttp(parseInt(size, 10)) : null}
name={user.name}
idName={user.userId}
width={size}
height={size}
size={size}
/>
);
}

View File

@ -22,13 +22,12 @@ import { IApp, isAppWidget } from "../../../stores/WidgetStore";
import BaseAvatar, { BaseAvatarType } from "./BaseAvatar";
import { mediaFromMxc } from "../../../customisations/Media";
interface IProps extends Omit<ComponentProps<BaseAvatarType>, "name" | "url" | "urls" | "height" | "width"> {
interface IProps extends Omit<ComponentProps<BaseAvatarType>, "name" | "url" | "urls"> {
app: IApp | IWidget;
height?: number;
width?: number;
size: string;
}
const WidgetAvatar: React.FC<IProps> = ({ app, className, width = 20, height = 20, ...props }) => {
const WidgetAvatar: React.FC<IProps> = ({ app, className, size = "20px", ...props }) => {
let iconUrls = [require("../../../../res/img/element-icons/room/default_app.svg").default];
// heuristics for some better icons until Widgets support their own icons
if (app.type.includes("jitsi")) {
@ -49,8 +48,7 @@ const WidgetAvatar: React.FC<IProps> = ({ app, className, width = 20, height = 2
// MSC2765
url={isAppWidget(app) && app.avatar_url ? mediaFromMxc(app.avatar_url).getSquareThumbnailHttp(20) : null}
urls={iconUrls}
width={width}
height={height}
size={size}
/>
);
};

View File

@ -53,7 +53,7 @@ const BeaconListItem: React.FC<Props & HTMLProps<HTMLLIElement>> = ({ beacon, ..
return (
<li className="mx_BeaconListItem" {...rest}>
{isSelfLocation ? (
<MemberAvatar className="mx_BeaconListItem_avatar" member={beaconMember} height={32} width={32} />
<MemberAvatar className="mx_BeaconListItem_avatar" member={beaconMember} size="32px" />
) : (
<StyledLiveBeaconIcon className="mx_BeaconListItem_avatarIcon" />
)}

View File

@ -54,12 +54,7 @@ const DialogOwnBeaconStatus: React.FC<Props> = ({ roomId }) => {
return (
<div className="mx_DialogOwnBeaconStatus">
{isSelfLocation ? (
<MemberAvatar
className="mx_DialogOwnBeaconStatus_avatar"
member={beaconMember}
height={32}
width={32}
/>
<MemberAvatar className="mx_DialogOwnBeaconStatus_avatar" member={beaconMember} size="32px" />
) : (
<StyledLiveBeaconIcon className="mx_DialogOwnBeaconStatus_avatarIcon" />
)}

View File

@ -62,9 +62,9 @@ export const Entry: React.FC<{
return (
<label className="mx_AddExistingToSpace_entry">
{room?.isSpaceRoom() ? (
<RoomAvatar room={room} height={32} width={32} />
<RoomAvatar room={room} size="32px" />
) : (
<DecoratedRoomAvatar room={room} avatarSize={32} />
<DecoratedRoomAvatar room={room} size="32px" />
)}
<span className="mx_AddExistingToSpace_entry_name">{room.name}</span>
<StyledCheckbox
@ -427,7 +427,7 @@ export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, spac
});
return (
<div key={space.roomId} className={classes}>
<RoomAvatar room={space} width={24} height={24} />
<RoomAvatar room={space} size="24px" />
{space.name || getDisplayAliasForRoom(space) || space.roomId}
</div>
);
@ -445,7 +445,7 @@ export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, spac
return (
<div className="mx_SubspaceSelector">
<RoomAvatar room={value} height={40} width={40} />
<RoomAvatar room={value} size="40px" />
<div>
<h1>{title}</h1>
{body}

View File

@ -102,7 +102,7 @@ export default class ConfirmUserActionDialog extends React.Component<IProps, ISt
);
}
const avatar = <MemberAvatar member={this.props.member} width={48} height={48} />;
const avatar = <MemberAvatar member={this.props.member} size="48px" />;
const name = this.props.member.name;
const userId = this.props.member.userId;

View File

@ -142,7 +142,7 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
title={_t("Open room")}
alignment={Alignment.Top}
>
<DecoratedRoomAvatar room={room} avatarSize={32} />
<DecoratedRoomAvatar room={room} size="32px" />
<span className="mx_ForwardList_entry_name">{room.name}</span>
<RoomContextDetails component="span" className="mx_ForwardList_entry_detail" room={room} />
</AccessibleTooltipButton>
@ -261,12 +261,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
<EntityTile
className="mx_EntityTile_ellipsis"
avatarJsx={
<BaseAvatar
url={require("../../../../res/img/ellipsis.svg").default}
name="..."
width={36}
height={36}
/>
<BaseAvatar url={require("../../../../res/img/ellipsis.svg").default} name="..." size="36px" />
}
name={text}
presenceState="online"

View File

@ -155,9 +155,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
name={oppProfile.displayname}
idName={this.props.verifier.userId}
url={url}
width={48}
height={48}
resizeMethod="crop"
size="48px"
/>
<h2>{oppProfile.displayname}</h2>
</div>
@ -168,8 +166,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
<BaseAvatar
name={this.props.verifier.userId.slice(1)}
idName={this.props.verifier.userId}
width={48}
height={48}
size="48px"
/>
<h2>{this.props.verifier.userId}</h2>
</div>

View File

@ -126,7 +126,7 @@ class DMUserTile extends React.PureComponent<IDMUserTileProps> {
};
public render(): React.ReactNode {
const avatarSize = 20;
const avatarSize = "20px";
const avatar = <SearchResultAvatar user={this.props.member} size={avatarSize} />;
let closeButton;
@ -233,20 +233,21 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
timestamp = <span className="mx_InviteDialog_tile--room_time">{humanTs}</span>;
}
const avatarSize = 36;
const avatarSize = "36px";
const avatar = (this.props.member as ThreepidMember).isEmail ? (
<EmailPillAvatarIcon width={avatarSize} height={avatarSize} />
) : (
<BaseAvatar
url={
this.props.member.getMxcAvatarUrl()
? mediaFromMxc(this.props.member.getMxcAvatarUrl()!).getSquareThumbnailHttp(avatarSize)
? mediaFromMxc(this.props.member.getMxcAvatarUrl()!).getSquareThumbnailHttp(
parseInt(avatarSize, 10),
)
: null
}
name={this.props.member.name}
idName={this.props.member.userId}
width={avatarSize}
height={avatarSize}
size={avatarSize}
/>
);

View File

@ -54,11 +54,7 @@ const Entry: React.FC<{
<label className="mx_ManageRestrictedJoinRuleDialog_entry">
<div>
<div>
{localRoom ? (
<RoomAvatar room={room} height={20} width={20} />
) : (
<RoomAvatar oobData={room} height={20} width={20} />
)}
{localRoom ? <RoomAvatar room={room} size="20px" /> : <RoomAvatar oobData={room} size="20px" />}
<span className="mx_ManageRestrictedJoinRuleDialog_entry_name">{room.name}</span>
</div>
{description && (

View File

@ -53,7 +53,7 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
throw new Error("Cannot render unknown context: " + c.constructor.name);
const header = (
<div className="mx_ServerOfflineDialog_content_context_timeline_header">
<RoomAvatar width={24} height={24} room={c.room} />
<RoomAvatar size="24px" room={c.room} />
<span>{c.room.name}</span>
</div>
);

View File

@ -88,7 +88,7 @@ import { Filter } from "./Filter";
const MAX_RECENT_SEARCHES = 10;
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
const AVATAR_SIZE = 24;
const AVATAR_SIZE = "24px";
interface IProps {
initialText?: string;
@ -609,11 +609,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
endAdornment={<RoomResultContextMenus room={result.room} />}
{...ariaProperties}
>
<DecoratedRoomAvatar
room={result.room}
avatarSize={AVATAR_SIZE}
tooltipProps={{ tabIndex: -1 }}
/>
<DecoratedRoomAvatar room={result.room} size={AVATAR_SIZE} tooltipProps={{ tabIndex: -1 }} />
{result.room.name}
<NotificationBadge notification={notification} />
<RoomContextDetails
@ -702,8 +698,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
avatarUrl: result.publicRoom.avatar_url,
roomType: result.publicRoom.room_type,
}}
width={AVATAR_SIZE}
height={AVATAR_SIZE}
size={AVATAR_SIZE}
/>
<PublicRoomResultDetails
room={result.publicRoom}
@ -843,11 +838,12 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
idName={room.room_id}
url={
room.avatar_url
? mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(AVATAR_SIZE)
? mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(
parseInt(AVATAR_SIZE, 10),
)
: null
}
width={AVATAR_SIZE}
height={AVATAR_SIZE}
size={AVATAR_SIZE}
/>
{room.name || room.canonical_alias}
{room.name && room.canonical_alias && (
@ -1037,7 +1033,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
>
<DecoratedRoomAvatar
room={room}
avatarSize={AVATAR_SIZE}
size={AVATAR_SIZE}
tooltipProps={{ tabIndex: -1 }}
/>
{room.name}
@ -1075,7 +1071,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
viewRoom({ roomId: room.roomId }, false, ev.type !== "click");
}}
>
<DecoratedRoomAvatar room={room} avatarSize={32} tooltipProps={{ tabIndex: -1 }} />
<DecoratedRoomAvatar room={room} size="32px" tooltipProps={{ tabIndex: -1 }} />
{room.name}
</TooltipOption>
))}

View File

@ -94,9 +94,9 @@ export default class AppPermission extends React.Component<IProps, IState> {
const userId = displayName === this.props.creatorUserId ? null : this.props.creatorUserId;
const avatar = this.state.roomMember ? (
<MemberAvatar member={this.state.roomMember} width={38} height={38} />
<MemberAvatar member={this.state.roomMember} size="38px" />
) : (
<BaseAvatar name={this.props.creatorUserId} width={38} height={38} />
<BaseAvatar name={this.props.creatorUserId} size="38px" />
);
const warningTooltipText = (

View File

@ -526,7 +526,7 @@ export default class AppTile extends React.Component<IProps, IState> {
return (
<span>
<WidgetAvatar app={this.props.app} />
<WidgetAvatar app={this.props.app} size="20px" />
<b>{name}</b>
<span>
{title ? titleSpacer : ""}

View File

@ -23,25 +23,19 @@ import TextWithTooltip from "./TextWithTooltip";
interface IProps extends HTMLAttributes<HTMLSpanElement> {
members: RoomMember[];
faceSize: number;
size: string;
overflow: boolean;
tooltip?: ReactNode;
children?: ReactNode;
}
const FacePile: FC<IProps> = ({ members, faceSize, overflow, tooltip, children, ...props }) => {
const FacePile: FC<IProps> = ({ members, size, overflow, tooltip, children, ...props }) => {
const faces = members.map(
tooltip
? (m) => <MemberAvatar key={m.userId} member={m} width={faceSize} height={faceSize} hideTitle />
? (m) => <MemberAvatar key={m.userId} member={m} size={size} hideTitle />
: (m) => (
<TooltipTarget key={m.userId} label={m.name}>
<MemberAvatar
member={m}
width={faceSize}
height={faceSize}
viewUserOnClick={!props.onClick}
hideTitle
/>
<MemberAvatar member={m} size={size} viewUserOnClick={!props.onClick} hideTitle />
</TooltipTarget>
),
);

View File

@ -103,7 +103,7 @@ const GenericEventListSummary: React.FC<IProps> = ({
}),
(member) => member.getMxcAvatarUrl(),
);
const avatars = uniqueMembers.map((m) => <MemberAvatar key={m.userId} member={m} width={14} height={14} />);
const avatars = uniqueMembers.map((m) => <MemberAvatar key={m.userId} member={m} size="14px" />);
body = (
<div className="mx_EventTile_line">
<div className="mx_EventTile_info">

View File

@ -477,8 +477,7 @@ export default class ImageView extends React.Component<IProps, IState> {
<MemberAvatar
member={mxEvent.sender}
fallbackUserId={mxEvent.getSender()}
width={32}
height={32}
size="32px"
viewUserOnClick={true}
/>
);

View File

@ -26,7 +26,7 @@ import { chromeFileInputFix } from "../../../utils/BrowserWorkarounds";
import AccessibleButton from "./AccessibleButton";
import Spinner from "./Spinner";
export const AVATAR_SIZE = 52;
export const AVATAR_SIZE = "52px";
interface IProps {
hasAvatar: boolean;

View File

@ -44,7 +44,7 @@ export const pillRoomNotifLen = (): number => {
return "@room".length;
};
const linkIcon = <LinkIcon className="mx_Pill_LinkIcon mx_BaseAvatar mx_BaseAvatar_image" />;
const linkIcon = <LinkIcon className="mx_Pill_LinkIcon mx_BaseAvatar" />;
const PillRoomAvatar: React.FC<{
shouldShowPillAvatar: boolean;
@ -55,7 +55,7 @@ const PillRoomAvatar: React.FC<{
}
if (room) {
return <RoomAvatar room={room} width={16} height={16} aria-hidden="true" />;
return <RoomAvatar room={room} size="16px" aria-hidden="true" />;
}
return linkIcon;
};
@ -69,9 +69,9 @@ const PillMemberAvatar: React.FC<{
}
if (member) {
return <MemberAvatar member={member} width={16} height={16} aria-hidden="true" hideTitle />;
return <MemberAvatar member={member} size="16px" aria-hidden="true" hideTitle />;
}
return <UserIcon className="mx_Pill_UserIcon mx_BaseAvatar mx_BaseAvatar_image" />;
return <UserIcon className="mx_Pill_UserIcon mx_BaseAvatar" />;
};
export interface PillProps {

View File

@ -77,13 +77,7 @@ const RoomFacePile: FC<IProps> = ({ room, onlyKnownUsers = true, numShown = DEFA
);
return (
<FacePile
members={shownMembers}
faceSize={28}
overflow={members.length > numShown}
tooltip={tooltip}
{...props}
>
<FacePile members={shownMembers} size="28px" overflow={members.length > numShown} tooltip={tooltip} {...props}>
{onlyKnownUsers && (
<span className="mx_FacePile_summary">
{_t("%(count)s people you know have already joined", { count: members.length })}

View File

@ -78,8 +78,7 @@ const Marker = React.forwardRef<HTMLDivElement, Props>(({ id, roomMember, useMem
{roomMember ? (
<MemberAvatar
member={roomMember}
width={36}
height={36}
size="36px"
viewUserOnClick={false}
// no mxid on hover when marker has tooltip
hideTitle={!!tooltip}

View File

@ -31,8 +31,8 @@ const UserAvatar: React.FC = () => {
const userId = matrixClient.getSafeUserId();
const displayName = OwnProfileStore.instance.displayName ?? undefined;
// 40 - 2px border
const avatarSize = 36;
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize) ?? undefined;
const avatarSize = "36px";
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(parseInt(avatarSize, 10)) ?? undefined;
return (
<div className={`mx_ShareType_option-icon ${LocationShareType.Own}`}>
@ -40,9 +40,7 @@ const UserAvatar: React.FC = () => {
idName={userId}
name={displayName}
url={avatarUrl}
width={avatarSize}
height={avatarSize}
resizeMethod="crop"
size={avatarSize}
className="mx_UserMenu_userAvatar_BaseAvatar"
/>
</div>

View File

@ -62,8 +62,7 @@ const ActiveCallEvent = forwardRef<any, ActiveCallEventProps>(
member={mxEvent.sender}
fallbackUserId={mxEvent.getSender()}
viewUserOnClick
width={24}
height={24}
size="24px"
/>
<div className="mx_CallEvent_columns">
<div className="mx_CallEvent_details">
@ -76,7 +75,7 @@ const ActiveCallEvent = forwardRef<any, ActiveCallEventProps>(
active={false}
participantCount={participatingMembers.length}
/>
<FacePile members={facePileMembers} faceSize={24} overflow={facePileOverflow} />
<FacePile members={facePileMembers} size="24px" overflow={facePileOverflow} />
</div>
{call && <GroupCallDuration groupCall={call.groupCall} />}
<AccessibleTooltipButton

View File

@ -290,7 +290,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
<div className={className}>
{silenceIcon}
<div className="mx_LegacyCallEvent_info">
<MemberAvatar member={event.sender} width={32} height={32} />
<MemberAvatar member={event.sender} size="32px" />
<div className="mx_LegacyCallEvent_info_basic">
<div className="mx_LegacyCallEvent_sender">{sender}</div>
<div className="mx_LegacyCallEvent_type">

View File

@ -82,7 +82,7 @@ export default class RoomAvatarEvent extends React.Component<IProps> {
className="mx_RoomAvatarEvent_avatar"
onClick={this.onAvatarClick}
>
<RoomAvatar width={14} height={14} oobData={oobData} />
<RoomAvatar size="14px" oobData={oobData} />
</AccessibleButton>
),
},

View File

@ -186,7 +186,7 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
forceHide={!(isPinned || isMaximised)}
disabled={isPinned || isMaximised}
>
<WidgetAvatar app={app} />
<WidgetAvatar app={app} size="20px" />
<span>{name}</span>
{subtitle}
</AccessibleTooltipButton>
@ -307,7 +307,7 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose })
const header = (
<React.Fragment>
<div className="mx_RoomSummaryCard_avatar" role="presentation">
<RoomAvatar room={room} height={54} width={54} viewAvatarOnClick />
<RoomAvatar room={room} size="54px" viewAvatarOnClick />
<TextWithTooltip
tooltip={isRoomEncrypted ? _t("Encrypted") : _t("Not encrypted")}
class={classNames("mx_RoomSummaryCard_e2ee", {

View File

@ -68,7 +68,6 @@ import ConfirmUserActionDialog from "../dialogs/ConfirmUserActionDialog";
import RoomAvatar from "../avatars/RoomAvatar";
import RoomName from "../elements/RoomName";
import { mediaFromMxc } from "../../../customisations/Media";
import UIStore from "../../../stores/UIStore";
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
import ConfirmSpaceUserActionDialog from "../dialogs/ConfirmSpaceUserActionDialog";
import { bulkSpaceBehaviour } from "../../../utils/space";
@ -1579,8 +1578,7 @@ export const UserInfoHeader: React.FC<{
<MemberAvatar
key={member.userId} // to instantly blank the avatar when UserInfo changes members
member={member as RoomMember}
width={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh
height={2 * 0.3 * UIStore.instance.windowHeight} // 2x@30vh
size="30vh" // 2x@30vh
resizeMethod="scale"
fallbackUserId={member.userId}
onClick={onMemberAvatarClick}
@ -1724,7 +1722,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
if (room?.isSpaceRoom()) {
scopeHeader = (
<div data-testid="space-header" className="mx_RightPanel_scopeHeader">
<RoomAvatar room={room} height={32} width={32} />
<RoomAvatar room={room} size="32px" />
<RoomName room={room} />
</div>
);

View File

@ -184,9 +184,7 @@ export default class EntityTile extends React.PureComponent<IProps, IState> {
e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
}
const av = this.props.avatarJsx || (
<BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />
);
const av = this.props.avatarJsx || <BaseAvatar name={this.props.name} size="36px" aria-hidden="true" />;
// The wrapping div is required to make the magic mouse listener work, for some reason.
return (

View File

@ -1006,28 +1006,28 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
let avatar: JSX.Element | null = null;
let sender: JSX.Element | null = null;
let avatarSize: number;
let avatarSize: string;
let needsSenderProfile: boolean;
if (isRenderingNotification) {
avatarSize = 24;
avatarSize = "24px";
needsSenderProfile = true;
} else if (isInfoMessage) {
// a small avatar, with no sender profile, for
// joins/parts/etc
avatarSize = 14;
avatarSize = "14px";
needsSenderProfile = false;
} else if (
this.context.timelineRenderingType === TimelineRenderingType.ThreadsList ||
(this.context.timelineRenderingType === TimelineRenderingType.Thread && !this.props.continuation)
) {
avatarSize = 32;
avatarSize = "32px";
needsSenderProfile = true;
} else if (eventType === EventType.RoomCreate || isBubbleMessage) {
avatarSize = 0;
avatarSize = "0";
needsSenderProfile = false;
} else if (this.props.layout == Layout.IRC) {
avatarSize = 14;
avatarSize = "14px";
needsSenderProfile = true;
} else if (
(this.props.continuation && this.context.timelineRenderingType !== TimelineRenderingType.File) ||
@ -1035,10 +1035,10 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
ElementCall.CALL_EVENT_TYPE.matches(eventType)
) {
// no avatar or sender profile for continuation messages and call tiles
avatarSize = 0;
avatarSize = "0";
needsSenderProfile = false;
} else {
avatarSize = 30;
avatarSize = "30px";
needsSenderProfile = true;
}
@ -1062,8 +1062,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
<div className="mx_EventTile_avatar">
<MemberAvatar
member={member}
width={avatarSize}
height={avatarSize}
size={avatarSize}
viewUserOnClick={viewUserOnClick}
forceHistorical={this.props.mxEvent.getType() === EventType.RoomMember}
/>
@ -1309,7 +1308,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
</div>
{isRenderingNotification && room ? (
<div className="mx_EventTile_avatar">
<RoomAvatar room={room} width={28} height={28} />
<RoomAvatar room={room} size="28px" />
</div>
) : (
avatar

View File

@ -729,7 +729,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
roomAvatar = (
<DecoratedRoomAvatar
room={this.props.room}
avatarSize={24}
size="24px"
oobData={this.props.oobData}
viewAvatarOnClick={true}
/>

View File

@ -241,12 +241,7 @@ export default class MemberList extends React.Component<IProps, IState> {
<EntityTile
className="mx_EntityTile_ellipsis"
avatarJsx={
<BaseAvatar
url={require("../../../../res/img/ellipsis.svg").default}
name="..."
width={36}
height={36}
/>
<BaseAvatar url={require("../../../../res/img/ellipsis.svg").default} name="..." size="36px" />
}
name={text}
presenceState="online"
@ -412,7 +407,7 @@ export default class MemberList extends React.Component<IProps, IState> {
if (room?.isSpaceRoom()) {
scopeHeader = (
<div className="mx_RightPanel_scopeHeader">
<RoomAvatar room={room} height={32} width={32} />
<RoomAvatar room={room} size="32px" />
<RoomName room={room} />
</div>
);

View File

@ -186,7 +186,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
const name = this.getDisplayName();
const presenceState = member.user?.presence as PresenceState | undefined;
const av = <MemberAvatar member={member} width={36} height={36} aria-hidden="true" />;
const av = <MemberAvatar member={member} size="36px" aria-hidden="true" />;
if (member.user) {
this.userLastModifiedTime = member.user.getLastModifiedTime();

View File

@ -87,8 +87,7 @@ const NewRoomIntro: React.FC = () => {
<React.Fragment>
<RoomAvatar
room={room}
width={AVATAR_SIZE}
height={AVATAR_SIZE}
size={AVATAR_SIZE}
onClick={() => {
defaultDispatcher.dispatch<ViewUserPayload>({
action: Action.ViewUser,
@ -223,9 +222,7 @@ const NewRoomIntro: React.FC = () => {
}
const avatarUrl = room.currentState.getStateEvents(EventType.RoomAvatar, "")?.getContent()?.url;
let avatar = (
<RoomAvatar room={room} width={AVATAR_SIZE} height={AVATAR_SIZE} viewAvatarOnClick={!!avatarUrl} />
);
let avatar = <RoomAvatar room={room} size={AVATAR_SIZE} viewAvatarOnClick={!!avatarUrl} />;
if (!avatarUrl) {
avatar = (

View File

@ -37,7 +37,7 @@ interface IProps {
onUnpinClicked?(): void;
}
const AVATAR_SIZE = 24;
const AVATAR_SIZE = "24px";
export default class PinnedEventTile extends React.Component<IProps> {
public static contextType = MatrixClientContext;
@ -89,8 +89,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
<MemberAvatar
className="mx_PinnedEventTile_senderAvatar"
member={this.props.event.sender}
width={AVATAR_SIZE}
height={AVATAR_SIZE}
size={AVATAR_SIZE}
fallbackUserId={sender}
/>

View File

@ -272,8 +272,7 @@ function ReadReceiptPerson({
<MemberAvatar
member={roomMember}
fallbackUserId={userId}
width={24}
height={24}
size="24px"
aria-hidden="true"
aria-live="off"
resizeMethod="crop"

View File

@ -214,9 +214,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
fallbackUserId={this.props.fallbackUserId}
aria-hidden="true"
aria-live="off"
width={14}
height={14}
resizeMethod="crop"
size="14px"
style={style}
inputRef={this.avatar as RefObject<HTMLImageElement>}
hideTitle

View File

@ -143,7 +143,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
if (!hasOwnSender) {
sender = (
<div className="mx_ReplyTile_sender">
<MemberAvatar member={mxEvent.sender} fallbackUserId={mxEvent.getSender()} width={16} height={16} />
<MemberAvatar member={mxEvent.sender} fallbackUserId={mxEvent.getSender()} size="16px" />
<SenderProfile mxEvent={mxEvent} />
</div>
);

View File

@ -59,7 +59,7 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v
>
<DecoratedRoomAvatar
room={room}
avatarSize={32}
size="32px"
displayBadge={true}
forceCount={true}
tooltipProps={{ tabIndex: isActive ? 0 : -1 }}

View File

@ -113,15 +113,20 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
const globalNotificationState = useGlobalNotificationState();
return (
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
<DecoratedRoomAvatar room={room} avatarSize={40} displayBadge={false} />
<Box
flex="1"
className="mx_RoomHeader_info"
onClick={() => {
showOrHidePanel(RightPanelPhases.RoomSummary);
}}
>
<Flex
as="header"
align="center"
gap="var(--cpd-space-3x)"
className="mx_RoomHeader light-panel"
onClick={() => {
const rightPanel = RightPanelStore.instance;
rightPanel.isOpen
? rightPanel.togglePanel(null)
: rightPanel.setCard({ phase: RightPanelPhases.RoomSummary });
}}
>
<DecoratedRoomAvatar room={room} size="40px" displayBadge={false} />
<Box flex="1" className="mx_RoomHeader_info">
<BodyText
as="div"
size="lg"

View File

@ -564,9 +564,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
name,
avatarUrl: room.avatar_url,
}}
width={32}
height={32}
resizeMethod="crop"
size="32px"
/>
);
const viewRoom = (ev: SyntheticEvent): void => {

View File

@ -95,7 +95,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
inviterSection = (
<div className="mx_RoomPreviewCard_inviter">
<MemberAvatar member={inviter} fallbackUserId={inviteSender} width={32} height={32} />
<MemberAvatar member={inviter} fallbackUserId={inviteSender} size="32px" />
<div>
<div className="mx_RoomPreviewCard_inviter_name">
{_t(
@ -160,15 +160,15 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
if (isVideoRoom) {
avatarRow = (
<>
<RoomAvatar room={room} height={50} width={50} viewAvatarOnClick />
<RoomAvatar room={room} size="50px" viewAvatarOnClick />
<div className="mx_RoomPreviewCard_video" />
<BetaPill onClick={viewLabs} tooltipTitle={_t("Video rooms are a beta feature")} />
</>
);
} else if (room.isSpaceRoom()) {
avatarRow = <RoomAvatar room={room} height={80} width={80} viewAvatarOnClick />;
avatarRow = <RoomAvatar room={room} size="80px" viewAvatarOnClick />;
} else {
avatarRow = <RoomAvatar room={room} height={50} width={50} viewAvatarOnClick />;
avatarRow = <RoomAvatar room={room} size="50px" viewAvatarOnClick />;
}
let notice: string | null = null;

View File

@ -479,7 +479,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
>
<DecoratedRoomAvatar
room={this.props.room}
avatarSize={32}
size="32px"
displayBadge={this.props.isMinimized}
tooltipProps={{ tabIndex: isActive ? 0 : -1 }}
/>

View File

@ -134,7 +134,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
if (this.room?.isSpaceRoom()) {
scopeHeader = (
<div className="mx_RightPanel_scopeHeader">
<RoomAvatar room={this.room} height={32} width={32} />
<RoomAvatar room={this.room} size="32px" />
<RoomName room={this.room} />
</div>
);

View File

@ -101,8 +101,7 @@ export const ThreadMessagePreview: React.FC<IPreviewProps> = ({ thread, showDisp
<MemberAvatar
member={lastReply.sender}
fallbackUserId={lastReply.getSender()}
width={24}
height={24}
size="24px"
className="mx_ThreadSummary_avatar"
/>
{showDisplayname && (

View File

@ -177,8 +177,7 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
<MemberAvatar
key={u.userId}
member={u}
width={24}
height={24}
size="24px"
resizeMethod="crop"
viewUserOnClick={true}
aria-live="off"

View File

@ -133,9 +133,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
networkIcon = (
<BaseAvatar
className="mx_RoomSettingsDialog_protocolIcon"
width={48}
height={48}
resizeMethod="crop"
size="48px"
name={protocolName}
idName={protocolName}
url={avatarUrl}

View File

@ -253,7 +253,7 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
{shownSpaces.map((room) => {
return (
<span key={room.roomId}>
<RoomAvatar room={room} height={32} width={32} />
<RoomAvatar room={room} size="32px" />
{room.name}
</span>
);

View File

@ -82,7 +82,7 @@ const Knock: VFC<{
return (
<div className="mx_PeopleRoomSettingsTab_knock">
<MemberAvatar height={42} member={roomMember} width={42} />
<MemberAvatar member={roomMember} size="42px" />
<div className="mx_PeopleRoomSettingsTab_content">
<span className="mx_PeopleRoomSettingsTab_name">{roomMember.name}</span>
<Timestamp roomMember={roomMember} />

View File

@ -119,7 +119,7 @@ interface IMetaSpaceButtonProps extends ComponentProps<typeof SpaceButton> {
type MetaSpaceButtonProps = Pick<IMetaSpaceButtonProps, "selected" | "isPanelCollapsed">;
const MetaSpaceButton: React.FC<IMetaSpaceButtonProps> = ({ selected, isPanelCollapsed, ...props }) => {
const MetaSpaceButton: React.FC<IMetaSpaceButtonProps> = ({ selected, isPanelCollapsed, size = "32px", ...props }) => {
return (
<li
className={classNames("mx_SpaceItem", {
@ -128,7 +128,7 @@ const MetaSpaceButton: React.FC<IMetaSpaceButtonProps> = ({ selected, isPanelCol
role="treeitem"
aria-selected={selected}
>
<SpaceButton {...props} selected={selected} isNarrow={isPanelCollapsed} />
<SpaceButton {...props} selected={selected} isNarrow={isPanelCollapsed} size={size} />
</li>
);
};
@ -160,6 +160,7 @@ const HomeButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollapsed
notificationState={notificationState}
ContextMenuComponent={HomeButtonContextMenu}
contextMenuTooltip={_t("common|options")}
size="32px"
/>
);
};
@ -173,6 +174,7 @@ const FavouritesButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCol
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Favourites)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Favourites)}
size="32px"
/>
);
};
@ -186,6 +188,7 @@ const PeopleButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollaps
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.People)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.People)}
size="32px"
/>
);
};
@ -199,6 +202,7 @@ const OrphansButton: React.FC<MetaSpaceButtonProps> = ({ selected, isPanelCollap
isPanelCollapsed={isPanelCollapsed}
label={getMetaSpaceName(MetaSpace.Orphans)}
notificationState={SpaceStore.instance.getNotificationState(MetaSpace.Orphans)}
size="32px"
/>
);
};
@ -244,6 +248,7 @@ const CreateSpaceButton: React.FC<Pick<IInnerSpacePanelProps, "isPanelCollapsed"
onClick={onNewClick}
isNarrow={isPanelCollapsed}
innerRef={handle}
size="32px"
/>
{contextMenu}

View File

@ -48,7 +48,7 @@ import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "onClick"> {
interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "onClick" | "size"> {
space?: Room;
spaceKey?: SpaceKey;
className?: string;
@ -57,7 +57,7 @@ interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButto
contextMenuTooltip?: string;
notificationState?: NotificationState;
isNarrow?: boolean;
avatarSize?: number;
size: string;
innerRef?: RefObject<HTMLElement>;
ContextMenuComponent?: ComponentType<ComponentProps<typeof SpaceContextMenu>>;
onClick?(ev?: ButtonEvent): void;
@ -71,7 +71,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
label,
contextMenuTooltip,
notificationState,
avatarSize,
size,
isNarrow,
children,
innerRef,
@ -90,7 +90,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
</div>
);
if (space) {
avatar = <RoomAvatar width={avatarSize} height={avatarSize} room={space} />;
avatar = <RoomAvatar size={size} room={space} type="square" />;
}
let notifBadge;
@ -374,7 +374,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
contextMenuTooltip={_t("Space options")}
notificationState={notificationState}
isNarrow={isPanelCollapsed}
avatarSize={isNested ? 24 : 32}
size={isNested ? "24px" : "32px"}
onKeyDown={this.onKeyDown}
ContextMenuComponent={this.props.space.getMyMembership() === "join" ? SpaceContextMenu : undefined}
>

View File

@ -246,7 +246,7 @@ export const Lobby: FC<LobbyProps> = ({ room, joinCallButtonDisabledTooltip, con
<div className="mx_CallView_lobby">
{children}
<div className="mx_CallView_preview">
<MemberAvatar key={me.userId} member={me} width={200} height={200} resizeMethod="scale" />
<MemberAvatar key={me.userId} member={me} size="200px" resizeMethod="scale" />
<video
ref={videoRef}
style={{ visibility: videoMuted ? "hidden" : undefined }}
@ -398,7 +398,7 @@ const JoinCallView: FC<JoinCallViewProps> = ({ room, resizing, call }) => {
facePile = (
<div className="mx_CallView_participants">
{_t("%(count)s people joined", { count: members.length })}
<FacePile members={shownMembers} faceSize={24} overflow={overflow} />
<FacePile members={shownMembers} size="24px" overflow={overflow} />
</div>
);
}

View File

@ -420,7 +420,7 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
const callRoomId = LegacyCallHandler.instance.roomIdForCall(call);
const callRoom = (callRoomId ? MatrixClientPeg.safeGet().getRoom(callRoomId) : undefined) ?? undefined;
const avatarSize = pipMode ? 76 : 160;
const avatarSize = pipMode ? "76px" : "160px";
const transfereeCall = LegacyCallHandler.instance.getTransfereeForCallId(call.callId);
const isOnHold = isLocalOnHold || isRemoteOnHold;
@ -507,7 +507,7 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
className="mx_LegacyCallView_avatarContainer"
style={{ width: avatarSize, height: avatarSize }}
>
<RoomAvatar room={callRoom} height={avatarSize} width={avatarSize} />
<RoomAvatar room={callRoom} size={avatarSize} />
</div>
</div>
<div className="mx_LegacyCallView_status">{_t("Connecting")}</div>

View File

@ -62,7 +62,7 @@ interface ISecondaryCallInfoProps {
const SecondaryCallInfo: React.FC<ISecondaryCallInfoProps> = ({ callRoom }) => {
return (
<span className="mx_LegacyCallViewHeader_secondaryCallInfo">
<RoomAvatar room={callRoom} height={16} width={16} />
<RoomAvatar room={callRoom} size="16px" />
<span className="mx_LegacyCallView_secondaryCall_roomName">
{_t("%(name)s on hold", { name: callRoom.name })}
</span>
@ -101,7 +101,7 @@ const LegacyCallViewHeader: React.FC<LegacyCallViewHeaderProps> = ({
}
return (
<div className="mx_LegacyCallViewHeader mx_LegacyCallViewHeader_pip" onMouseDown={onPipMouseDown}>
<RoomAvatar room={callRoom} height={32} width={32} />
<RoomAvatar room={callRoom} size="32px" />
<div className="mx_LegacyCallViewHeader_callInfo">
<div className="mx_LegacyCallViewHeader_roomName">{callRoomName}</div>
{onHoldCallRoom && <SecondaryCallInfo callRoom={onHoldCallRoom} />}

View File

@ -203,12 +203,12 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
const callRoom = (callRoomId ? MatrixClientPeg.safeGet().getRoom(callRoomId) : undefined) ?? undefined;
let avatarSize;
if (pipMode && primary) avatarSize = 76;
else if (pipMode && !primary) avatarSize = 16;
else if (!pipMode && primary) avatarSize = 160;
if (pipMode && primary) avatarSize = "76px";
else if (pipMode && !primary) avatarSize = "16px";
else if (!pipMode && primary) avatarSize = "160px";
else; // TBD
content = <RoomAvatar room={callRoom} height={avatarSize} width={avatarSize} />;
content = <RoomAvatar room={callRoom} size={avatarSize} />;
} else {
const videoClasses = classnames("mx_VideoFeed_video", {
mx_VideoFeed_video_mirror:

View File

@ -130,7 +130,7 @@ export function IncomingCallToast({ callEvent }: Props): JSX.Element {
return (
<React.Fragment>
<RoomAvatar room={room ?? undefined} height={24} width={24} />
<RoomAvatar room={room ?? undefined} size="24px" />
<div className="mx_IncomingCallToast_content">
<div className="mx_IncomingCallToast_info">
<span className="mx_IncomingCallToast_room">{room ? room.name : _t("Unknown room")}</span>

View File

@ -112,7 +112,7 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
return (
<React.Fragment>
<RoomAvatar room={room ?? undefined} height={32} width={32} />
<RoomAvatar room={room ?? undefined} size="32px" />
<div className={contentClass}>
<span className="mx_LegacyCallEvent_caller">{room ? room.name : _t("Unknown caller")}</span>
<div className="mx_LegacyCallEvent_type">

View File

@ -76,14 +76,7 @@ export default class HTMLExporter extends Exporter {
}
}
const avatar = (
<BaseAvatar
width={32}
height={32}
name={this.room.name}
title={this.room.name}
url={blob ? avatarPath : ""}
resizeMethod="crop"
/>
<BaseAvatar size="32px" name={this.room.name} title={this.room.name} url={blob ? avatarPath : ""} />
);
return renderToStaticMarkup(avatar);
}

View File

@ -113,7 +113,7 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
});
};
let roomAvatar = <RoomAvatar room={room} width={32} height={32} />;
let roomAvatar = <RoomAvatar room={room} size="32px" />;
let roomName = (
<div className="mx_VoiceBroadcastHeader_room_wrapper">
<div className="mx_VoiceBroadcastHeader_room">{room.name}</div>

View File

@ -95,26 +95,15 @@ exports[`MessagePanel should handle lots of membership events quickly 1`] = `
class="mx_GenericEventListSummary_avatars"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="7"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 14px;"
title="@user:id"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 9.1px; width: 14px; line-height: 14px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 14px; height: 14px;"
title="@user:id"
/>
u
</span>
</span>
<span

View File

@ -18,25 +18,14 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1
class="mx_DecoratedRoomAvatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 24px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 15.600000000000001px; width: 24px; line-height: 24px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 24px; height: 24px;"
/>
u
</span>
</div>
</div>
@ -111,25 +100,14 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
class="mx_DecoratedRoomAvatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 24px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 15.600000000000001px; width: 24px; line-height: 24px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 24px; height: 24px;"
/>
u
</span>
</div>
</div>
@ -198,30 +176,18 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
</span>
</div>
</div>
<span
<button
aria-label="Avatar"
aria-live="off"
class="mx_AccessibleButton mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="button"
tabindex="0"
style="--cpd-avatar-size: 52px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 33.800000000000004px; width: 52px; line-height: 52px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 52px; height: 52px;"
/>
</span>
u
</button>
<h2>
@user:example.com
</h2>
@ -301,25 +267,14 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
class="mx_DecoratedRoomAvatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 24px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 15.600000000000001px; width: 24px; line-height: 24px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 24px; height: 24px;"
/>
u
</span>
</div>
</div>
@ -388,30 +343,18 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
</span>
</div>
</div>
<span
<button
aria-label="Avatar"
aria-live="off"
class="mx_AccessibleButton mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="button"
tabindex="0"
style="--cpd-avatar-size: 52px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 33.800000000000004px; width: 52px; line-height: 52px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 52px; height: 52px;"
/>
</span>
u
</button>
<h2>
@user:example.com
</h2>
@ -566,25 +509,14 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
class="mx_DecoratedRoomAvatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 24px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 15.600000000000001px; width: 24px; line-height: 24px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 24px; height: 24px;"
/>
u
</span>
</div>
</div>
@ -652,30 +584,18 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
<li
class="mx_NewRoomIntro"
>
<span
<button
aria-label="Avatar"
aria-live="off"
class="mx_AccessibleButton mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="button"
tabindex="0"
style="--cpd-avatar-size: 52px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 33.800000000000004px; width: 52px; line-height: 52px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 52px; height: 52px;"
/>
</span>
u
</button>
<h2>
@user:example.com
</h2>

View File

@ -71,25 +71,14 @@ exports[`SpaceHierarchy <SpaceHierarchy /> renders 1`] = `
class="mx_SpaceHierarchy_roomTile_avatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="7"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 13px; width: 20px; line-height: 20px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 20px; height: 20px;"
/>
U
</span>
</div>
<div
@ -152,25 +141,14 @@ exports[`SpaceHierarchy <SpaceHierarchy /> renders 1`] = `
class="mx_SpaceHierarchy_roomTile_avatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="8"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 13px; width: 20px; line-height: 20px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 20px; height: 20px;"
/>
U
</span>
</div>
<div
@ -234,25 +212,14 @@ exports[`SpaceHierarchy <SpaceHierarchy /> renders 1`] = `
class="mx_SpaceHierarchy_roomTile_avatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="8"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 13px; width: 20px; line-height: 20px;"
>
N
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 20px; height: 20px;"
/>
N
</span>
</div>
<div
@ -322,25 +289,14 @@ exports[`SpaceHierarchy <SpaceHierarchy /> renders 1`] = `
class="mx_SpaceHierarchy_roomTile_avatar"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="2"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 13px; width: 20px; line-height: 20px;"
>
N
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 20px; height: 20px;"
/>
N
</span>
</div>
<div

View File

@ -18,25 +18,14 @@ exports[`<UserMenu> when rendered should render as expected 1`] = `
class="mx_UserMenu_userAvatar"
>
<span
class="mx_BaseAvatar mx_UserMenu_userAvatar_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar mx_UserMenu_userAvatar_BaseAvatar"
data-color="2"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 32px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 20.8px; width: 32px; line-height: 32px;"
>
U
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 32px; height: 32px;"
/>
u
</span>
</div>
</div>

View File

@ -36,7 +36,7 @@ describe("MemberAvatar", () => {
function getComponent(props: Partial<ComponentProps<typeof MemberAvatar>>) {
return (
<RoomContext.Provider value={getRoomContext(room, {})}>
<MemberAvatar member={null} width={35} height={35} {...props} />
<MemberAvatar member={null} size="35px" {...props} />
</RoomContext.Provider>
);
}

View File

@ -55,7 +55,6 @@ describe("RoomAvatar", () => {
const room = new Room("!room:example.com", client, client.getSafeUserId());
room.name = "test room";
expect(render(<RoomAvatar room={room} />).container).toMatchSnapshot();
expect(AvatarModule.defaultAvatarUrlForString).toHaveBeenCalledWith(room.roomId);
});
it("should render as expected for a DM room", () => {
@ -64,7 +63,6 @@ describe("RoomAvatar", () => {
room.name = "DM room";
mocked(DMRoomMap.shared().getUserIdForRoomId).mockReturnValue(userId);
expect(render(<RoomAvatar room={room} />).container).toMatchSnapshot();
expect(AvatarModule.defaultAvatarUrlForString).toHaveBeenCalledWith(userId);
});
it("should render as expected for a LocalRoom", () => {
@ -73,6 +71,5 @@ describe("RoomAvatar", () => {
localRoom.name = "local test room";
localRoom.targets.push(new DirectoryMember({ user_id: userId }));
expect(render(<RoomAvatar room={localRoom} />).container).toMatchSnapshot();
expect(AvatarModule.defaultAvatarUrlForString).toHaveBeenCalledWith(userId);
});
});

View File

@ -3,25 +3,14 @@
exports[`RoomAvatar should render as expected for a DM room 1`] = `
<div>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="1"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
D
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
/>
D
</span>
</div>
`;
@ -29,25 +18,14 @@ exports[`RoomAvatar should render as expected for a DM room 1`] = `
exports[`RoomAvatar should render as expected for a LocalRoom 1`] = `
<div>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="7"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
L
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
/>
l
</span>
</div>
`;
@ -55,25 +33,14 @@ exports[`RoomAvatar should render as expected for a LocalRoom 1`] = `
exports[`RoomAvatar should render as expected for a Room 1`] = `
<div>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="2"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
T
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
/>
t
</span>
</div>
`;

View File

@ -11,26 +11,15 @@ exports[`<BeaconMarker /> renders marker when beacon has location 1`] = `
class="mx_Marker_border"
>
<span
class="mx_BaseAvatar"
class="_avatar_i91o9_17 mx_BaseAvatar"
data-color="8"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
title="@alice:server"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
A
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
title="@alice:server"
/>
a
</span>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More