diff --git a/apps/web/src/Modal.tsx b/apps/web/src/Modal.tsx index cb63d4cbb3..8ba4313576 100644 --- a/apps/web/src/Modal.tsx +++ b/apps/web/src/Modal.tsx @@ -446,6 +446,8 @@ export class ModalManager extends TypedEventEmitter
{this.staticModal.elem}
+ {/* We break the rule here as this is a mouse-only interaction */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
{modal.elem}
+ {/* We break the rule here as this is a mouse-only interaction */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
{ return ( {({ onKeyDownHandler }) => ( + // This may be wrong but seems to work, this is a roving-toolbar, so the focus follows one of the children + // oxlint-disable-next-line jsx-a11y/interactive-supports-focus
{children}
diff --git a/apps/web/src/autocomplete/CommandProvider.tsx b/apps/web/src/autocomplete/CommandProvider.tsx index f93ea6c8ce..065fa9cca0 100644 --- a/apps/web/src/autocomplete/CommandProvider.tsx +++ b/apps/web/src/autocomplete/CommandProvider.tsx @@ -104,7 +104,6 @@ export default class CommandProvider extends AutocompleteProvider { return (
{completions} diff --git a/apps/web/src/autocomplete/EmojiProvider.tsx b/apps/web/src/autocomplete/EmojiProvider.tsx index 2d31095acd..82851e4c14 100644 --- a/apps/web/src/autocomplete/EmojiProvider.tsx +++ b/apps/web/src/autocomplete/EmojiProvider.tsx @@ -175,7 +175,6 @@ export default class EmojiProvider extends AutocompleteProvider { return (
{completions} diff --git a/apps/web/src/autocomplete/NotifProvider.tsx b/apps/web/src/autocomplete/NotifProvider.tsx index 2a6e070efa..3a0fbf3909 100644 --- a/apps/web/src/autocomplete/NotifProvider.tsx +++ b/apps/web/src/autocomplete/NotifProvider.tsx @@ -68,7 +68,6 @@ export default class NotifProvider extends AutocompleteProvider { return (
{completions} diff --git a/apps/web/src/autocomplete/RoomProvider.tsx b/apps/web/src/autocomplete/RoomProvider.tsx index 5c06856b08..88f11c83ac 100644 --- a/apps/web/src/autocomplete/RoomProvider.tsx +++ b/apps/web/src/autocomplete/RoomProvider.tsx @@ -136,7 +136,6 @@ export default class RoomProvider extends AutocompleteProvider { return (
{completions} diff --git a/apps/web/src/autocomplete/UserProvider.tsx b/apps/web/src/autocomplete/UserProvider.tsx index e6b8c46e99..973339357b 100644 --- a/apps/web/src/autocomplete/UserProvider.tsx +++ b/apps/web/src/autocomplete/UserProvider.tsx @@ -196,7 +196,6 @@ export default class UserProvider extends AutocompleteProvider { return (
{completions} diff --git a/apps/web/src/components/structures/AutocompleteInput.tsx b/apps/web/src/components/structures/AutocompleteInput.tsx index 9767bd5761..95fcb83b4d 100644 --- a/apps/web/src/components/structures/AutocompleteInput.tsx +++ b/apps/web/src/components/structures/AutocompleteInput.tsx @@ -115,6 +115,8 @@ export const AutocompleteInput: React.FC = ({ return (
+ {/* We break the rule here as this is a mouse-only interaction */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
= ({ if (hasPermissions) { checkbox = ( = ({ ev.stopPropagation(); }} > - + ); } @@ -287,8 +281,9 @@ const Tile: React.FC = ({ let childSection: JSX.Element | undefined; let onKeyDown: KeyboardEventHandler | undefined; if (children) { - // the chevron is purposefully a div rather than a button as it should be ignored for a11y childToggle = ( + // the chevron is purposefully a div rather than a button as it should be ignored for a11y + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
({ tab, isActive, showToolip, onClick }: ITab const label = _t(tab.label); return ( + // The RovingAccessibleComponent correctly sets the tabIndex based on roving context + // oxlint-disable-next-line jsx-a11y/interactive-supports-focus > = ({ beacon, .. > {/* eat events from interactive share buttons so parent click handlers are not triggered */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
{})}>
diff --git a/apps/web/src/components/views/elements/Dropdown.tsx b/apps/web/src/components/views/elements/Dropdown.tsx index ead5966e41..fb245a7e3e 100644 --- a/apps/web/src/components/views/elements/Dropdown.tsx +++ b/apps/web/src/components/views/elements/Dropdown.tsx @@ -54,6 +54,9 @@ class MenuOption extends React.Component { }); return ( + // We break the rule here as this is a mouse-only interaction, + // the keyboard interaction is handled by the Dropdown parent component + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
  • { onClick={this.onRemove} className="mx_EditableItem_delete" title={_t("action|remove")} - role="button" > diff --git a/apps/web/src/components/views/elements/EditableText.tsx b/apps/web/src/components/views/elements/EditableText.tsx index 1e1d00d14c..1538dca015 100644 --- a/apps/web/src/components/views/elements/EditableText.tsx +++ b/apps/web/src/components/views/elements/EditableText.tsx @@ -201,6 +201,8 @@ export default class EditableText extends React.Component { if (!editable || (this.state.phase === Phases.Display && (label || labelClassName) && !this.value)) { // show the label editableEl = ( + // We break the rule here as this is a mouse-only shortcut + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
    {label || initialValue}
    diff --git a/apps/web/src/components/views/elements/GenericEventListSummary.tsx b/apps/web/src/components/views/elements/GenericEventListSummary.tsx index cc5d6cc6b5..c369e44dbc 100644 --- a/apps/web/src/components/views/elements/GenericEventListSummary.tsx +++ b/apps/web/src/components/views/elements/GenericEventListSummary.tsx @@ -99,6 +99,9 @@ const GenericEventListSummary: React.FC = ({ body = (
    + {/* We break the rule here as this is a mouse-only interaction */} + {/* mx_GenericEventListSummary_toggle is the keyboard friendly outer one */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */} {avatars} diff --git a/apps/web/src/components/views/elements/RoomTopic.tsx b/apps/web/src/components/views/elements/RoomTopic.tsx index e539c9c7d3..f7b7751bb3 100644 --- a/apps/web/src/components/views/elements/RoomTopic.tsx +++ b/apps/web/src/components/views/elements/RoomTopic.tsx @@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details. import React, { type JSX, useCallback, useContext, useState } from "react"; import { type Room, EventType } from "matrix-js-sdk/src/matrix"; import classNames from "classnames"; -import { Tooltip } from "@vector-im/compound-web"; import { LinkedText } from "@element-hq/web-shared-components"; import { useTopic } from "../../../hooks/room/useTopic"; @@ -20,15 +19,16 @@ import Modal from "../../../Modal"; import InfoDialog from "../dialogs/InfoDialog"; import { useDispatcher } from "../../../hooks/useDispatcher"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import AccessibleButton from "./AccessibleButton"; +import AccessibleButton, { type ButtonEvent } from "./AccessibleButton"; import { topicToHtml } from "../../../HtmlUtils"; import { tryTransformPermalinkToLocalHref } from "../../../utils/permalinks/Permalinks"; -interface IProps extends React.HTMLProps { +interface IProps { room: Room; + className?: string; } -export function onRoomTopicLinkClick(e: React.MouseEvent): void { +export function onRoomTopicLinkClick(e: ButtonEvent): void { const anchor = e.target as HTMLLinkElement; const localHref = tryTransformPermalinkToLocalHref(anchor.href); @@ -39,28 +39,23 @@ export function onRoomTopicLinkClick(e: React.MouseEvent): void { } } -export default function RoomTopic({ room, className, ...props }: IProps): JSX.Element { +export default function RoomTopic({ room, className }: IProps): JSX.Element { const client = useContext(MatrixClientContext); const [disableTooltip, setDisableTooltip] = useState(false); const topic = useTopic(room); const body = topicToHtml(topic?.text, topic?.html); - const onClick = useCallback( - (e: React.MouseEvent) => { - props.onClick?.(e); + const onClick = useCallback((e: ButtonEvent) => { + const target = e.target as HTMLElement; - const target = e.target as HTMLElement; + if (target.tagName.toUpperCase() !== "A") { + dis.fire(Action.ShowRoomTopic); + return; + } - if (target.tagName.toUpperCase() !== "A") { - dis.fire(Action.ShowRoomTopic); - return; - } - - onRoomTopicLinkClick(e); - }, - [props], - ); + onRoomTopicLinkClick(e); + }, []); const onHover = (ev: React.MouseEvent | React.FocusEvent): void => { setDisableTooltip((ev.target as HTMLElement).tagName.toUpperCase() === "A"); @@ -100,19 +95,15 @@ export default function RoomTopic({ room, className, ...props }: IProps): JSX.El if (!body) return
    ; return ( - -
    - {body} -
    -
    + + {body} + ); } diff --git a/apps/web/src/components/views/elements/ToggleSwitch.tsx b/apps/web/src/components/views/elements/ToggleSwitch.tsx index 6139b32669..106b3fb839 100644 --- a/apps/web/src/components/views/elements/ToggleSwitch.tsx +++ b/apps/web/src/components/views/elements/ToggleSwitch.tsx @@ -50,6 +50,7 @@ export default ({ checked, disabled = false, onChange, title, tooltip, ...props className={classes} onClick={_onClick} role="switch" + tabIndex={0} aria-label={title} aria-checked={checked} aria-disabled={disabled} diff --git a/apps/web/src/components/views/location/Map.tsx b/apps/web/src/components/views/location/Map.tsx index cb6f64ad83..55597acbe4 100644 --- a/apps/web/src/components/views/location/Map.tsx +++ b/apps/web/src/components/views/location/Map.tsx @@ -174,6 +174,8 @@ const MapComponent: React.FC = ({ }; return ( + // We break the rule here as this is a mouse-only interaction + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
    {!!children && !!map && children({ map })}
    diff --git a/apps/web/src/components/views/location/MapError.tsx b/apps/web/src/components/views/location/MapError.tsx index e2059f9cd1..8716d7a1ba 100644 --- a/apps/web/src/components/views/location/MapError.tsx +++ b/apps/web/src/components/views/location/MapError.tsx @@ -24,6 +24,8 @@ export interface MapErrorProps { } export const MapError: React.FC = ({ error, isMinimised, className, onFinished, onClick }) => ( + // We break the rule here as this is a mouse-only interaction + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
    {children} {isVisible && tooltip} diff --git a/apps/web/src/components/views/messages/CodeBlock.tsx b/apps/web/src/components/views/messages/CodeBlock.tsx index 04916a9140..172ea82984 100644 --- a/apps/web/src/components/views/messages/CodeBlock.tsx +++ b/apps/web/src/components/views/messages/CodeBlock.tsx @@ -13,6 +13,8 @@ import { CollapseIcon, CopyIcon, ExpandIcon } from "@vector-im/compound-design-t import { useSettingValue } from "../../../hooks/useSettings.ts"; import { CopyTextButton } from "../elements/CopyableText.tsx"; +import AccessibleButton from "../elements/AccessibleButton.tsx"; +import { _t } from "../../../i18n"; const MAX_HIGHLIGHT_LENGTH = 4096; const MAX_LINES_BEFORE_COLLAPSE = 5; @@ -26,9 +28,14 @@ const ExpandCollapseButton: React.FC<{ onClick(this: void): void; }> = ({ expanded, onClick }) => { return ( - + {expanded ? : } - + ); }; diff --git a/apps/web/src/components/views/messages/MStickerBody.tsx b/apps/web/src/components/views/messages/MStickerBody.tsx index a9ae9ed92c..fe6dd4ef55 100644 --- a/apps/web/src/components/views/messages/MStickerBody.tsx +++ b/apps/web/src/components/views/messages/MStickerBody.tsx @@ -14,10 +14,11 @@ import { BLURHASH_FIELD } from "../../../utils/image-media"; import IconsShowStickersSvg from "../../../../res/img/icons-show-stickers.svg"; import { type IBodyProps } from "./IBodyProps"; import { useMediaVisible } from "../../../hooks/useMediaVisible"; +import AccessibleButton, { type ButtonEvent } from "../elements/AccessibleButton.tsx"; class MStickerBodyInner extends ImageBodyBaseInner { // Mostly empty to prevent default behaviour of MImageBody - protected onClick = (ev: React.MouseEvent): void => { + protected onClick = (ev: ButtonEvent): void => { ev.preventDefault(); if (!this.props.mediaVisible) { this.props.setMediaVisible(true); @@ -27,16 +28,15 @@ class MStickerBodyInner extends ImageBodyBaseInner { // MStickerBody doesn't need a wrapping ``, but it does need extra padding // which is added by mx_MStickerBody_wrapper protected wrapImage(contentUrl: string, children: React.ReactNode): JSX.Element { - let onClick: React.MouseEventHandler | undefined; - if (!this.props.mediaVisible) { - onClick = this.onClick; + const content = <> {children} ; + if (this.props.mediaVisible) { + return ( + + {content} + + ); } - return ( -
    - {" "} - {children}{" "} -
    - ); + return
    {content}
    ; } // Placeholder to show in place of the sticker image if img onLoad hasn't fired yet. diff --git a/apps/web/src/components/views/polls/PollOption.tsx b/apps/web/src/components/views/polls/PollOption.tsx index 9e334b6b57..d2af3f93ce 100644 --- a/apps/web/src/components/views/polls/PollOption.tsx +++ b/apps/web/src/components/views/polls/PollOption.tsx @@ -112,6 +112,8 @@ export const PollOption: React.FC = ({ const isWinner = isEnded && isChecked; const answerPercent = totalVoteCount === 0 ? 0 : Math.round((100.0 * voteCount) / totalVoteCount); return ( + // We break the rule here as ActivePollOption is keyboard accessible, we are just making the click target larger + // oxlint-disable-next-line jsx-a11y/click-events-have-key-events
    onOptionSelected?.(answer.id)}> = ({ event, onClick }) => { } const formattedDate = formatLocalDateShort(event.getTs()); return ( -
  • - +
  • +
    {formattedDate} {pollEvent.question.text}
    - +
  • ); }; diff --git a/apps/web/src/components/views/polls/pollHistory/PollListItemEnded.tsx b/apps/web/src/components/views/polls/pollHistory/PollListItemEnded.tsx index 39d2d0e07d..d7913f08fa 100644 --- a/apps/web/src/components/views/polls/pollHistory/PollListItemEnded.tsx +++ b/apps/web/src/components/views/polls/pollHistory/PollListItemEnded.tsx @@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details. import React, { useEffect, useState } from "react"; import { type PollAnswerSubevent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent"; import { type MatrixEvent, type Poll, PollEvent, type Relations } from "matrix-js-sdk/src/matrix"; -import { Tooltip } from "@vector-im/compound-web"; import { PollsEndIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { _t } from "../../../../languageHandler"; @@ -17,6 +16,7 @@ import { formatLocalDateShort } from "../../../../DateUtils"; import { allVotes, collectUserVotes, countVotes } from "../../messages/MPollBody"; import { PollOption } from "../../polls/PollOption"; import { Caption } from "../../typography/Caption"; +import AccessibleButton from "../../elements/AccessibleButton.tsx"; interface Props { event: MatrixEvent; @@ -93,36 +93,39 @@ export const PollListItemEnded: React.FC = ({ event, poll, onClick }) => const formattedDate = formatLocalDateShort(event.getTs()); return ( -
  • - -
    -
    - - {pollEvent.question.text} - {formattedDate} -
    - {!!winningAnswers?.length && ( -
    - {winningAnswers?.map(({ answer, voteCount, optionNumber }) => ( - - ))} -
    - )} -
    - {_t("right_panel|poll|final_result", { count: totalVoteCount })} -
    +
  • + +
    + + {pollEvent.question.text} + {formattedDate}
    - + {!!winningAnswers?.length && ( +
    + {winningAnswers?.map(({ answer, voteCount, optionNumber }) => ( + + ))} +
    + )} +
    + {_t("right_panel|poll|final_result", { count: totalVoteCount })} +
    +
  • ); }; diff --git a/apps/web/src/components/views/right_panel/BaseCard.tsx b/apps/web/src/components/views/right_panel/BaseCard.tsx index c9d850b3b0..754c63b35e 100644 --- a/apps/web/src/components/views/right_panel/BaseCard.tsx +++ b/apps/web/src/components/views/right_panel/BaseCard.tsx @@ -128,6 +128,7 @@ const BaseCard: React.FC = ({ weight="medium" className="mx_BaseCard_header_title_heading" role="heading" + aria-level={1} > {header} diff --git a/apps/web/src/components/views/rooms/BasicMessageComposer.tsx b/apps/web/src/components/views/rooms/BasicMessageComposer.tsx index c81d60fd61..05d446cc92 100644 --- a/apps/web/src/components/views/rooms/BasicMessageComposer.tsx +++ b/apps/web/src/components/views/rooms/BasicMessageComposer.tsx @@ -857,6 +857,8 @@ export default class BasicMessageEditor extends React.Component aria-multiline="true" aria-autocomplete="list" aria-haspopup="listbox" + // This is not strictly speaking a supported role, we should investigate the impact of this in the future + // oxlint-disable-next-line jsx-a11y/role-supports-aria-props aria-expanded={hasAutocomplete ? !this.autocompleteRef.current?.state.hide : undefined} aria-owns={hasAutocomplete ? "mx_Autocomplete" : undefined} aria-activedescendant={activeDescendant} diff --git a/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx b/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx index fad0b3f0da..92aca2e220 100644 --- a/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx +++ b/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx @@ -46,6 +46,7 @@ export function MemberTileView(props: Props): JSX.Element { aria-label={props?.ariaLabel} tabIndex={props.tabIndex} role="option" + aria-selected={props.tabIndex === 0} aria-posinset={props.memberIndex + 1} aria-setsize={props.memberCount} > diff --git a/apps/web/src/components/views/rooms/ThirdPartyMemberInfo.tsx b/apps/web/src/components/views/rooms/ThirdPartyMemberInfo.tsx index fb440d98bd..ef5e248bd4 100644 --- a/apps/web/src/components/views/rooms/ThirdPartyMemberInfo.tsx +++ b/apps/web/src/components/views/rooms/ThirdPartyMemberInfo.tsx @@ -114,7 +114,7 @@ export default class ThirdPartyMemberInfo extends React.Component - + {_t("user_info|admin_tools_section")}
    + {/* We break the rule here as this is a mouse-only interaction */} + {/* oxlint-disable-next-line jsx-a11y/click-events-have-key-events */}
    {})}> {children}
    diff --git a/apps/web/test/unit-tests/components/structures/__snapshots__/FilePanel-test.tsx.snap b/apps/web/test/unit-tests/components/structures/__snapshots__/FilePanel-test.tsx.snap index 6a45b1d723..a784ecf63a 100644 --- a/apps/web/test/unit-tests/components/structures/__snapshots__/FilePanel-test.tsx.snap +++ b/apps/web/test/unit-tests/components/structures/__snapshots__/FilePanel-test.tsx.snap @@ -12,6 +12,7 @@ exports[`FilePanel renders empty state 1`] = ` class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap b/apps/web/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap index b427de0de8..9d12ef1b2e 100644 --- a/apps/web/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap +++ b/apps/web/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap @@ -3628,6 +3628,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = ` class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/structures/__snapshots__/SpaceHierarchy-test.tsx.snap b/apps/web/test/unit-tests/components/structures/__snapshots__/SpaceHierarchy-test.tsx.snap index 1213f4401b..ff86cab70c 100644 --- a/apps/web/test/unit-tests/components/structures/__snapshots__/SpaceHierarchy-test.tsx.snap +++ b/apps/web/test/unit-tests/components/structures/__snapshots__/SpaceHierarchy-test.tsx.snap @@ -137,7 +137,6 @@ exports[`SpaceHierarchy renders 1`] = ` aria-labelledby="react-use-id-1" class="_input_153f2_18" id="checkbox_MwbPDmfGtm" - role="presentation" tabindex="-1" type="checkbox" /> @@ -235,7 +234,6 @@ exports[`SpaceHierarchy renders 1`] = ` aria-labelledby="react-use-id-2" class="_input_153f2_18" id="checkbox_GQvdMWe954" - role="presentation" tabindex="-1" type="checkbox" /> @@ -334,7 +332,6 @@ exports[`SpaceHierarchy renders 1`] = ` aria-labelledby="react-use-id-3" class="_input_153f2_18" id="checkbox_DVIAu5CsiH" - role="presentation" tabindex="-1" type="checkbox" /> @@ -455,7 +452,6 @@ exports[`SpaceHierarchy renders 1`] = ` class="_input_153f2_18" disabled="" id="checkbox_RD7nyrA2oh" - role="presentation" tabindex="-1" type="checkbox" /> @@ -556,7 +552,6 @@ exports[`SpaceHierarchy renders 1`] = ` aria-labelledby="react-use-id-6" class="_input_153f2_18" id="checkbox_jWVJIPauy1" - role="presentation" tabindex="-1" type="checkbox" /> @@ -727,7 +722,6 @@ exports[`SpaceHierarchy should not render cycles 1`] = ` aria-labelledby="react-use-id-1" class="_input_153f2_18" id="checkbox_EetmBG4yVC" - role="presentation" tabindex="-1" type="checkbox" /> @@ -825,7 +819,6 @@ exports[`SpaceHierarchy should not render cycles 1`] = ` aria-labelledby="react-use-id-2" class="_input_153f2_18" id="checkbox_eEefiPqpMR" - role="presentation" tabindex="-1" type="checkbox" /> @@ -924,7 +917,6 @@ exports[`SpaceHierarchy should not render cycles 1`] = ` aria-labelledby="react-use-id-3" class="_input_153f2_18" id="checkbox_MwbPDmfGtm" - role="presentation" tabindex="-1" type="checkbox" /> diff --git a/apps/web/test/unit-tests/components/views/messages/__snapshots__/TextualBody-test.tsx.snap b/apps/web/test/unit-tests/components/views/messages/__snapshots__/TextualBody-test.tsx.snap index fde65afb0c..8028d123fa 100644 --- a/apps/web/test/unit-tests/components/views/messages/__snapshots__/TextualBody-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/messages/__snapshots__/TextualBody-test.tsx.snap @@ -467,8 +467,11 @@ num_sqrt = num **

    - - +
  • -
    @@ -176,7 +180,7 @@ exports[` renders a list of active polls when there are polls in Question?
    -
    +
  • diff --git a/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItem-test.tsx.snap b/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItem-test.tsx.snap index 5c95b64f26..b56e20c0a7 100644 --- a/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItem-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItem-test.tsx.snap @@ -6,11 +6,13 @@ exports[` renders a poll 1`] = ` class="mx_PollListItem" data-testid="pollListItem-$mypoll" > -
    @@ -34,7 +36,7 @@ exports[` renders a poll 1`] = ` Question?
    -
    +
    `; diff --git a/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItemEnded-test.tsx.snap b/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItemEnded-test.tsx.snap index d54739ab81..a700787ef0 100644 --- a/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItemEnded-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/polls/pollHistory/__snapshots__/PollListItemEnded-test.tsx.snap @@ -6,53 +6,51 @@ exports[` renders a poll with no responses 1`] = ` class="mx_PollListItemEnded" data-testid="pollListItem-1" > -
    -
    - - - - - - Question? - - - 02/02/23 - -
    -
    + + + - - Final result based on 0 votes - -
    + Question? + + + 02/02/23 +
    -
    +
    + + Final result based on 0 votes + +
    +
    `; diff --git a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/BaseCard-test.tsx.snap b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/BaseCard-test.tsx.snap index f9364f2ac1..5d7c150081 100644 --- a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/BaseCard-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/BaseCard-test.tsx.snap @@ -12,6 +12,7 @@ exports[` should close when clicking X button 1`] = ` class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/ExtensionsCard-test.tsx.snap b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/ExtensionsCard-test.tsx.snap index 2c2b81a8f3..d427defa90 100644 --- a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/ExtensionsCard-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/ExtensionsCard-test.tsx.snap @@ -12,6 +12,7 @@ exports[` should render empty state 1`] = ` class="mx_BaseCard_header_title" >

    @@ -113,6 +114,7 @@ exports[` should render widgets 1`] = ` class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap index 4688291580..8745232a2a 100644 --- a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/PinnedMessagesCard-test.tsx.snap @@ -12,6 +12,7 @@ exports[` should show the empty state when there are no pi class="mx_BaseCard_header_title" >

    @@ -94,6 +95,7 @@ exports[` should show two pinned messages 1`] = ` class="mx_BaseCard_header_title" >

    @@ -322,6 +324,7 @@ exports[` unpin all should not allow to unpinall 1`] = ` class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap index 19b079ce45..5429dab1f0 100644 --- a/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/right_panel/__snapshots__/UserInfo-test.tsx.snap @@ -12,6 +12,7 @@ exports[` with crypto enabled renders 1`] = ` class="mx_BaseCard_header_title" >

    @@ -314,6 +315,7 @@ exports[` with crypto enabled should render a deactivate button for class="mx_BaseCard_header_title" >

    diff --git a/apps/web/test/unit-tests/components/views/rooms/__snapshots__/ThirdPartyMemberInfo-test.tsx.snap b/apps/web/test/unit-tests/components/views/rooms/__snapshots__/ThirdPartyMemberInfo-test.tsx.snap index ef08979503..a8bf5bb2d0 100644 --- a/apps/web/test/unit-tests/components/views/rooms/__snapshots__/ThirdPartyMemberInfo-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/rooms/__snapshots__/ThirdPartyMemberInfo-test.tsx.snap @@ -12,6 +12,7 @@ exports[` should render invite 1`] = ` class="mx_BaseCard_header_title" >

    @@ -58,6 +59,7 @@ exports[` should render invite 1`] = ` style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: start; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;" > @@ -87,6 +89,7 @@ exports[` should render invite when room in not availabl class="mx_BaseCard_header_title" >

    @@ -133,6 +136,7 @@ exports[` should render invite when room in not availabl style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: start; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;" > diff --git a/apps/web/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap b/apps/web/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap index 22532ebea9..592c742886 100644 --- a/apps/web/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap +++ b/apps/web/test/unit-tests/components/views/rooms/memberlist/__snapshots__/MemberTileView-test.tsx.snap @@ -6,6 +6,7 @@ exports[`MemberTileView RoomMemberTileView should display an verified E2EIcon wh

    displays name edit form on rename button click { "container":
    diff --git a/oxlint.config.ts b/oxlint.config.ts index 703e6cbd81..4e457e6190 100644 --- a/oxlint.config.ts +++ b/oxlint.config.ts @@ -163,18 +163,14 @@ export default defineConfig({ "react-perf/jsx-no-new-array-as-prop": "off", "react/no-did-update-set-state": "off", "react/no-did-mount-set-state": "off", - "jsx-a11y/interactive-supports-focus": "off", "jsx-a11y/no-static-element-interactions": "off", - "jsx-a11y/click-events-have-key-events": "off", "vitest/no-conditional-tests": "off", "jsx-a11y/no-noninteractive-element-interactions": "off", "react/no-array-index-key": "off", "jsx-a11y/control-has-associated-label": "off", - "jsx-a11y/role-supports-aria-props": "off", "jsx-a11y/media-has-caption": "off", "jsx-a11y/no-noninteractive-element-to-interactive-role": "off", "jsx-a11y/aria-activedescendant-has-tabindex": "off", - "jsx-a11y/role-has-required-aria-props": "off", }, overrides: [ { @@ -417,13 +413,17 @@ export default defineConfig({ ], "jsdoc/check-tag-names": "off", - "react/jsx-no-constructed-context-values": "off", + // Disable a11y rules for components in tests + "jsx-a11y/role-has-required-aria-props": "off", "jsx-a11y/interactive-supports-focus": "off", "jsx-a11y/no-static-element-interactions": "off", - "react/no-array-index-key": "off", "jsx-a11y/click-events-have-key-events": "off", "jsx-a11y/media-has-caption": "off", "jsx-a11y/no-noninteractive-element-to-interactive-role": "off", + "jsx-a11y/role-supports-aria-props": "off", + + "react/jsx-no-constructed-context-values": "off", + "react/no-array-index-key": "off", "react/forbid-elements": "off", // This would be good to enable in the future "typescript/await-thenable": "off", diff --git a/packages/shared-components/src/room-list/RoomListPrimaryFilters/RoomListPrimaryFilters.tsx b/packages/shared-components/src/room-list/RoomListPrimaryFilters/RoomListPrimaryFilters.tsx index 5b325156b5..679120c0ed 100644 --- a/packages/shared-components/src/room-list/RoomListPrimaryFilters/RoomListPrimaryFilters.tsx +++ b/packages/shared-components/src/room-list/RoomListPrimaryFilters/RoomListPrimaryFilters.tsx @@ -104,6 +104,8 @@ export const RoomListPrimaryFilters = memo(function RoomListPrimaryFilters({ onToggleFilter(filterId)} > diff --git a/packages/shared-components/src/room/timeline/event-tile/actions/ActionBarView/ActionBarView.tsx b/packages/shared-components/src/room/timeline/event-tile/actions/ActionBarView/ActionBarView.tsx index e6de27a38d..e2d2039a0c 100644 --- a/packages/shared-components/src/room/timeline/event-tile/actions/ActionBarView/ActionBarView.tsx +++ b/packages/shared-components/src/room/timeline/event-tile/actions/ActionBarView/ActionBarView.tsx @@ -376,6 +376,8 @@ export function ActionBarView({ vm, className }: Readonly): return ( {({ onKeyDownHandler }) => ( + // This may be wrong but seems to work, this is a roving-toolbar, so the focus follows one of the children + // oxlint-disable-next-line jsx-a11y/interactive-supports-focus