diff --git a/src/components/views/context_menus/DialpadContextMenu.tsx b/src/components/views/context_menus/DialpadContextMenu.tsx index 0bb96f9397..01c7c6c1d8 100644 --- a/src/components/views/context_menus/DialpadContextMenu.tsx +++ b/src/components/views/context_menus/DialpadContextMenu.tsx @@ -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 { + private numberEntryFieldRef: React.RefObject = createRef(); + constructor(props) { super(props); @@ -40,9 +43,16 @@ export default class DialpadContextMenu extends React.Component }; } - 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
void; private debounceTimer: number = null; // actually number because we're in the browser private editorRef = createRef(); + private numberEntryFieldRef: React.RefObject = createRef(); private unmounted = false; constructor(props) { @@ -1283,13 +1284,27 @@ export default class InviteDialog extends React.PureComponent { + 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; } else { dialPadField = void; + onBackspacePress: (ev: ButtonEvent) => void; } export default class DialPadBackspaceButton extends React.PureComponent { diff --git a/src/components/views/voip/DialPad.tsx b/src/components/views/voip/DialPad.tsx index 3b4a29b3f9..46584e0870 100644 --- a/src/components/views/voip/DialPad.tsx +++ b/src/components/views/voip/DialPad.tsx @@ -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 { - 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 { } 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") diff --git a/src/components/views/voip/DialPadModal.tsx b/src/components/views/voip/DialPadModal.tsx index a36fc37dff..4d69260565 100644 --- a/src/components/views/voip/DialPadModal.tsx +++ b/src/components/views/voip/DialPadModal.tsx @@ -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 { + private numberEntryFieldRef: React.RefObject = createRef(); + constructor(props) { super(props); this.state = { @@ -54,13 +57,27 @@ export default class DialpadModal extends React.PureComponent { 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 { let dialPadField; if (this.state.value.length !== 0) { dialPadField = { />; } else { dialPadField =