Merge pull request #3563 from matrix-org/t3chguy/timeline_a11y
Accessibility Improvements
This commit is contained in:
commit
3c14aed534
9 changed files with 75 additions and 25 deletions
|
@ -114,6 +114,15 @@ limitations under the License.
|
|||
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 {
|
||||
mask: url('$(res)/img/emojipicker/search.svg') no-repeat;
|
||||
mask-size: 100%;
|
||||
|
|
|
@ -116,6 +116,21 @@ const LeftPanel = createReactClass({
|
|||
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) {
|
||||
if (!this.focusedElement) return;
|
||||
|
||||
|
@ -255,6 +270,7 @@ const LeftPanel = createReactClass({
|
|||
enableRoomSearchFocus={true}
|
||||
blurredPlaceholder={ _t('Filter') }
|
||||
placeholder={ _t('Filter rooms…') }
|
||||
onKeyDown={this._onFilterKeyDown}
|
||||
onSearch={ this.onSearch }
|
||||
onCleared={ this.onSearchCleared }
|
||||
onFocus={this._onSearchFocus}
|
||||
|
@ -273,18 +289,19 @@ const LeftPanel = createReactClass({
|
|||
<TopLeftMenuButton collapsed={this.props.collapsed} />
|
||||
{ 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" onKeyDown={this._onKeyDown} onFocus={this._onFocus} onBlur={this._onBlur}>
|
||||
{ exploreButton }
|
||||
{ searchBox }
|
||||
</div>
|
||||
<RoomList
|
||||
onKeyDown={this._onKeyDown}
|
||||
onFocus={this._onFocus}
|
||||
onBlur={this._onBlur}
|
||||
ref={this.collectRoomList}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
collapsed={this.props.collapsed}
|
||||
searchFilter={this.state.searchFilter}
|
||||
ConferenceHandler={VectorConferenceHandler} />
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,6 +30,7 @@ module.exports = createReactClass({
|
|||
propTypes: {
|
||||
onSearch: PropTypes.func,
|
||||
onCleared: PropTypes.func,
|
||||
onKeyDown: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
placeholder: PropTypes.string.isRequired,
|
||||
|
||||
|
@ -93,6 +94,7 @@ module.exports = createReactClass({
|
|||
this._clearSearch("keyboard");
|
||||
break;
|
||||
}
|
||||
if (this.props.onKeyDown) this.props.onKeyDown(ev);
|
||||
},
|
||||
|
||||
_onFocus: function(ev) {
|
||||
|
|
|
@ -24,7 +24,7 @@ class ReactionPicker extends React.Component {
|
|||
mxEvent: PropTypes.object.isRequired,
|
||||
onFinished: PropTypes.func.isRequired,
|
||||
closeMenu: PropTypes.func.isRequired,
|
||||
reactions: PropTypes.object.isRequired,
|
||||
reactions: PropTypes.object,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
|
@ -35,13 +35,22 @@ class Search extends React.PureComponent {
|
|||
}
|
||||
|
||||
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 (
|
||||
<div className="mx_EmojiPicker_search">
|
||||
<input autoFocus type="text" placeholder="Search" value={this.props.query}
|
||||
onChange={ev => this.props.onChange(ev.target.value)} ref={this.inputRef} />
|
||||
<button onClick={() => this.props.onChange("")}
|
||||
className={`mx_EmojiPicker_search_icon ${this.props.query ? "mx_EmojiPicker_search_clear" : ""}`}
|
||||
title={this.props.query ? _t("Cancel search") : _t("Search")} />
|
||||
{rightButton}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,11 @@ export default class DateSeparator extends React.Component {
|
|||
}
|
||||
|
||||
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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -770,9 +770,17 @@ module.exports = createReactClass({
|
|||
|
||||
const subListComponents = this._mapSubListProps(subLists);
|
||||
|
||||
const {resizeNotifier, collapsed, searchFilter, ConferenceHandler, ...props} = this.props; // eslint-disable-line
|
||||
return (
|
||||
<div ref={this._collectResizeContainer} className="mx_RoomList" role="tree" aria-label={_t("Rooms")}
|
||||
onMouseMove={this.onMouseMove} onMouseLeave={this.onMouseLeave}>
|
||||
<div
|
||||
{...props}
|
||||
ref={this._collectResizeContainer}
|
||||
className="mx_RoomList"
|
||||
role="tree"
|
||||
aria-label={_t("Rooms")}
|
||||
onMouseMove={this.onMouseMove}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
>
|
||||
{ subListComponents }
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue