Tooltip: Improve the accessibility of the composer and the rich text editor (#12459)

* Use `AccessibleButton` in `RovingAccessibleTooltipButton`

* Update snapshots

* Update @vector-im/compound-web

* Update composer

* Update formating buttons

* Update snapshots

* Remove placement

* Update snapshots

* Use kbd

* Update ``@vector-im/compound-web`
This commit is contained in:
Florian Duros 2024-05-15 10:32:53 +02:00 committed by GitHub
parent 6e31f69118
commit 77a724526e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 36 additions and 63 deletions

View file

@ -76,7 +76,7 @@
"@sentry/browser": "^7.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@vector-im/compound-design-tokens": "^1.2.0",
"@vector-im/compound-web": "^4.1.2",
"@vector-im/compound-web": "^4.2.0",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-en": "^3.0.2",

View file

@ -102,9 +102,4 @@ limitations under the License.
font-weight: var(--cpd-font-weight-semibold);
min-width: 54px;
text-align: center;
.mx_MessageComposerFormatBar_tooltipShortcut {
font-size: $font-9px;
opacity: 0.7;
}
}

View file

@ -64,19 +64,11 @@ limitations under the License.
}
}
.mx_FormattingButtons_Tooltip {
padding: 0 2px 0 2px;
.mx_FormattingButtons_Tooltip_KeyboardShortcut {
color: $tertiary-content;
kbd {
margin-top: 2px;
text-align: center;
display: inline-block;
text-transform: capitalize;
font-size: 12px;
font-family: Inter, sans-serif;
}
}
}

View file

@ -92,12 +92,12 @@ type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> &
/**
* The tooltip to show on hover or focus.
*/
title?: string;
title?: TooltipProps["label"];
/**
* The caption is a secondary text displayed under the `title` of the tooltip.
* Only valid when used in conjunction with `title`.
*/
caption?: string;
caption?: TooltipProps["caption"];
/**
* The placement of the tooltip.
*/

View file

@ -35,7 +35,6 @@ import { makeRoomPermalink, RoomPermalinkCreator } from "../../../utils/permalin
import E2EIcon from "./E2EIcon";
import SettingsStore from "../../../settings/SettingsStore";
import { aboveLeftOf, MenuProps } from "../../structures/ContextMenu";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import ReplyPreview from "./ReplyPreview";
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import VoiceRecordComposerTile from "./VoiceRecordComposerTile";
@ -52,7 +51,7 @@ import UIStore, { UI_EVENTS } from "../../../stores/UIStore";
import RoomContext from "../../../contexts/RoomContext";
import { SettingUpdatedPayload } from "../../../dispatcher/payloads/SettingUpdatedPayload";
import MessageComposerButtons from "./MessageComposerButtons";
import { ButtonEvent } from "../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
import { Features } from "../../../settings/Settings";
@ -75,7 +74,7 @@ interface ISendButtonProps {
function SendButton(props: ISendButtonProps): JSX.Element {
return (
<AccessibleTooltipButton
<AccessibleButton
className="mx_MessageComposer_sendMessage"
onClick={props.onClick}
title={props.title ?? _t("composer|send_button_title")}

View file

@ -19,7 +19,6 @@ import { IEventRelation, Room, MatrixClient, THREAD_RELATION_TYPE, M_POLL_START
import React, { createContext, ReactElement, ReactNode, useContext, useRef } from "react";
import { _t } from "../../../languageHandler";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { CollapsibleButton } from "./CollapsibleButton";
import { MenuProps } from "../../structures/ContextMenu";
import dis from "../../../dispatcher/dispatcher";
@ -37,7 +36,7 @@ import IconizedContextMenu, { IconizedContextMenuOptionList } from "../context_m
import { EmojiButton } from "./EmojiButton";
import { filterBoolean } from "../../../utils/arrays";
import { useSettingValue } from "../../../hooks/useSettings";
import { ButtonEvent } from "../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
interface IProps {
addEmoji: (emoji: string) => boolean;
@ -128,7 +127,7 @@ const MessageComposerButtons: React.FC<IProps> = (props: IProps) => {
<UploadButtonContextProvider roomId={room.roomId} relation={props.relation}>
{mainButtons}
{moreButtons.length > 0 && (
<AccessibleTooltipButton
<AccessibleButton
className={moreOptionsClasses}
onClick={props.toggleButtonMenu}
title={_t("quick_settings|sidebar_settings")}

View file

@ -30,54 +30,42 @@ import { Icon as NumberedListIcon } from "../../../../../../res/img/element-icon
import { Icon as CodeBlockIcon } from "../../../../../../res/img/element-icons/room/composer/code_block.svg";
import { Icon as IndentIcon } from "../../../../../../res/img/element-icons/room/composer/indent_increase.svg";
import { Icon as UnIndentIcon } from "../../../../../../res/img/element-icons/room/composer/indent_decrease.svg";
import AccessibleTooltipButton from "../../../elements/AccessibleTooltipButton";
import { Alignment } from "../../../elements/Tooltip";
import { KeyboardShortcut } from "../../../settings/KeyboardShortcut";
import { KeyCombo } from "../../../../../KeyBindingsManager";
import { _t } from "../../../../../languageHandler";
import { ButtonEvent } from "../../../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton";
import { openLinkModal } from "./LinkModal";
import { useComposerContext } from "../ComposerContext";
import { KeyboardShortcut } from "../../../settings/KeyboardShortcut";
import { KeyCombo } from "../../../../../KeyBindingsManager";
interface TooltipProps {
interface ButtonProps {
icon: ReactNode;
actionState: ActionState;
onClick: MouseEventHandler<HTMLButtonElement>;
label: string;
keyCombo?: KeyCombo;
}
function Tooltip({ label, keyCombo }: TooltipProps): JSX.Element {
return (
<div className="mx_FormattingButtons_Tooltip">
{label}
{keyCombo && (
<KeyboardShortcut value={keyCombo} className="mx_FormattingButtons_Tooltip_KeyboardShortcut" />
)}
</div>
);
}
interface ButtonProps extends TooltipProps {
icon: ReactNode;
actionState: ActionState;
onClick: MouseEventHandler<HTMLButtonElement>;
}
function Button({ label, keyCombo, onClick, actionState, icon }: ButtonProps): JSX.Element {
return (
<AccessibleTooltipButton
<AccessibleButton
element="button"
onClick={onClick as (e: ButtonEvent) => void}
title={label}
aria-label={label}
className={classNames("mx_FormattingButtons_Button", {
mx_FormattingButtons_active: actionState === "reversed",
mx_FormattingButtons_Button_hover: actionState === "enabled",
mx_FormattingButtons_disabled: actionState === "disabled",
})}
tooltip={keyCombo && <Tooltip label={label} keyCombo={keyCombo} />}
forceHide={actionState === "disabled"}
alignment={Alignment.Top}
title={actionState === "disabled" ? undefined : label}
caption={
keyCombo && (
<KeyboardShortcut value={keyCombo} className="mx_FormattingButtons_Tooltip_KeyboardShortcut" />
)
}
placement="top"
>
{icon}
</AccessibleTooltipButton>
</AccessibleButton>
);
}

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from "react";
import { cleanup, render, screen } from "@testing-library/react";
import { cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ActionState, ActionTypes, AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
@ -135,7 +135,7 @@ describe("FormattingButtons", () => {
const { label } = testCase;
await userEvent.hover(screen.getByLabelText(label));
expect(screen.getByText(label)).toBeInTheDocument();
await waitFor(() => expect(screen.getByText(label)).toBeInTheDocument());
}
});

View file

@ -3097,10 +3097,10 @@
dependencies:
svg2vectordrawable "^2.9.1"
"@vector-im/compound-web@^4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-4.1.2.tgz#d8f9ba523700660942722a800c64406216bbbfea"
integrity sha512-u/jj8HF8qpX1NU+sh6f/S1B7HUMGcoAGYLH0wc5lVbf6x6elBsYKD0LSa+/8NDPuQqVWMztu76chUsM5slC49w==
"@vector-im/compound-web@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@vector-im/compound-web/-/compound-web-4.2.0.tgz#16915a5e64c405360fc049ddfa39b5185725f950"
integrity sha512-VSZxIFToDesjiiCGLOj+DrrKv1I0rtpzJbdylarJXY7REnHzVdgaBBtGm403iJ8KkZ2Rn16Mxe+P1/+VS4yiAA==
dependencies:
"@floating-ui/react" "^0.26.9"
"@floating-ui/react-dom" "^2.0.8"