Skip to content
66 changes: 65 additions & 1 deletion packages/main/cypress/specs/Icon.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,68 @@ describe("Icon general interaction", () => {
.find(".ui5-icon-root")
.should("have.attr", "role", "img");
});
});

it("Tests accessibilityInfo getter", () => {
const interactiveMode = "Interactive";
const imageMode = "Image";
const decorativeMode = "Decorative";
const accessibleName = "Test Icon";

// Test with Interactive mode
cy.mount(
<Icon
name="add-equipment"
mode={interactiveMode}
accessibleName={accessibleName}
/>
);

cy.get("[ui5-icon][mode='Interactive']").then($icon => {
const icon = $icon[0] as any;
const accessibilityInfo = icon.accessibilityInfo;

// For Interactive mode, accessibilityInfo should have role, type and description
expect(accessibilityInfo).to.not.be.undefined;
expect(accessibilityInfo.role).to.equal("button");
expect(accessibilityInfo.type).to.equal("Button");
expect(accessibilityInfo.description).to.equal(accessibleName);
});

// Test with Decorative mode
cy.mount(
<Icon
name="add-equipment"
mode={decorativeMode}
accessibleName={accessibleName}
/>
);

cy.get("[ui5-icon][mode='Decorative']").then($icon => {
const icon = $icon[0] as any;
const accessibilityInfo = icon.accessibilityInfo;

// For Decorative mode, accessibilityInfo should return an empty object
expect(accessibilityInfo).to.deep.equal({});
});

// Test with Image mode
cy.mount(
<Icon
name="add-equipment"
mode={imageMode}
accessibleName={accessibleName}
/>
);

cy.get("[ui5-icon][mode='Image']").then($icon => {
const icon = $icon[0] as any;
const accessibilityInfo = icon.accessibilityInfo;

// For Image mode, accessibilityInfo should have role, type and description
expect(accessibilityInfo).to.not.be.undefined;
expect(accessibilityInfo.role).to.equal("img");
expect(accessibilityInfo.type).to.equal("Image");
expect(accessibilityInfo.description).to.equal(accessibleName);
});
});
});
32 changes: 32 additions & 0 deletions packages/main/src/Icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import jsxRender from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import type { AriaRole } from "@ui5/webcomponents-base/dist/types.js";
import type { IconData, UnsafeIconData } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js";
import { getIconData, getIconDataSync } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js";
import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js";
import executeTemplate from "@ui5/webcomponents-base/dist/renderer/executeTemplate.js";
import IconTemplate from "./IconTemplate.js";
import type IconDesign from "./types/IconDesign.js";
import IconMode from "./types/IconMode.js";

import { ICON_ARIA_TYPE_IMAGE, ICON_ARIA_TYPE_INTERACTIVE } from "./generated/i18n/i18n-defaults.js";

// Styles
import iconCss from "./generated/themes/Icon.css.js";

Expand Down Expand Up @@ -117,6 +122,10 @@ class Icon extends UI5Element implements IIcon {
eventDetails!: {
click: void
}

@i18n("@ui5/webcomponents")
static i18nBundle: I18nBundle;

/**
* Defines the component semantic design.
* @default "Default"
Expand Down Expand Up @@ -327,6 +336,29 @@ class Icon extends UI5Element implements IIcon {
get hasIconTooltip() {
return this.showTooltip && this.effectiveAccessibleName;
}

_getAriaTypeDescription() {
switch (this.mode) {
case IconMode.Interactive:
return Icon.i18nBundle.getText(ICON_ARIA_TYPE_INTERACTIVE);
case IconMode.Image:
return Icon.i18nBundle.getText(ICON_ARIA_TYPE_IMAGE);
default:
return "";
}
}

get accessibilityInfo() {
if (this.mode === IconMode.Decorative) {
return {};
}

return {
role: this.effectiveAccessibleRole as AriaRole,
type: this._getAriaTypeDescription(),
description: this.effectiveAccessibleName,
};
}
}

Icon.define();
Expand Down
6 changes: 6 additions & 0 deletions packages/main/src/i18n/messagebundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,9 @@ DYNAMIC_DATE_RANGE_NEXT_COMBINED_TEXT=Next X {0} (included)

#XFLD: Suffix text for included date range options.
DYNAMIC_DATE_RANGE_INCLUDED_TEXT=(included)

#XACT: ARIA announcement for icon type image
ICON_ARIA_TYPE_IMAGE=Image

#XACT: ARIA announcement for icon type interactive
ICON_ARIA_TYPE_INTERACTIVE=Button
Loading