diff --git a/packages/jui/src/Tree/SpeedSearchTree/SpeedSearchTree.cy.tsx b/packages/jui/src/Tree/SpeedSearchTree/SpeedSearchTree.cy.tsx
index da1e272a..d911a7e9 100644
--- a/packages/jui/src/Tree/SpeedSearchTree/SpeedSearchTree.cy.tsx
+++ b/packages/jui/src/Tree/SpeedSearchTree/SpeedSearchTree.cy.tsx
@@ -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(
+
+ -
+
- node 1.1
+ - node 1.2
+
+
+ );
+
+ 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();
diff --git a/packages/jui/src/Tree/Tree.cy.tsx b/packages/jui/src/Tree/Tree.cy.tsx
index 238f6706..1e414ec8 100644
--- a/packages/jui/src/Tree/Tree.cy.tsx
+++ b/packages/jui/src/Tree/Tree.cy.tsx
@@ -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(
+
+ -
+
- node 1.1
+ - node 1.2
+
+
+ );
+
+ 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();
diff --git a/packages/jui/src/Tree/TreeKeyboardDelegate.tsx b/packages/jui/src/Tree/TreeKeyboardDelegate.tsx
index fed961d9..c6baa8a3 100644
--- a/packages/jui/src/Tree/TreeKeyboardDelegate.tsx
+++ b/packages/jui/src/Tree/TreeKeyboardDelegate.tsx
@@ -5,11 +5,19 @@ import React, { Key, RefObject } from "react";
export class TreeKeyboardDelegate extends ListKeyboardDelegate {
constructor(
private collection: Collection>,
- private disabledKeys: Set,
+ disabledKeys: Set,
ref: RefObject,
collator?: Intl.Collator
) {
- super(collection, disabledKeys, ref, collator);
+ super({
+ collection,
+ disabledKeys,
+ ref,
+ collator,
+ // Since @react-aria/selection@3.16.0 getKeyLeftOf and getKeyRightOf is
+ // removed if orientation is vertical and layout is "stack".
+ layout: "grid",
+ });
}
getKeyLeftOf(key: React.Key): React.Key {