First step towards a11y in the new room list
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
0549ef83db
commit
289f40ce29
6 changed files with 158 additions and 19 deletions
|
@ -35,6 +35,7 @@ import { DefaultTagID, TagID } from "../../../stores/room-list/models";
|
|||
import dis from "../../../dispatcher/dispatcher";
|
||||
import NotificationBadge from "./NotificationBadge";
|
||||
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
|
||||
import { Key } from "../../../Keyboard";
|
||||
|
||||
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||
|
@ -80,6 +81,9 @@ interface IState {
|
|||
}
|
||||
|
||||
export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||
private headerButton = createRef<HTMLDivElement>();
|
||||
private sublistRef = createRef<HTMLDivElement>();
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
|
@ -215,8 +219,52 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
sublist.scrollIntoView({behavior: 'smooth'});
|
||||
} else {
|
||||
// on screen - toggle collapse
|
||||
this.props.layout.isCollapsed = !this.props.layout.isCollapsed;
|
||||
this.forceUpdate(); // because the layout doesn't trigger an update
|
||||
this.toggleCollapsed();
|
||||
}
|
||||
};
|
||||
|
||||
private toggleCollapsed = () => {
|
||||
this.props.layout.isCollapsed = !this.props.layout.isCollapsed;
|
||||
this.forceUpdate(); // because the layout doesn't trigger an update
|
||||
};
|
||||
|
||||
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
||||
const isCollapsed = this.props.layout && this.props.layout.isCollapsed;
|
||||
switch (ev.key) {
|
||||
case Key.ARROW_LEFT:
|
||||
ev.stopPropagation();
|
||||
if (!isCollapsed) {
|
||||
// On ARROW_LEFT collapse the room sublist if it isn't already
|
||||
this.toggleCollapsed();
|
||||
}
|
||||
break;
|
||||
case Key.ARROW_RIGHT: {
|
||||
ev.stopPropagation();
|
||||
if (isCollapsed) {
|
||||
// On ARROW_RIGHT expand the room sublist if it isn't already
|
||||
this.toggleCollapsed();
|
||||
} else if (this.sublistRef.current) {
|
||||
// otherwise focus the first room
|
||||
const element = this.sublistRef.current.querySelector(".mx_RoomTile2") as HTMLDivElement;
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
switch (ev.key) {
|
||||
// On ARROW_LEFT go to the sublist header
|
||||
case Key.ARROW_LEFT:
|
||||
ev.stopPropagation();
|
||||
this.headerButton.current.focus();
|
||||
break;
|
||||
// Consume ARROW_RIGHT so it doesn't cause focus to get sent to composer
|
||||
case Key.ARROW_RIGHT:
|
||||
ev.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -335,7 +383,6 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
return (
|
||||
<RovingTabIndexWrapper>
|
||||
{({onFocus, isActive, ref}) => {
|
||||
// TODO: Use onFocus: https://github.com/vector-im/riot-web/issues/14180
|
||||
const tabIndex = isActive ? 0 : -1;
|
||||
|
||||
const badge = (
|
||||
|
@ -382,13 +429,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
// doesn't become sticky.
|
||||
// The same applies to the notification badge.
|
||||
return (
|
||||
<div className={classes}>
|
||||
<div className='mx_RoomSublist2_stickable'>
|
||||
<div className={classes} onKeyDown={this.onHeaderKeyDown} onFocus={onFocus}>
|
||||
<div className="mx_RoomSublist2_stickable">
|
||||
<AccessibleButton
|
||||
onFocus={onFocus}
|
||||
inputRef={ref}
|
||||
tabIndex={tabIndex}
|
||||
className={"mx_RoomSublist2_headerText"}
|
||||
className="mx_RoomSublist2_headerText"
|
||||
role="treeitem"
|
||||
aria-level={1}
|
||||
onClick={this.onHeaderClick}
|
||||
|
@ -516,12 +563,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: onKeyDown support: https://github.com/vector-im/riot-web/issues/14180
|
||||
return (
|
||||
<div
|
||||
ref={this.sublistRef}
|
||||
className={classes}
|
||||
role="group"
|
||||
aria-label={this.props.label}
|
||||
onKeyDown={this.onKeyDown}
|
||||
>
|
||||
{this.renderHeader()}
|
||||
{content}
|
||||
|
|
|
@ -235,7 +235,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
|||
private onClickMentions = ev => this.saveNotifState(ev, MENTIONS_ONLY);
|
||||
private onClickMute = ev => this.saveNotifState(ev, MUTE);
|
||||
|
||||
private renderNotificationsMenu(): React.ReactElement {
|
||||
private renderNotificationsMenu(isActive: boolean): React.ReactElement {
|
||||
if (this.props.isMinimized || MatrixClientPeg.get().isGuest() || this.props.tag === DefaultTagID.Invite) {
|
||||
// the menu makes no sense in these cases so do not show one
|
||||
return null;
|
||||
|
@ -296,6 +296,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
|||
onClick={this.onNotificationsMenuOpenClick}
|
||||
label={_t("Notification options")}
|
||||
isExpanded={!!this.state.notificationsMenuPosition}
|
||||
tabIndex={isActive ? 0 : -1}
|
||||
/>
|
||||
{contextMenu}
|
||||
</React.Fragment>
|
||||
|
@ -434,7 +435,7 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
|
|||
{roomAvatar}
|
||||
{nameContainer}
|
||||
{badge}
|
||||
{this.renderNotificationsMenu()}
|
||||
{this.renderNotificationsMenu(isActive)}
|
||||
{this.renderGeneralMenu()}
|
||||
</AccessibleButton>
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue