Skip to content

Commit

Permalink
feat(ui5-list): handle arrow up and down navigation for load more but…
Browse files Browse the repository at this point in the history
…ton (#10251)

The "Load More" button can now be accessed using the arrow up and down keys:

Pressing the arrow down key while focused on the last list item now moves focus to the "Load More" button.
Pressing the arrow up key while focused on the "Load More" button navigates back to the last item in the list.
Tests added for:

End key navigation: Moves focus from first item to last item and then to growing button
Arrow down/up navigation: Moves focus between last list item and growing button
Home key on growing button: Moves focus to first list item
  • Loading branch information
NakataCode authored Nov 28, 2024
1 parent 3b6cc84 commit 3150793
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 1 deletion.
84 changes: 84 additions & 0 deletions packages/main/cypress/specs/List.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,88 @@ describe("List Tests", () => {
cy.get("@loadMore")
.should("have.been.calledOnce");
});

it("Arrow down and up navigation between last item and growing button", () => {
cy.mount(html`
<ui5-list id="infiniteScrollEx2" growing="Button">
<ui5-li>Laptop Lenovo</ui5-li>
<ui5-li>IPhone 3</ui5-li>
<ui5-li>HP Monitor 24</ui5-li>
<ui5-li id="lastItem">Last Item</ui5-li>
</ui5-list>
`);

cy.get("#lastItem")
.shadow()
.find("li[role='listitem']")
.invoke("attr", "tabindex", "0")
.focus();

cy.get("#infiniteScrollEx2")
.realPress("ArrowDown");

cy.get("#infiniteScrollEx2")
.shadow()
.find("[id$=\"growing-btn\"]")
.should("be.focused");

cy.get("#infiniteScrollEx2")
.realPress("ArrowUp");

cy.get("#lastItem")
.should("be.focused");
});

it("Home key on growing button moves focus to first item", () => {
cy.mount(html`
<ui5-list id="infiniteScrollEx2" growing="Button">
<ui5-li id="firstItem">Laptop Lenovo</ui5-li>
<ui5-li>IPhone 3</ui5-li>
<ui5-li>HP Monitor 24</ui5-li>
<ui5-li id="lastItem">Last Item</ui5-li>
</ui5-list>
`);

cy.get("#infiniteScrollEx2")
.shadow()
.find("[id$=\"growing-btn\"]")
.focus();

cy.get("#infiniteScrollEx2")
.realPress("Home");

cy.get("#firstItem")
.should("be.focused");
});

it("End key navigation moves focus from first item to last item and then to growing button", () => {
cy.mount(html`
<ui5-list id="infiniteScrollEx2" growing="Button">
<ui5-li id="firstItem">Laptop Lenovo</ui5-li>
<ui5-li>IPhone 3</ui5-li>
<ui5-li>HP Monitor 24</ui5-li>
<ui5-li id="lastItem">Last Item</ui5-li>
</ui5-list>
`);

cy.get("#firstItem")
.shadow()
.find("li[role='listitem']")
.invoke("attr", "tabindex", "0")
.focus();

cy.get("#infiniteScrollEx2")
.realPress("End");

cy.get("#lastItem")
.should("be.focused");

cy.get("#infiniteScrollEx2")
.realPress("End");

cy.get("#infiniteScrollEx2")
.shadow()
.find("[id$='growing-btn']")
.should("be.focused");
});
});
37 changes: 36 additions & 1 deletion packages/main/src/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
isCtrl,
isEnd,
isHome,
isDown,
isUp,
} from "@ui5/webcomponents-base/dist/Keys.js";
import DragRegistry from "@ui5/webcomponents-base/dist/util/dragAndDrop/DragRegistry.js";
import { findClosestPosition, findClosestPositionsByKey } from "@ui5/webcomponents-base/dist/util/dragAndDrop/findClosestPosition.js";
Expand Down Expand Up @@ -965,6 +967,12 @@ class List extends UI5Element {
return;
}

if (isDown(e)) {
this._handleDown();
e.preventDefault();
return;
}

if (isCtrl(e)) {
this._moveItem(e.target as ListItemBase, e);
return;
Expand Down Expand Up @@ -1032,6 +1040,11 @@ class List extends UI5Element {
this.focusAfterElement();
}

if (isUp(e)) {
this._handleLodeMoreUp(e);
return;
}

if (isTabPrevious(e)) {
if (this.getPreviouslyFocusedItem()) {
this.focusPreviouslyFocusedItem();
Expand Down Expand Up @@ -1061,6 +1074,20 @@ class List extends UI5Element {
this.loadMore();
}

_handleLodeMoreUp(e: KeyboardEvent) {
const growingButton = this.getGrowingButton();

if (growingButton === e.target) {
const items = this.getItems();
const lastItem = items[items.length - 1];

this.focusItem(lastItem);

e.preventDefault();
e.stopImmediatePropagation();
}
}

checkListInViewport() {
this._inViewport = isElementInView(this.getDomRef()!);
}
Expand Down Expand Up @@ -1113,6 +1140,14 @@ class List extends UI5Element {
this._shouldFocusGrowingButton();
}

_handleDown() {
if (!this.growsWithButton) {
return;
}

this._shouldFocusGrowingButton();
}

_onfocusin(e: FocusEvent) {
const target = getNormalizedTarget(e.target as HTMLElement);
// If the focusin event does not origin from one of the 'triggers' - ignore it.
Expand Down Expand Up @@ -1347,7 +1382,7 @@ class List extends UI5Element {
_shouldFocusGrowingButton() {
const items = this.getItems();
const lastIndex = items.length - 1;
const currentIndex = items.indexOf(document.activeElement as ListItemBase);
const currentIndex = this._itemNavigation._currentIndex;

if (currentIndex !== -1 && currentIndex === lastIndex) {
this.focusGrowingButton();
Expand Down

0 comments on commit 3150793

Please sign in to comment.