Skip to content

Commit 70f5563

Browse files
authoredMay 28, 2021
feat(ui5-wizard): set initial focus when a step is changed (#3310)
1 parent 9c8ce88 commit 70f5563

File tree

4 files changed

+47
-33
lines changed

4 files changed

+47
-33
lines changed
 

‎packages/fiori/src/Wizard.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import clamp from "@ui5/webcomponents-base/dist/util/clamp.js";
88
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
99
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
1010
import debounce from "@ui5/webcomponents-base/dist/util/debounce.js";
11+
import { getFirstFocusableElement } from "@ui5/webcomponents-base/dist/util/FocusableElements.js";
1112
import Button from "@ui5/webcomponents/dist/Button.js";
1213
import ResponsivePopover from "@ui5/webcomponents/dist/ResponsivePopover.js";
1314

@@ -133,7 +134,7 @@ const metadata = {
133134
* @event sap.ui.webcomponents.fiori.Wizard#step-change
134135
* @param {HTMLElement} step the new step
135136
* @param {HTMLElement} previousStep the previous step
136-
* @param {Boolean} changeWithClick the step change occurs due to user's click on step within the navigation
137+
* @param {Boolean} changeWithClick the step change occurs due to user's click or 'Enter'/'Space' key press on step within the navigation
137138
* @public
138139
*/
139140
"step-change": {
@@ -427,7 +428,7 @@ class Wizard extends UI5Element {
427428
*/
428429
onSelectionChangeRequested(event) {
429430
this.selectionRequestedByClick = true;
430-
this.changeSelectionByStepClick(event.target);
431+
this.changeSelectionByStepAction(event.target);
431432
}
432433

433434
/**
@@ -649,16 +650,20 @@ class Wizard extends UI5Element {
649650
/**
650651
* Called upon <code>onSelectionChangeRequested</code>.
651652
* Selects the external step (ui5-wizard-step),
652-
* based on the clicked step in the header (ui5-wizard-tab).
653+
* based on the clicked or activated via keyboard step in the header (ui5-wizard-tab).
653654
* @param {HTMLElement} stepInHeader the step equivalent in the header
654655
* @private
655656
*/
656-
changeSelectionByStepClick(stepInHeader) {
657+
async changeSelectionByStepAction(stepInHeader) {
657658
const stepRefId = stepInHeader.getAttribute("data-ui5-content-ref-id");
658659
const selectedStep = this.selectedStep;
659660
const stepToSelect = this.getStepByRefId(stepRefId);
660661
const bExpanded = stepInHeader.getAttribute(EXPANDED_STEP) === "true";
661662
const newlySelectedIndex = this.slottedSteps.indexOf(stepToSelect);
663+
const firstFocusableElement = await getFirstFocusableElement(stepToSelect.firstElementChild);
664+
665+
// Focus the first focusable element within the step content corresponding to the currently focused tab
666+
firstFocusableElement.focus();
662667

663668
// If the currently selected (active) step is clicked,
664669
// just scroll to its starting point and stop.

‎packages/fiori/src/WizardTab.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
22
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
33
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js";
4-
import Icon from "@ui5/webcomponents/dist/Icon.js";
54

5+
import Icon from "@ui5/webcomponents/dist/Icon.js";
66
import WizardTabTemplate from "./generated/templates/WizardTabTemplate.lit.js";
77
import WizardTabCss from "./generated/themes/WizardTab.css.js";
88

@@ -181,11 +181,8 @@ class WizardTab extends UI5Element {
181181
return;
182182
}
183183

184-
if (isSpace(event)) {
184+
if (isSpace(event) || isEnter(event)) {
185185
event.preventDefault();
186-
}
187-
188-
if (isEnter(event)) {
189186
this.fireEvent("selection-change-requested");
190187
}
191188
}

‎packages/fiori/test/pages/Wizard.html

-9
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,6 @@ <h2>Wizard non-standard 2</h2>
372372
<ui5-label wrap>
373373
Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien
374374
</ui5-label>
375-
<ui5-messagestrip>
376-
The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with.
377-
</ui5-messagestrip><br>
378375

379376
<div style="display: flex; flex-direction: column;">
380377
<div style="display: flex; flex-direction: row; justify-content: flex-end; align-items: center; margin-top: 1rem">
@@ -496,9 +493,6 @@ <h2>Wizard non-standard 3</h2>
496493
<ui5-label wrap>
497494
Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien
498495
</ui5-label>
499-
<ui5-messagestrip>
500-
The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with.
501-
</ui5-messagestrip><br>
502496

503497
<div style="display: flex; flex-direction: column;">
504498
<div style="display: flex; flex-direction: row; justify-content: flex-end; align-items: center; margin-top: 1rem">
@@ -536,9 +530,6 @@ <h2>Wizard non-standard 3</h2>
536530
<ui5-label wrap>
537531
Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec ppellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien corper eu, posuere malesuada nisl. Integer pellentesque leo sit amet dui vehicula, quis ullamcorper est pulvinar. Nam in libero sem. Suspendisse arcu metus, molestie a turpis a, molestie aliquet dui. Donec pulvinar, sapien
538532
</ui5-label>
539-
<ui5-messagestrip>
540-
The Wizard control is supposed to break down large tasks, into smaller steps, easier for the user to work with.
541-
</ui5-messagestrip><br>
542533

543534
<div style="display: flex; flex-direction: column;">
544535
<div style="display: flex; flex-direction: row; justify-content: flex-end; align-items: center; margin-top: 1rem">

‎packages/fiori/test/specs/Wizard.spec.js

+36-15
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,16 @@ describe("Wizard general interaction", () => {
8383
const wiz = browser.$("#wizTest");
8484
const step1 = browser.$("#st1");
8585
const step2 = browser.$("#st2");
86+
8687
const step1InHeader = wiz.shadow$(`[data-ui5-index="1"]`);
8788
const step2InHeader = wiz.shadow$(`[data-ui5-index="2"]`);
8889
const inpStepChangeCounter = browser.$("#inpStepChangeCounter");
8990
const inpStepChangeCause = browser.$("#inpStepChangeCause");
9091

92+
const wizardStep = browser.$("ui5-wizard-step");
93+
const messageStrip = wizardStep.shadow$("ui5-messagestrip")
94+
const firstFocusableElement = messageStrip.shadow$(`ui5-button`);
95+
9196
// act - click on the first step in the header
9297
step1InHeader.click();
9398

@@ -101,6 +106,16 @@ describe("Wizard general interaction", () => {
101106
assert.strictEqual(step1InHeader.getAttribute("disabled"), null,
102107
"First step in header is enabled.");
103108

109+
assert.strictEqual(firstFocusableElement.getAttribute("focused"), "true", "The First focusable element in the step content is focused.");
110+
111+
step1InHeader.keys(["Shift", "Tab"]);
112+
step2InHeader.keys("Space");
113+
assert.strictEqual(firstFocusableElement.getAttribute("focused"), "true", "The First focusable element in the step content is focused.");
114+
115+
step1InHeader.keys(["Shift", "Tab"]);
116+
step2InHeader.keys("Enter");
117+
assert.strictEqual(firstFocusableElement.getAttribute("focused"), "true", "The First focusable element in the step content is focused.");
118+
104119
// assert - that second step in the content and in the header are not selected
105120
assert.strictEqual(step2.getAttribute("selected"), null,
106121
"Second step in the content is not selected.");
@@ -126,6 +141,7 @@ describe("Wizard general interaction", () => {
126141
// act - bring the focus to the first step in the header
127142
// act - use keyboard to move to step2
128143
step1InHeader.click();
144+
step1InHeader.keys(["Shift", "Tab"]);
129145
step1InHeader.keys("ArrowRight");
130146
step2InHeader.keys("Space");
131147

@@ -146,29 +162,34 @@ describe("Wizard general interaction", () => {
146162
// assert - step-change second time
147163
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "2", "Event step-change fired 2nd time.");
148164

149-
// act - use keyboard to move back to step1
150-
step2InHeader.keys("ArrowLeft");
165+
// act - move back to step1 then move the focus to the step 2 and press enter
166+
step1InHeader.click();
167+
step1InHeader.keys(["Shift", "Tab"]);
168+
step1InHeader.keys("ArrowRight");
151169
step1InHeader.keys("Enter");
152170

153171
// assert - that first step in the content and in the header are selected
154-
assert.strictEqual(step1.getAttribute("selected"), "true",
172+
assert.strictEqual(step2.getAttribute("selected"), "true",
155173
"First step in the content is not selected.");
156-
assert.strictEqual(step1InHeader.getAttribute("selected"), "true",
174+
assert.strictEqual(step2InHeader.getAttribute("selected"), "true",
157175
"First step in the header not is selected.");
158-
assert.strictEqual(step1.getAttribute("disabled"), null,
176+
assert.strictEqual(step2.getAttribute("disabled"), null,
159177
"First step is enabled.");
160-
assert.strictEqual(step1InHeader.getAttribute("disabled"), null,
178+
assert.strictEqual(step2InHeader.getAttribute("disabled"), null,
161179
"First step in header is enabled.");
162180

163-
// assert - that second step in the content and in the header are not selected
164-
assert.strictEqual(step2.getAttribute("selected"), null,
181+
// assert - that first step in the content and in the header are not selected
182+
assert.strictEqual(step1.getAttribute("selected"), null,
165183
"Second step in the content is not selected.");
166-
assert.strictEqual(step2InHeader.getAttribute("selected"), null,
184+
assert.strictEqual(step1InHeader.getAttribute("selected"), null,
167185
"Second step in the header is not selected.");
168186

169187
// assert - step-change second time
170-
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "3",
171-
"Event step-change fired 3rd time.");
188+
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "4",
189+
"Event step-change fired 4th time.");
190+
191+
// Activate the first step for the next tests
192+
step1InHeader.click();
172193
});
173194

174195
it("move to next step by scroll", () => {
@@ -191,8 +212,8 @@ describe("Wizard general interaction", () => {
191212
assert.strictEqual(step2.getAttribute("disabled"), null, "Second step is enabled.");
192213
assert.strictEqual(step2InHeader.getAttribute("disabled"), null, "Second step in header is enabled.");
193214

194-
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "4",
195-
"Event step-change fired 4th time due to scrolling.");
215+
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "6",
216+
"Event step-change fired 6th time due to scrolling.");
196217

197218
// assert - step-change fired not because of user click
198219
assert.strictEqual(inpStepChangeCause.getProperty("value"), "false",
@@ -219,8 +240,8 @@ describe("Wizard general interaction", () => {
219240
"Third step in the content is selected.");
220241
assert.strictEqual(step3InHeader.getAttribute("selected"), "true",
221242
"Third step in the header is selected.");
222-
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "5",
223-
"Event step-change fired once for 5th time due to scrolling.");
243+
assert.strictEqual(inpStepChangeCounter.getProperty("value"), "7",
244+
"Event step-change fired once for 7th time due to scrolling.");
224245
});
225246

226247
it("tests no scrolling to step, if the step was not changed", ()=>{

0 commit comments

Comments
 (0)
Please sign in to comment.