Improve icon rendering accessibility (#31791)
* Switch to rendered svg for Field select decoration instead of SVG mask Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Replace warning.svg with Compound icon Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Replace device kind icons with Compound Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Draw notification badge decoration using SVG rather than CSS masks Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Replace {collapse,expand}-message icons with Compound Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove stale icon prefetch Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Render icons in AddExistingToSpaceDialog using SVGs rather than CSS masks Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Render icons in Jitsi landing page using SVGs rather than CSS masks Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update screenshot Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix field label Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Revert icon colour Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch to rendering icons as SVG over CSS masks in PollOption Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch to rendering icons as SVG over CSS masks in AnalyticsLearnMoreDialog Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove unused class Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch to rendering icons as SVG over CSS masks in customisedCancelButton mixin Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch to rendering icons as SVG over CSS masks in ThreadSummaryIcon mixin Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Switch to rendering icons as SVG over CSS masks in LegacyCallButton mixin Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove unused classes in TabbedView Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update snapshots Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix `[Object object]` Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix layout issue 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:
committed by
GitHub
parent
edb63922e0
commit
de9a52d046
@@ -93,11 +93,7 @@ function TabLabel<T extends string>({ tab, isActive, showToolip, onClick }: ITab
|
||||
|
||||
let tabIcon: JSX.Element | undefined;
|
||||
if (tab.icon) {
|
||||
if (typeof tab.icon === "object") {
|
||||
tabIcon = tab.icon;
|
||||
} else if (typeof tab.icon === "string") {
|
||||
tabIcon = <span className={`mx_TabbedView_maskedIcon ${tab.icon}`} />;
|
||||
}
|
||||
tabIcon = tab.icon;
|
||||
}
|
||||
|
||||
const id = domIDForTabID(tab.id);
|
||||
|
||||
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React from "react";
|
||||
import { Glass } from "@vector-im/compound-web";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { Phase, SetupEncryptionStore } from "../../../stores/SetupEncryptionStore";
|
||||
@@ -92,7 +93,9 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
||||
onClick={this.onSkipClick}
|
||||
className="mx_CompleteSecurity_skip"
|
||||
aria-label={_t("encryption|verification|after_new_login|skip_verification")}
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
import { RestartIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { CloseIcon, RestartIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import AccessibleButton from "../../../views/elements/AccessibleButton";
|
||||
@@ -77,7 +77,9 @@ export const VerifyEmailModal: React.FC<Props> = ({
|
||||
onClick={onCloseClick}
|
||||
className="mx_Dialog_cancelButton"
|
||||
aria-label={_t("dialog_close_label")}
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import { type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton";
|
||||
import ContextMenu, { type IProps as IContextMenuProps } from "../../structures/ContextMenu";
|
||||
@@ -65,7 +66,9 @@ export default class DialpadContextMenu extends React.Component<IProps, IState>
|
||||
<ContextMenu {...this.props}>
|
||||
<div className="mx_DialPadContextMenuWrapper">
|
||||
<div>
|
||||
<AccessibleButton className="mx_DialPadContextMenu_cancel" onClick={this.onCancelClick} />
|
||||
<AccessibleButton className="mx_DialPadContextMenu_cancel" onClick={this.onCancelClick}>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
<div className="mx_DialPadContextMenu_header">
|
||||
<Field
|
||||
|
||||
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { CheckCircleIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { _t } from "../../../languageHandler";
|
||||
@@ -72,9 +73,18 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
|
||||
{_t("analytics|pseudonymous_usage_data", { analyticsOwner })}
|
||||
</div>
|
||||
<ul className="mx_AnalyticsLearnMore_bullets">
|
||||
<li>{_t("analytics|bullet_1", {}, { Bold: (sub) => <strong>{sub}</strong> })}</li>
|
||||
<li>{_t("analytics|bullet_2", {}, { Bold: (sub) => <strong>{sub}</strong> })}</li>
|
||||
<li>{_t("analytics|disable_prompt")}</li>
|
||||
<li>
|
||||
<CheckCircleIcon />
|
||||
{_t("analytics|bullet_1", {}, { Bold: (sub) => <strong>{sub}</strong> })}
|
||||
</li>
|
||||
<li>
|
||||
<CheckCircleIcon />
|
||||
{_t("analytics|bullet_2", {}, { Bold: (sub) => <strong>{sub}</strong> })}
|
||||
</li>
|
||||
<li>
|
||||
<CheckCircleIcon />
|
||||
{_t("analytics|disable_prompt")}
|
||||
</li>
|
||||
</ul>
|
||||
{privacyPolicyLink}
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import FocusLock from "react-focus-lock";
|
||||
import classNames from "classnames";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { I18nContext } from "@element-hq/web-shared-components";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
@@ -134,7 +135,9 @@ export default class BaseDialog extends React.Component<IProps> {
|
||||
title={_t("action|close")}
|
||||
aria-label={_t("dialog_close_label")}
|
||||
placement="bottom"
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
import React, { type FormEvent } from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import FocusLock from "react-focus-lock";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
@@ -91,7 +92,9 @@ export default abstract class ScrollableBaseModal<
|
||||
onClick={this.onCancel}
|
||||
className="mx_CompoundDialog_cancelButton"
|
||||
aria-label={_t("dialog_close_label")}
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
<form onSubmit={this.onSubmit} className="mx_CompoundDialog_form">
|
||||
<div className="mx_CompoundDialog_content">{this.renderContent()}</div>
|
||||
<div className="mx_CompoundDialog_footer">
|
||||
|
||||
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, type ChangeEvent } from "react";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import Field from "./Field";
|
||||
@@ -74,12 +75,14 @@ export class EditableItem extends React.Component<IItemProps, IItemState> {
|
||||
|
||||
return (
|
||||
<div className="mx_EditableItem">
|
||||
<div
|
||||
<AccessibleButton
|
||||
onClick={this.onRemove}
|
||||
className="mx_EditableItem_delete"
|
||||
title={_t("action|remove")}
|
||||
role="button"
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
<span className="mx_EditableItem_item">{this.props.value}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type Ref } from "react";
|
||||
import React, { type JSX, type Ref } from "react";
|
||||
import classnames from "classnames";
|
||||
|
||||
interface IProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
@@ -16,6 +16,11 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
// If false, they'll be in a div. Putting interactive components that have labels
|
||||
// themselves in labels can cause strange bugs like https://github.com/vector-im/element-web/issues/18031
|
||||
childrenInLabel?: boolean;
|
||||
|
||||
/**
|
||||
* If provided will override the default dot icon drawn for checked state
|
||||
*/
|
||||
icon?: JSX.Element;
|
||||
}
|
||||
|
||||
export default class StyledRadioButton extends React.PureComponent<IProps> {
|
||||
@@ -25,7 +30,7 @@ export default class StyledRadioButton extends React.PureComponent<IProps> {
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const { children, className, disabled, outlined, childrenInLabel, inputRef, ...otherProps } = this.props;
|
||||
const { children, className, disabled, outlined, childrenInLabel, inputRef, icon, ...otherProps } = this.props;
|
||||
const _className = classnames("mx_StyledRadioButton", className, {
|
||||
mx_StyledRadioButton_disabled: disabled,
|
||||
mx_StyledRadioButton_enabled: !disabled,
|
||||
@@ -42,9 +47,9 @@ export default class StyledRadioButton extends React.PureComponent<IProps> {
|
||||
disabled={disabled}
|
||||
{...otherProps}
|
||||
/>
|
||||
{/* Used to render the radio button circle */}
|
||||
<div>
|
||||
<div />
|
||||
{/* Empty div is used to render the radio button circle */}
|
||||
<div>{icon}</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -6,12 +6,21 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, createRef } from "react";
|
||||
import React, { createRef, type JSX } from "react";
|
||||
import { type MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { CallErrorCode, CallState } from "matrix-js-sdk/src/webrtc/call";
|
||||
import classNames from "classnames";
|
||||
import { Clock } from "@element-hq/web-shared-components";
|
||||
import { VolumeOffSolidIcon, VolumeOnSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import {
|
||||
EndCallIcon,
|
||||
VideoCallDeclinedSolidIcon,
|
||||
VideoCallMissedSolidIcon,
|
||||
VideoCallSolidIcon,
|
||||
VoiceCallMissedSolidIcon,
|
||||
VoiceCallSolidIcon,
|
||||
VolumeOffSolidIcon,
|
||||
VolumeOnSolidIcon,
|
||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
@@ -36,6 +45,17 @@ interface IState {
|
||||
length: number;
|
||||
}
|
||||
|
||||
export function getCallStateIcon(isVoice: boolean, state: undefined | "missed" | "declined"): JSX.Element {
|
||||
let icon = isVoice ? <VoiceCallSolidIcon /> : <VideoCallSolidIcon />;
|
||||
if (state === "missed") {
|
||||
icon = isVoice ? <VoiceCallMissedSolidIcon /> : <VideoCallMissedSolidIcon />;
|
||||
} else if (state === "declined") {
|
||||
icon = isVoice ? <EndCallIcon /> : <VideoCallDeclinedSolidIcon />;
|
||||
}
|
||||
|
||||
return <div className="mx_LegacyCallEvent_type_icon">{icon}</div>;
|
||||
}
|
||||
|
||||
export default class LegacyCallEvent extends React.PureComponent<IProps, IState> {
|
||||
private wrapperElement = createRef<HTMLDivElement>();
|
||||
private resizeObserver?: ResizeObserver;
|
||||
@@ -90,11 +110,12 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
||||
private renderCallBackButton(text: string): JSX.Element {
|
||||
return (
|
||||
<AccessibleButton
|
||||
className="mx_LegacyCallEvent_content_button mx_LegacyCallEvent_content_button_callBack"
|
||||
className="mx_LegacyCallEvent_content_button"
|
||||
onClick={this.props.callEventGrouper.callBack}
|
||||
kind="primary"
|
||||
>
|
||||
<span> {text} </span>
|
||||
{this.props.callEventGrouper.isVoice ? <VoiceCallSolidIcon /> : <VideoCallSolidIcon />}
|
||||
{text}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
@@ -122,18 +143,20 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{silenceIcon}
|
||||
<AccessibleButton
|
||||
className="mx_LegacyCallEvent_content_button mx_LegacyCallEvent_content_button_reject"
|
||||
className="mx_LegacyCallEvent_content_button"
|
||||
onClick={this.props.callEventGrouper.rejectCall}
|
||||
kind="danger"
|
||||
>
|
||||
<span> {_t("action|decline")} </span>
|
||||
<EndCallIcon />
|
||||
{_t("action|decline")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton
|
||||
className="mx_LegacyCallEvent_content_button mx_LegacyCallEvent_content_button_answer"
|
||||
className="mx_LegacyCallEvent_content_button"
|
||||
onClick={this.props.callEventGrouper.answerCall}
|
||||
kind="primary"
|
||||
>
|
||||
<span> {_t("action|accept")} </span>
|
||||
{this.props.callEventGrouper.isVoice ? <VoiceCallSolidIcon /> : <VideoCallSolidIcon />}
|
||||
{_t("action|accept")}
|
||||
</AccessibleButton>
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
@@ -265,15 +288,23 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
||||
mx_LegacyCallEvent_voice: isVoice,
|
||||
mx_LegacyCallEvent_video: !isVoice,
|
||||
mx_LegacyCallEvent_narrow: this.state.narrow,
|
||||
mx_LegacyCallEvent_missed: this.props.callEventGrouper.callWasMissed,
|
||||
mx_LegacyCallEvent_noAnswer: callState === CallState.Ended && hangupReason === CallErrorCode.InviteTimeout,
|
||||
mx_LegacyCallEvent_rejected: callState === CallState.Ended && this.props.callEventGrouper.gotRejected,
|
||||
});
|
||||
|
||||
let silenceIcon;
|
||||
if (this.state.narrow && this.state.callState === CallState.Ringing) {
|
||||
silenceIcon = this.renderSilenceIcon();
|
||||
}
|
||||
|
||||
let iconState: Parameters<typeof getCallStateIcon>[1] = undefined;
|
||||
if (this.props.callEventGrouper.callWasMissed) {
|
||||
iconState = "missed";
|
||||
} else if (
|
||||
callState === CallState.Ended &&
|
||||
(hangupReason === CallErrorCode.InviteTimeout || this.props.callEventGrouper.gotRejected)
|
||||
) {
|
||||
iconState = "declined";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_wrapper" ref={this.wrapperElement}>
|
||||
<div className={className}>
|
||||
@@ -283,7 +314,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
||||
<div className="mx_LegacyCallEvent_info_basic">
|
||||
<div className="mx_LegacyCallEvent_sender">{sender}</div>
|
||||
<div className="mx_LegacyCallEvent_type">
|
||||
<div className="mx_LegacyCallEvent_type_icon" />
|
||||
{getCallStateIcon(!!isVoice, iconState)}
|
||||
{callType}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
import React, { type ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { type PollAnswerSubevent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
|
||||
import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { Icon as TrophyIcon } from "../../../../res/img/element-icons/trophy.svg";
|
||||
@@ -85,6 +86,7 @@ const ActivePollOption: React.FC<Omit<PollOptionProps, "totalVoteCount"> & { chi
|
||||
disabled={isEnded}
|
||||
aria-label={ariaLabel}
|
||||
onChange={() => onOptionSelected?.(answer.id)}
|
||||
icon={isChecked ? <CheckIcon /> : undefined}
|
||||
>
|
||||
<div aria-hidden="true">{children}</div>
|
||||
</StyledRadioButton>
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
} from "matrix-js-sdk/src/crypto-api";
|
||||
import { Tooltip } from "@vector-im/compound-web";
|
||||
import { uniqueId } from "lodash";
|
||||
import { CircleIcon, CheckCircleIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { CircleIcon, CheckCircleIcon, ThreadsIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import ReplyChain from "../elements/ReplyChain";
|
||||
import { _t } from "../../../languageHandler";
|
||||
@@ -498,6 +498,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
|
||||
return (
|
||||
<div className="mx_ThreadPanel_replies">
|
||||
<ThreadsIcon />
|
||||
<span className="mx_ThreadPanel_replies_amount">{this.state.thread.length}</span>
|
||||
<ThreadMessagePreview thread={this.state.thread} />
|
||||
</div>
|
||||
@@ -515,12 +516,18 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
if (this.props.highlightLink) {
|
||||
return (
|
||||
<a className="mx_ThreadSummary_icon" href={this.props.highlightLink}>
|
||||
<ThreadsIcon />
|
||||
{_t("timeline|thread_info_basic")}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return <p className="mx_ThreadSummary_icon">{_t("timeline|thread_info_basic")}</p>;
|
||||
return (
|
||||
<p className="mx_ThreadSummary_icon">
|
||||
<ThreadsIcon />
|
||||
{_t("timeline|thread_info_basic")}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type ChangeEvent, createRef, type SyntheticEvent } from "react";
|
||||
import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton";
|
||||
import Field from "../elements/Field";
|
||||
@@ -106,7 +107,9 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
|
||||
return (
|
||||
<div className="mx_DialPadModal">
|
||||
<div>
|
||||
<AccessibleButton className="mx_DialPadModal_cancel" onClick={this.onCancelClick} />
|
||||
<AccessibleButton className="mx_DialPadModal_cancel" onClick={this.onCancelClick}>
|
||||
<CloseIcon />
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
<div className="mx_DialPadModal_header">
|
||||
<form onSubmit={this.onFormSubmit}>{dialPadField}</form>
|
||||
|
||||
@@ -11,14 +11,20 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React from "react";
|
||||
import { CallType, type MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||
import classNames from "classnames";
|
||||
import { VolumeOffSolidIcon, VolumeOnSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import {
|
||||
EndCallIcon,
|
||||
VideoCallSolidIcon,
|
||||
VoiceCallSolidIcon,
|
||||
VolumeOffSolidIcon,
|
||||
VolumeOnSolidIcon,
|
||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../LegacyCallHandler";
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import { _t } from "../languageHandler";
|
||||
import RoomAvatar from "../components/views/avatars/RoomAvatar";
|
||||
import AccessibleButton, { type ButtonEvent } from "../components/views/elements/AccessibleButton";
|
||||
import { getCallStateIcon } from "../components/views/messages/LegacyCallEvent.tsx";
|
||||
|
||||
export const getIncomingLegacyCallToastKey = (callId: string): string => `call_${callId}`;
|
||||
|
||||
@@ -95,34 +101,31 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
|
||||
silenceButtonTooltip = _t("voip|silenced");
|
||||
}
|
||||
|
||||
const contentClass = classNames("mx_IncomingLegacyCallToast_content", {
|
||||
mx_IncomingLegacyCallToast_content_voice: isVoice,
|
||||
mx_IncomingLegacyCallToast_content_video: !isVoice,
|
||||
});
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<RoomAvatar room={room ?? undefined} size="32px" />
|
||||
<div className={contentClass}>
|
||||
<div className="mx_IncomingLegacyCallToast_content">
|
||||
<span className="mx_LegacyCallEvent_caller">{room ? room.name : _t("voip|unknown_caller")}</span>
|
||||
<div className="mx_LegacyCallEvent_type">
|
||||
<div className="mx_LegacyCallEvent_type_icon" />
|
||||
{getCallStateIcon(isVoice, undefined)}
|
||||
{isVoice ? _t("voip|voice_call") : _t("voip|video_call")}
|
||||
</div>
|
||||
<div className="mx_IncomingLegacyCallToast_buttons">
|
||||
<AccessibleButton
|
||||
className="mx_IncomingLegacyCallToast_button mx_IncomingLegacyCallToast_button_decline"
|
||||
className="mx_IncomingLegacyCallToast_button"
|
||||
onClick={this.onRejectClick}
|
||||
kind="danger"
|
||||
>
|
||||
<span> {_t("action|decline")} </span>
|
||||
<EndCallIcon />
|
||||
{_t("action|decline")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton
|
||||
className="mx_IncomingLegacyCallToast_button mx_IncomingLegacyCallToast_button_accept"
|
||||
className="mx_IncomingLegacyCallToast_button"
|
||||
onClick={this.onAnswerClick}
|
||||
kind="primary"
|
||||
>
|
||||
<span> {_t("action|accept")} </span>
|
||||
{isVoice ? <VoiceCallSolidIcon /> : <VideoCallSolidIcon />}
|
||||
{_t("action|accept")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user