Make everything use the KeyBindingManager (#7907)

This commit is contained in:
Šimon Brandner 2022-02-28 17:05:52 +01:00 committed by GitHub
parent 5f8441216c
commit df591ee835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 529 additions and 277 deletions

View file

@ -30,7 +30,6 @@ import * as Email from '../../../email';
import IdentityAuthClient from '../../../IdentityAuthClient';
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils';
import { abbreviateUrl } from '../../../utils/UrlUtils';
import { Key } from "../../../Keyboard";
import { Action } from "../../../dispatcher/actions";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import AddressSelector from '../elements/AddressSelector';
@ -38,6 +37,8 @@ import AddressTile from '../elements/AddressTile';
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
import AccessibleButton from '../elements/AccessibleButton';
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
const TRUNCATE_QUERY_LIST = 40;
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
@ -167,40 +168,38 @@ export default class AddressPickerDialog extends React.Component<IProps, IState>
private onKeyDown = (e: React.KeyboardEvent): void => {
const textInput = this.textinput.current ? this.textinput.current.value : undefined;
let handled = true;
const action = getKeyBindingsManager().getAccessibilityAction(e);
if (e.key === Key.ESCAPE) {
e.stopPropagation();
e.preventDefault();
if (action === KeyBindingAction.Escape) {
this.props.onFinished(false);
} else if (e.key === Key.ARROW_UP) {
e.stopPropagation();
e.preventDefault();
if (this.addressSelector.current) this.addressSelector.current.moveSelectionUp();
} else if (e.key === Key.ARROW_DOWN) {
e.stopPropagation();
e.preventDefault();
if (this.addressSelector.current) this.addressSelector.current.moveSelectionDown();
} else if (this.state.suggestedList.length > 0 && [Key.COMMA, Key.ENTER, Key.TAB].includes(e.key)) {
e.stopPropagation();
e.preventDefault();
if (this.addressSelector.current) this.addressSelector.current.chooseSelection();
} else if (textInput.length === 0 && this.state.selectedList.length && e.key === Key.BACKSPACE) {
e.stopPropagation();
e.preventDefault();
} else if (e.key === KeyBindingAction.ArrowUp) {
this.addressSelector.current?.moveSelectionUp();
} else if (e.key === KeyBindingAction.ArrowDown) {
this.addressSelector.current?.moveSelectionDown();
} else if (
[KeyBindingAction.Comma, KeyBindingAction.Enter, KeyBindingAction.Tab].includes(action) &&
this.state.suggestedList.length > 0
) {
this.addressSelector.current?.chooseSelection();
} else if (textInput.length === 0 && this.state.selectedList.length && action === KeyBindingAction.Backspace) {
this.onDismissed(this.state.selectedList.length - 1)();
} else if (e.key === Key.ENTER) {
e.stopPropagation();
e.preventDefault();
} else if (e.key === KeyBindingAction.Enter) {
if (textInput === '') {
// if there's nothing in the input box, submit the form
this.onButtonClick();
} else {
this.addAddressesToList([textInput]);
}
} else if (textInput && (e.key === Key.COMMA || e.key === Key.TAB)) {
} else if (textInput && [KeyBindingAction.Comma, KeyBindingAction.Tab].includes(action)) {
this.addAddressesToList([textInput]);
} else {
handled = false;
}
if (handled) {
e.stopPropagation();
e.preventDefault();
this.addAddressesToList([textInput]);
}
};

View file

@ -21,7 +21,6 @@ import FocusLock from 'react-focus-lock';
import classNames from 'classnames';
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Key } from '../../../Keyboard';
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { _t } from "../../../languageHandler";
@ -30,6 +29,8 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
import Heading from '../typography/Heading';
import { IDialogProps } from "./IDialogProps";
import { PosthogScreenTracker, ScreenName } from "../../../PosthogTrackers";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IProps extends IDialogProps {
// Whether the dialog should have a 'close' button that will
@ -99,10 +100,16 @@ export default class BaseDialog extends React.Component<IProps> {
if (this.props.onKeyDown) {
this.props.onKeyDown(e);
}
if (this.props.hasCancel && e.key === Key.ESCAPE) {
e.stopPropagation();
e.preventDefault();
this.props.onFinished(false);
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) {
case KeyBindingAction.Escape:
if (!this.props.hasCancel) break;
e.stopPropagation();
e.preventDefault();
this.props.onFinished(false);
break;
}
};

View file

@ -23,7 +23,6 @@ import SdkConfig from '../../../SdkConfig';
import withValidation, { IFieldState } from '../elements/Validation';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { Key } from "../../../Keyboard";
import { IOpts, privateShouldBeEncrypted } from "../../../createRoom";
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
import { replaceableComponent } from "../../../utils/replaceableComponent";
@ -34,6 +33,8 @@ import DialogButtons from "../elements/DialogButtons";
import BaseDialog from "../dialogs/BaseDialog";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import JoinRuleDropdown from "../elements/JoinRuleDropdown";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IProps {
defaultPublic?: boolean;
@ -136,10 +137,13 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
}
private onKeyDown = (event: KeyboardEvent) => {
if (event.key === Key.ENTER) {
this.onOk();
event.preventDefault();
event.stopPropagation();
const action = getKeyBindingsManager().getAccessibilityAction(event);
switch (action) {
case KeyBindingAction.Enter:
this.onOk();
event.preventDefault();
event.stopPropagation();
break;
}
};

View file

@ -45,7 +45,6 @@ import {
showAnyInviteErrors,
showCommunityInviteDialog,
} from "../../../RoomInvite";
import { Key } from "../../../Keyboard";
import { Action } from "../../../dispatcher/actions";
import { DefaultTagID } from "../../../stores/room-list/models";
import RoomListStore from "../../../stores/room-list/RoomListStore";
@ -71,6 +70,8 @@ import UserIdentifierCustomisations from '../../../customisations/UserIdentifier
import CopyableText from "../elements/CopyableText";
import { ScreenName } from '../../../PosthogTrackers';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */
@ -803,20 +804,36 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
private onKeyDown = (e) => {
if (this.state.busy) return;
let handled = true;
const value = e.target.value.trim();
const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey;
if (!value && this.state.targets.length > 0 && e.key === Key.BACKSPACE && !hasModifiers) {
// when the field is empty and the user hits backspace remove the right-most target
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) {
case KeyBindingAction.Backspace:
if (value || this.state.targets.length <= 0) break;
// when the field is empty and the user hits backspace remove the right-most target
this.removeMember(this.state.targets[this.state.targets.length - 1]);
break;
case KeyBindingAction.Space:
if (!value || !value.includes("@") || value.includes(" ")) break;
// when the user hits space and their input looks like an e-mail/MXID then try to convert it
this.convertFilter();
break;
case KeyBindingAction.Enter:
if (!value) break;
// when the user hits enter with something in their field try to convert it
this.convertFilter();
break;
default:
handled = false;
}
if (handled) {
e.preventDefault();
this.removeMember(this.state.targets[this.state.targets.length - 1]);
} else if (value && e.key === Key.ENTER && !hasModifiers) {
// when the user hits enter with something in their field try to convert it
e.preventDefault();
this.convertFilter();
} else if (value && e.key === Key.SPACE && !hasModifiers && value.includes("@") && !value.includes(" ")) {
// when the user hits space and their input looks like an e-mail/MXID then try to convert it
e.preventDefault();
this.convertFilter();
}
};

View file

@ -19,11 +19,12 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import FocusLock from "react-focus-lock";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { Key } from "../../../Keyboard";
import { IDialogProps } from "./IDialogProps";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
export interface IScrollableBaseState {
canSubmit: boolean;
@ -45,10 +46,13 @@ export default abstract class ScrollableBaseModal<TProps extends IDialogProps, T
}
private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => {
if (e.key === Key.ESCAPE) {
e.stopPropagation();
e.preventDefault();
this.cancel();
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) {
case KeyBindingAction.Escape:
e.stopPropagation();
e.preventDefault();
this.cancel();
break;
}
};

View file

@ -46,7 +46,6 @@ import {
Type,
useRovingTabIndex,
} from "../../../accessibility/RovingTabIndex";
import { Key } from "../../../Keyboard";
import AccessibleButton from "../elements/AccessibleButton";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import SpaceStore from "../../../stores/spaces/SpaceStore";
@ -596,23 +595,33 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
}
const onDialogKeyDown = (ev: KeyboardEvent) => {
const navAction = getKeyBindingsManager().getNavigationAction(ev);
switch (navAction) {
case "KeyBinding.closeDialogOrContextMenu" as KeyBindingAction:
const navigationAction = getKeyBindingsManager().getNavigationAction(ev);
switch (navigationAction) {
case KeyBindingAction.FilterRooms:
ev.stopPropagation();
ev.preventDefault();
onFinished();
break;
}
const accessibilityAction = getKeyBindingsManager().getAccessibilityAction(ev);
switch (accessibilityAction) {
case KeyBindingAction.Escape:
ev.stopPropagation();
ev.preventDefault();
onFinished();
break;
}
};
const onKeyDown = (ev: KeyboardEvent) => {
let ref: RefObject<HTMLElement>;
switch (ev.key) {
case Key.ARROW_UP:
case Key.ARROW_DOWN:
const action = getKeyBindingsManager().getAccessibilityAction(ev);
switch (action) {
case KeyBindingAction.ArrowUp:
case KeyBindingAction.ArrowDown:
ev.stopPropagation();
ev.preventDefault();
@ -629,12 +638,12 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
}
const idx = refs.indexOf(rovingContext.state.activeRef);
ref = findSiblingElement(refs, idx + (ev.key === Key.ARROW_UP ? -1 : 1));
ref = findSiblingElement(refs, idx + (action === KeyBindingAction.ArrowUp ? -1 : 1));
}
break;
case Key.ARROW_LEFT:
case Key.ARROW_RIGHT:
case KeyBindingAction.ArrowLeft:
case KeyBindingAction.ArrowRight:
// only handle these keys when we are in the recently viewed row of options
if (!query &&
rovingContext.state.refs.length > 0 &&
@ -646,11 +655,10 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
const refs = rovingContext.state.refs.filter(refIsForRecentlyViewed);
const idx = refs.indexOf(rovingContext.state.activeRef);
ref = findSiblingElement(refs, idx + (ev.key === Key.ARROW_LEFT ? -1 : 1));
ref = findSiblingElement(refs, idx + (action === KeyBindingAction.ArrowLeft ? -1 : 1));
}
break;
case Key.ENTER:
case KeyBindingAction.Enter:
ev.stopPropagation();
ev.preventDefault();
rovingContext.state.activeRef?.current?.click();