Skip to content

Commit

Permalink
fix(Tree): fix a regression in keyboard navigation
Browse files Browse the repository at this point in the history
Since @react-aria/[email protected] getKeyLeftOf and getKeyRightOf is removed if orientation is vertical and layout is "stack".

Using the single-argument overload of the base constructor doesn't set a default value for orientation (which seems a little random), which in turn makes the if statement that removes the methods not run.

https://github.com/adobe/react-spectrum/blob/8228e4efd9be99973058a1f90fc7f7377e673f78/packages/%40react-aria/selection/src/ListKeyboardDelegate.ts#L67
  • Loading branch information
alirezamirian committed Dec 12, 2024
1 parent 8215b39 commit f50ccab
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 2 deletions.
35 changes: 35 additions & 0 deletions packages/jui/src/Tree/SpeedSearchTree/SpeedSearchTree.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,41 @@ const { Dynamic, HighlightsWithSpace } = composeStories(stories);
const OS_NORMALIZED_META = Cypress.platform === "darwin" ? "Meta" : "Control";

describe("SpeedSearchTree", () => {
it("expands/collapses and navigates nodes by arrow keys", () => {
cy.mount(
<SpeedSearchTree selectionMode="multiple">
<Item title="node 1">
<Item>node 1.1</Item>
<Item>node 1.2</Item>
</Item>
</SpeedSearchTree>
);

cy.findByRole("treeitem") // only one should be visible initially
.click() // focus
.realPress("ArrowRight");
// node 1 should be expanded
cy.findByRole("treeitem", { name: "node 1.1" });
cy.findByRole("treeitem", { name: "node 1.2" });
// but selection doesn't go to the children right away
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowDown");
cy.findByRole("treeitem", { name: "node 1.1", selected: true });
cy.realPress("ArrowDown");
cy.findByRole("treeitem", { name: "node 1.2", selected: true });
cy.realPress("ArrowLeft"); // selection should move to node 1 but it remains expanded
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowLeft"); // the second ArrowLeft closes the node
cy.findAllByRole("treeitem").should("have.length", 1);

cy.realPress("ArrowRight"); // expanding the node again and going down with ArrowRight this time
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowRight");
cy.findByRole("treeitem", { name: "node 1.1", selected: true });
cy.realPress("ArrowRight");
cy.findByRole("treeitem", { name: "node 1.2", selected: true });
});

it("supports Speed Search in dynamic items mode", () => {
cy.mount(<Dynamic />);

Expand Down
35 changes: 35 additions & 0 deletions packages/jui/src/Tree/Tree.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,41 @@ import { Item } from "../Collections";
const { Static, ScrollAndContainerWidth } = composeStories(stories);

describe("Tree", () => {
it("expands/collapses and navigates nodes by arrow keys", () => {
cy.mount(
<Tree selectionMode="multiple">
<Item title="node 1">
<Item>node 1.1</Item>
<Item>node 1.2</Item>
</Item>
</Tree>
);

cy.findByRole("treeitem") // only one should be visible initially
.click() // focus
.realPress("ArrowRight");
// node 1 should be expanded
cy.findByRole("treeitem", { name: "node 1.1" });
cy.findByRole("treeitem", { name: "node 1.2" });
// but selection doesn't go to the children right away
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowDown");
cy.findByRole("treeitem", { name: "node 1.1", selected: true });
cy.realPress("ArrowDown");
cy.findByRole("treeitem", { name: "node 1.2", selected: true });
cy.realPress("ArrowLeft"); // selection should move to node 1 but it remains expanded
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowLeft"); // the second ArrowLeft closes the node
cy.findAllByRole("treeitem").should("have.length", 1);

cy.realPress("ArrowRight"); // expanding the node again and going down with ArrowRight this time
cy.findByRole("treeitem", { name: "node 1", selected: true });
cy.realPress("ArrowRight");
cy.findByRole("treeitem", { name: "node 1.1", selected: true });
cy.realPress("ArrowRight");
cy.findByRole("treeitem", { name: "node 1.2", selected: true });
});

it("opens nested expandable single-child items", () => {
cy.mount(<Static />);

Expand Down
12 changes: 10 additions & 2 deletions packages/jui/src/Tree/TreeKeyboardDelegate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ import React, { Key, RefObject } from "react";
export class TreeKeyboardDelegate<T> extends ListKeyboardDelegate<T> {
constructor(
private collection: Collection<Node<T>>,
private disabledKeys: Set<Key>,
disabledKeys: Set<Key>,
ref: RefObject<HTMLElement>,
collator?: Intl.Collator
) {
super(collection, disabledKeys, ref, collator);
super({
collection,
disabledKeys,
ref,
collator,
// Since @react-aria/[email protected] getKeyLeftOf and getKeyRightOf is
// removed if orientation is vertical and layout is "stack".
layout: "grid",
});
}

getKeyLeftOf(key: React.Key): React.Key {
Expand Down

0 comments on commit f50ccab

Please sign in to comment.