Merge pull request #3563 from matrix-org/t3chguy/timeline_a11y

Accessibility Improvements
This commit is contained in:
Travis Ralston 2019-10-23 13:37:04 -06:00 committed by GitHub
commit 3c14aed534
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 25 deletions

View file

@ -114,6 +114,15 @@ limitations under the License.
cursor: pointer; cursor: pointer;
} }
.mx_EmojiPicker_search_icon {
width: 16px;
margin: 8px;
}
.mx_EmojiPicker_search_icon:not(.mx_EmojiPicker_search_clear) {
pointer-events: none;
}
.mx_EmojiPicker_search_icon::after { .mx_EmojiPicker_search_icon::after {
mask: url('$(res)/img/emojipicker/search.svg') no-repeat; mask: url('$(res)/img/emojipicker/search.svg') no-repeat;
mask-size: 100%; mask-size: 100%;

View file

@ -116,6 +116,21 @@ const LeftPanel = createReactClass({
this.focusedElement = null; this.focusedElement = null;
}, },
_onFilterKeyDown: function(ev) {
if (!this.focusedElement) return;
switch (ev.key) {
// On enter of rooms filter select and activate first room if such one exists
case Key.ENTER: {
const firstRoom = ev.target.closest(".mx_LeftPanel").querySelector(".mx_RoomTile");
if (firstRoom) {
firstRoom.click();
}
break;
}
}
},
_onKeyDown: function(ev) { _onKeyDown: function(ev) {
if (!this.focusedElement) return; if (!this.focusedElement) return;
@ -255,6 +270,7 @@ const LeftPanel = createReactClass({
enableRoomSearchFocus={true} enableRoomSearchFocus={true}
blurredPlaceholder={ _t('Filter') } blurredPlaceholder={ _t('Filter') }
placeholder={ _t('Filter rooms…') } placeholder={ _t('Filter rooms…') }
onKeyDown={this._onFilterKeyDown}
onSearch={ this.onSearch } onSearch={ this.onSearch }
onCleared={ this.onSearchCleared } onCleared={ this.onSearchCleared }
onFocus={this._onSearchFocus} onFocus={this._onSearchFocus}
@ -273,18 +289,19 @@ const LeftPanel = createReactClass({
<TopLeftMenuButton collapsed={this.props.collapsed} /> <TopLeftMenuButton collapsed={this.props.collapsed} />
{ breadcrumbs } { breadcrumbs }
<CallPreview ConferenceHandler={VectorConferenceHandler} /> <CallPreview ConferenceHandler={VectorConferenceHandler} />
<div className="mx_LeftPanel_Rooms" onKeyDown={this._onKeyDown} onFocus={this._onFocus} onBlur={this._onBlur}> <div className="mx_LeftPanel_exploreAndFilterRow" onKeyDown={this._onKeyDown} onFocus={this._onFocus} onBlur={this._onBlur}>
<div className="mx_LeftPanel_exploreAndFilterRow">
{ exploreButton } { exploreButton }
{ searchBox } { searchBox }
</div> </div>
<RoomList <RoomList
onKeyDown={this._onKeyDown}
onFocus={this._onFocus}
onBlur={this._onBlur}
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

@ -30,6 +30,7 @@ module.exports = createReactClass({
propTypes: { propTypes: {
onSearch: PropTypes.func, onSearch: PropTypes.func,
onCleared: PropTypes.func, onCleared: PropTypes.func,
onKeyDown: PropTypes.func,
className: PropTypes.string, className: PropTypes.string,
placeholder: PropTypes.string.isRequired, placeholder: PropTypes.string.isRequired,
@ -93,6 +94,7 @@ module.exports = createReactClass({
this._clearSearch("keyboard"); this._clearSearch("keyboard");
break; break;
} }
if (this.props.onKeyDown) this.props.onKeyDown(ev);
}, },
_onFocus: function(ev) { _onFocus: function(ev) {

View file

@ -24,7 +24,7 @@ class ReactionPicker extends React.Component {
mxEvent: PropTypes.object.isRequired, mxEvent: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,
closeMenu: PropTypes.func.isRequired, closeMenu: PropTypes.func.isRequired,
reactions: PropTypes.object.isRequired, reactions: PropTypes.object,
}; };
constructor(props) { constructor(props) {

View file

@ -35,13 +35,22 @@ class Search extends React.PureComponent {
} }
render() { render() {
let rightButton;
if (this.props.query) {
rightButton = (
<button onClick={() => this.props.onChange("")}
className="mx_EmojiPicker_search_icon mx_EmojiPicker_search_clear"
title={_t("Cancel search")} />
);
} else {
rightButton = <span className="mx_EmojiPicker_search_icon" />;
}
return ( return (
<div className="mx_EmojiPicker_search"> <div className="mx_EmojiPicker_search">
<input autoFocus type="text" placeholder="Search" value={this.props.query} <input autoFocus type="text" placeholder="Search" value={this.props.query}
onChange={ev => this.props.onChange(ev.target.value)} ref={this.inputRef} /> onChange={ev => this.props.onChange(ev.target.value)} ref={this.inputRef} />
<button onClick={() => this.props.onChange("")} {rightButton}
className={`mx_EmojiPicker_search_icon ${this.props.query ? "mx_EmojiPicker_search_clear" : ""}`}
title={this.props.query ? _t("Cancel search") : _t("Search")} />
</div> </div>
); );
} }

View file

@ -56,6 +56,11 @@ export default class DateSeparator extends React.Component {
} }
render() { render() {
return <h2 className="mx_DateSeparator"><hr /><div>{ this.getLabel() }</div><hr /></h2>; // ARIA treats <hr/>s as separators, here we abuse them slightly so manually treat this entire thing as one
return <h2 className="mx_DateSeparator" role="separator">
<hr role="none" />
<div>{ this.getLabel() }</div>
<hr role="none" />
</h2>;
} }
} }

View file

@ -705,7 +705,7 @@ module.exports = createReactClass({
{ timestamp } { timestamp }
</a> </a>
</div> </div>
<div className="mx_EventTile_line" > <div className="mx_EventTile_line">
<EventTileType ref="tile" <EventTileType ref="tile"
mxEvent={this.props.mxEvent} mxEvent={this.props.mxEvent}
highlights={this.props.highlights} highlights={this.props.highlights}
@ -719,7 +719,7 @@ module.exports = createReactClass({
case 'file_grid': { case 'file_grid': {
return ( return (
<div className={classes}> <div className={classes}>
<div className="mx_EventTile_line" > <div className="mx_EventTile_line">
<EventTileType ref="tile" <EventTileType ref="tile"
mxEvent={this.props.mxEvent} mxEvent={this.props.mxEvent}
highlights={this.props.highlights} highlights={this.props.highlights}

View file

@ -770,9 +770,17 @@ module.exports = createReactClass({
const subListComponents = this._mapSubListProps(subLists); const subListComponents = this._mapSubListProps(subLists);
const {resizeNotifier, collapsed, searchFilter, ConferenceHandler, ...props} = this.props; // eslint-disable-line
return ( return (
<div ref={this._collectResizeContainer} className="mx_RoomList" role="tree" aria-label={_t("Rooms")} <div
onMouseMove={this.onMouseMove} onMouseLeave={this.onMouseLeave}> {...props}
ref={this._collectResizeContainer}
className="mx_RoomList"
role="tree"
aria-label={_t("Rooms")}
onMouseMove={this.onMouseMove}
onMouseLeave={this.onMouseLeave}
>
{ subListComponents } { subListComponents }
</div> </div>
); );