From 4b57d501a515059de7aa2268fb3f9c1c614a13bc Mon Sep 17 00:00:00 2001 From: Todor Stoyanov Date: Mon, 3 Feb 2025 09:12:14 +0200 Subject: [PATCH 1/3] fix(ui5-timeline):Enhance keyboard navigation --- packages/fiori/cypress/specs/Timeline.cy.ts | 6 +- packages/fiori/src/Timeline.ts | 71 +++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/packages/fiori/cypress/specs/Timeline.cy.ts b/packages/fiori/cypress/specs/Timeline.cy.ts index 6b2e717c776d..05eda1a11cf8 100644 --- a/packages/fiori/cypress/specs/Timeline.cy.ts +++ b/packages/fiori/cypress/specs/Timeline.cy.ts @@ -230,18 +230,18 @@ describe("Timeline with growing mode", () => { .last() .should("be.focused"); - cy.realPress("Tab"); + cy.realPress("ArrowDown"); cy.get("@timeline") .shadow() .find("[id$='growing-btn']") .should("be.focused"); - cy.realPress("Tab"); + cy.realPress("ArrowUp"); cy.get("@timeline") .find("ui5-timeline-item") - .first() + .last() .should("be.focused"); }); }); diff --git a/packages/fiori/src/Timeline.ts b/packages/fiori/src/Timeline.ts index 1c91071baf82..5da9fde5617c 100644 --- a/packages/fiori/src/Timeline.ts +++ b/packages/fiori/src/Timeline.ts @@ -11,6 +11,10 @@ import { isTabPrevious, isSpace, isEnter, + isUp, + isDown, + isLeft, + isRight, } from "@ui5/webcomponents-base/dist/Keys.js"; import type { ITabbable } from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; import type ToggleButton from "@ui5/webcomponents/dist/ToggleButton.js"; @@ -338,6 +342,19 @@ class Timeline extends UI5Element { _onkeydown(e: KeyboardEvent) { const target = e.target as ITimelineItem; + if (isDown(e) || isRight(e)) { + + this._handleDown(); + e.preventDefault(); + return; + } + + if (isUp(e) || isLeft(e)) { + this._handleLodeMoreUp(e); + e.preventDefault(); + return; + } + if (target.nameClickable && !target.getFocusDomRef()!.matches(":has(:focus-within)")) { return; } @@ -371,6 +388,60 @@ class Timeline extends UI5Element { } } + _handleDown() { + if (!this.growsWithButton) { + return; + } + + this._shouldFocusGrowingButton(); + } + + _shouldFocusGrowingButton() { + const items = this._navigableItems; + const lastIndex = items.length - 1; + const currentIndex = this._itemNavigation._currentIndex; + + if (currentIndex !== -1 && currentIndex === lastIndex) { + this.focusGrowingButton(); + } + } + + focusGrowingButton() { + const growingBtn = this.getGrowingButton(); + + if (growingBtn) { + growingBtn.focus(); + } + } + + getGrowingButton() { + return this.shadowRoot!.querySelector(`[id="${this._id}-growing-btn"]`) as HTMLElement; + } + + _handleLodeMoreUp(e: KeyboardEvent) { + const growingButton = this.getGrowingButton(); + + if (growingButton === e.target) { + const items = this._navigableItems; + const lastItem = items[items.length - 1]; + + this.focusItem(lastItem); + + e.preventDefault(); + e.stopImmediatePropagation(); + } + } + + /** + * Focuses a list item and sets its tabindex to "0" via the ItemNavigation + * @protected + * @param item + */ + focusItem(item: ITimelineItem | ToggleButton) { + this._itemNavigation.setCurrentItem(item); + item.focus(); + } + get _navigableItems() { const navigatableItems: Array = []; From dd770f4b088eb627fbfc1b9effdf1ea048095c9b Mon Sep 17 00:00:00 2001 From: Todor Stoyanov Date: Tue, 4 Feb 2025 09:46:36 +0200 Subject: [PATCH 2/3] fix: correction based on code review suggestions --- packages/fiori/src/Timeline.ts | 34 ++++++++----------------- packages/fiori/src/TimelineTemplate.tsx | 2 +- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/packages/fiori/src/Timeline.ts b/packages/fiori/src/Timeline.ts index 5da9fde5617c..6b1bf39dd0d9 100644 --- a/packages/fiori/src/Timeline.ts +++ b/packages/fiori/src/Timeline.ts @@ -167,6 +167,9 @@ class Timeline extends UI5Element { @query(".ui5-timeline-end-marker") timelineEndMarker!: HTMLElement; + @query((`[id="ui5-timeline-growing-btn"]`)) + growingButton!: HTMLElement; + @i18n("@ui5/webcomponents-fiori") static i18nBundle: I18nBundle; @@ -343,14 +346,13 @@ class Timeline extends UI5Element { const target = e.target as ITimelineItem; if (isDown(e) || isRight(e)) { - this._handleDown(); e.preventDefault(); return; } if (isUp(e) || isLeft(e)) { - this._handleLodeMoreUp(e); + this._handleUp(e); e.preventDefault(); return; } @@ -389,39 +391,23 @@ class Timeline extends UI5Element { } _handleDown() { - if (!this.growsWithButton) { - return; + if (this.growsWithButton) { + this.focusGrowingButton(); } - - this._shouldFocusGrowingButton(); } - _shouldFocusGrowingButton() { + focusGrowingButton() { const items = this._navigableItems; const lastIndex = items.length - 1; const currentIndex = this._itemNavigation._currentIndex; if (currentIndex !== -1 && currentIndex === lastIndex) { - this.focusGrowingButton(); + this.growingButton?.focus(); } } - focusGrowingButton() { - const growingBtn = this.getGrowingButton(); - - if (growingBtn) { - growingBtn.focus(); - } - } - - getGrowingButton() { - return this.shadowRoot!.querySelector(`[id="${this._id}-growing-btn"]`) as HTMLElement; - } - - _handleLodeMoreUp(e: KeyboardEvent) { - const growingButton = this.getGrowingButton(); - - if (growingButton === e.target) { + _handleUp(e: KeyboardEvent) { + if ( this.growingButton === e.target) { const items = this._navigableItems; const lastItem = items[items.length - 1]; diff --git a/packages/fiori/src/TimelineTemplate.tsx b/packages/fiori/src/TimelineTemplate.tsx index d2b6685432e0..e3e2baeeeda8 100644 --- a/packages/fiori/src/TimelineTemplate.tsx +++ b/packages/fiori/src/TimelineTemplate.tsx @@ -36,7 +36,7 @@ function moreRow(this: Timeline) {