diff --git a/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.test.tsx b/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.test.tsx
index 7ca3dd8e86..995081d006 100644
--- a/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.test.tsx
+++ b/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.test.tsx
@@ -197,6 +197,54 @@ describe("", () => {
});
});
+ describe("pointer drag activation", () => {
+ beforeEach(() => {
+ (Sections.args.changeRoomSection as any).mockClear?.();
+ });
+
+ it("does not start a drag when a finger moves (touch scrolling the list)", async () => {
+ // For touch, dragging only activates after a 250ms hold; moving the finger first aborts
+ // it so the list scrolls instead of dragging a room. Simulate a finger press that moves
+ // immediately (as when scrolling) and assert no drag ever starts.
+ const user = userEvent.setup();
+ renderWithMockContext();
+
+ const status = screen.getByRole("status");
+ const roomButton = await screen.findByRole("button", { name: "Open room General" });
+
+ await user.pointer([
+ { keys: "[TouchA>]", target: roomButton, coords: { x: 20, y: 20 } },
+ { pointerName: "TouchA", coords: { x: 20, y: 140 } },
+ { keys: "[/TouchA]" },
+ ]);
+
+ expect(status).toHaveTextContent("");
+ expect(Sections.args.changeRoomSection).not.toHaveBeenCalled();
+ });
+
+ it("starts a drag when the mouse moves past the activation distance", async () => {
+ // For mouse, dragging activates as soon as the pointer moves past 5px, so the same
+ // press-and-move gesture that scrolls on touch drags the room into another section.
+ const user = userEvent.setup();
+ renderWithMockContext();
+
+ const status = screen.getByRole("status");
+ const roomButton = await screen.findByRole("button", { name: "Open room General" });
+
+ await user.pointer([
+ { keys: "[MouseLeft>]", target: roomButton, coords: { x: 20, y: 20 } },
+ { coords: { x: 20, y: 140 } },
+ ]);
+
+ // The drag has activated: the live region reflects the ongoing drag.
+ await waitFor(() => expect(status).toHaveTextContent("General"));
+
+ await user.pointer({ keys: "[/MouseLeft]" }); // release to drop
+
+ await waitFor(() => expect(Sections.args.changeRoomSection).toHaveBeenCalled());
+ });
+ });
+
describe("scrollToSectionTag", () => {
it("skips scroll when scrollToSectionTag does not match any section", () => {
const roomListState = {
diff --git a/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.tsx b/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.tsx
index 927f87fd6e..13ae53f6bd 100644
--- a/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.tsx
+++ b/packages/shared-components/src/room-list/VirtualizedRoomListView/VirtualizedRoomListView.tsx
@@ -600,10 +600,17 @@ export function VirtualizedRoomListView({ vm, renderAvatar, onKeyDown }: Virtual
}
}}
sensors={[
- // By default, the PointerSensor activates dragging immediately on pointer down, which interferes with keyboard navigation.
- // So we start dragging after the pointer has moved by 5 pixels, to allow for click without dragging
+ // By default, PointerSensor activates dragging immediately on mouse pointer down, which interferes
+ // with clicking a room and keyboard navigation, so for mouse/pen we require a small drag distance
+ // before a drag starts (allowing a plain click without dragging).
+ // For touch, a Delay constraint that aborts the drag if the finger moves before the delay elapses is used to avoid accidental drags when scrolling the list with a finger.
PointerSensor.configure({
- activationConstraints: [new PointerActivationConstraints.Distance({ value: 5 })],
+ activationConstraints(event) {
+ if (event.pointerType === "touch") {
+ return [new PointerActivationConstraints.Delay({ value: 250, tolerance: 5 })];
+ }
+ return [new PointerActivationConstraints.Distance({ value: 5 })];
+ },
}),
// By default, the KeyboardSensor uses both space and enter to start dragging, which interferes with the keyboard enter shortcut to open a room.
KeyboardSensor.configure({