Use Compound tooltips instead of homegrown in TextWithTooltip & InfoTooltip (#12052)

* Migrate InfoTooltip to use Compound Tooltip

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

* Migrate DecoratedRoomAvatar.tsx to Compound tooltips

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

* Small type tweaks

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

* Remove unused props

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

* Migrate TextWithTooltip.tsx to Compound tooltips

This adds `contain: strict` to #matrixchat which may have side effects.

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

* Update snapshots

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

* Add comment

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

* Update snapshot

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

* Revert accidental layout change to TextWithTooltip from inline to block

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

* Improve test coverage and simplify

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

* Update snapshots

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

* Ditch the sleep call

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

* Improve coverage

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2023-12-19 17:19:54 +00:00 committed by GitHub
parent 5f92dad273
commit 2212fbadd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 209 additions and 75 deletions

View file

@ -16,8 +16,9 @@ limitations under the License.
import React from "react";
import classNames from "classnames";
import { Room, RoomEvent, MatrixEvent, User, UserEvent, EventType, JoinRule } from "matrix-js-sdk/src/matrix";
import { EventType, JoinRule, MatrixEvent, Room, RoomEvent, User, UserEvent } from "matrix-js-sdk/src/matrix";
import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue";
import { Tooltip } from "@vector-im/compound-web";
import RoomAvatar from "./RoomAvatar";
import NotificationBadge from "../rooms/NotificationBadge";
@ -26,10 +27,8 @@ import { NotificationState } from "../../../stores/notifications/NotificationSta
import { isPresenceEnabled } from "../../../utils/presence";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from "../../../languageHandler";
import TextWithTooltip from "../elements/TextWithTooltip";
import DMRoomMap from "../../../utils/DMRoomMap";
import { IOOBData } from "../../../stores/ThreepidInviteStore";
import TooltipTarget from "../elements/TooltipTarget";
interface IProps {
room: Room;
@ -38,7 +37,9 @@ interface IProps {
forceCount?: boolean;
oobData?: IOOBData;
viewAvatarOnClick?: boolean;
tooltipProps?: Omit<React.ComponentProps<typeof TooltipTarget>, "label" | "tooltipClassName" | "className">;
tooltipProps?: {
tabIndex?: number;
};
}
interface IState {
@ -94,9 +95,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
}
private get isPublicRoom(): boolean {
const joinRules = this.props.room.currentState.getStateEvents(EventType.RoomJoinRules, "");
const joinRule = joinRules && joinRules.getContent().join_rule;
return joinRule === JoinRule.Public;
return this.props.room.getJoinRule() === JoinRule.Public;
}
private get dmUser(): User | null {
@ -191,10 +190,9 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
let icon: JSX.Element | undefined;
if (this.state.icon !== Icon.None) {
icon = (
<TextWithTooltip
tooltip={tooltipText(this.state.icon)}
tooltipProps={this.props.tooltipProps}
class={`mx_DecoratedRoomAvatar_icon mx_DecoratedRoomAvatar_icon_${this.state.icon.toLowerCase()}`}
<div
tabIndex={this.props.tooltipProps?.tabIndex ?? 0}
className={`mx_DecoratedRoomAvatar_icon mx_DecoratedRoomAvatar_icon_${this.state.icon.toLowerCase()}`}
/>
);
}
@ -211,7 +209,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
oobData={this.props.oobData}
viewAvatarOnClick={this.props.viewAvatarOnClick}
/>
{icon}
{icon && <Tooltip label={tooltipText(this.state.icon)!}>{icon}</Tooltip>}
{badge}
</div>
);

View file

@ -182,7 +182,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
let defaultServerName: React.ReactNode = this.defaultServer.hsName;
if (this.defaultServer.hsNameIsDifferent) {
defaultServerName = (
<TextWithTooltip class="mx_Login_underlinedServerName" tooltip={this.defaultServer.hsUrl}>
<TextWithTooltip className="mx_Login_underlinedServerName" tooltip={this.defaultServer.hsUrl}>
{this.defaultServer.hsName}
</TextWithTooltip>
);

View file

@ -27,9 +27,9 @@ import MemberAvatar from "../avatars/MemberAvatar";
import BaseAvatar from "../avatars/BaseAvatar";
import Heading from "../typography/Heading";
import AccessibleButton from "./AccessibleButton";
import TextWithTooltip from "./TextWithTooltip";
import { parseUrl } from "../../../utils/UrlUtils";
import { Icon as HelpIcon } from "../../../../res/img/feather-customised/help-circle.svg";
import TooltipTarget from "./TooltipTarget";
interface IProps {
url: string;
@ -116,13 +116,14 @@ export default class AppPermission extends React.Component<IProps, IState> {
</div>
);
const warningTooltip = (
<TextWithTooltip
tooltip={warningTooltipText}
tooltipClass="mx_Tooltip--appPermission mx_Tooltip--appPermission--dark"
class="mx_TextWithTooltip_target--helpIcon"
<TooltipTarget
label={warningTooltipText}
tooltipClassName="mx_Tooltip--appPermission mx_Tooltip--appPermission--dark"
tooltipTargetClassName="mx_TextWithTooltip_target mx_TextWithTooltip_target--helpIcon"
className="mx_TextWithTooltip_tooltip"
>
<HelpIcon className="mx_Icon mx_Icon_12" />
</TextWithTooltip>
</TooltipTarget>
);
// Due to i18n limitations, we can't dedupe the code for variables in these two messages.

View file

@ -17,47 +17,38 @@ limitations under the License.
import React, { ReactNode } from "react";
import classNames from "classnames";
import { Tooltip } from "@vector-im/compound-web";
import { Alignment } from "./Tooltip";
import { _t } from "../../../languageHandler";
import TooltipTarget from "./TooltipTarget";
export enum InfoTooltipKind {
Info = "info",
Warning = "warning",
}
interface ITooltipProps {
tooltip?: React.ReactNode;
interface TooltipProps {
tooltip?: string;
className?: string;
tooltipClassName?: string;
kind?: InfoTooltipKind;
children?: ReactNode;
tabIndex?: number;
}
export default class InfoTooltip extends React.PureComponent<ITooltipProps> {
public constructor(props: ITooltipProps) {
super(props);
}
export default class InfoTooltip extends React.PureComponent<TooltipProps> {
public render(): React.ReactNode {
const { tooltip, children, tooltipClassName, className, kind } = this.props;
const { tooltip, children, className, kind } = this.props;
const title = _t("info_tooltip_title");
const iconClassName =
kind !== InfoTooltipKind.Warning ? "mx_InfoTooltip_icon_info" : "mx_InfoTooltip_icon_warning";
// Tooltip are forced on the right for a more natural feel to them on info icons
return (
<TooltipTarget
tooltipTargetClassName={classNames("mx_InfoTooltip", className)}
className="mx_InfoTooltip_container"
tooltipClassName={classNames("mx_InfoTooltip_tooltip", tooltipClassName)}
label={tooltip || title}
alignment={Alignment.Right}
>
<span className={classNames("mx_InfoTooltip_icon", iconClassName)} aria-label={title} />
{children}
</TooltipTarget>
<Tooltip label={tooltip || title} side="right">
<div className={classNames("mx_InfoTooltip", className)} tabIndex={this.props.tabIndex ?? 0}>
<span className={classNames("mx_InfoTooltip_icon", iconClassName)} aria-label={title} />
{children}
</div>
</Tooltip>
);
}
}

View file

@ -77,7 +77,7 @@ const ServerPicker: React.FC<IProps> = ({ title, dialogTitle, serverConfig, onSe
let serverName: React.ReactNode = serverConfig.isNameResolvable ? serverConfig.hsName : serverConfig.hsUrl;
if (serverConfig.hsNameIsDifferent) {
serverName = (
<TextWithTooltip class="mx_Login_underlinedServerName" tooltip={serverConfig.hsUrl}>
<TextWithTooltip className="mx_Login_underlinedServerName" tooltip={serverConfig.hsUrl}>
{serverConfig.hsName}
</TextWithTooltip>
);

View file

@ -15,16 +15,13 @@
*/
import React, { HTMLAttributes } from "react";
import classNames from "classnames";
import TooltipTarget from "./TooltipTarget";
import { Tooltip } from "@vector-im/compound-web";
interface IProps extends HTMLAttributes<HTMLSpanElement> {
class?: string;
tooltipClass?: string;
tooltip: React.ReactNode;
tooltipProps?: Omit<React.ComponentProps<typeof TooltipTarget>, "label" | "tooltipClassName" | "className">;
onClick?: (ev: React.MouseEvent) => void;
tooltip: string;
tooltipProps?: {
tabIndex?: number;
};
}
export default class TextWithTooltip extends React.Component<IProps> {
@ -33,20 +30,14 @@ export default class TextWithTooltip extends React.Component<IProps> {
}
public render(): React.ReactNode {
const { class: className, children, tooltip, tooltipClass, tooltipProps, ...props } = this.props;
const { className, children, tooltip, tooltipProps } = this.props;
return (
<TooltipTarget
onClick={this.props.onClick}
tooltipTargetClassName={classNames("mx_TextWithTooltip_target", className)}
{...tooltipProps}
label={tooltip}
tooltipClassName={tooltipClass}
className="mx_TextWithTooltip_tooltip"
{...props}
>
{children}
</TooltipTarget>
<Tooltip label={tooltip} side="right">
<span className={className} tabIndex={tooltipProps?.tabIndex ?? 0}>
{children}
</span>
</Tooltip>
);
}
}

View file

@ -170,7 +170,6 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
tabIndex={tabIndex}
onClick={openMenu}
className="mx_RoomSublist_auxButton"
tooltipClassName="mx_RoomSublist_addRoomTooltip"
aria-label={_t("action|add_people")}
title={_t("action|add_people")}
isExpanded={menuDisplayed}
@ -189,7 +188,6 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuCreateChatItem", e);
}}
className="mx_RoomSublist_auxButton"
tooltipClassName="mx_RoomSublist_addRoomTooltip"
aria-label={_t("action|start_chat")}
title={_t("action|start_chat")}
/>
@ -355,7 +353,6 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
tabIndex={tabIndex}
onClick={openMenu}
className="mx_RoomSublist_auxButton"
tooltipClassName="mx_RoomSublist_addRoomTooltip"
aria-label={_t("room_list|add_room_label")}
title={_t("room_list|add_room_label")}
isExpanded={menuDisplayed}

View file

@ -58,7 +58,7 @@ function JoinCallButtonWithCall({ onClick, call }: JoinCallButtonWithCallProps):
className="mx_IncomingCallToast_joinButton"
onClick={onClick}
disabled={disabledTooltip !== null}
tooltip={disabledTooltip}
tooltip={disabledTooltip ?? undefined}
kind="primary"
>
{_t("action|join")}