Make everything use the KeyBindingManager
(#7907)
This commit is contained in:
parent
5f8441216c
commit
df591ee835
37 changed files with 529 additions and 277 deletions
|
@ -17,7 +17,8 @@
|
|||
import React, { ReactHTML } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Key } from '../../../Keyboard';
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Element> | React.FormEvent<Element>;
|
||||
|
||||
|
@ -92,29 +93,36 @@ export default function AccessibleButton({
|
|||
// Browsers handle space and enter keypresses differently and we are only adjusting to the
|
||||
// inconsistencies here
|
||||
newProps.onKeyDown = (e) => {
|
||||
if (e.key === Key.ENTER) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return onClick(e);
|
||||
}
|
||||
if (e.key === Key.SPACE) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else {
|
||||
onKeyDown?.(e);
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return onClick(e);
|
||||
case KeyBindingAction.Space:
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
onKeyDown?.(e);
|
||||
}
|
||||
};
|
||||
newProps.onKeyUp = (e) => {
|
||||
if (e.key === Key.SPACE) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return onClick(e);
|
||||
}
|
||||
if (e.key === Key.ENTER) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
} else {
|
||||
onKeyUp?.(e);
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case KeyBindingAction.Space:
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return onClick(e);
|
||||
default:
|
||||
onKeyUp?.(e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,8 +20,9 @@ import classnames from 'classnames';
|
|||
|
||||
import AccessibleButton, { ButtonEvent } from './AccessibleButton';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import { Key } from "../../../Keyboard";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IMenuOptionProps {
|
||||
children: ReactElement;
|
||||
|
@ -181,10 +182,12 @@ export default class Dropdown extends React.Component<IProps, IState> {
|
|||
private onAccessibleButtonClick = (ev: ButtonEvent) => {
|
||||
if (this.props.disabled) return;
|
||||
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev as React.KeyboardEvent);
|
||||
|
||||
if (!this.state.expanded) {
|
||||
this.setState({ expanded: true });
|
||||
ev.preventDefault();
|
||||
} else if ((ev as React.KeyboardEvent).key === Key.ENTER) {
|
||||
} else if (action === KeyBindingAction.Enter) {
|
||||
// the accessible button consumes enter onKeyDown for firing onClick, so handle it here
|
||||
this.props.onOptionChange(this.state.highlightedOption);
|
||||
this.close();
|
||||
|
@ -214,14 +217,15 @@ export default class Dropdown extends React.Component<IProps, IState> {
|
|||
let handled = true;
|
||||
|
||||
// These keys don't generate keypress events and so needs to be on keyup
|
||||
switch (e.key) {
|
||||
case Key.ENTER:
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
this.props.onOptionChange(this.state.highlightedOption);
|
||||
// fallthrough
|
||||
case Key.ESCAPE:
|
||||
case KeyBindingAction.Escape:
|
||||
this.close();
|
||||
break;
|
||||
case Key.ARROW_DOWN:
|
||||
case KeyBindingAction.ArrowDown:
|
||||
if (this.state.expanded) {
|
||||
this.setState({
|
||||
highlightedOption: this.nextOption(this.state.highlightedOption),
|
||||
|
@ -230,7 +234,7 @@ export default class Dropdown extends React.Component<IProps, IState> {
|
|||
this.setState({ expanded: true });
|
||||
}
|
||||
break;
|
||||
case Key.ARROW_UP:
|
||||
case KeyBindingAction.ArrowUp:
|
||||
if (this.state.expanded) {
|
||||
this.setState({
|
||||
highlightedOption: this.prevOption(this.state.highlightedOption),
|
||||
|
|
|
@ -17,7 +17,8 @@ limitations under the License.
|
|||
|
||||
import React, { createRef } from 'react';
|
||||
|
||||
import { Key } from "../../../Keyboard";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
|
||||
enum Phases {
|
||||
|
@ -124,9 +125,12 @@ export default class EditableText extends React.Component<IProps, IState> {
|
|||
this.showPlaceholder(false);
|
||||
}
|
||||
|
||||
if (ev.key === Key.ENTER) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
break;
|
||||
}
|
||||
|
||||
// console.log("keyDown: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
|
||||
|
@ -141,10 +145,14 @@ export default class EditableText extends React.Component<IProps, IState> {
|
|||
this.value = (ev.target as HTMLDivElement).textContent;
|
||||
}
|
||||
|
||||
if (ev.key === Key.ENTER) {
|
||||
this.onFinish(ev);
|
||||
} else if (ev.key === Key.ESCAPE) {
|
||||
this.cancelEdit();
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Escape:
|
||||
this.cancelEdit();
|
||||
break;
|
||||
case KeyBindingAction.Enter:
|
||||
this.onFinish(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
// console.log("keyUp: textContent=" + ev.target.textContent + ", value=" + this.value + ", placeholder=" + this.placeholder);
|
||||
|
@ -179,7 +187,8 @@ export default class EditableText extends React.Component<IProps, IState> {
|
|||
): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
const submit = ("key" in ev && ev.key === Key.ENTER) || shouldSubmit;
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev as React.KeyboardEvent);
|
||||
const submit = action === KeyBindingAction.Enter || shouldSubmit;
|
||||
this.setState({
|
||||
phase: Phases.Display,
|
||||
}, () => {
|
||||
|
|
|
@ -22,7 +22,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
|||
|
||||
import { _t } from '../../../languageHandler';
|
||||
import AccessibleTooltipButton from "./AccessibleTooltipButton";
|
||||
import { Key } from "../../../Keyboard";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
|
||||
import MessageContextMenu from "../context_menus/MessageContextMenu";
|
||||
|
@ -38,6 +37,8 @@ import { normalizeWheelEvent } from "../../../utils/Mouse";
|
|||
import { IDialogProps } from '../dialogs/IDialogProps';
|
||||
import UIStore from '../../../stores/UIStore';
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
|
||||
// Max scale to keep gaps around the image
|
||||
const MAX_SCALE = 0.95;
|
||||
|
@ -292,10 +293,13 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onKeyDown = (ev: KeyboardEvent) => {
|
||||
if (ev.key === Key.ESCAPE) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished();
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Escape:
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -19,8 +19,9 @@ import React from 'react';
|
|||
import * as Roles from '../../../Roles';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Field from "./Field";
|
||||
import { Key } from "../../../Keyboard";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
|
||||
const CUSTOM_VALUE = "SELECT_VALUE_CUSTOM";
|
||||
|
||||
|
@ -130,16 +131,19 @@ export default class PowerSelector extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onCustomKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
|
||||
if (event.key === Key.ENTER) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(event);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Do not call the onChange handler directly here - it can cause an infinite loop.
|
||||
// Long story short, a user hits Enter to submit the value which onChange handles as
|
||||
// raising a dialog which causes a blur which causes a dialog which causes a blur and
|
||||
// so on. By not causing the onChange to be called here, we avoid the loop because we
|
||||
// handle the onBlur safely.
|
||||
(event.target as HTMLInputElement).blur();
|
||||
// Do not call the onChange handler directly here - it can cause an infinite loop.
|
||||
// Long story short, a user hits Enter to submit the value which onChange handles as
|
||||
// raising a dialog which causes a blur which causes a dialog which causes a blur and
|
||||
// so on. By not causing the onChange to be called here, we avoid the loop because we
|
||||
// handle the onBlur safely.
|
||||
(event.target as HTMLInputElement).blur();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue