Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARIA Accessibility improvements #10674

Merged
merged 12 commits into from
Apr 20, 2023
5 changes: 5 additions & 0 deletions res/css/views/dialogs/_SpotlightDialog.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ limitations under the License.
overflow-y: auto;
padding: $spacing-16;

ul {
padding: 0;
margin: 0;
}

.mx_SpotlightDialog_section {
> h4,
> .mx_SpotlightDialog_sectionHeader > h4 {
Expand Down
3 changes: 2 additions & 1 deletion res/css/views/right_panel/_BaseCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,11 @@ limitations under the License.
margin-right: $spacing-12;
}

> h1 {
> h2 {
color: $tertiary-content;
font-size: $font-12px;
font-weight: 500;
margin: $spacing-12;
}

.mx_BaseCard_Button {
Expand Down
5 changes: 3 additions & 2 deletions res/css/views/right_panel/_RoomSummaryCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ limitations under the License.
text-align: center;
margin-top: $spacing-20;

h2 {
h1 {
margin: $spacing-12 0 $spacing-4;
font-weight: $font-semi-bold;
}

.mx_RoomSummaryCard_alias {
Expand All @@ -30,7 +31,7 @@ limitations under the License.
text-overflow: ellipsis;
}

h2,
h1,
.mx_RoomSummaryCard_alias {
display: -webkit-box;
-webkit-line-clamp: 2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ limitations under the License.
*/

.mx_KeyboardUserSettingsTab .mx_SettingsTab_section {
ul {
margin: 0;
padding: 0;
}

.mx_KeyboardShortcut_shortcutRow,
.mx_KeyboardShortcut {
display: flex;
Expand Down
1 change: 1 addition & 0 deletions src/components/views/auth/CountryDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export default class CountryDropdown extends React.Component<IProps, IState> {
searchEnabled={true}
disabled={this.props.disabled}
label={_t("Country Dropdown")}
autoComplete="tel-country-code"
>
{options}
</Dropdown>
Expand Down
14 changes: 9 additions & 5 deletions src/components/views/dialogs/spotlight/Option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ limitations under the License.
*/

import classNames from "classnames";
import React, { ComponentProps, ReactNode } from "react";
import React, { ReactNode, RefObject } from "react";

import { RovingAccessibleButton } from "../../../../accessibility/roving/RovingAccessibleButton";
import { useRovingTabIndex } from "../../../../accessibility/RovingTabIndex";
import AccessibleButton from "../../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";

interface OptionProps extends ComponentProps<typeof RovingAccessibleButton> {
interface OptionProps {
inputRef?: RefObject<HTMLLIElement>;
endAdornment?: ReactNode;
id?: string;
className?: string;
onClick: ((ev: ButtonEvent) => void) | null;
}

export const Option: React.FC<OptionProps> = ({ inputRef, children, endAdornment, className, ...props }) => {
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLLIElement>(inputRef);
return (
<AccessibleButton
{...props}
Expand All @@ -36,6 +39,7 @@ export const Option: React.FC<OptionProps> = ({ inputRef, children, endAdornment
tabIndex={-1}
aria-selected={isActive}
role="option"
element="li"
>
{children}
<div className="mx_SpotlightDialog_option--endAdornment">
Expand Down
20 changes: 11 additions & 9 deletions src/components/views/elements/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface IMenuOptionProps {
highlighted?: boolean;
dropdownKey: string;
id?: string;
inputRef?: Ref<HTMLDivElement>;
inputRef?: Ref<HTMLLIElement>;
onClick(dropdownKey: string): void;
onMouseEnter(dropdownKey: string): void;
}
Expand All @@ -57,7 +57,7 @@ class MenuOption extends React.Component<IMenuOptionProps> {
});

return (
<div
<li
id={this.props.id}
className={optClasses}
onClick={this.onClick}
Expand All @@ -67,7 +67,7 @@ class MenuOption extends React.Component<IMenuOptionProps> {
ref={this.props.inputRef}
>
{this.props.children}
</div>
</li>
);
}
}
Expand All @@ -78,6 +78,7 @@ export interface DropdownProps {
label: string;
value?: string;
className?: string;
autoComplete?: string;
children: NonEmptyArray<ReactElement & { key: string }>;
// negative for consistency with HTML
disabled?: boolean;
Expand Down Expand Up @@ -318,28 +319,29 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
});
if (!options?.length) {
return [
<div key="0" className="mx_Dropdown_option" role="option" aria-selected={false}>
<li key="0" className="mx_Dropdown_option" role="option" aria-selected={false}>
{_t("No results")}
</div>,
</li>,
];
}
return options;
}

public render(): React.ReactNode {
let currentValue;
let currentValue: JSX.Element | undefined;

const menuStyle: CSSProperties = {};
if (this.props.menuWidth) menuStyle.width = this.props.menuWidth;

let menu;
let menu: JSX.Element | undefined;
if (this.state.expanded) {
if (this.props.searchEnabled) {
currentValue = (
<input
id={`${this.props.id}_input`}
type="text"
autoFocus={true}
autoComplete={this.props.autoComplete}
className="mx_Dropdown_option"
onChange={this.onInputChange}
value={this.state.searchQuery}
Expand All @@ -355,9 +357,9 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
);
}
menu = (
<div className="mx_Dropdown_menu" style={menuStyle} role="listbox" id={`${this.props.id}_listbox`}>
<ul className="mx_Dropdown_menu" style={menuStyle} role="listbox" id={`${this.props.id}_listbox`}>
{this.getMenuOptions()}
</div>
</ul>
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/right_panel/BaseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ interface IGroupProps {
export const Group: React.FC<IGroupProps> = ({ className, title, children }) => {
return (
<div className={classNames("mx_BaseCard_Group", className)}>
<h1>{title}</h1>
<h2>{title}</h2>
{children}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/right_panel/RoomSummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose })
/>
</div>

<RoomName room={room}>{(name) => <h2 title={name}>{name}</h2>}</RoomName>
<RoomName room={room}>{(name) => <h1 title={name}>{name}</h1>}</RoomName>
<div className="mx_RoomSummaryCard_alias" title={alias}>
{alias}
</div>
Expand Down
3 changes: 3 additions & 0 deletions src/components/views/rooms/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ export default class SearchBar extends React.Component<IProps, IState> {
type="text"
autoFocus={true}
placeholder={_t("Search…")}
aria-label={
this.state.scope === SearchScope.Room ? _t("Search this room") : _t("Search all rooms")
}
onKeyDown={this.onSearchChange}
/>
<AccessibleButton
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/settings/account/EmailAddresses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
<Field
type="text"
label={_t("Email Address")}
autoComplete="off"
autoComplete="email"
disabled={this.state.verifying}
value={this.state.newEmailAddress}
onChange={this.onChangeNewEmailAddress}
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/settings/account/PhoneNumbers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
<Field
type="text"
label={_t("Phone Number")}
autoComplete="off"
autoComplete="tel-national"
disabled={this.state.verifying}
prefixComponent={phoneCountry}
value={this.state.newPhoneNumber}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
onClick={this.toggleAdvancedSection}
kind="link"
className="mx_SettingsTab_showAdvanced"
aria-expanded={this.state.showAdvancedSection}
>
{this.state.showAdvancedSection ? _t("Hide advanced") : _t("Show advanced")}
</AccessibleButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I

const brand = SdkConfig.get().brand;
const toggle = (
<AccessibleButton kind="link" onClick={() => this.setState({ showAdvanced: !this.state.showAdvanced })}>
<AccessibleButton
kind="link"
onClick={() => this.setState({ showAdvanced: !this.state.showAdvanced })}
aria-expanded={this.state.showAdvanced}
>
{this.state.showAdvanced ? _t("Hide advanced") : _t("Show advanced")}
</AccessibleButton>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ const KeyboardShortcutRow: React.FC<IKeyboardShortcutRowProps> = ({ name }) => {
if (!displayName || !value) return null;

return (
<div className="mx_KeyboardShortcut_shortcutRow">
<li className="mx_KeyboardShortcut_shortcutRow">
{displayName}
<KeyboardShortcut value={value} />
</div>
</li>
);
};

Expand All @@ -59,12 +59,12 @@ const KeyboardShortcutSection: React.FC<IKeyboardShortcutSectionProps> = ({ cate
return (
<div className="mx_SettingsTab_section" key={categoryName}>
<div className="mx_SettingsTab_subheading">{_t(category.categoryLabel)}</div>
<div>
<ul>
{" "}
{category.settingNames.map((shortcutName) => {
return <KeyboardShortcutRow key={shortcutName} name={shortcutName} />;
})}{" "}
</div>
</ul>
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/components/views/spaces/QuickSettingsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ const QuickSettingsButton: React.FC<{
title={_t("Quick settings")}
inputRef={handle}
forceHide={!isPanelCollapsed}
aria-expanded={!isPanelCollapsed}
>
{!isPanelCollapsed ? _t("Settings") : null}
</AccessibleTooltipButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
onClick={toggleAdvancedSection}
kind="link"
className="mx_SettingsTab_showAdvanced"
aria-expanded={showAdvancedSection}
>
{showAdvancedSection ? _t("Hide advanced") : _t("Show advanced")}
</AccessibleButton>
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,8 @@
"This Room": "This Room",
"All Rooms": "All Rooms",
"Search…": "Search…",
"Search this room": "Search this room",
"Search all rooms": "Search all rooms",
"Failed to connect to integration manager": "Failed to connect to integration manager",
"You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
"Add some now": "Add some now",
Expand Down
14 changes: 7 additions & 7 deletions test/components/views/dialogs/SpotlightDialog-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe("Spotlight Dialog", () => {
expect(filterChip.innerHTML).toContain("Public rooms");

const content = document.querySelector("#mx_SpotlightDialog_content")!;
const options = content.querySelectorAll("div.mx_SpotlightDialog_option");
const options = content.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBe(1);
expect(options[0].innerHTML).toContain(testPublicRoom.name);
});
Expand All @@ -196,7 +196,7 @@ describe("Spotlight Dialog", () => {
expect(filterChip.innerHTML).toContain("People");

const content = document.querySelector("#mx_SpotlightDialog_content")!;
const options = content.querySelectorAll("div.mx_SpotlightDialog_option");
const options = content.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBeGreaterThanOrEqual(1);
expect(options[0]!.innerHTML).toContain(testPerson.display_name);
});
Expand Down Expand Up @@ -242,7 +242,7 @@ describe("Spotlight Dialog", () => {
expect(filterChip.innerHTML).toContain("Public rooms");

const content = document.querySelector("#mx_SpotlightDialog_content")!;
const options = content.querySelectorAll("div.mx_SpotlightDialog_option");
const options = content.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBe(1);
expect(options[0]!.innerHTML).toContain(testPublicRoom.name);

Expand All @@ -265,7 +265,7 @@ describe("Spotlight Dialog", () => {
expect(filterChip.innerHTML).toContain("People");

const content = document.querySelector("#mx_SpotlightDialog_content")!;
const options = content.querySelectorAll("div.mx_SpotlightDialog_option");
const options = content.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBeGreaterThanOrEqual(1);
expect(options[0]!.innerHTML).toContain(testPerson.display_name);
});
Expand Down Expand Up @@ -324,7 +324,7 @@ describe("Spotlight Dialog", () => {
await flushPromisesWithFakeTimers();

const content = document.querySelector("#mx_SpotlightDialog_content")!;
options = content.querySelectorAll("div.mx_SpotlightDialog_option");
options = content.querySelectorAll("li.mx_SpotlightDialog_option");
});

it("should find Rooms", () => {
Expand All @@ -350,7 +350,7 @@ describe("Spotlight Dialog", () => {
jest.advanceTimersByTime(200);
await flushPromisesWithFakeTimers();

const options = document.querySelectorAll("div.mx_SpotlightDialog_option");
const options = document.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBeGreaterThanOrEqual(1);
expect(options[0]!.innerHTML).toContain(testPerson.display_name);

Expand All @@ -372,7 +372,7 @@ describe("Spotlight Dialog", () => {
await flushPromisesWithFakeTimers();

const content = document.querySelector("#mx_SpotlightDialog_content")!;
const options = content.querySelectorAll("div.mx_SpotlightDialog_option");
const options = content.querySelectorAll("li.mx_SpotlightDialog_option");
expect(options.length).toBe(1);
expect(options[0].innerHTML).toContain(testPublicRoom.name);

Expand Down
Loading