From 9727a82a12f255500febc2890c870e0d7ad3d320 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 29 Nov 2021 17:18:35 +0000 Subject: [PATCH] Allow filtering room list during treeview navigation (#7219) --- src/accessibility/RovingTabIndex.tsx | 11 ++++++++--- src/components/structures/LeftPanel.tsx | 15 +++++++++++++++ src/components/structures/RoomSearch.tsx | 12 ++++++++++++ test/accessibility/RovingTabIndex-test.tsx | 5 +++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx index 8c49a4d6ae..51cc2322d1 100644 --- a/src/accessibility/RovingTabIndex.tsx +++ b/src/accessibility/RovingTabIndex.tsx @@ -123,9 +123,14 @@ export const reducer = (state: IState, action: IAction) => { if (state.refs.splice(oldIndex, 1)[0] === state.activeRef) { // we just removed the active ref, need to replace it - // pick the ref which is now in the index the old ref was in - const len = state.refs.length; - state.activeRef = oldIndex >= len ? state.refs[len - 1] : state.refs[oldIndex]; + // pick the ref closest to the index the old ref was in + if (oldIndex >= state.refs.length) { + state.activeRef = findSiblingElement(state.refs, state.refs.length - 1, true); + } else { + state.activeRef = findSiblingElement(state.refs, oldIndex) + || findSiblingElement(state.refs, oldIndex, true); + } + state.activeRef?.current?.focus(); } // update the refs list diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 98a92f4624..f25ae269da 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -42,6 +42,7 @@ import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager" import UIStore from "../../stores/UIStore"; import { findSiblingElement, IState as IRovingTabIndexState } from "../../accessibility/RovingTabIndex"; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import { Key } from "../../Keyboard"; interface IProps { isMinimized: boolean; @@ -304,6 +305,19 @@ export default class LeftPanel extends React.Component { } }; + private onRoomListKeydown = (ev: React.KeyboardEvent) => { + // we cannot handle Space as that is an activation key for all focusable elements in this widget + if (ev.key.length === 1) { + ev.preventDefault(); + ev.stopPropagation(); + this.roomSearchRef.current?.appendChar(ev.key); + } else if (ev.key === Key.BACKSPACE) { + ev.preventDefault(); + ev.stopPropagation(); + this.roomSearchRef.current?.backspace(); + } + }; + private selectRoom = () => { const firstRoom = this.listContainerRef.current.querySelector(".mx_RoomTile"); if (firstRoom) { @@ -411,6 +425,7 @@ export default class LeftPanel extends React.Component { // Firefox sometimes makes this element focusable due to // overflow:scroll;, so force it out of tab order. tabIndex={-1} + onKeyDown={this.onRoomListKeydown} > { roomList } diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index a6161c7d0d..600f4a0474 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -214,4 +214,16 @@ export default class RoomSearch extends React.PureComponent { ); } + + public appendChar(char: string): void { + this.setState({ + query: this.state.query + char, + }); + } + + public backspace(): void { + this.setState({ + query: this.state.query.substring(0, this.state.query.length - 1), + }); + } } diff --git a/test/accessibility/RovingTabIndex-test.tsx b/test/accessibility/RovingTabIndex-test.tsx index 7c08a676a9..9d9eefcc9a 100644 --- a/test/accessibility/RovingTabIndex-test.tsx +++ b/test/accessibility/RovingTabIndex-test.tsx @@ -45,6 +45,11 @@ const button2 = ; const button3 = ; const button4 = ; +// mock offsetParent +Object.defineProperty(HTMLElement.prototype, "offsetParent", { + get() { return this.parentNode; }, +}); + describe("RovingTabIndex", () => { it("RovingTabIndexProvider renders children as expected", () => { const wrapper = mount(