Use Compound tooltips more widely (#12128)

* Switch MIMageBody & MStickerBody to Compound Tooltip

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

* Switch E2ePadlock & SentReceipt to Compound Tooltips

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

* Workaround compound bug

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

* Fix tests

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

* Improve coverage

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

* Iterate tests

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

* Iterate tests

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

* Fix tests

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2024-01-11 11:49:24 +00:00 committed by GitHub
parent 88a57fbf39
commit 0820994463
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 76 deletions

View file

@ -21,6 +21,7 @@ import classNames from "classnames";
import { CSSTransition, SwitchTransition } from "react-transition-group";
import { logger } from "matrix-js-sdk/src/logger";
import { ClientEvent, ClientEventHandlerMap } from "matrix-js-sdk/src/matrix";
import { Tooltip } from "@vector-im/compound-web";
import MFileBody from "./MFileBody";
import Modal from "../../../Modal";
@ -520,10 +521,12 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
);
}
const thumbnail = (
const tooltipProps = this.getTooltipProps();
let thumbnail = (
<div
className="mx_MImageBody_thumbnail_container"
style={{ maxHeight, maxWidth, aspectRatio: `${infoWidth}/${infoHeight}` }}
tabIndex={tooltipProps ? 0 : undefined}
>
{placeholder}
@ -537,11 +540,19 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
{!this.props.forExport && !this.state.imgLoaded && (
<div style={{ height: maxHeight, width: maxWidth }} />
)}
{this.state.hover && this.getTooltip()}
</div>
);
if (tooltipProps) {
// We specify isTriggerInteractive=true and make the div interactive manually as a workaround for
// https://github.com/element-hq/compound/issues/294
thumbnail = (
<Tooltip {...tooltipProps} isTriggerInteractive={true}>
{thumbnail}
</Tooltip>
);
}
return this.wrapImage(contentUrl, thumbnail);
}
@ -578,7 +589,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
}
// Overridden by MStickerBody
protected getTooltip(): ReactNode {
protected getTooltipProps(): ComponentProps<typeof Tooltip> | null {
return null;
}

View file

@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ReactNode } from "react";
import React, { ComponentProps, ReactNode } from "react";
import { Tooltip } from "@vector-im/compound-web";
import MImageBody from "./MImageBody";
import { BLURHASH_FIELD } from "../../../utils/image-media";
import Tooltip from "../elements/Tooltip";
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
export default class MStickerBody extends MImageBody {
@ -63,16 +63,16 @@ export default class MStickerBody extends MImageBody {
}
// Tooltip to show on mouse over
protected getTooltip(): ReactNode {
protected getTooltipProps(): ComponentProps<typeof Tooltip> | null {
const content = this.props.mxEvent && this.props.mxEvent.getContent();
if (!content || !content.body || !content.info || !content.info.w) return null;
if (!content?.body || !content.info?.w) return null;
return (
<div style={{ left: content.info.w + "px" }} className="mx_MStickerBody_tooltip">
<Tooltip label={content.body} />
</div>
);
return {
align: "center",
side: "right",
label: content.body,
};
}
// Don't show "Download this_file.png ..."

View file

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { createRef, forwardRef, MouseEvent, ReactNode, useRef } from "react";
import React, { createRef, forwardRef, MouseEvent, ReactNode } from "react";
import classNames from "classnames";
import {
EventStatus,
@ -37,6 +37,7 @@ import { CallErrorCode } from "matrix-js-sdk/src/webrtc/call";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
import { EventShieldColour, EventShieldReason } from "matrix-js-sdk/src/crypto-api";
import { Tooltip } from "@vector-im/compound-web";
import ReplyChain from "../elements/ReplyChain";
import { _t } from "../../../languageHandler";
@ -49,7 +50,6 @@ import RoomAvatar from "../avatars/RoomAvatar";
import MessageContextMenu from "../context_menus/MessageContextMenu";
import { aboveRightOf } from "../../structures/ContextMenu";
import { objectHasDiff } from "../../../utils/objects";
import Tooltip, { Alignment } from "../elements/Tooltip";
import EditorStateTransfer from "../../../utils/EditorStateTransfer";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
@ -79,7 +79,6 @@ import TileErrorBoundary from "../messages/TileErrorBoundary";
import { haveRendererForEvent, isMessageEvent, renderTile } from "../../../events/EventTileFactory";
import ThreadSummary, { ThreadMessagePreview } from "./ThreadSummary";
import { ReadReceiptGroup } from "./ReadReceiptGroup";
import { useTooltip } from "../../../utils/useTooltip";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
import { ElementCall } from "../../../models/Call";
@ -1493,11 +1492,7 @@ interface IE2ePadlockProps {
title: string;
}
interface IE2ePadlockState {
hover: boolean;
}
class E2ePadlock extends React.Component<IE2ePadlockProps, IE2ePadlockState> {
class E2ePadlock extends React.Component<IE2ePadlockProps> {
public constructor(props: IE2ePadlockProps) {
super(props);
@ -1506,30 +1501,14 @@ class E2ePadlock extends React.Component<IE2ePadlockProps, IE2ePadlockState> {
};
}
private onHoverStart = (): void => {
this.setState({ hover: true });
};
private onHoverEnd = (): void => {
this.setState({ hover: false });
};
public render(): React.ReactNode {
let tooltip: JSX.Element | undefined;
if (this.state.hover) {
tooltip = <Tooltip className="mx_EventTile_e2eIcon_tooltip" label={this.props.title} />;
}
public render(): ReactNode {
const classes = `mx_EventTile_e2eIcon mx_EventTile_e2eIcon_${this.props.icon}`;
// We specify isTriggerInteractive=true and make the div interactive manually as a workaround for
// https://github.com/element-hq/compound/issues/294
return (
<div
className={classes}
onMouseEnter={this.onHoverStart}
onMouseLeave={this.onHoverEnd}
aria-label={this.props.title}
>
{tooltip}
</div>
<Tooltip label={this.props.title} isTriggerInteractive={true}>
<div className={classes} tabIndex={0} />
</Tooltip>
);
}
}
@ -1539,7 +1518,6 @@ interface ISentReceiptProps {
}
function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
const tooltipId = useRef(`mx_SentReceipt_${Math.random()}`).current;
const isSent = !messageState || messageState === "sent";
const isFailed = messageState === "not_sent";
const receiptClasses = classNames({
@ -1560,28 +1538,17 @@ function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
} else if (isFailed) {
label = _t("timeline|send_state_failed");
}
const [{ showTooltip, hideTooltip }, tooltip] = useTooltip({
id: tooltipId,
label: label,
alignment: Alignment.TopRight,
});
return (
<div className="mx_EventTile_msgOption">
<div className="mx_ReadReceiptGroup">
<div
className="mx_ReadReceiptGroup_button"
onMouseOver={showTooltip}
onMouseLeave={hideTooltip}
onFocus={showTooltip}
onBlur={hideTooltip}
aria-describedby={tooltipId}
>
<span className="mx_ReadReceiptGroup_container">
<span className={receiptClasses}>{nonCssBadge}</span>
</span>
</div>
{tooltip}
<Tooltip label={label} side="top" align="end">
<div className="mx_ReadReceiptGroup_button">
<span className="mx_ReadReceiptGroup_container">
<span className={receiptClasses}>{nonCssBadge}</span>
</span>
</div>
</Tooltip>
</div>
</div>
);