mirror of https://github.com/vector-im/riot-web
Fix accessibility issues around the room list and space panel (#10717)
* Fix room sublist group label being read twice in Orca * Fix room list sublist notification badges always having a tab stopt3chguy/dedup-icons-17oct
parent
c824c4a858
commit
43ffd89e58
|
@ -44,7 +44,7 @@ interface IClickableProps extends IProps, React.InputHTMLAttributes<Element> {
|
||||||
/**
|
/**
|
||||||
* If specified will return an AccessibleButton instead of a div.
|
* If specified will return an AccessibleButton instead of a div.
|
||||||
*/
|
*/
|
||||||
onClick?(ev: React.MouseEvent): void;
|
onClick(ev: React.MouseEvent): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -112,7 +112,7 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
/* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
|
/* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
|
||||||
const { notification, showUnsentTooltip, forceCount, onClick } = this.props;
|
const { notification, showUnsentTooltip, forceCount, onClick, tabIndex } = this.props;
|
||||||
|
|
||||||
if (notification.isIdle) return null;
|
if (notification.isIdle) return null;
|
||||||
if (forceCount) {
|
if (forceCount) {
|
||||||
|
@ -135,6 +135,7 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onMouseOver={this.onMouseOver}
|
onMouseOver={this.onMouseOver}
|
||||||
onMouseLeave={this.onMouseLeave}
|
onMouseLeave={this.onMouseLeave}
|
||||||
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
{tooltip}
|
{tooltip}
|
||||||
</StatelessNotificationBadge>
|
</StatelessNotificationBadge>
|
||||||
|
|
|
@ -21,19 +21,32 @@ import { formatCount } from "../../../../utils/FormattingUtils";
|
||||||
import AccessibleButton from "../../elements/AccessibleButton";
|
import AccessibleButton from "../../elements/AccessibleButton";
|
||||||
import { NotificationColor } from "../../../../stores/notifications/NotificationColor";
|
import { NotificationColor } from "../../../../stores/notifications/NotificationColor";
|
||||||
import { useSettingValue } from "../../../../hooks/useSettings";
|
import { useSettingValue } from "../../../../hooks/useSettings";
|
||||||
|
import { XOR } from "../../../../@types/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
symbol: string | null;
|
symbol: string | null;
|
||||||
count: number;
|
count: number;
|
||||||
color: NotificationColor;
|
color: NotificationColor;
|
||||||
onClick?: (ev: MouseEvent) => void;
|
|
||||||
onMouseOver?: (ev: MouseEvent) => void;
|
onMouseOver?: (ev: MouseEvent) => void;
|
||||||
onMouseLeave?: (ev: MouseEvent) => void;
|
onMouseLeave?: (ev: MouseEvent) => void;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
label?: string;
|
label?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StatelessNotificationBadge({ symbol, count, color, ...props }: Props): JSX.Element {
|
interface ClickableProps extends Props {
|
||||||
|
/**
|
||||||
|
* If specified will return an AccessibleButton instead of a div.
|
||||||
|
*/
|
||||||
|
onClick(ev: React.MouseEvent): void;
|
||||||
|
tabIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatelessNotificationBadge({
|
||||||
|
symbol,
|
||||||
|
count,
|
||||||
|
color,
|
||||||
|
...props
|
||||||
|
}: XOR<Props, ClickableProps>): JSX.Element {
|
||||||
const hideBold = useSettingValue("feature_hidebold");
|
const hideBold = useSettingValue("feature_hidebold");
|
||||||
|
|
||||||
// Don't show a badge if we don't need to
|
// Don't show a badge if we don't need to
|
||||||
|
|
|
@ -85,6 +85,10 @@ interface IProps {
|
||||||
onListCollapse?: (isExpanded: boolean) => void;
|
onListCollapse?: (isExpanded: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLabelId(tagId: TagID): string {
|
||||||
|
return `mx_RoomSublist_label_${tagId}`;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Use re-resizer's NumberSize when it is exposed as the type
|
// TODO: Use re-resizer's NumberSize when it is exposed as the type
|
||||||
interface ResizeDelta {
|
interface ResizeDelta {
|
||||||
width: number;
|
width: number;
|
||||||
|
@ -712,7 +716,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
||||||
title={this.props.isMinimized ? this.props.label : undefined}
|
title={this.props.isMinimized ? this.props.label : undefined}
|
||||||
>
|
>
|
||||||
<span className={collapseClasses} />
|
<span className={collapseClasses} />
|
||||||
<span>{this.props.label}</span>
|
<span id={getLabelId(this.props.tagId)}>{this.props.label}</span>
|
||||||
</Button>
|
</Button>
|
||||||
{this.renderMenu()}
|
{this.renderMenu()}
|
||||||
{this.props.isMinimized ? null : badgeContainer}
|
{this.props.isMinimized ? null : badgeContainer}
|
||||||
|
@ -880,7 +884,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
||||||
className={classes}
|
className={classes}
|
||||||
role="group"
|
role="group"
|
||||||
aria-hidden={hidden}
|
aria-hidden={hidden}
|
||||||
aria-label={this.props.label}
|
aria-labelledby={getLabelId(this.props.tagId)}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
>
|
>
|
||||||
{this.renderHeader()}
|
{this.renderHeader()}
|
||||||
|
|
Loading…
Reference in New Issue