Refactor ExtraTile to use functional components (#10191)

This commit is contained in:
Germain 2023-02-23 11:57:37 +00:00 committed by GitHub
parent 9349526d94
commit 8f7f855ad4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 73 deletions

View file

@ -1,5 +1,5 @@
/*
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
Copyright 2020 - 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -21,8 +21,9 @@ import { RovingAccessibleButton, RovingAccessibleTooltipButton } from "../../../
import NotificationBadge from "./NotificationBadge";
import { NotificationState } from "../../../stores/notifications/NotificationState";
import { ButtonEvent } from "../elements/AccessibleButton";
import useHover from "../../../hooks/useHover";
interface IProps {
interface ExtraTileProps {
isMinimized: boolean;
isSelected: boolean;
displayName: string;
@ -31,83 +32,68 @@ interface IProps {
onClick: (ev: ButtonEvent) => void;
}
interface IState {
hover: boolean;
}
export default function ExtraTile({
isSelected,
isMinimized,
notificationState,
displayName,
onClick,
avatar,
}: ExtraTileProps): JSX.Element {
const [, { onMouseOver, onMouseLeave }] = useHover(() => false);
export default class ExtraTile extends React.Component<IProps, IState> {
public constructor(props: IProps) {
super(props);
// XXX: We copy classes because it's easier
const classes = classNames({
mx_ExtraTile: true,
mx_RoomTile: true,
mx_RoomTile_selected: isSelected,
mx_RoomTile_minimized: isMinimized,
});
this.state = {
hover: false,
};
let badge: JSX.Element | null = null;
if (notificationState) {
badge = <NotificationBadge notification={notificationState} forceCount={false} />;
}
private onTileMouseEnter = (): void => {
this.setState({ hover: true });
};
let name = displayName;
if (typeof name !== "string") name = "";
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
private onTileMouseLeave = (): void => {
this.setState({ hover: false });
};
const nameClasses = classNames({
mx_RoomTile_title: true,
mx_RoomTile_titleHasUnreadEvents: notificationState?.isUnread,
});
public render(): React.ReactElement {
// XXX: We copy classes because it's easier
const classes = classNames({
mx_ExtraTile: true,
mx_RoomTile: true,
mx_RoomTile_selected: this.props.isSelected,
mx_RoomTile_minimized: this.props.isMinimized,
});
let nameContainer: JSX.Element | null = (
<div className="mx_RoomTile_titleContainer">
<div title={name} className={nameClasses} tabIndex={-1} dir="auto">
{name}
</div>
</div>
);
if (isMinimized) nameContainer = null;
let badge;
if (this.props.notificationState) {
badge = <NotificationBadge notification={this.props.notificationState} forceCount={false} />;
}
let Button = RovingAccessibleButton;
if (isMinimized) {
Button = RovingAccessibleTooltipButton;
}
let name = this.props.displayName;
if (typeof name !== "string") name = "";
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
const nameClasses = classNames({
mx_RoomTile_title: true,
mx_RoomTile_titleHasUnreadEvents: this.props.notificationState?.isUnread,
});
let nameContainer = (
<div className="mx_RoomTile_titleContainer">
<div title={name} className={nameClasses} tabIndex={-1} dir="auto">
{name}
return (
<Button
className={classes}
onMouseEnter={onMouseOver}
onMouseLeave={onMouseLeave}
onClick={onClick}
role="treeitem"
title={isMinimized ? name : undefined}
>
<div className="mx_RoomTile_avatarContainer">{avatar}</div>
<div className="mx_RoomTile_details">
<div className="mx_RoomTile_primaryDetails">
{nameContainer}
<div className="mx_RoomTile_badgeContainer">{badge}</div>
</div>
</div>
);
if (this.props.isMinimized) nameContainer = null;
let Button = RovingAccessibleButton;
if (this.props.isMinimized) {
Button = RovingAccessibleTooltipButton;
}
return (
<React.Fragment>
<Button
className={classes}
onMouseEnter={this.onTileMouseEnter}
onMouseLeave={this.onTileMouseLeave}
onClick={this.props.onClick}
role="treeitem"
title={this.props.isMinimized ? name : undefined}
>
<div className="mx_RoomTile_avatarContainer">{this.props.avatar}</div>
<div className="mx_RoomTile_details">
<div className="mx_RoomTile_primaryDetails">
{nameContainer}
<div className="mx_RoomTile_badgeContainer">{badge}</div>
</div>
</div>
</Button>
</React.Fragment>
);
}
</Button>
);
}

View file

@ -82,7 +82,7 @@ interface IProps {
alwaysVisible?: boolean;
forceExpanded?: boolean;
resizeNotifier: ResizeNotifier;
extraTiles?: ReactComponentElement<typeof ExtraTile>[];
extraTiles?: ReactComponentElement<typeof ExtraTile>[] | null;
onListCollapse?: (isExpanded: boolean) => void;
}
@ -170,7 +170,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
return RoomSublist.calcNumTiles(this.state.rooms, this.extraTiles);
}
private static calcNumTiles(rooms: Room[], extraTiles: any[]): number {
private static calcNumTiles(rooms: Room[], extraTiles?: any[] | null): number {
return (rooms || []).length + (extraTiles || []).length;
}