Merge pull request #3562 from matrix-org/t3chguy/a11y_iteration
A11Y fixes in the Left Panel
This commit is contained in:
commit
fc45a69bb7
4 changed files with 54 additions and 53 deletions
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue