Make everything use the KeyBindingManager
(#7907)
This commit is contained in:
parent
5f8441216c
commit
df591ee835
37 changed files with 529 additions and 277 deletions
|
@ -21,11 +21,12 @@ import ReactDOM from "react-dom";
|
|||
import classNames from "classnames";
|
||||
import FocusLock from "react-focus-lock";
|
||||
|
||||
import { Key } from "../../Keyboard";
|
||||
import { Writeable } from "../../@types/common";
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import UIStore from "../../stores/UIStore";
|
||||
import { checkInputableElement, RovingTabIndexProvider } from "../../accessibility/RovingTabIndex";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
|
||||
// Shamelessly ripped off Modal.js. There's probably a better way
|
||||
// of doing reusable widgets like dialog boxes & menus where we go and
|
||||
|
@ -191,30 +192,32 @@ export default class ContextMenu extends React.PureComponent<IProps, IState> {
|
|||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
ev.stopPropagation(); // prevent keyboard propagating out of the context menu, we're focus-locked
|
||||
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
|
||||
// If someone is managing their own focus, we will only exit for them with Escape.
|
||||
// They are probably using props.focusLock along with this option as well.
|
||||
if (!this.props.managed) {
|
||||
if (ev.key === Key.ESCAPE) {
|
||||
if (action === KeyBindingAction.Escape) {
|
||||
this.props.onFinished();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// When an <input> is focused, only handle the Escape key
|
||||
if (checkInputableElement(ev.target as HTMLElement) && ev.key !== Key.ESCAPE) {
|
||||
if (checkInputableElement(ev.target as HTMLElement) && action !== KeyBindingAction.Escape) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
ev.key === Key.ESCAPE ||
|
||||
if ([
|
||||
KeyBindingAction.Escape,
|
||||
// You can only navigate the ContextMenu by arrow keys and Home/End (see RovingTabIndex).
|
||||
// Tabbing to the next section of the page, will close the ContextMenu.
|
||||
ev.key === Key.TAB ||
|
||||
KeyBindingAction.Tab,
|
||||
// When someone moves left or right along a <Toolbar /> (like the
|
||||
// MessageActionBar), we should close any ContextMenu that is open.
|
||||
ev.key === Key.ARROW_LEFT ||
|
||||
ev.key === Key.ARROW_RIGHT
|
||||
) {
|
||||
KeyBindingAction.ArrowLeft,
|
||||
KeyBindingAction.ArrowRight,
|
||||
].includes(action)) {
|
||||
this.props.onFinished();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,7 +35,6 @@ import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
|||
import UIStore from "../../stores/UIStore";
|
||||
import { findSiblingElement, IState as IRovingTabIndexState } from "../../accessibility/RovingTabIndex";
|
||||
import RoomListHeader from "../views/rooms/RoomListHeader";
|
||||
import { Key } from "../../Keyboard";
|
||||
import RecentlyViewedButton from "../views/rooms/RecentlyViewedButton";
|
||||
import { BreadcrumbsStore } from "../../stores/BreadcrumbsStore";
|
||||
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomListStore";
|
||||
|
@ -316,12 +315,15 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
private onRoomListKeydown = (ev: React.KeyboardEvent) => {
|
||||
if (ev.altKey || ev.ctrlKey || ev.metaKey) return;
|
||||
if (SettingsStore.getValue("feature_spotlight")) return;
|
||||
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
|
||||
// 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) {
|
||||
} else if (action === KeyBindingAction.Backspace) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.roomSearchRef.current?.backspace();
|
||||
|
|
|
@ -20,7 +20,6 @@ import classNames from "classnames";
|
|||
|
||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||
import { useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
||||
import { Key } from "../../Keyboard";
|
||||
import { useLocalStorageState } from "../../hooks/useLocalStorageState";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import WidgetUtils, { IWidgetEvent } from "../../utils/WidgetUtils";
|
||||
|
@ -28,6 +27,8 @@ import { useAccountData } from "../../hooks/useAccountData";
|
|||
import AppTile from "../views/elements/AppTile";
|
||||
import { useSettingValue } from "../../hooks/useSettings";
|
||||
import UIStore from "../../stores/UIStore";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
const MIN_HEIGHT = 100;
|
||||
const MAX_HEIGHT = 500; // or 50% of the window height
|
||||
|
@ -91,16 +92,16 @@ const LeftPanelWidget: React.FC = () => {
|
|||
onFocus={onFocus}
|
||||
className="mx_LeftPanelWidget_headerContainer"
|
||||
onKeyDown={(ev: React.KeyboardEvent) => {
|
||||
switch (ev.key) {
|
||||
case Key.ARROW_LEFT:
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.ArrowLeft:
|
||||
ev.stopPropagation();
|
||||
setExpanded(false);
|
||||
break;
|
||||
case Key.ARROW_RIGHT: {
|
||||
case KeyBindingAction.ArrowRight:
|
||||
ev.stopPropagation();
|
||||
setExpanded(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -19,9 +19,10 @@ import React, { createRef, HTMLProps } from 'react';
|
|||
import { throttle } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Key } from '../../Keyboard';
|
||||
import AccessibleButton from '../../components/views/elements/AccessibleButton';
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IProps extends HTMLProps<HTMLInputElement> {
|
||||
onSearch?: (query: string) => void;
|
||||
|
@ -66,8 +67,9 @@ export default class SearchBox extends React.Component<IProps, IState> {
|
|||
}, 200, { trailing: true, leading: true });
|
||||
|
||||
private onKeyDown = (ev: React.KeyboardEvent): void => {
|
||||
switch (ev.key) {
|
||||
case Key.ESCAPE:
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Escape:
|
||||
this.clearSearch("keyboard");
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
|||
import { linkifyElement } from "../../HtmlUtils";
|
||||
import { useDispatcher } from "../../hooks/useDispatcher";
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import { Key } from "../../Keyboard";
|
||||
import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
||||
import { getDisplayAliasForRoom } from "./RoomDirectory";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
|
@ -64,6 +63,8 @@ import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
|
|||
import RoomViewStore from "../../stores/RoomViewStore";
|
||||
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
|
||||
interface IProps {
|
||||
space: Room;
|
||||
|
@ -247,10 +248,13 @@ const Tile: React.FC<ITileProps> = ({
|
|||
|
||||
if (showChildren) {
|
||||
const onChildrenKeyDown = (e) => {
|
||||
if (e.key === Key.ARROW_LEFT) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
ref.current?.focus();
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.ArrowLeft:
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
ref.current?.focus();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -266,15 +270,16 @@ const Tile: React.FC<ITileProps> = ({
|
|||
onKeyDown = (e) => {
|
||||
let handled = false;
|
||||
|
||||
switch (e.key) {
|
||||
case Key.ARROW_LEFT:
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.ArrowLeft:
|
||||
if (showChildren) {
|
||||
handled = true;
|
||||
toggleShowChildren();
|
||||
}
|
||||
break;
|
||||
|
||||
case Key.ARROW_RIGHT:
|
||||
case KeyBindingAction.ArrowRight:
|
||||
handled = true;
|
||||
if (showChildren) {
|
||||
const childSection = ref.current?.nextElementSibling;
|
||||
|
@ -700,7 +705,11 @@ const SpaceHierarchy = ({
|
|||
}
|
||||
|
||||
const onKeyDown = (ev: KeyboardEvent, state: IState): void => {
|
||||
if (ev.key === Key.ARROW_DOWN && ev.currentTarget.classList.contains("mx_SpaceHierarchy_search")) {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
if (
|
||||
action === KeyBindingAction.ArrowDown &&
|
||||
ev.currentTarget.classList.contains("mx_SpaceHierarchy_search")
|
||||
) {
|
||||
state.refs[0]?.current?.focus();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -37,7 +37,6 @@ import UserActivity from "../../UserActivity";
|
|||
import Modal from "../../Modal";
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import { Action } from '../../dispatcher/actions';
|
||||
import { Key } from '../../Keyboard';
|
||||
import Timer from '../../utils/Timer';
|
||||
import shouldHideEvent from '../../shouldHideEvent';
|
||||
import { haveTileForEvent } from "../views/rooms/EventTile";
|
||||
|
@ -54,6 +53,8 @@ import EditorStateTransfer from '../../utils/EditorStateTransfer';
|
|||
import ErrorDialog from '../views/dialogs/ErrorDialog';
|
||||
import CallEventGrouper, { buildCallEventGroupers } from "./CallEventGrouper";
|
||||
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
const PAGINATE_SIZE = 20;
|
||||
const INITIAL_SIZE = 20;
|
||||
|
@ -1086,11 +1087,12 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
* We pass it down to the scroll panel.
|
||||
*/
|
||||
public handleScrollKey = ev => {
|
||||
if (!this.messagePanel.current) { return; }
|
||||
if (!this.messagePanel.current) return;
|
||||
|
||||
// jump to the live timeline on ctrl-end, rather than the end of the
|
||||
// timeline window.
|
||||
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.END) {
|
||||
const action = getKeyBindingsManager().getRoomAction(ev);
|
||||
if (action === KeyBindingAction.JumpToLatestMessage) {
|
||||
this.jumpToLiveTimeline();
|
||||
} else {
|
||||
this.messagePanel.current.handleScrollKey(ev);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue