diff --git a/packages/main/cypress/specs/FileUploader.cy.tsx b/packages/main/cypress/specs/FileUploader.cy.tsx index b2537c4decec..280b0611b7d0 100644 --- a/packages/main/cypress/specs/FileUploader.cy.tsx +++ b/packages/main/cypress/specs/FileUploader.cy.tsx @@ -478,6 +478,31 @@ describe("Interaction", () => { }); describe("Accessibility", () => { + it("value state hidden text contains type label and default message", () => { + cy.mount( + + ); + + cy.get("#uploader") + .shadow() + .find("#valueStateDesc") + .should("have.text", "Value State Error Invalid entry"); + }); + + it("value state hidden text contains type label and custom message", () => { + cy.mount( + +
Custom error message.
+
+ ); + + cy.get("#uploader") + .shadow() + .find("#valueStateDesc") + .should("include.text", "Value State Error") + .and("include.text", "Custom error message."); + }); + it("A11y attributes", () => { cy.mount( <> diff --git a/packages/main/src/FileUploader.ts b/packages/main/src/FileUploader.ts index 1c55c49063d3..9f8f14218861 100644 --- a/packages/main/src/FileUploader.ts +++ b/packages/main/src/FileUploader.ts @@ -35,6 +35,10 @@ import { VALUE_STATE_INFORMATION, VALUE_STATE_ERROR, VALUE_STATE_WARNING, + VALUE_STATE_TYPE_SUCCESS, + VALUE_STATE_TYPE_INFORMATION, + VALUE_STATE_TYPE_ERROR, + VALUE_STATE_TYPE_WARNING, FILEUPLOADER_DEFAULT_PLACEHOLDER, FILEUPLOADER_DEFAULT_MULTIPLE_PLACEHOLDER, FILEUPLOADER_ROLE_DESCRIPTION, @@ -55,6 +59,8 @@ import ValueStateMessageCss from "./generated/themes/ValueStateMessage.css.js"; const convertBytesToMegabytes = (bytes: number) => (bytes / 1024) / 1024; +type MappedValueState = Exclude<`${ValueState}`, "None">; + type FileData = { fileName: string, fileSize: number, @@ -624,9 +630,35 @@ class FileUploader extends UI5Element implements IFormInputElement { "ariaHasPopup": "dialog", "ariaLabel": getAllAccessibleNameRefTexts(this) || getEffectiveAriaLabelText(this) || getAssociatedLabelForTexts(this) || undefined, "ariaDescription": getAllAccessibleDescriptionRefTexts(this) || getEffectiveAriaDescriptionText(this) || undefined, + "ariaDescribedBy": this.hasValueState ? "valueStateDesc" : undefined, + }; + } + + get valueStateTypeMappings(): Record { + return { + "Positive": FileUploader.i18nBundle.getText(VALUE_STATE_TYPE_SUCCESS), + "Information": FileUploader.i18nBundle.getText(VALUE_STATE_TYPE_INFORMATION), + "Negative": FileUploader.i18nBundle.getText(VALUE_STATE_TYPE_ERROR), + "Critical": FileUploader.i18nBundle.getText(VALUE_STATE_TYPE_WARNING), }; } + get ariaValueStateHiddenText(): string | undefined { + if (!this.hasValueState) { + return undefined; + } + + const valueStateType = this.valueStateTypeMappings[this.valueState as MappedValueState]; + + if (this.shouldDisplayDefaultValueStateMessage) { + return this.valueStateText ? `${valueStateType} ${this.valueStateText}` : valueStateType; + } + + return this.valueStateMessage.length + ? `${valueStateType} ${this.valueStateMessage.map(el => el.textContent).join(" ")}` + : valueStateType; + } + get inputTitle(): string { return FileUploader.i18nBundle.getText(FILEUPLOADER_INPUT_TOOLTIP); } @@ -645,7 +677,7 @@ class FileUploader extends UI5Element implements IFormInputElement { return this.placeholder ?? (this.multiple ? multiplePlaceholder : singlePlaceholder); } - get valueStateTextMappings(): Record { + get valueStateTextMappings(): Record { return { "Positive": FileUploader.i18nBundle.getText(VALUE_STATE_SUCCESS), "Information": FileUploader.i18nBundle.getText(VALUE_STATE_INFORMATION), @@ -654,8 +686,8 @@ class FileUploader extends UI5Element implements IFormInputElement { }; } - get valueStateText(): string { - return this.valueStateTextMappings[this.valueState]; + get valueStateText(): string | undefined { + return this.valueStateTextMappings[this.valueState as MappedValueState]; } get hasValueState(): boolean { diff --git a/packages/main/src/FileUploaderTemplate.tsx b/packages/main/src/FileUploaderTemplate.tsx index bbceeaa01d3d..a54954d0ca88 100644 --- a/packages/main/src/FileUploaderTemplate.tsx +++ b/packages/main/src/FileUploaderTemplate.tsx @@ -35,10 +35,14 @@ export default function FileUploaderTemplate(this: FileUploader) { aria-description={this.accInfo.ariaDescription} aria-required={this.accInfo.ariaRequired} aria-invalid={this.accInfo.ariaInvalid} + aria-describedby={this.accInfo.ariaDescribedBy} onClick={this._onNativeInputClick} onChange={this._onChange} data-sap-focus-ref /> + {this.hasValueState && + {this.ariaValueStateHiddenText} + } {this.hideInput ? (