Improve a11y:

+ Close context menu on escape
+ Use AccessibleButtons for more things (Context Menus and TabbedView)

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2019-09-26 14:52:20 +01:00
parent 8ec0ffea3a
commit c37e27f03d
6 changed files with 86 additions and 94 deletions

View file

@ -21,6 +21,7 @@ import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {focusCapturedRef} from "../../utils/Accessibility";
import {KeyCode} from "../../Keyboard";
// Shamelessly ripped off Modal.js. There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
@ -67,7 +68,7 @@ export default class ContextualMenu extends React.Component {
// on resize callback
windowResize: PropTypes.func,
// method to close menu
closeMenu: PropTypes.func,
closeMenu: PropTypes.func.isRequired,
};
constructor() {
@ -114,6 +115,14 @@ export default class ContextualMenu extends React.Component {
}
}
_onKeyDown = (ev) => {
if (ev.keyCode === KeyCode.ESCAPE) {
ev.stopPropagation();
ev.preventDefault();
this.props.closeMenu();
}
};
render() {
const position = {};
let chevronFace = null;
@ -210,7 +219,7 @@ export default class ContextualMenu extends React.Component {
// FIXME: If a menu uses getDefaultProps it clobbers the onFinished
// property set here so you can't close the menu from a button click!
return <div className={className} style={{...position, ...wrapperStyle}}>
return <div className={className} style={{...position, ...wrapperStyle}} onKeyDown={this._onKeyDown}>
<div className={menuClasses} style={menuStyle} ref={this.collectContextMenuRect} tabIndex={0}>
{ chevron }
<ElementClass {...props} onFinished={props.closeMenu} onResize={props.windowResize} />

View file

@ -17,9 +17,9 @@ limitations under the License.
*/
import * as React from "react";
import {_t} from '../../languageHandler';
import {KeyCode} from "../../Keyboard";
import {_t} from '../../languageHandler';``
import PropTypes from "prop-types";
import sdk from "../../index";
/**
* Represents a tab for the TabbedView.
@ -72,6 +72,8 @@ export class TabbedView extends React.Component {
}
_renderTabLabel(tab) {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
let classes = "mx_TabbedView_tabLabel ";
const idx = this.props.tabs.indexOf(tab);
@ -83,30 +85,15 @@ export class TabbedView extends React.Component {
}
const onClickHandler = () => this._setActiveTab(tab);
const onKeyDownHandler = (e) => {
if (e.keyCode === KeyCode.ENTER || e.keyCode === KeyCode.SPACE) {
e.stopPropagation();
e.preventDefault();
this._setActiveTab(tab);
}
};
const label = _t(tab.label);
return (
<span
className={classes}
key={"tab_label_" + tab.label}
onClick={onClickHandler}
onKeyDown={onKeyDownHandler}
role="button"
aria-label={label}
tabIndex={0}
>
<AccessibleButton className={classes} key={"tab_label_" + tab.label} onClick={onClickHandler}>
{tabIcon}
<span className="mx_TabbedView_tabLabel_text">
{ label }
</span>
</span>
</AccessibleButton>
);
}

View file

@ -109,10 +109,11 @@ export default class TopLeftMenuButton extends React.Component {
return (
<AccessibleButton
className="mx_TopLeftMenuButton"
role="button"
onClick={this.onToggleMenu}
inputRef={(r) => this._buttonRef = r}
aria-label={_t("Your profile")}
aria-haspopup={true}
aria-expanded={this.state.menuDisplayed}
>
<BaseAvatar
idName={MatrixClientPeg.get().getUserId()}