diff --git a/res/css/views/rooms/RoomListPanel/_RoomListItemView.pcss b/res/css/views/rooms/RoomListPanel/_RoomListItemView.pcss
index ee228ec262e..bbe2bb575ee 100644
--- a/res/css/views/rooms/RoomListPanel/_RoomListItemView.pcss
+++ b/res/css/views/rooms/RoomListPanel/_RoomListItemView.pcss
@@ -18,10 +18,6 @@
all: unset;
cursor: pointer;
- &:hover {
- background-color: var(--cpd-color-bg-action-secondary-hovered);
- }
-
.mx_RoomListItemView_container {
padding-left: var(--cpd-space-2x);
font: var(--cpd-font-body-md-regular);
@@ -44,12 +40,12 @@
}
}
-.mx_RoomListItemView_menu_open {
+.mx_RoomListItemView_hover {
background-color: var(--cpd-color-bg-action-secondary-hovered);
+}
- .mx_RoomListItemView_content {
- padding-right: var(--cpd-space-1-5x);
- }
+.mx_RoomListItemView_menu_open .mx_RoomListItemView_content {
+ padding-right: var(--cpd-space-1-5x);
}
.mx_RoomListItemView_selected {
diff --git a/src/components/views/rooms/RoomListPanel/RoomList.tsx b/src/components/views/rooms/RoomListPanel/RoomList.tsx
index 628723246fc..80fb82220c7 100644
--- a/src/components/views/rooms/RoomListPanel/RoomList.tsx
+++ b/src/components/views/rooms/RoomListPanel/RoomList.tsx
@@ -5,8 +5,8 @@
* Please see LICENSE files in the repository root for full details.
*/
-import React, { useCallback, type JSX } from "react";
-import { AutoSizer, List, type ListRowProps } from "react-virtualized";
+import React, { useCallback, type JSX, useState, useEffect } from "react";
+import { ArrowKeyStepper, AutoSizer, List, type ListRowProps } from "react-virtualized";
import { type RoomListViewState } from "../../../viewmodels/roomlist/RoomListViewModel";
import { _t } from "../../../../languageHandler";
@@ -23,11 +23,22 @@ interface RoomListProps {
* A virtualized list of rooms.
*/
export function RoomList({ vm: { rooms, activeIndex } }: RoomListProps): JSX.Element {
+ const [focusedIndex, setFocusedIndex] = useState(activeIndex);
+ useEffect(() => {
+ setFocusedIndex(activeIndex);
+ }, [activeIndex]);
+
const roomRendererMemoized = useCallback(
({ key, index, style }: ListRowProps) => (
-
+
),
- [rooms, activeIndex],
+ [rooms, activeIndex, focusedIndex],
);
// The first div is needed to make the virtualized list take all the remaining space and scroll correctly
@@ -35,16 +46,30 @@ export function RoomList({ vm: { rooms, activeIndex } }: RoomListProps): JSX.Ele
{({ height, width }) => (
-
+ isControlled={true}
+ scrollToRow={focusedIndex ?? 0}
+ onScrollToChange={({ scrollToRow }) => setFocusedIndex(scrollToRow)}
+ >
+ {({ onSectionRendered, scrollToRow }) => (
+
+ )}
+
)}
diff --git a/src/components/views/rooms/RoomListPanel/RoomListItemView.tsx b/src/components/views/rooms/RoomListPanel/RoomListItemView.tsx
index 36839d75b08..ab91bd2d7d1 100644
--- a/src/components/views/rooms/RoomListPanel/RoomListItemView.tsx
+++ b/src/components/views/rooms/RoomListPanel/RoomListItemView.tsx
@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
-import React, { type JSX, memo, useState } from "react";
+import React, { type JSX, memo, useEffect, useRef, useState } from "react";
import { type Room } from "matrix-js-sdk/src/matrix";
import classNames from "classnames";
@@ -24,6 +24,10 @@ interface RoomListItemViewPropsProps extends React.HTMLAttributes(null);
const vm = useRoomListItemViewModel(room);
const [isHover, setIsHover] = useState(false);
const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+ // Focus the button when the room is selected via keyboard navigation
+ useEffect(() => {
+ if (isKeyboardSelected) {
+ ref.current?.focus();
+ } else {
+ ref.current?.blur();
+ }
+ }, [isKeyboardSelected]);
+
// The compound menu in RoomListItemMenuView needs to be rendered when the hover menu is shown
// Using display: none; and then display:flex when hovered in CSS causes the menu to be misaligned
- const showHoverDecoration = (isMenuOpen || isHover) && vm.showHoverMenu;
+ const showHoverDecoration = isMenuOpen || isHover;
+ const showHoverMenu = showHoverDecoration && vm.showHoverMenu;
- const isNotificationDecorationVisible = !showHoverDecoration && vm.showNotificationDecoration;
+ const isInvitation = vm.notificationState.invited;
+ const isNotificationDecorationVisible = isInvitation || (!showHoverDecoration && vm.showNotificationDecoration);
return (