Keep number field in focus when pressing dialpad buttons (#6520)

pull/21833/head
Andrew Morgan 2021-08-12 18:58:06 +01:00 committed by GitHub
parent 1a1a76e2d7
commit 1ad35b1564
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 18 deletions

View File

@ -14,8 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import AccessibleButton from "../elements/AccessibleButton";
import * as React from "react";
import { createRef } from "react";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { ContextMenu, IProps as IContextMenuProps } from '../../structures/ContextMenu';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import Field from "../elements/Field";
@ -32,6 +33,8 @@ interface IState {
@replaceableComponent("views.context_menus.DialpadContextMenu")
export default class DialpadContextMenu extends React.Component<IProps, IState> {
private numberEntryFieldRef: React.RefObject<Field> = createRef();
constructor(props) {
super(props);
@ -40,9 +43,16 @@ export default class DialpadContextMenu extends React.Component<IProps, IState>
};
}
onDigitPress = (digit) => {
onDigitPress = (digit: string, ev: ButtonEvent) => {
this.props.call.sendDtmfDigit(digit);
this.setState({ value: this.state.value + digit });
// Keep the number field focused so that keyboard entry is still available
// However, don't focus if this wasn't the result of directly clicking on the button,
// i.e someone using keyboard navigation.
if (ev.type === "click") {
this.numberEntryFieldRef.current?.focus();
}
};
onCancelClick = () => {
@ -68,6 +78,7 @@ export default class DialpadContextMenu extends React.Component<IProps, IState>
</div>
<div className="mx_DialPadContextMenu_header">
<Field
ref={this.numberEntryFieldRef}
className="mx_DialPadContextMenu_dialled"
value={this.state.value}
autoFocus={true}

View File

@ -55,7 +55,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromMxc } from "../../../customisations/Media";
import { getAddressType } from "../../../UserAddress";
import BaseAvatar from '../avatars/BaseAvatar';
import AccessibleButton from '../elements/AccessibleButton';
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
import { compare } from '../../../utils/strings';
import { IInvite3PID } from "matrix-js-sdk/src/@types/requests";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
@ -394,6 +394,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
private closeCopiedTooltip: () => void;
private debounceTimer: number = null; // actually number because we're in the browser
private editorRef = createRef<HTMLInputElement>();
private numberEntryFieldRef: React.RefObject<Field> = createRef();
private unmounted = false;
constructor(props) {
@ -1283,13 +1284,27 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
this.setState({ dialPadValue: ev.currentTarget.value });
};
private onDigitPress = digit => {
private onDigitPress = (digit: string, ev: ButtonEvent) => {
this.setState({ dialPadValue: this.state.dialPadValue + digit });
// Keep the number field focused so that keyboard entry is still available
// However, don't focus if this wasn't the result of directly clicking on the button,
// i.e someone using keyboard navigation.
if (ev.type === "click") {
this.numberEntryFieldRef.current?.focus();
}
};
private onDeletePress = () => {
private onDeletePress = (ev: ButtonEvent) => {
if (this.state.dialPadValue.length === 0) return;
this.setState({ dialPadValue: this.state.dialPadValue.slice(0, -1) });
// Keep the number field focused so that keyboard entry is still available
// However, don't focus if this wasn't the result of directly clicking on the button,
// i.e someone using keyboard navigation.
if (ev.type === "click") {
this.numberEntryFieldRef.current?.focus();
}
};
private onTabChange = (tabId: TabId) => {
@ -1543,6 +1558,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
let dialPadField;
if (this.state.dialPadValue.length !== 0) {
dialPadField = <Field
ref={this.numberEntryFieldRef}
className="mx_InviteDialog_dialPadField"
id="dialpad_number"
value={this.state.dialPadValue}
@ -1552,6 +1568,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
/>;
} else {
dialPadField = <Field
ref={this.numberEntryFieldRef}
className="mx_InviteDialog_dialPadField"
id="dialpad_number"
value={this.state.dialPadValue}

View File

@ -15,11 +15,11 @@ limitations under the License.
*/
import * as React from "react";
import AccessibleButton from "./AccessibleButton";
import AccessibleButton, { ButtonEvent } from "./AccessibleButton";
interface IProps {
// Callback for when the button is pressed
onBackspacePress: () => void;
onBackspacePress: (ev: ButtonEvent) => void;
}
export default class DialPadBackspaceButton extends React.PureComponent<IProps> {

View File

@ -15,7 +15,7 @@ limitations under the License.
*/
import * as React from "react";
import AccessibleButton from "../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { replaceableComponent } from "../../../utils/replaceableComponent";
const BUTTONS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
@ -30,12 +30,12 @@ interface IButtonProps {
kind: DialPadButtonKind;
digit?: string;
digitSubtext?: string;
onButtonPress: (string) => void;
onButtonPress: (digit: string, ev: ButtonEvent) => void;
}
class DialPadButton extends React.PureComponent<IButtonProps> {
onClick = () => {
this.props.onButtonPress(this.props.digit);
onClick = (ev: ButtonEvent) => {
this.props.onButtonPress(this.props.digit, ev);
};
render() {
@ -54,10 +54,10 @@ class DialPadButton extends React.PureComponent<IButtonProps> {
}
interface IProps {
onDigitPress: (string) => void;
onDigitPress: (digit: string, ev: ButtonEvent) => void;
hasDial: boolean;
onDeletePress?: (string) => void;
onDialPress?: (string) => void;
onDeletePress?: (ev: ButtonEvent) => void;
onDialPress?: () => void;
}
@replaceableComponent("views.voip.DialPad")

View File

@ -15,7 +15,8 @@ limitations under the License.
*/
import * as React from "react";
import AccessibleButton from "../elements/AccessibleButton";
import { createRef } from "react";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import Field from "../elements/Field";
import DialPad from './DialPad';
import dis from '../../../dispatcher/dispatcher';
@ -34,6 +35,8 @@ interface IState {
@replaceableComponent("views.voip.DialPadModal")
export default class DialpadModal extends React.PureComponent<IProps, IState> {
private numberEntryFieldRef: React.RefObject<Field> = createRef();
constructor(props) {
super(props);
this.state = {
@ -54,13 +57,27 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
this.onDialPress();
};
onDigitPress = (digit) => {
onDigitPress = (digit: string, ev: ButtonEvent) => {
this.setState({ value: this.state.value + digit });
// Keep the number field focused so that keyboard entry is still available.
// However, don't focus if this wasn't the result of directly clicking on the button,
// i.e someone using keyboard navigation.
if (ev.type === "click") {
this.numberEntryFieldRef.current?.focus();
}
};
onDeletePress = () => {
onDeletePress = (ev: ButtonEvent) => {
if (this.state.value.length === 0) return;
this.setState({ value: this.state.value.slice(0, -1) });
// Keep the number field focused so that keyboard entry is still available
// However, don't focus if this wasn't the result of directly clicking on the button,
// i.e someone using keyboard navigation.
if (ev.type === "click") {
this.numberEntryFieldRef.current?.focus();
}
};
onDialPress = async () => {
@ -82,6 +99,7 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
let dialPadField;
if (this.state.value.length !== 0) {
dialPadField = <Field
ref={this.numberEntryFieldRef}
className="mx_DialPadModal_field"
id="dialpad_number"
value={this.state.value}
@ -91,6 +109,7 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
/>;
} else {
dialPadField = <Field
ref={this.numberEntryFieldRef}
className="mx_DialPadModal_field"
id="dialpad_number"
value={this.state.value}