Merge pull request #3562 from matrix-org/t3chguy/a11y_iteration

A11Y fixes in the Left Panel
This commit is contained in:
Michael Telatynski 2019-10-23 16:17:17 +01:00 committed by GitHub
commit fc45a69bb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 53 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -19,7 +20,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { MatrixClient } from 'matrix-js-sdk'; import { MatrixClient } from 'matrix-js-sdk';
import { KeyCode } from '../../Keyboard'; import { Key } from '../../Keyboard';
import sdk from '../../index'; import sdk from '../../index';
import dis from '../../dispatcher'; import dis from '../../dispatcher';
import VectorConferenceHandler from '../../VectorConferenceHandler'; import VectorConferenceHandler from '../../VectorConferenceHandler';
@ -117,35 +118,21 @@ const LeftPanel = createReactClass({
_onKeyDown: function(ev) { _onKeyDown: function(ev) {
if (!this.focusedElement) return; if (!this.focusedElement) return;
let handled = true;
switch (ev.keyCode) { switch (ev.key) {
case KeyCode.TAB: case Key.TAB:
this._onMoveFocus(ev.shiftKey); this._onMoveFocus(ev, ev.shiftKey);
break; break;
case KeyCode.UP: case Key.ARROW_UP:
this._onMoveFocus(true); this._onMoveFocus(ev, true, true);
break; break;
case KeyCode.DOWN: case Key.ARROW_DOWN:
this._onMoveFocus(false); this._onMoveFocus(ev, false, true);
break; break;
case KeyCode.ENTER:
this._onMoveFocus(false);
if (this.focusedElement) {
this.focusedElement.click();
}
break;
default:
handled = false;
}
if (handled) {
ev.stopPropagation();
ev.preventDefault();
} }
}, },
_onMoveFocus: function(up) { _onMoveFocus: function(ev, up, trap) {
let element = this.focusedElement; let element = this.focusedElement;
// unclear why this isn't needed // unclear why this isn't needed
@ -179,29 +166,24 @@ const LeftPanel = createReactClass({
if (element) { if (element) {
classes = element.classList; classes = element.classList;
if (classes.contains("mx_LeftPanel")) { // we hit the top
element = up ? element.lastElementChild : element.firstElementChild;
descending = true;
}
} }
} while (element && !( } while (element && !(
classes.contains("mx_RoomTile") || classes.contains("mx_RoomTile") ||
classes.contains("mx_RoomSubList_label") || classes.contains("mx_RoomSubList_label") ||
classes.contains("mx_textinput_search"))); classes.contains("mx_LeftPanel_filterRooms")));
if (element) { if (element) {
ev.stopPropagation();
ev.preventDefault();
element.focus(); element.focus();
this.focusedElement = element; this.focusedElement = element;
this.focusedDescending = descending; } else if (trap) {
// if navigation is via up/down arrow-keys, trap in the widget so it doesn't send to composer
ev.stopPropagation();
ev.preventDefault();
} }
}, },
onHideClick: function() {
dis.dispatch({
action: 'hide_left_panel',
});
},
onSearch: function(term) { onSearch: function(term) {
this.setState({ searchFilter: term }); this.setState({ searchFilter: term });
}, },
@ -269,6 +251,7 @@ const LeftPanel = createReactClass({
} }
const searchBox = (<SearchBox const searchBox = (<SearchBox
className="mx_LeftPanel_filterRooms"
enableRoomSearchFocus={true} enableRoomSearchFocus={true}
blurredPlaceholder={ _t('Filter') } blurredPlaceholder={ _t('Filter') }
placeholder={ _t('Filter rooms…') } placeholder={ _t('Filter rooms…') }
@ -286,20 +269,22 @@ const LeftPanel = createReactClass({
return ( return (
<div className={containerClasses}> <div className={containerClasses}>
{ tagPanelContainer } { tagPanelContainer }
<aside className={"mx_LeftPanel dark-panel"} onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }> <aside className="mx_LeftPanel dark-panel">
<TopLeftMenuButton collapsed={ this.props.collapsed } /> <TopLeftMenuButton collapsed={this.props.collapsed} />
{ breadcrumbs } { breadcrumbs }
<CallPreview ConferenceHandler={VectorConferenceHandler} />
<div className="mx_LeftPanel_Rooms" onKeyDown={this._onKeyDown} onFocus={this._onFocus} onBlur={this._onBlur}>
<div className="mx_LeftPanel_exploreAndFilterRow"> <div className="mx_LeftPanel_exploreAndFilterRow">
{ exploreButton } { exploreButton }
{ searchBox } { searchBox }
</div> </div>
<CallPreview ConferenceHandler={VectorConferenceHandler} />
<RoomList <RoomList
ref={this.collectRoomList} ref={this.collectRoomList}
resizeNotifier={this.props.resizeNotifier} resizeNotifier={this.props.resizeNotifier}
collapsed={this.props.collapsed} collapsed={this.props.collapsed}
searchFilter={this.state.searchFilter} searchFilter={this.state.searchFilter}
ConferenceHandler={VectorConferenceHandler} /> ConferenceHandler={VectorConferenceHandler} />
</div>
</aside> </aside>
</div> </div>
); );

View file

@ -324,6 +324,7 @@ const RoomSubList = createReactClass({
aria-expanded={!isCollapsed} aria-expanded={!isCollapsed}
inputRef={this._headerButton} inputRef={this._headerButton}
role="treeitem" role="treeitem"
aria-level="1"
> >
{ chevron } { chevron }
<span>{this.props.label}</span> <span>{this.props.label}</span>

View file

@ -346,8 +346,15 @@ export default class RoomBreadcrumbs extends React.Component {
} }
return ( return (
<AccessibleButton className={classes} key={r.room.roomId} onClick={() => this._viewRoom(r.room, i)} <AccessibleButton
onMouseEnter={() => this._onMouseEnter(r.room)} onMouseLeave={() => this._onMouseLeave(r.room)}> className={classes}
key={r.room.roomId}
onClick={() => this._viewRoom(r.room, i)}
onMouseEnter={() => this._onMouseEnter(r.room)}
onMouseLeave={() => this._onMouseLeave(r.room)}
aria-label={_t("Room %(name)s", {name: r.room.name})}
role="listitem"
>
<RoomAvatar room={r.room} width={32} height={32} /> <RoomAvatar room={r.room} width={32} height={32} />
{badge} {badge}
{dmIndicator} {dmIndicator}
@ -356,10 +363,16 @@ export default class RoomBreadcrumbs extends React.Component {
); );
}); });
return ( return (
<IndicatorScrollbar ref="scroller" className="mx_RoomBreadcrumbs" <div role="list" aria-orientation="horizontal" aria-roledescription={_t("Recent rooms")}>
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}> <IndicatorScrollbar
ref="scroller"
className="mx_RoomBreadcrumbs"
trackHorizontalOverflow={true}
verticalScrollsHorizontally={true}
>
{ avatars } { avatars }
</IndicatorScrollbar> </IndicatorScrollbar>
</div>
); );
} }
} }

View file

@ -896,6 +896,8 @@
"Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Seen by %(displayName)s (%(userName)s) at %(dateTime)s", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Seen by %(displayName)s (%(userName)s) at %(dateTime)s",
"Replying": "Replying", "Replying": "Replying",
"Direct Chat": "Direct Chat", "Direct Chat": "Direct Chat",
"Room %(name)s": "Room %(name)s",
"Recent rooms": "Recent rooms",
"No rooms to show": "No rooms to show", "No rooms to show": "No rooms to show",
"Unnamed room": "Unnamed room", "Unnamed room": "Unnamed room",
"World readable": "World readable", "World readable": "World readable",