Fix e2e icon rendering (#31454)
* Fix e2e icon rendering Regressed by change to compound icons, due to it relying on a hack of rendering icons atop each other to draw a background. Also fixes a nested tooltip which became annoying during testing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
import React, { type JSX, type ComponentProps, type CSSProperties } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
import { ErrorSolidIcon, ShieldIcon, LockSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t, _td, type TranslationKey } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
@@ -32,31 +33,20 @@ interface Props {
|
||||
onClick?: () => void;
|
||||
hideTooltip?: boolean;
|
||||
tooltipPlacement?: ComponentProps<typeof Tooltip>["placement"];
|
||||
bordered?: boolean;
|
||||
status: E2EStatus;
|
||||
isUser?: boolean;
|
||||
}
|
||||
|
||||
const E2EIcon: React.FC<Props> = ({
|
||||
isUser,
|
||||
status,
|
||||
className,
|
||||
size,
|
||||
onClick,
|
||||
hideTooltip,
|
||||
tooltipPlacement,
|
||||
bordered,
|
||||
}) => {
|
||||
const classes = classNames(
|
||||
{
|
||||
mx_E2EIcon: true,
|
||||
mx_E2EIcon_bordered: bordered,
|
||||
mx_E2EIcon_warning: status === E2EStatus.Warning,
|
||||
mx_E2EIcon_normal: status === E2EStatus.Normal,
|
||||
mx_E2EIcon_verified: status === E2EStatus.Verified,
|
||||
},
|
||||
className,
|
||||
);
|
||||
const icons: Record<E2EStatus, JSX.Element> = {
|
||||
[E2EStatus.Warning]: <ErrorSolidIcon className="mx_E2EIcon_warning" />,
|
||||
[E2EStatus.Normal]: <LockSolidIcon className="mx_E2EIcon_normal" />,
|
||||
[E2EStatus.Verified]: <ShieldIcon className="mx_E2EIcon_verified" />,
|
||||
};
|
||||
|
||||
const E2EIcon: React.FC<Props> = ({ isUser, status, className, size, onClick, hideTooltip, tooltipPlacement }) => {
|
||||
const icon = icons[status];
|
||||
|
||||
const classes = classNames("mx_E2EIcon", className);
|
||||
|
||||
let e2eTitle: TranslationKey | undefined;
|
||||
if (isUser) {
|
||||
@@ -74,19 +64,17 @@ const E2EIcon: React.FC<Props> = ({
|
||||
|
||||
let content: JSX.Element;
|
||||
if (onClick) {
|
||||
content = <AccessibleButton onClick={onClick} className={classes} style={style} data-testid="e2e-icon" />;
|
||||
content = (
|
||||
<AccessibleButton onClick={onClick} className={classes} style={style} data-testid="e2e-icon">
|
||||
{icon}
|
||||
</AccessibleButton>
|
||||
);
|
||||
} else {
|
||||
// Verified and warning icon have a transparent cutout, so add a white background.
|
||||
// The normal icon already has the correct shape and size, so reuse that.
|
||||
if (status === E2EStatus.Verified || status === E2EStatus.Warning) {
|
||||
content = (
|
||||
<div className={classes} style={style} data-testid="e2e-icon">
|
||||
<div className="mx_E2EIcon_normal" />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = <div className={classes} style={style} data-testid="e2e-icon" />;
|
||||
}
|
||||
content = (
|
||||
<div className={classes} style={style} data-testid="e2e-icon">
|
||||
{icon}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!e2eTitle || hideTooltip) {
|
||||
|
||||
@@ -533,8 +533,8 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||
<Tooltip label={_t("composer|room_unencrypted")}>
|
||||
<LockOffIcon
|
||||
aria-label={_t("composer|room_unencrypted")}
|
||||
width={12}
|
||||
height={12}
|
||||
width="12px"
|
||||
height="12px"
|
||||
color="var(--cpd-color-icon-info-primary)"
|
||||
className="mx_E2EIcon mx_MessageComposer_e2eIcon"
|
||||
/>
|
||||
@@ -544,7 +544,12 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||
} else if (this.props.e2eStatus !== E2EStatus.Normal) {
|
||||
leftIcon = (
|
||||
<div className="mx_MessageComposer_e2eIconWrapper">
|
||||
<E2EIcon key="e2eIcon" status={this.props.e2eStatus} className="mx_MessageComposer_e2eIcon" />
|
||||
<E2EIcon
|
||||
key="e2eIcon"
|
||||
status={this.props.e2eStatus}
|
||||
className="mx_MessageComposer_e2eIcon"
|
||||
size={12}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -587,14 +592,20 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
const isTooltipOpen = Boolean(this.state.recordingTimeLeftSeconds);
|
||||
const secondsLeft = this.state.recordingTimeLeftSeconds
|
||||
? Math.round(this.state.recordingTimeLeftSeconds)
|
||||
: 0;
|
||||
controls.push(
|
||||
<VoiceRecordComposerTile
|
||||
key="controls_voice_record"
|
||||
ref={this.voiceRecordingButton}
|
||||
room={this.props.room}
|
||||
relation={this.props.relation}
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
/>,
|
||||
<Tooltip open={isTooltipOpen} description={formatTimeLeft(secondsLeft)} placement="bottom">
|
||||
<VoiceRecordComposerTile
|
||||
key="controls_voice_record"
|
||||
ref={this.voiceRecordingButton}
|
||||
room={this.props.room}
|
||||
relation={this.props.relation}
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
/>
|
||||
</Tooltip>,
|
||||
);
|
||||
} else if (this.context.tombstone) {
|
||||
const replacementRoomId = this.context.tombstone.getContent()["replacement_room"];
|
||||
@@ -636,9 +647,6 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||
);
|
||||
}
|
||||
|
||||
const isTooltipOpen = Boolean(this.state.recordingTimeLeftSeconds);
|
||||
const secondsLeft = this.state.recordingTimeLeftSeconds ? Math.round(this.state.recordingTimeLeftSeconds) : 0;
|
||||
|
||||
const threadId =
|
||||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation.event_id : null;
|
||||
|
||||
@@ -663,55 +671,51 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
||||
});
|
||||
|
||||
return (
|
||||
<Tooltip open={isTooltipOpen} description={formatTimeLeft(secondsLeft)} placement="bottom">
|
||||
<div className={classes} ref={this.ref} role="region" aria-label={_t("a11y|message_composer")}>
|
||||
<div className="mx_MessageComposer_wrapper">
|
||||
<UserIdentityWarning room={this.props.room} key={this.props.room.roomId} />
|
||||
<ReplyPreview
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
/>
|
||||
<div className="mx_MessageComposer_row">
|
||||
{leftIcon}
|
||||
{composer}
|
||||
<div className="mx_MessageComposer_actions">
|
||||
{controls}
|
||||
{canSendMessages && (
|
||||
<MessageComposerButtons
|
||||
addEmoji={this.addEmoji}
|
||||
haveRecording={this.state.haveRecording}
|
||||
isMenuOpen={this.state.isMenuOpen}
|
||||
isStickerPickerOpen={this.state.isStickerPickerOpen}
|
||||
menuPosition={menuPosition}
|
||||
relation={this.props.relation}
|
||||
onRecordStartEndClick={this.onRecordStartEndClick}
|
||||
setStickerPickerOpen={this.setStickerPickerOpen}
|
||||
showLocationButton={
|
||||
!window.electron && SettingsStore.getValue(UIFeature.LocationSharing)
|
||||
}
|
||||
showPollsButton={this.state.showPollsButton}
|
||||
showStickersButton={this.showStickersButton}
|
||||
isRichTextEnabled={this.state.isRichTextEnabled}
|
||||
onComposerModeClick={this.onRichTextToggle}
|
||||
toggleButtonMenu={this.toggleButtonMenu}
|
||||
/>
|
||||
)}
|
||||
{showSendButton && (
|
||||
<SendButton
|
||||
key="controls_send"
|
||||
onClick={this.sendMessage}
|
||||
title={
|
||||
this.state.haveRecording
|
||||
? _t("composer|send_button_voice_message")
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes} ref={this.ref} role="region" aria-label={_t("a11y|message_composer")}>
|
||||
<div className="mx_MessageComposer_wrapper">
|
||||
<UserIdentityWarning room={this.props.room} key={this.props.room.roomId} />
|
||||
<ReplyPreview
|
||||
replyToEvent={this.props.replyToEvent}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
/>
|
||||
<div className="mx_MessageComposer_row">
|
||||
{leftIcon}
|
||||
{composer}
|
||||
<div className="mx_MessageComposer_actions">
|
||||
{controls}
|
||||
{canSendMessages && (
|
||||
<MessageComposerButtons
|
||||
addEmoji={this.addEmoji}
|
||||
haveRecording={this.state.haveRecording}
|
||||
isMenuOpen={this.state.isMenuOpen}
|
||||
isStickerPickerOpen={this.state.isStickerPickerOpen}
|
||||
menuPosition={menuPosition}
|
||||
relation={this.props.relation}
|
||||
onRecordStartEndClick={this.onRecordStartEndClick}
|
||||
setStickerPickerOpen={this.setStickerPickerOpen}
|
||||
showLocationButton={
|
||||
!window.electron && SettingsStore.getValue(UIFeature.LocationSharing)
|
||||
}
|
||||
showPollsButton={this.state.showPollsButton}
|
||||
showStickersButton={this.showStickersButton}
|
||||
isRichTextEnabled={this.state.isRichTextEnabled}
|
||||
onComposerModeClick={this.onRichTextToggle}
|
||||
toggleButtonMenu={this.toggleButtonMenu}
|
||||
/>
|
||||
)}
|
||||
{showSendButton && (
|
||||
<SendButton
|
||||
key="controls_send"
|
||||
onClick={this.sendMessage}
|
||||
title={
|
||||
this.state.haveRecording ? _t("composer|send_button_voice_message") : undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function SendWysiwygComposer({
|
||||
/>
|
||||
);
|
||||
} else if (e2eStatus !== E2EStatus.Normal) {
|
||||
leftIcon = <E2EIcon status={e2eStatus} />;
|
||||
leftIcon = <E2EIcon status={e2eStatus} size={12} />;
|
||||
}
|
||||
return (
|
||||
<ComposerContext.Provider value={defaultContextValue}>
|
||||
|
||||
Reference in New Issue
Block a user