Skip to content

Commit df8804a

Browse files
authored
feat(ui5-date-picker): provide accessible description API (#11831)
For the following list of components: - ui5-date-picker - ui5-daterange-picker - ui5-datetime-picker - ui5-time-picker - ui5-file-uploader we've made the following changes: - Introduced accessibleDescription and accessibleDescriptionRef APIs. - Adjusted the value help popover accessible name according to the specification. - Announce the external label references. Fixes: #12004
1 parent 78c6d46 commit df8804a

18 files changed

+515
-136
lines changed

docs/2-advanced/09-accessibility.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ The `accessibleDescription` property is currently supported in:
214214
* [Popover](https://sap.github.io/ui5-webcomponents/nightly/components/Popover/)
215215
* [ResponsivePopover](https://sap.github.io/ui5-webcomponents/nightly/components/ResponsivePopover/)
216216
* [Dialog](https://sap.github.io/ui5-webcomponents/nightly/components/Dialog/)
217+
* [DatePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DatePicker/)
218+
* [DateRangePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DateRangePicker/)
219+
* [DateTimePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DateTimePicker/)
220+
* [TimePicker](https://sap.github.io/ui5-webcomponents/nightly/components/TimePicker/)
221+
* [FileUploader](https://sap.github.io/ui5-webcomponents/nightly/components/FileUploader/)
217222

218223
---
219224

@@ -243,6 +248,11 @@ The `accessibleDescriptionRef` property is currently supported in:
243248
* [Popover](https://sap.github.io/ui5-webcomponents/nightly/components/Popover/)
244249
* [ResponsivePopover](https://sap.github.io/ui5-webcomponents/nightly/components/ResponsivePopover/)
245250
* [Dialog](https://sap.github.io/ui5-webcomponents/nightly/components/Dialog/)
251+
* [DatePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DatePicker/)
252+
* [DateRangePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DateRangePicker/)
253+
* [DateTimePicker](https://sap.github.io/ui5-webcomponents/nightly/components/DateTimePicker/)
254+
* [TimePicker](https://sap.github.io/ui5-webcomponents/nightly/components/TimePicker/)
255+
* [FileUploader](https://sap.github.io/ui5-webcomponents/nightly/components/FileUploader/)
246256

247257
---
248258

@@ -304,6 +314,7 @@ The `accessibilityAttributes` property is currently supported in:
304314
* [Avatar](https://sap.github.io/ui5-webcomponents/nightly/components/Avatar/)
305315
* [AvatarGroup](https://sap.github.io/ui5-webcomponents/nightly/components/AvatarGroup/)
306316
* [Button](https://sap.github.io/ui5-webcomponents/nightly/components/Button/)
317+
* [Button](https://sap.github.io/ui5-webcomponents/nightly/components/ai/Button/)
307318
* [Link](https://sap.github.io/ui5-webcomponents/nightly/components/Link/)
308319
* [ToggleButton](https://sap.github.io/ui5-webcomponents/nightly/components/ToggleButton/)
309320
* [Link](https://sap.github.io/ui5-webcomponents/nightly/components/Link/)
@@ -313,6 +324,7 @@ The `accessibilityAttributes` property is currently supported in:
313324
* [FlexibleColumnLayout](https://sap.github.io/ui5-webcomponents/nightly/components/fiori/FlexibleColumnLayout/)
314325
* [ShellBar](https://sap.github.io/ui5-webcomponents/nightly/components/fiori/ShellBar/)
315326
* [ShellBarItem](https://sap.github.io/ui5-webcomponents/nightly/components/fiori/ShellBarItem/)
327+
* [SplitButton](https://sap.github.io/ui5-webcomponents/nightly/components/SplitButton/)
316328
* [MenuItem](https://sap.github.io/ui5-webcomponents/nightly/components/MenuItem/)
317329
* [List](https://sap.github.io/ui5-webcomponents/nightly/components/List/)
318330

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

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import DatePicker from "../../src/DatePicker.js";
55
import Label from "../../src/Label.js";
66

77
describe("Date Picker Tests", () => {
8+
89
it("input renders", () => {
910
cy.mount(<DatePicker></DatePicker>);
1011

@@ -1548,19 +1549,6 @@ describe("Date Picker Tests", () => {
15481549
.find("ui5-yearpicker")
15491550
.should("be.visible");
15501551
});
1551-
1552-
it("picker popover should have accessible name", () => {
1553-
cy.mount(<DatePicker></DatePicker>);
1554-
1555-
cy.get("[ui5-date-picker]")
1556-
.as("datePicker")
1557-
.ui5DatePickerValueHelpIconPress();
1558-
1559-
cy.get<DatePicker>("@datePicker")
1560-
.shadow()
1561-
.find("ui5-responsive-popover")
1562-
.should("have.attr", "accessible-name", "Choose Date");
1563-
});
15641552
});
15651553

15661554
describe("Legacy date customization and Islamic calendar type", () => {
@@ -1689,3 +1677,84 @@ describe("Legacy date customization and Islamic calendar type", () => {
16891677
.should("have.attr", "value-state", "None");
16901678
});
16911679
});
1680+
1681+
describe("Accessibility", () => {
1682+
it("picker popover accessible name with external label", () => {
1683+
const LABEL = "Deadline";
1684+
1685+
cy.mount(
1686+
<>
1687+
<Label for="datePicker">{LABEL}</Label>
1688+
<DatePicker id="datePicker"></DatePicker>
1689+
</>
1690+
);
1691+
1692+
cy.get("[ui5-date-picker]")
1693+
.as("datePicker")
1694+
.ui5DatePickerValueHelpIconPress();
1695+
1696+
cy.get<DatePicker>("@datePicker")
1697+
.shadow()
1698+
.find("ui5-responsive-popover")
1699+
.should("have.attr", "accessible-name", `Choose Date for ${LABEL}`);
1700+
});
1701+
1702+
it("picker popover accessible name", () => {
1703+
const LABEL = "Deadline";
1704+
cy.mount(
1705+
<DatePicker id="datePicker" accessible-name={LABEL}></DatePicker>
1706+
);
1707+
1708+
cy.get("[ui5-date-picker]")
1709+
.as("datePicker")
1710+
.ui5DatePickerValueHelpIconPress();
1711+
1712+
cy.get<DatePicker>("@datePicker")
1713+
.shadow()
1714+
.find("ui5-responsive-popover")
1715+
.should("have.attr", "accessible-name", `Choose Date for ${LABEL}`);
1716+
});
1717+
1718+
it("accessibleDescription property", () => {
1719+
const DESCRIPTION = "This is a date picker";
1720+
cy.mount(<DatePicker accessibleDescription={DESCRIPTION}></DatePicker>);
1721+
1722+
cy.get("[ui5-date-picker]")
1723+
.as("datePicker");
1724+
1725+
cy.get<DatePicker>("@datePicker")
1726+
.ui5DatePickerGetInnerInput()
1727+
.should("have.attr", "aria-describedby", "descr");
1728+
1729+
cy.get<DatePicker>("@datePicker")
1730+
.shadow()
1731+
.find("[ui5-datetime-input]")
1732+
.shadow()
1733+
.find("span#descr")
1734+
.should("have.text", DESCRIPTION);
1735+
});
1736+
1737+
it("accessibleDescriptionRef property", () => {
1738+
const DESCRIPTION = "This is a date picker";
1739+
cy.mount(
1740+
<>
1741+
<p id="datePickerDescription">{DESCRIPTION}</p>
1742+
<DatePicker accessibleDescriptionRef="datePickerDescription"></DatePicker>
1743+
</>
1744+
);
1745+
1746+
cy.get("[ui5-date-picker]")
1747+
.as("datePicker");
1748+
1749+
cy.get<DatePicker>("@datePicker")
1750+
.ui5DatePickerGetInnerInput()
1751+
.should("have.attr", "aria-describedby", "descr");
1752+
1753+
cy.get<DatePicker>("@datePicker")
1754+
.shadow()
1755+
.find("[ui5-datetime-input]")
1756+
.shadow()
1757+
.find("span#descr")
1758+
.should("have.text", DESCRIPTION);
1759+
});
1760+
});

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

Lines changed: 131 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import "../../dist/Assets.js";
22
import { setLanguage } from "@ui5/webcomponents-base/dist/config/Language.js";
33
import DateRangePicker from "../../src/DateRangePicker.js";
4+
import Label from "../../src/Label.js";
45

56
type DateTimePickerTemplateOptions = Partial<{
67
formatPattern: string;
@@ -487,72 +488,6 @@ describe("DateRangePicker general interaction", () => {
487488
});
488489
});
489490

490-
it("Picker popover should have accessible name", () => {
491-
cy.mount(<DateRangePicker></DateRangePicker>);
492-
493-
cy.get<DateRangePicker>("[ui5-daterange-picker]")
494-
.as("dateRangePicker")
495-
.shadow()
496-
.find("[ui5-datetime-input]")
497-
.realClick()
498-
.should("be.focused");
499-
500-
cy.realPress("F4");
501-
502-
cy.get<DateRangePicker>("@dateRangePicker")
503-
.ui5DateRangePickerExpectToBeOpen()
504-
505-
cy.get("@dateRangePicker")
506-
.shadow()
507-
.find("[ui5-responsive-popover]")
508-
.should("have.attr", "accessible-name", "Choose Date Range");
509-
});
510-
511-
it("Selected days: accessibility semantics", () => {
512-
cy.wrap({ setLanguage })
513-
.then(api => {
514-
return api.setLanguage("en");
515-
})
516-
517-
cy.mount(<DateRangePickerTemplate formatPattern="dd/MM/yyyy" />);
518-
519-
cy.get<DateRangePicker>("[ui5-daterange-picker]")
520-
.as("dateRangePicker")
521-
.shadow()
522-
.find("[ui5-datetime-input]")
523-
.realClick()
524-
.should("be.focused");
525-
526-
cy.realType("09/06/2024 - 15/06/2024");
527-
528-
cy.realPress("Enter")
529-
530-
cy.get<DateRangePicker>("@dateRangePicker")
531-
.should("have.value", "09/06/2024 - 15/06/2024");
532-
533-
cy.realPress("F4");
534-
535-
cy.get<DateRangePicker>("@dateRangePicker")
536-
.ui5DateRangePickerExpectToBeOpen()
537-
538-
cy.get<DateRangePicker>("@dateRangePicker")
539-
.shadow()
540-
.find("[ui5-calendar]")
541-
.shadow()
542-
.find("[ui5-daypicker]")
543-
.shadow()
544-
.find(".ui5-dp-root .ui5-dp-content div > .ui5-dp-item")
545-
.should(days => {
546-
const startSelectionDay = days[14];
547-
const dayInBetween = days[15];
548-
const endSelectionDay = days[20];
549-
550-
expect(startSelectionDay).to.have.attr("aria-selected", "true");
551-
expect(dayInBetween).to.have.attr("aria-selected", "true");
552-
expect(endSelectionDay).to.have.attr("aria-selected", "true");
553-
});
554-
});
555-
556491
it("Min and max dates are set without format-pattern by using ISO (yyyy-MM-dd) format", () => {
557492
cy.wrap({ setLanguage })
558493
.then(api => {
@@ -721,3 +656,133 @@ describe("DateRangePicker general interaction", () => {
721656
});
722657
});
723658
});
659+
660+
describe("Accessibility", () => {
661+
it("Picker popover accessible name", () => {
662+
const LABEL = "Deadline";
663+
cy.mount(<DateRangePicker accessible-name={LABEL}></DateRangePicker>);
664+
665+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
666+
.as("dateRangePicker")
667+
.shadow()
668+
.find("[ui5-datetime-input]")
669+
.realClick()
670+
.should("be.focused");
671+
672+
cy.realPress("F4");
673+
674+
cy.get<DateRangePicker>("@dateRangePicker")
675+
.ui5DateRangePickerExpectToBeOpen()
676+
677+
cy.get("@dateRangePicker")
678+
.shadow()
679+
.find("[ui5-responsive-popover]")
680+
.should("have.attr", "accessible-name", `Choose Date Range for ${LABEL}`);
681+
});
682+
683+
it("Picker popover accessible name with external label", () => {
684+
const LABEL = "Deadline";
685+
cy.mount(<>
686+
<Label for="dateRangePicker">{LABEL}</Label>
687+
<DateRangePicker id="dateRangePicker"></DateRangePicker>
688+
</>);
689+
690+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
691+
.as("dateRangePicker")
692+
.shadow()
693+
.find("[ui5-datetime-input]")
694+
.realClick()
695+
.should("be.focused");
696+
697+
cy.realPress("F4");
698+
699+
cy.get<DateRangePicker>("@dateRangePicker")
700+
.ui5DateRangePickerExpectToBeOpen()
701+
702+
cy.get("@dateRangePicker")
703+
.shadow()
704+
.find("[ui5-responsive-popover]")
705+
.should("have.attr", "accessible-name", `Choose Date Range for ${LABEL}`);
706+
});
707+
708+
it("accessibleDescription property", () => {
709+
const DESCRIPTION = "Some description";
710+
cy.mount(<DateRangePicker accessibleDescription={DESCRIPTION}></DateRangePicker>);
711+
712+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
713+
.ui5DatePickerGetInnerInput()
714+
.should("have.attr", "aria-describedby", "descr");
715+
716+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
717+
.shadow()
718+
.find("[ui5-datetime-input]")
719+
.shadow()
720+
.find("span#descr")
721+
.should("have.text", DESCRIPTION);
722+
});
723+
724+
it("accessibleDescriptionRef property", () => {
725+
const DESCRIPTION = "External description";
726+
cy.mount(
727+
<>
728+
<p id="descr">{DESCRIPTION}</p>
729+
<DateRangePicker accessibleDescriptionRef="descr"></DateRangePicker>
730+
</>
731+
);
732+
733+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
734+
.shadow()
735+
.find("[ui5-datetime-input]")
736+
.shadow()
737+
.find("input")
738+
.should("have.attr", "aria-describedby")
739+
.and("contain", "descr");
740+
741+
cy.get("#descr").should("have.text", DESCRIPTION);
742+
});
743+
744+
it("Selected days: accessibility semantics", () => {
745+
cy.wrap({ setLanguage })
746+
.then(api => {
747+
return api.setLanguage("en");
748+
})
749+
750+
cy.mount(<DateRangePickerTemplate formatPattern="dd/MM/yyyy" />);
751+
752+
cy.get<DateRangePicker>("[ui5-daterange-picker]")
753+
.as("dateRangePicker")
754+
.shadow()
755+
.find("[ui5-datetime-input]")
756+
.realClick()
757+
.should("be.focused");
758+
759+
cy.realType("09/06/2024 - 15/06/2024");
760+
761+
cy.realPress("Enter")
762+
763+
cy.get<DateRangePicker>("@dateRangePicker")
764+
.should("have.value", "09/06/2024 - 15/06/2024");
765+
766+
cy.realPress("F4");
767+
768+
cy.get<DateRangePicker>("@dateRangePicker")
769+
.ui5DateRangePickerExpectToBeOpen()
770+
771+
cy.get<DateRangePicker>("@dateRangePicker")
772+
.shadow()
773+
.find("[ui5-calendar]")
774+
.shadow()
775+
.find("[ui5-daypicker]")
776+
.shadow()
777+
.find(".ui5-dp-root .ui5-dp-content div > .ui5-dp-item")
778+
.should(days => {
779+
const startSelectionDay = days[14];
780+
const dayInBetween = days[15];
781+
const endSelectionDay = days[20];
782+
783+
expect(startSelectionDay).to.have.attr("aria-selected", "true");
784+
expect(dayInBetween).to.have.attr("aria-selected", "true");
785+
expect(endSelectionDay).to.have.attr("aria-selected", "true");
786+
});
787+
});
788+
});

0 commit comments

Comments
 (0)