From 26dee35ceb6f07c8e760768a493c2d2377ff17f5 Mon Sep 17 00:00:00 2001 From: Boyan Rakilovski Date: Tue, 11 Jun 2024 17:32:36 +0300 Subject: [PATCH] fix(ui5-date-picker): provide accessible name to the popover (#8693) Fixes: #8598 --- packages/main/src/DatePicker.ts | 5 +++++ packages/main/src/DatePickerPopover.hbs | 1 + packages/main/src/DateRangePicker.ts | 15 ++++++++++++++- packages/main/src/DateTimePicker.ts | 11 +++++++++++ packages/main/src/TimePicker.ts | 5 +++++ packages/main/src/TimePickerPopover.hbs | 1 + packages/main/src/i18n/messagebundle.properties | 12 ++++++++++++ packages/main/test/specs/DatePicker.spec.js | 11 +++++++++++ packages/main/test/specs/DateRangePicker.spec.js | 12 ++++++++++++ packages/main/test/specs/DateTimePicker.spec.js | 10 ++++++++++ packages/main/test/specs/TimePicker.spec.js | 12 ++++++++++++ 11 files changed, 94 insertions(+), 1 deletion(-) diff --git a/packages/main/src/DatePicker.ts b/packages/main/src/DatePicker.ts index 3e637d7440c6..b2ea4039f5c9 100644 --- a/packages/main/src/DatePicker.ts +++ b/packages/main/src/DatePicker.ts @@ -38,6 +38,7 @@ import { DATEPICKER_DATE_DESCRIPTION, INPUT_SUGGESTIONS_TITLE, FORM_TEXTFIELD_REQUIRED, + DATEPICKER_POPOVER_ACCESSIBLE_NAME, } from "./generated/i18n/i18n-defaults.js"; import DateComponentBase from "./DateComponentBase.js"; import Icon from "./Icon.js"; @@ -704,6 +705,10 @@ class DatePicker extends DateComponentBase implements IFormInputElement { return DatePicker.i18nBundle.getText(DATEPICKER_DATE_DESCRIPTION); } + get pickerAccessibleName() { + return DatePicker.i18nBundle.getText(DATEPICKER_POPOVER_ACCESSIBLE_NAME); + } + /** * Defines whether the dialog on mobile should have header * @private diff --git a/packages/main/src/DatePickerPopover.hbs b/packages/main/src/DatePickerPopover.hbs index 32cc87a08603..a295d9661b19 100644 --- a/packages/main/src/DatePickerPopover.hbs +++ b/packages/main/src/DatePickerPopover.hbs @@ -5,6 +5,7 @@ allow-target-overlap placement="Bottom" horizontal-align="Start" + accessible-name="{{pickerAccessibleName}}" hide-arrow ?_hide-header={{_shouldHideHeader}} @keydown="{{_onkeydown}}" diff --git a/packages/main/src/DateRangePicker.ts b/packages/main/src/DateRangePicker.ts index b84b675b6b68..c16aeebf2118 100644 --- a/packages/main/src/DateRangePicker.ts +++ b/packages/main/src/DateRangePicker.ts @@ -5,7 +5,10 @@ import type { IFormInputElement } from "@ui5/webcomponents-base/dist/features/In import CalendarDate from "@ui5/webcomponents-localization/dist/dates/CalendarDate.js"; import modifyDateBy from "@ui5/webcomponents-localization/dist/dates/modifyDateBy.js"; import getTodayUTCTimestamp from "@ui5/webcomponents-localization/dist/dates/getTodayUTCTimestamp.js"; -import { DATERANGE_DESCRIPTION } from "./generated/i18n/i18n-defaults.js"; +import { + DATERANGE_DESCRIPTION, + DATERANGEPICKER_POPOVER_ACCESSIBLE_NAME, +} from "./generated/i18n/i18n-defaults.js"; import DateRangePickerTemplate from "./generated/templates/DateRangePickerTemplate.lit.js"; // Styles @@ -191,10 +194,20 @@ class DateRangePicker extends DatePicker implements IFormInputElement { return this.placeholder !== undefined ? this.placeholder : `${this._displayFormat} ${this._effectiveDelimiter} ${this._displayFormat}`; } + /** + * @override + */ get dateAriaDescription() { return DateRangePicker.i18nBundle.getText(DATERANGE_DESCRIPTION); } + /** + * @override + */ + get pickerAccessibleName() { + return DateRangePicker.i18nBundle.getText(DATERANGEPICKER_POPOVER_ACCESSIBLE_NAME); + } + /** * @override */ diff --git a/packages/main/src/DateTimePicker.ts b/packages/main/src/DateTimePicker.ts index 9803b65b9489..cf5cb2fe1441 100644 --- a/packages/main/src/DateTimePicker.ts +++ b/packages/main/src/DateTimePicker.ts @@ -31,6 +31,7 @@ import { DATETIME_DESCRIPTION, DATETIME_PICKER_DATE_BUTTON, DATETIME_PICKER_TIME_BUTTON, + DATETIMEPICKER_POPOVER_ACCESSIBLE_NAME, } from "./generated/i18n/i18n-defaults.js"; // Template @@ -276,10 +277,20 @@ class DateTimePicker extends DatePicker implements IFormInputElement { return super.phone || this._phoneMode; } + /** + * @override + */ get dateAriaDescription() { return DateTimePicker.i18nBundle.getText(DATETIME_DESCRIPTION); } + /** + * @override + */ + get pickerAccessibleName() { + return DateTimePicker.i18nBundle.getText(DATETIMEPICKER_POPOVER_ACCESSIBLE_NAME); + } + /** * Defines whether the dialog on mobile should have header * @private diff --git a/packages/main/src/TimePicker.ts b/packages/main/src/TimePicker.ts index 1d5d7088ae38..4a072b615f64 100644 --- a/packages/main/src/TimePicker.ts +++ b/packages/main/src/TimePicker.ts @@ -43,6 +43,7 @@ import { TIMEPICKER_SUBMIT_BUTTON, TIMEPICKER_CANCEL_BUTTON, TIMEPICKER_INPUT_DESCRIPTION, + TIMEPICKER_POPOVER_ACCESSIBLE_NAME, } from "./generated/i18n/i18n-defaults.js"; // Styles @@ -326,6 +327,10 @@ class TimePicker extends UI5Element implements IFormInputElement { return TimePicker.i18nBundle.getText(TIMEPICKER_INPUT_DESCRIPTION); } + get pickerAccessibleName() { + return TimePicker.i18nBundle.getText(TIMEPICKER_POPOVER_ACCESSIBLE_NAME); + } + get accInfo() { return { "ariaRoledescription": this.dateAriaDescription, diff --git a/packages/main/src/TimePickerPopover.hbs b/packages/main/src/TimePickerPopover.hbs index bcdb544355f0..9349db992885 100644 --- a/packages/main/src/TimePickerPopover.hbs +++ b/packages/main/src/TimePickerPopover.hbs @@ -8,6 +8,7 @@ allow-target-overlap _hide-header hide-arrow + accessible-name="{{pickerAccessibleName}}" @ui5-close="{{onResponsivePopoverAfterClose}}" @ui5-open="{{onResponsivePopoverAfterOpen}}" @wheel="{{_handleWheel}}" diff --git a/packages/main/src/i18n/messagebundle.properties b/packages/main/src/i18n/messagebundle.properties index 77fd4aa86409..306868d6d949 100644 --- a/packages/main/src/i18n/messagebundle.properties +++ b/packages/main/src/i18n/messagebundle.properties @@ -154,6 +154,15 @@ DATETIME_DESCRIPTION=Date Time Input #XACT: Aria information for the Date Range Picker DATERANGE_DESCRIPTION=Date Range Input +#XACT: Aria information for the Date Picker popover +DATEPICKER_POPOVER_ACCESSIBLE_NAME=Choose Date + +#XACT: Aria information for the Date Time Picker popover +DATETIMEPICKER_POPOVER_ACCESSIBLE_NAME=Choose Date and Time + +#XACT: Aria information for the Date Range Picker popover +DATERANGEPICKER_POPOVER_ACCESSIBLE_NAME=Choose Date Range + DELETE=Delete FILEUPLOAD_BROWSE=Browse... @@ -373,6 +382,9 @@ TIMEPICKER_CANCEL_BUTTON=Cancel #XACT: Aria information for the Time Picker TIMEPICKER_INPUT_DESCRIPTION=Time Input +#XACT: Aria information for the Time Picker popover +TIMEPICKER_POPOVER_ACCESSIBLE_NAME=Choose Time + #XACT: Aria information for the Time Picker Clock Dial TIMEPICKER_CLOCK_DIAL_LABEL=Clock Dial diff --git a/packages/main/test/specs/DatePicker.spec.js b/packages/main/test/specs/DatePicker.spec.js index 34c5c81e9d19..b8ad37f3a8c5 100644 --- a/packages/main/test/specs/DatePicker.spec.js +++ b/packages/main/test/specs/DatePicker.spec.js @@ -1393,4 +1393,15 @@ describe("Date Picker Tests", () => { assert.ok(await datepicker.isPickerOpen(), "Datepicker is open"); assert.equal(currentPicker, "day", "calendar is opened on days"); }); + + it("picker popover should have accessible name", async () => { + datepicker.id = "#dp"; + await datepicker.openPicker(); + + const popover = await datepicker.getPopover(); + + assert.strictEqual(await popover.getAttribute("accessible-name"), "Choose Date", "Picker popover has an accessible name"); + + await datepicker.closePicker(); + }); }); diff --git a/packages/main/test/specs/DateRangePicker.spec.js b/packages/main/test/specs/DateRangePicker.spec.js index 51e56c3c51b0..f38165366a3c 100644 --- a/packages/main/test/specs/DateRangePicker.spec.js +++ b/packages/main/test/specs/DateRangePicker.spec.js @@ -261,4 +261,16 @@ describe("DateRangePicker general interaction", () => { assert.strictEqual(await dateRangePickerInput.getProperty("valueState"), "Negative", "Min and max dates are set correctly"); }); + + it("picker popover should have accessible name", async () => { + const daterangepicker = await browser.$("#daterange-picker3"); + await daterangepicker.click(); + await browser.keys("F4"); + + const popover = await daterangepicker.shadow$("ui5-responsive-popover"); + + assert.strictEqual(await popover.getAttribute("accessible-name"), "Choose Date Range", "Picker popover has an accessible name"); + + await browser.keys("Escape"); + }); }); diff --git a/packages/main/test/specs/DateTimePicker.spec.js b/packages/main/test/specs/DateTimePicker.spec.js index 825ca3b3ba47..5e403f00395f 100644 --- a/packages/main/test/specs/DateTimePicker.spec.js +++ b/packages/main/test/specs/DateTimePicker.spec.js @@ -289,5 +289,15 @@ describe("DateTimePicker general interaction", () => { assert.strictEqual(await nextButton.hasClass("ui5-calheader-arrowbtn-disabled"), true, "The next button is disabled."); }); + it("picker popover should have accessible name", async () => { + await openPickerById("dt1"); + + const popover = await getPicker("dt1"); + + assert.strictEqual(await popover.getAttribute("accessible-name"), "Choose Date and Time", "Picker popover has an accessible name"); + + await closePickerById("dt1"); + }); + // TO DO: Create new testing page test secondary calendar type behaviour. }); diff --git a/packages/main/test/specs/TimePicker.spec.js b/packages/main/test/specs/TimePicker.spec.js index 341cdfe5bea2..c3356bae5519 100644 --- a/packages/main/test/specs/TimePicker.spec.js +++ b/packages/main/test/specs/TimePicker.spec.js @@ -233,4 +233,16 @@ describe("TimePicker general interaction", () => { assert.strictEqual(await timepickerPopover.getProperty("open"), true, "The popover is opened"); }) + + it("picker popover should have accessible name", async () => { + const timepicker = await browser.$("#timepicker"); + await timepicker.click(); + await browser.keys("F4"); + + const popover = await timepicker.shadow$("ui5-responsive-popover"); + + assert.strictEqual(await popover.getAttribute("accessible-name"), "Choose Time", "Picker popover has an accessible name"); + + await browser.keys("Escape"); + }); });