Move RovingTabIndex to shared component and use it in ActionBarView (#33263)

* Create a new shared component and a wrapper in app/web

* Move unit tests and add new for better coverage

* Refactor ActionBarView to use the RovingTabIndexProvider

* Clean up the interface and adjust callers

* Added documentation and renamed type for better readabililty

* Reverting the clean up of IContext

* Fix Sonar issues

* More Sonar issus fixed
This commit is contained in:
rbondesson
2026-04-23 09:33:32 +00:00
committed by GitHub
parent 1a6b0e22a1
commit bb4a7e9613
14 changed files with 1067 additions and 602 deletions
@@ -50,9 +50,9 @@ import { RoomContextDetails } from "../rooms/RoomContextDetails";
import { filterBoolean } from "../../../utils/arrays";
import {
type IState,
RovingStateActionType,
RovingTabIndexContext,
RovingTabIndexProvider,
Type,
useRovingTabIndex,
} from "../../../accessibility/RovingTabIndex";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
@@ -368,7 +368,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
const node = context.state.nodes[0];
if (node) {
context.dispatch({
type: Type.SetFocus,
type: RovingStateActionType.SetFocus,
payload: { node },
});
node?.scrollIntoView?.({
@@ -44,10 +44,10 @@ import {
import { KeyBindingAction } from "../../../../accessibility/KeyboardShortcuts";
import {
findSiblingElement,
findNextSiblingElement,
RovingStateActionType,
RovingTabIndexContext,
RovingTabIndexProvider,
Type,
} from "../../../../accessibility/RovingTabIndex";
import { mediaFromMxc } from "../../../../customisations/Media";
import { Action } from "../../../../dispatcher/actions";
@@ -537,7 +537,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
const node = rovingContext.state.nodes[0];
if (node) {
rovingContext.dispatch({
type: Type.SetFocus,
type: RovingStateActionType.SetFocus,
payload: { node },
});
node?.scrollIntoView?.({
@@ -1181,7 +1181,10 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
}
const idx = nodes.indexOf(rovingContext.state.activeNode);
node = findSiblingElement(nodes, idx + (accessibilityAction === KeyBindingAction.ArrowUp ? -1 : 1));
node = findNextSiblingElement(
nodes,
idx + (accessibilityAction === KeyBindingAction.ArrowUp ? -1 : 1),
);
}
break;
@@ -1201,7 +1204,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
const nodes = rovingContext.state.nodes.filter(nodeIsForRecentlyViewed);
const idx = nodes.indexOf(rovingContext.state.activeNode);
node = findSiblingElement(
node = findNextSiblingElement(
nodes,
idx + (accessibilityAction === KeyBindingAction.ArrowLeft ? -1 : 1),
);
@@ -1211,7 +1214,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
if (node) {
rovingContext.dispatch({
type: Type.SetFocus,
type: RovingStateActionType.SetFocus,
payload: { node },
});
node?.scrollIntoView({
@@ -25,7 +25,7 @@ import {
type IAction as RovingAction,
type IState as RovingState,
RovingTabIndexProvider,
Type,
RovingStateActionType,
} from "../../../accessibility/RovingTabIndex";
import { Key } from "../../../Keyboard";
import { type ButtonEvent } from "../elements/AccessibleButton";
@@ -187,7 +187,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
focusNode?.focus();
}
dispatch({
type: Type.SetFocus,
type: RovingStateActionType.SetFocus,
payload: { node: focusNode },
});
@@ -212,7 +212,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
// Reset to first emoji when showing highlight for the first time (or after it was hidden)
if (state.nodes.length > 0) {
dispatch({
type: Type.SetFocus,
type: RovingStateActionType.SetFocus,
payload: { node: state.nodes[0] },
});
}