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
This commit is contained in:
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

@ -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: