Skip to content

Commit a9b3c69

Browse files
authored
feat(ui5-menu, ui5-timeline, ui5-calendar-legend, ui5-color-palette): add getFocusDomRef (#11997)
related to: #11490
1 parent 006123b commit a9b3c69

File tree

10 files changed

+331
-0
lines changed

10 files changed

+331
-0
lines changed

packages/fiori/cypress/specs/Timeline.cy.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import calendar from "@ui5/webcomponents-icons/dist/calendar.js";
66
import messageInformation from "@ui5/webcomponents-icons/dist/message-information.js";
77
import Label from "@ui5/webcomponents/dist/Label.js";
88
import Avatar from "@ui5/webcomponents/dist/Avatar.js";
9+
import UI5Element from "@ui5/webcomponents-base";
910

1011
function Sample() {
1112
return <Timeline layout="Vertical" accessibleName="vertical" id="timelineAccName">
@@ -311,3 +312,58 @@ describe("Accessibility", () => {
311312
});
312313
});
313314
});
315+
316+
describe("Timeline - getFocusDomRef", () => {
317+
it("should return undefined when the Timeline is empty", () => {
318+
cy.mount(<Timeline></Timeline>);
319+
320+
cy.get<Timeline>("[ui5-timeline]")
321+
.then(($el) => {
322+
expect($el[0].getFocusDomRef()).to.be.undefined;
323+
});
324+
});
325+
326+
it("should return first item if no item was focused before", () => {
327+
cy.mount(
328+
<Timeline growing="Button">
329+
<TimelineItem id="firstItem" titleText="first item" subtitleText="20.02.2017 11:30" ></TimelineItem>
330+
<TimelineItem titleText="coming up" subtitleText="20.02.2017 11:30"></TimelineItem>
331+
<TimelineItem titleText="coming up" subtitleText="20.02.2017 11:30" ></TimelineItem>
332+
</Timeline>
333+
);
334+
335+
cy.get<UI5Element>("[ui5-timeline], #firstItem")
336+
.then(($el) => {
337+
const timeline = $el[0],
338+
firstItem = $el[1];
339+
expect(timeline.getFocusDomRef()).to.equal(firstItem.getFocusDomRef());
340+
});
341+
});
342+
343+
it("should return last focused item in the Timeline", () => {
344+
cy.mount(
345+
<Timeline growing="Button">
346+
<TimelineItem titleText="first item" subtitleText="20.02.2017 11:30" ></TimelineItem>
347+
<TimelineItem titleText="coming up" subtitleText="20.02.2017 11:30"></TimelineItem>
348+
<TimelineItem id="lastItem" titleText="coming up" subtitleText="20.02.2017 11:30" ></TimelineItem>
349+
</Timeline>
350+
);
351+
352+
cy.get("[ui5-timeline]")
353+
.as("timeline");
354+
355+
cy.get("[ui5-timeline]")
356+
.find("#lastItem")
357+
.realClick();
358+
359+
cy.get<UI5Element>("[ui5-timeline], #lastItem")
360+
.then(($el) => {
361+
const timeline = $el[0],
362+
lastItem = $el[1];
363+
expect(timeline.getFocusDomRef()).to.equal(lastItem.getFocusDomRef());
364+
});
365+
});
366+
});
367+
368+
369+

packages/fiori/src/Timeline.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ class Timeline extends UI5Element {
265265
this.fireDecoratorEvent("load-more");
266266
}
267267

268+
getFocusDomRef(): HTMLElement | undefined {
269+
return this._itemNavigation._getCurrentItem();
270+
}
271+
268272
_onLoadMoreKeydown(e: KeyboardEvent) {
269273
if (isSpace(e)) {
270274
e.preventDefault();

packages/main/cypress/specs/CalendarLegend.cy.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import CalendarDate from "../../src/CalendarDate.js";
33
import CalendarLegend from "../../src/CalendarLegend.js";
44
import CalendarLegendItem from "../../src/CalendarLegendItem.js";
55
import SpecialCalendarDate from "../../src/SpecialCalendarDate.js";
6+
import type UI5Element from "@ui5/webcomponents-base";
67

78
const getCalendarWithLegend = () => {
89
return (
@@ -75,3 +76,75 @@ describe("Calendar Legend tests", () => {
7576
.should("have.length", 2);
7677
});
7778
});
79+
80+
describe("Calendar Legend - getFocusDomRef", () => {
81+
it("should return undefined when the CalendarLegend is empty", () => {
82+
cy.mount(
83+
<Calendar id="calendar1">
84+
<CalendarDate value="Mar 31, 2024"></CalendarDate>
85+
<SpecialCalendarDate slot="specialDates" value="Mar 30, 2024" type="Type01"></SpecialCalendarDate>
86+
<SpecialCalendarDate slot="specialDates" value="Mar 29, 2024" type="Type02"></SpecialCalendarDate>
87+
88+
<CalendarLegend slot="calendarLegend" id="calendarLegend" hideToday hideSelectedDay hideWorkingDay hideNonWorkingDay></CalendarLegend>
89+
</Calendar>
90+
);
91+
92+
cy.get<CalendarLegend>("#calendarLegend")
93+
.then(($el) => {
94+
expect($el[0].getFocusDomRef()).to.be.undefined;
95+
});
96+
});
97+
98+
it("should return first item if no item was focused before", () => {
99+
cy.mount(
100+
<Calendar id="calendar1">
101+
<CalendarDate value="Mar 31, 2024"></CalendarDate>
102+
<SpecialCalendarDate slot="specialDates" value="Mar 30, 2024" type="Type01"></SpecialCalendarDate>
103+
<SpecialCalendarDate slot="specialDates" value="Mar 29, 2024" type="Type02"></SpecialCalendarDate>
104+
105+
<CalendarLegend hideToday hideSelectedDay hideWorkingDay hideNonWorkingDay slot="calendarLegend" id="calendarLegend">
106+
<CalendarLegendItem type="Type01" text="Placeholder 01"></CalendarLegendItem>
107+
<CalendarLegendItem type="Type02" text="Placeholder 02"></CalendarLegendItem>
108+
</CalendarLegend>
109+
</Calendar>
110+
);
111+
112+
cy.get<CalendarLegend>("#calendarLegend")
113+
.then(($el) => {
114+
const legend = $el[0];
115+
cy.get<UI5Element>('ui5-calendar-legend-item[type="Type01"]').then(($item) => {
116+
const firstItem = $item[0];
117+
expect(legend.getFocusDomRef()).to.equal(firstItem.getFocusDomRef());
118+
});
119+
});
120+
});
121+
122+
it("should return last focused item in the Calendar Legend", () => {
123+
cy.mount(
124+
<Calendar id="calendar1">
125+
<CalendarDate value="Mar 31, 2024"></CalendarDate>
126+
<SpecialCalendarDate slot="specialDates" value="Mar 30, 2024" type="Type01"></SpecialCalendarDate>
127+
<SpecialCalendarDate slot="specialDates" value="Mar 29, 2024" type="Type02"></SpecialCalendarDate>
128+
129+
<CalendarLegend hideToday hideSelectedDay hideWorkingDay hideNonWorkingDay slot="calendarLegend" id="calendarLegend">
130+
<CalendarLegendItem type="Type01" text="Placeholder 01"></CalendarLegendItem>
131+
<CalendarLegendItem type="Type02" text="Placeholder 02"></CalendarLegendItem>
132+
</CalendarLegend>
133+
</Calendar>
134+
);
135+
136+
cy.get('ui5-calendar-legend-item[type="Type02"]').realClick();
137+
cy.get('ui5-calendar-legend-item[type="Type02"]').should("be.focused");
138+
139+
cy.get<CalendarLegend>("#calendarLegend")
140+
.then(($el) => {
141+
const legend = $el[0];
142+
cy.get<UI5Element>('ui5-calendar-legend-item[type="Type02"]').then(($item) => {
143+
const lastFocusesItem = $item[0];
144+
expect(legend.getFocusDomRef()).to.equal(lastFocusesItem.getFocusDomRef());
145+
});
146+
});
147+
});
148+
});
149+
150+

packages/main/cypress/specs/ColorPalette.cy.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import UI5Element from "@ui5/webcomponents-base";
12
import ColorPalette from "../../src/ColorPalette.js";
23
import ColorPaletteItem from "../../src/ColorPaletteItem.js";
34

@@ -211,3 +212,72 @@ describe("Color Palette tests", () => {
211212
.should("have.attr", "selected");
212213
});
213214
});
215+
216+
describe("Color Palette - getFocusDomRef", () => {
217+
it("should return undefined when the ColorPalette is empty", () => {
218+
cy.mount(<ColorPalette></ColorPalette>);
219+
220+
cy.get<ColorPalette>("[ui5-color-palette]")
221+
.then(($el) => {
222+
expect($el[0].getFocusDomRef()).to.be.undefined;
223+
});
224+
});
225+
226+
it("should return first item if no item was focused before", () => {
227+
cy.mount(
228+
<ColorPalette>
229+
<ColorPaletteItem id="darkBlue" value="darkblue"></ColorPaletteItem>
230+
<ColorPaletteItem value="pink"></ColorPaletteItem>
231+
<ColorPaletteItem value="#444444"></ColorPaletteItem>
232+
<ColorPaletteItem value="rgb(0,200,0)"></ColorPaletteItem>
233+
<ColorPaletteItem value="green"></ColorPaletteItem>
234+
<ColorPaletteItem value="darkred"></ColorPaletteItem>
235+
<ColorPaletteItem value="yellow"></ColorPaletteItem>
236+
<ColorPaletteItem value="blue"></ColorPaletteItem>
237+
<ColorPaletteItem value="cyan"></ColorPaletteItem>
238+
<ColorPaletteItem value="orange"></ColorPaletteItem>
239+
<ColorPaletteItem value="#5480e7"></ColorPaletteItem>
240+
<ColorPaletteItem value="#ff6699"></ColorPaletteItem>
241+
</ColorPalette>
242+
);
243+
244+
cy.get<UI5Element>("[ui5-color-palette], #darkBlue")
245+
.then(($el) => {
246+
const colorPalette = $el[0],
247+
firstColor = $el[1];
248+
expect(colorPalette.getFocusDomRef()).to.equal(firstColor.getFocusDomRef());
249+
});
250+
});
251+
252+
it("should return last focused item in the ColorPalette", () => {
253+
cy.mount(
254+
<ColorPalette>
255+
<ColorPaletteItem value="darkblue"></ColorPaletteItem>
256+
<ColorPaletteItem value="pink"></ColorPaletteItem>
257+
<ColorPaletteItem value="#444444"></ColorPaletteItem>
258+
<ColorPaletteItem value="rgb(0,200,0)"></ColorPaletteItem>
259+
<ColorPaletteItem id="green" value="green"></ColorPaletteItem>
260+
<ColorPaletteItem value="darkred"></ColorPaletteItem>
261+
<ColorPaletteItem value="yellow"></ColorPaletteItem>
262+
<ColorPaletteItem value="blue"></ColorPaletteItem>
263+
<ColorPaletteItem value="cyan"></ColorPaletteItem>
264+
<ColorPaletteItem value="orange"></ColorPaletteItem>
265+
<ColorPaletteItem value="#5480e7"></ColorPaletteItem>
266+
<ColorPaletteItem value="#ff6699"></ColorPaletteItem>
267+
</ColorPalette>
268+
);
269+
270+
cy.get("[ui5-color-palette]")
271+
.find("#green")
272+
.realClick()
273+
.realClick()
274+
.should("be.focused")
275+
276+
cy.get<UI5Element>("[ui5-color-palette], #green")
277+
.then(($el) => {
278+
const colorPalette = $el[0],
279+
lastFocusItem = $el[1];
280+
expect(colorPalette.getFocusDomRef()).to.equal(lastFocusItem.getFocusDomRef());
281+
});
282+
});
283+
});

packages/main/cypress/specs/Menu.cy.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import openFolder from "@ui5/webcomponents-icons/dist/open-folder.js";
77
import addFolder from "@ui5/webcomponents-icons/dist/add-folder.js";
88
import locked from "@ui5/webcomponents-icons/dist/locked.js";
99
import favorite from "@ui5/webcomponents-icons/dist/favorite.js";
10+
import UI5Element from "@ui5/webcomponents-base";
1011

1112
describe("Menu interaction", () => {
1213
it("Menu opens after button click", () => {
@@ -1100,3 +1101,65 @@ describe("Menu interaction", () => {
11001101
});
11011102
});
11021103
});
1104+
1105+
describe("Menu - getFocusDomRef", () => {
1106+
it("should return undefined when the Menu is empty", () => {
1107+
cy.mount(<Menu></Menu>);
1108+
1109+
cy.get<Menu>("[ui5-menu]")
1110+
.then(($el) => {
1111+
expect($el[0].getFocusDomRef()).to.be.undefined;
1112+
});
1113+
});
1114+
1115+
it("should return first item if no item was focused before", () => {
1116+
cy.mount(
1117+
<>
1118+
<Button id="btnOpen">Open Menu</Button>
1119+
<Menu id="menu" opener="btnOpen">
1120+
<MenuItem id="item1" text="Item 1"/>
1121+
<MenuItem text="Item2"/>
1122+
</Menu>
1123+
</>
1124+
);
1125+
1126+
cy.get("[ui5-menu]")
1127+
.ui5MenuOpen();
1128+
1129+
cy.get<UI5Element>("[ui5-menu], #item1")
1130+
.then(($el) => {
1131+
const menu = $el[0],
1132+
firstItem = $el[1];
1133+
expect(menu.getFocusDomRef()).equal(firstItem.getFocusDomRef());
1134+
});
1135+
});
1136+
1137+
it("should return last focused item in the Menu", () => {
1138+
cy.mount(
1139+
<>
1140+
<Button id="btnOpen">Open Menu</Button>
1141+
<Menu id="menu" opener="btnOpen">
1142+
<MenuItem text="Item 1"/>
1143+
<MenuItem text="Item 2" id="item2"/>
1144+
</Menu>
1145+
</>
1146+
);
1147+
1148+
cy.get("[ui5-menu]")
1149+
.ui5MenuOpen();
1150+
1151+
cy.get("[ui5-menu-item][text='Item 2']")
1152+
.as("item")
1153+
.ui5MenuItemClick();
1154+
1155+
cy.get("[ui5-menu-item][text='Item 2']")
1156+
.should("be.focused");
1157+
1158+
cy.get<UI5Element>("[ui5-menu], #item2")
1159+
.then(($el) => {
1160+
const menu = $el[0],
1161+
clickedItem = $el[1];
1162+
expect(menu.getFocusDomRef()).equal(clickedItem.getFocusDomRef());
1163+
});
1164+
});
1165+
});

packages/main/cypress/specs/SegmentedButton.cy.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import SegmentedButton from "../../src/SegmentedButton.js";
22
import SegmentedButtonItem from "../../src/SegmentedButtonItem.js";
3+
import type UI5Element from "@ui5/webcomponents-base";
34

45
describe("SegmentedButton general interaction tests", () => {
56
it("should have first item selected by default", () => {
@@ -181,6 +182,54 @@ describe("SegmentedButton general interaction tests", () => {
181182
});
182183
});
183184

185+
describe("SegmentedButton - getFocusDomRef", () => {
186+
it("should return undefined when the SegmentedButton is empty", () => {
187+
cy.mount(<SegmentedButton></SegmentedButton>);
188+
189+
cy.get<SegmentedButton>("[ui5-segmented-button]")
190+
.then(($el) => {
191+
expect($el[0].getFocusDomRef()).to.be.undefined;
192+
});
193+
});
194+
195+
it("should return first item if no item was focused before", () => {
196+
cy.mount(
197+
<SegmentedButton>
198+
<SegmentedButtonItem id="button1" title="Button 1"></SegmentedButtonItem>
199+
<SegmentedButtonItem title="Button 2"></SegmentedButtonItem>
200+
</SegmentedButton>
201+
);
202+
203+
cy.get<UI5Element>("[ui5-segmented-button], #button1")
204+
.then(($el) => {
205+
const wrapper = $el[0],
206+
firstButton = $el[1];
207+
208+
expect(wrapper.getFocusDomRef()).to.equal(firstButton.getFocusDomRef());
209+
});
210+
});
211+
212+
it("should return last focused item in the SegmentedButton", () => {
213+
cy.mount(
214+
<SegmentedButton>
215+
<SegmentedButtonItem title="Button 1"></SegmentedButtonItem>
216+
<SegmentedButtonItem id="button2" title="Button 2"></SegmentedButtonItem>
217+
</SegmentedButton>
218+
);
219+
220+
cy.get('#button2').realClick();
221+
cy.get('#button2').should("be.focused");
222+
223+
cy.get<UI5Element>("[ui5-segmented-button], #button2")
224+
.then(($el) => {
225+
const wrapper = $el[0],
226+
secondButton = $el[1];
227+
228+
expect(wrapper.getFocusDomRef()).to.equal(secondButton.getFocusDomRef());
229+
});
230+
});
231+
});
232+
184233
describe("Accessibility", () => {
185234
it("should have correct aria labels", () => {
186235
cy.mount(

packages/main/src/CalendarLegend.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ class CalendarLegend extends UI5Element {
130130
}
131131
}
132132

133+
getFocusDomRef(): HTMLElement | undefined {
134+
return this._itemNavigation._getCurrentItem();
135+
}
136+
133137
_onMouseDown(e: MouseEvent) {
134138
e.stopPropagation();
135139
const target = e.target as CalendarLegendItem;

packages/main/src/ColorPalette.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ class ColorPalette extends UI5Element {
352352
this._ensureSingleSelectionOrDeselectAll();
353353
}
354354

355+
getFocusDomRef(): HTMLElement | undefined {
356+
return this._itemNavigation._getCurrentItem();
357+
}
358+
355359
_handleDefaultColorClick(e: KeyboardEvent) {
356360
e.preventDefault();
357361
this._onDefaultColorClick();

0 commit comments

Comments
 (0)