Tooltip: improve accessibility in room (#12493)

* Migrate to `AccessibleButton`

* Update snapshots

* Update snapshots
This commit is contained in:
Florian Duros 2024-05-07 12:20:46 +02:00 committed by GitHub
parent 18ef97161a
commit caef3c1921
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 38 additions and 69 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

@ -49,8 +49,3 @@ limitations under the License.
height: 32px;
}
}
.mx_RoomBreadcrumbs_Tooltip {
margin-left: -42px;
margin-top: -42px;
}

View file

@ -18,7 +18,6 @@ import React, { ComponentProps, useContext } from "react";
import classNames from "classnames";
import AccessibleButton from "../elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { OverflowMenuContext } from "./MessageComposerButtons";
import { IconizedContextMenuOption } from "../context_menus/IconizedContextMenu";
import { Ref } from "../../../accessibility/roving/types";
@ -43,13 +42,8 @@ export const CollapsibleButton: React.FC<Props> = ({
}
return (
<AccessibleTooltipButton
{...props}
title={title}
className={classNames(className, iconClassName)}
ref={inputRef}
>
<AccessibleButton {...props} title={title} className={classNames(className, iconClassName)} ref={inputRef}>
{children}
</AccessibleTooltipButton>
</AccessibleButton>
);
};

View file

@ -33,7 +33,6 @@ import RoomHeaderButtons from "../right_panel/LegacyRoomHeaderButtons";
import E2EIcon from "./E2EIcon";
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import RoomTopic from "../elements/RoomTopic";
import RoomName from "../elements/RoomName";
import { E2EStatus } from "../../../utils/ShieldUtils";
@ -68,7 +67,6 @@ import IconizedContextMenu, {
} from "../context_menus/IconizedContextMenu";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { SessionDuration } from "../voip/CallDuration";
import { Alignment } from "../elements/Tooltip";
import RoomCallBanner from "../beacon/RoomCallBanner";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
@ -111,12 +109,12 @@ const VoiceCallButton: FC<VoiceCallButtonProps> = ({ room, busy, setBusy, behavi
}, [behavior, room, setBusy]);
return (
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_voiceCallButton"
onClick={onClick}
title={_t("voip|voice_call")}
tooltip={tooltip ?? _t("voip|voice_call")}
alignment={Alignment.Bottom}
aria-label={_t("voip|voice_call")}
title={tooltip ?? _t("voip|voice_call")}
placement="bottom"
disabled={disabled || busy}
/>
);
@ -237,13 +235,13 @@ const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavi
return (
<>
<AccessibleTooltipButton
<AccessibleButton
ref={buttonRef}
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_videoCallButton"
onClick={onClick}
title={_t("voip|video_call")}
tooltip={tooltip ?? _t("voip|video_call")}
alignment={Alignment.Bottom}
aria-label={_t("voip|video_call")}
title={tooltip ?? _t("voip|video_call")}
placement="bottom"
disabled={disabled || busy}
/>
{menu}
@ -442,7 +440,7 @@ const CallLayoutSelector: FC<CallLayoutSelectorProps> = ({ call }) => {
return (
<>
<AccessibleTooltipButton
<AccessibleButton
ref={buttonRef}
className={classNames("mx_LegacyRoomHeader_button", {
"mx_LegacyRoomHeader_layoutButton--freedom": layout === Layout.Tile,
@ -450,7 +448,7 @@ const CallLayoutSelector: FC<CallLayoutSelectorProps> = ({ call }) => {
})}
onClick={onClick}
title={_t("room|header|video_call_ec_change_layout")}
alignment={Alignment.Bottom}
placement="bottom"
key="layout"
/>
{menu}
@ -600,11 +598,11 @@ export default class RoomHeader extends React.Component<IProps, IState> {
if (!this.props.viewingCall && this.props.onForgetClick) {
startButtons.push(
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_forgetButton"
onClick={this.props.onForgetClick}
title={_t("room|header|forget_room_button")}
alignment={Alignment.Bottom}
placement="bottom"
key="forget"
/>,
);
@ -612,7 +610,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
if (!this.props.viewingCall && this.props.onAppsClick) {
startButtons.push(
<AccessibleTooltipButton
<AccessibleButton
className={classNames("mx_LegacyRoomHeader_button mx_LegacyRoomHeader_appsButton", {
mx_LegacyRoomHeader_appsButton_highlight: this.props.appsShown,
})}
@ -623,7 +621,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
: _t("room|header|show_widgets_button")
}
aria-checked={this.props.appsShown}
alignment={Alignment.Bottom}
placement="bottom"
key="apps"
/>,
);
@ -631,11 +629,11 @@ export default class RoomHeader extends React.Component<IProps, IState> {
if (!this.props.viewingCall && this.props.onSearchClick && this.props.inRoom) {
startButtons.push(
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_searchButton"
onClick={this.props.onSearchClick}
title={_t("action|search")}
alignment={Alignment.Bottom}
placement="bottom"
key="search"
/>,
);
@ -643,11 +641,11 @@ export default class RoomHeader extends React.Component<IProps, IState> {
if (this.props.onInviteClick && (!this.props.viewingCall || isVideoRoom) && this.props.inRoom) {
startButtons.push(
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_inviteButton"
onClick={this.props.onInviteClick}
title={_t("action|invite")}
alignment={Alignment.Bottom}
placement="bottom"
key="invite"
/>,
);
@ -667,11 +665,11 @@ export default class RoomHeader extends React.Component<IProps, IState> {
);
} else {
endButtons.push(
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyRoomHeader_button mx_LegacyRoomHeader_minimiseButton"
onClick={this.onHideCallClick}
title={_t("room|header|video_room_view_chat_button")}
alignment={Alignment.Bottom}
placement="bottom"
key="minimise"
/>,
);
@ -754,7 +752,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
onClick={this.onContextMenuOpenClick}
isExpanded={!!this.state.contextMenuPosition}
title={_t("room|context_menu|title")}
alignment={Alignment.Bottom}
placement="bottom"
>
{roomName}
{this.props.room && <div className="mx_LegacyRoomHeader_chevron" />}

View file

@ -27,7 +27,6 @@ import { _t } from "../../../languageHandler";
import { formatDate } from "../../../DateUtils";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { getUserNameColorClass } from "../../../utils/FormattingUtils";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
@ -76,7 +75,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
let unpinButton: JSX.Element | undefined;
if (this.props.onUnpinClicked) {
unpinButton = (
<AccessibleTooltipButton
<AccessibleButton
onClick={this.props.onUnpinClicked}
className="mx_PinnedEventTile_unpinButton"
title={_t("action|unpin")}

View file

@ -26,9 +26,8 @@ import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
import Toolbar from "../../../accessibility/Toolbar";
import { Action } from "../../../dispatcher/actions";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { ButtonEvent } from "../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
interface IProps {}
@ -47,15 +46,15 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v
const [onFocus, isActive, ref] = useRovingTabIndex();
return (
<AccessibleTooltipButton
<AccessibleButton
className="mx_RoomBreadcrumbs_crumb"
onClick={onClick}
aria-label={_t("a11y|room_name", { name: room.name })}
title={room.name}
tooltipClassName="mx_RoomBreadcrumbs_Tooltip"
onFocus={onFocus}
ref={ref}
tabIndex={isActive ? 0 : -1}
placement="right"
>
<DecoratedRoomAvatar
room={room}
@ -64,7 +63,7 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v
hideIfDot={true}
tooltipProps={{ tabIndex: isActive ? 0 : -1 }}
/>
</AccessibleTooltipButton>
</AccessibleButton>
);
};

View file

@ -57,10 +57,10 @@ import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import ExtraTile from "./ExtraTile";
import RoomSublist, { IAuxButtonProps } from "./RoomSublist";
import { SdkContextClass } from "../../../contexts/SDKContext";
import AccessibleButton from "../elements/AccessibleButton";
interface IProps {
onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void;
@ -185,7 +185,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
);
} else if (!activeSpace && showCreateRooms) {
return (
<AccessibleTooltipButton
<AccessibleButton
tabIndex={tabIndex}
onClick={(e) => {
dispatcher.dispatch({ action: "view_create_chat" });

View file

@ -49,7 +49,6 @@ import ContextMenu, {
StyledMenuItemRadio,
} from "../../structures/ContextMenu";
import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import ExtraTile from "./ExtraTile";
import SettingsStore from "../../../settings/SettingsStore";
import { SlidingSyncManager } from "../../../SlidingSyncManager";
@ -684,11 +683,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
const badgeContainer = <div className="mx_RoomSublist_badgeContainer">{badge}</div>;
let Button: React.ComponentType<React.ComponentProps<typeof AccessibleButton>> = AccessibleButton;
if (this.props.isMinimized) {
Button = AccessibleTooltipButton;
}
// Note: the addRoomButton conditionally gets moved around
// the DOM depending on whether or not the list is minimized.
// If we're minimized, we want it below the header so it
@ -707,7 +701,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
>
<div className="mx_RoomSublist_stickableContainer">
<div className="mx_RoomSublist_stickable">
<Button
<AccessibleButton
onFocus={onFocus}
ref={ref}
tabIndex={tabIndex}
@ -719,7 +713,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
>
<span className={collapseClasses} />
<span id={getLabelId(this.props.tagId)}>{this.props.label}</span>
</Button>
</AccessibleButton>
{this.renderMenu()}
{this.props.isMinimized ? null : badgeContainer}
{this.props.isMinimized ? null : addRoomButton}

View file

@ -37,7 +37,6 @@ import NotificationBadge from "./NotificationBadge";
import { ActionPayload } from "../../../dispatcher/payloads";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { NotificationState, NotificationStateEvents } from "../../../stores/notifications/NotificationState";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
import { CachedRoomKey, RoomEchoChamber } from "../../../stores/local-echo/RoomEchoChamber";
import { PROPERTY_UPDATED } from "../../../stores/local-echo/GenericEchoChamber";
@ -464,21 +463,11 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
ariaDescribedBy = messagePreviewId(this.props.room.roomId);
}
const props: Partial<React.ComponentProps<typeof AccessibleTooltipButton>> = {};
let Button: React.ComponentType<React.ComponentProps<typeof AccessibleButton>> = AccessibleButton;
if (this.props.isMinimized) {
Button = AccessibleTooltipButton;
props.title = name;
// force the tooltip to hide whilst we are showing the context menu
props.forceHide = !!this.state.generalMenuPosition;
}
return (
<React.Fragment>
<RovingTabIndexWrapper inputRef={this.roomTileRef}>
{({ onFocus, isActive, ref }) => (
<Button
{...props}
<AccessibleButton
onFocus={onFocus}
tabIndex={isActive ? 0 : -1}
ref={ref}
@ -489,6 +478,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
aria-label={ariaLabel}
aria-selected={this.state.selected}
aria-describedby={ariaDescribedBy}
title={this.props.isMinimized && !this.state.generalMenuPosition ? name : undefined}
>
<DecoratedRoomAvatar
room={this.props.room}
@ -500,7 +490,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
{badge}
{this.renderGeneralMenu()}
{this.renderNotificationsMenu(isActive)}
</Button>
</AccessibleButton>
)}
</RovingTabIndexWrapper>
</React.Fragment>

View file

@ -19,7 +19,6 @@ import { Room, IEventRelation, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { Optional } from "matrix-events-sdk";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { _t } from "../../../languageHandler";
import { RecordingState } from "../../../audio/VoiceRecording";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
@ -44,6 +43,7 @@ import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import RoomContext from "../../../contexts/RoomContext";
import { IUpload, VoiceMessageRecording } from "../../../audio/VoiceMessageRecording";
import { createVoiceMessageContent } from "../../../utils/createVoiceMessageContent";
import AccessibleButton from "../elements/AccessibleButton";
interface IProps {
room: Room;
@ -271,7 +271,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
}
stopBtn = (
<AccessibleTooltipButton
<AccessibleButton
className="mx_VoiceRecordComposerTile_stop"
onClick={this.onRecordStartEndClick}
title={tooltip}
@ -284,7 +284,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
if (this.state.recorder && this.state.recordingPhase !== RecordingState.Uploading) {
deleteButton = (
<AccessibleTooltipButton
<AccessibleButton
className="mx_VoiceRecordComposerTile_delete"
title={_t("action|delete")}
onClick={this.onCancel}