diff --git a/packages/base/src/Keys.js b/packages/base/src/Keys.js index e0961d330f2f..951d6315da0c 100644 --- a/packages/base/src/Keys.js +++ b/packages/base/src/Keys.js @@ -187,6 +187,8 @@ const isF4 = event => { const isF4Shift = event => (event.key ? event.key === "F4" : event.keyCode === KeyCodes.F4) && checkModifierKeys(event, false, false, true); +const isF7 = event => (event.key ? event.key === "F7" : event.keyCode === KeyCodes.F7) && !hasModifierKeys(event); + const isShowByArrows = event => { return ((event.key === "ArrowDown" || event.key === "Down") || (event.key === "ArrowUp" || event.key === "Up")) && checkModifierKeys(event, /* Ctrl */ false, /* Alt */ true, /* Shift */ false); }; @@ -230,6 +232,7 @@ export { isShow, isF4, isF4Shift, + isF7, isPageUp, isPageDown, isPageUpShift, diff --git a/packages/main/src/Carousel.hbs b/packages/main/src/Carousel.hbs index a4cf1b8c2046..d75c9a0ce85f 100644 --- a/packages/main/src/Carousel.hbs +++ b/packages/main/src/Carousel.hbs @@ -3,6 +3,7 @@ tabindex="0" role="listbox" aria-activedescendant="{{ariaActiveDescendant}}" + @focusin="{{_onfocusin}}" @keydown={{_onkeydown}} @mouseout="{{_onmouseout}}" @mouseover="{{_onmouseover}}" diff --git a/packages/main/src/Carousel.js b/packages/main/src/Carousel.js index 56579158ccb9..8d9462a3d867 100644 --- a/packages/main/src/Carousel.js +++ b/packages/main/src/Carousel.js @@ -6,6 +6,7 @@ import { isRight, isDown, isUp, + isF7, } from "@ui5/webcomponents-base/dist/Keys.js"; import { fetchI18nBundle, @@ -13,6 +14,7 @@ import { } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import ScrollEnablement from "@ui5/webcomponents-base/dist/delegate/ScrollEnablement.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; +import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js"; import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js"; import AnimationMode from "@ui5/webcomponents-base/dist/types/AnimationMode.js"; import { getAnimationMode } from "@ui5/webcomponents-base/dist/config/AnimationMode.js"; @@ -285,6 +287,9 @@ class Carousel extends UI5Element { this.i18nBundle = getI18nBundle("@ui5/webcomponents"); this._onResizeBound = this._onResize.bind(this); this._resizing = false; // indicates if the carousel is in process of resizing + + this._lastFocusedElements = []; + this._orderOfLastFocusedPages = []; } onBeforeRendering() { @@ -348,15 +353,53 @@ class Carousel extends UI5Element { } } - _onkeydown(event) { + async _onkeydown(event) { + if (isF7(event)) { + this._handleF7Key(event); + return; + } + if (event.target !== this.getDomRef()) { return; } if (isLeft(event) || isDown(event)) { this.navigateLeft(); + await renderFinished(); + this.getDomRef().focus(); } else if (isRight(event) || isUp(event)) { this.navigateRight(); + await renderFinished(); + this.getDomRef().focus(); + } + } + + _onfocusin(event) { + if (event.target === this.getDomRef()) { + return; + } + + let pageIndex = -1; + + for (let i = 0; i < this.content.length; i++) { + if (this.content[i].contains(event.target)) { + pageIndex = i; + break; + } + } + + if (pageIndex === -1) { + return; + } + + // Save reference of the last focused element for each page + this._lastFocusedElements[pageIndex] = event.target; + + const sortedPageIndex = this._orderOfLastFocusedPages.indexOf(pageIndex); + if (sortedPageIndex === -1) { + this._orderOfLastFocusedPages.unshift(pageIndex); + } else { + this._orderOfLastFocusedPages.splice(0, 0, this._orderOfLastFocusedPages.splice(sortedPageIndex, 1)[0]); } } @@ -372,6 +415,28 @@ class Carousel extends UI5Element { } } + _handleF7Key(event) { + const lastFocusedElement = this._lastFocusedElements[this._getLastFocusedActivePageIndex]; + + if (event.target === this.getDomRef() && lastFocusedElement) { + lastFocusedElement.focus(); + } else { + this.getDomRef().focus(); + } + } + + get _getLastFocusedActivePageIndex() { + for (let i = 0; i < this._orderOfLastFocusedPages.length; i++) { + const pageIndex = this._orderOfLastFocusedPages[i]; + + if (this.isItemInViewport(pageIndex)) { + return pageIndex; + } + } + + return this._selectedIndex; + } + navigateLeft() { this._resizing = false; diff --git a/packages/main/test/pages/Carousel.html b/packages/main/test/pages/Carousel.html index 4f0c8a51fd3f..a4040fdda495 100644 --- a/packages/main/test/pages/Carousel.html +++ b/packages/main/test/pages/Carousel.html @@ -25,7 +25,6 @@ height: 100%; } - @@ -475,6 +474,70 @@ Button 3 + F7 keyboard navigation testing + + +
+ Page 1
+ Button 1 +
+ Button 2 +
+ +
+
+ +
+ Page 2
+ Button 1 +
+ Button 2 +
+ +
+
+ +
+ Page 3
+ Button 1 +
+ Button 2 +
+ +
+
+ +
+ Page 4
+ Button 1 +
+ Button 2 +
+ +
+
+ +
+ Page 5
+ Button 1 +
+ Button 2 +
+ +
+
+ +
+ Page 6
+ Button 1 +
+ Button 2 +
+ +
+
+
+