Skip to content

Commit adc9a49

Browse files
committed
Merge branch 'main' into ai-textarea-adjustments
2 parents 00f36ad + dda0591 commit adc9a49

File tree

22 files changed

+517
-16
lines changed

22 files changed

+517
-16
lines changed

.github/workflows/release.yaml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ on:
1313
- 'stable'
1414
- 'hotfix'
1515
- 'experimental'
16+
- 'v1'
1617
default: 'rc'
1718
new_version:
18-
description: 'version (stable and hotfix only)'
19+
description: 'version (relevant for stable, hotfix, and v1)' # Updated description
1920
required: false
2021
default: ''
2122
type: string
@@ -268,3 +269,46 @@ jobs:
268269
- name: Publish
269270
run: |
270271
yarn lerna publish from-git --yes --dist-tag experimental --pre-dist-tag experimental
272+
273+
# ✅ Job 5: V1 Release Flow
274+
v1-release:
275+
if: ${{ github.event.inputs.release_type == 'v1' && github.event.inputs.new_version != '' }}
276+
permissions:
277+
contents: write
278+
id-token: write
279+
runs-on: ubuntu-latest
280+
steps:
281+
- name: Checkout
282+
uses: actions/checkout@v4
283+
with:
284+
token: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }}
285+
fetch-depth: 0
286+
287+
- name: Setup Node
288+
uses: actions/setup-node@v4.1.0
289+
with:
290+
node-version: 22
291+
cache: 'yarn'
292+
293+
- name: Install Dependencies
294+
run: yarn --immutable
295+
296+
- name: Build
297+
run: yarn ci:releasebuild
298+
299+
- name: Version Bump
300+
env:
301+
GH_TOKEN: ${{ secrets.UI5_WEBCOMP_BOT_GH_TOKEN }}
302+
run: |
303+
git config user.name "${{ secrets.UI5_WEBCOMP_BOT_NAME }}"
304+
git config user.email "${{ secrets.UI5_WEBCOMP_BOT_EMAIL }}"
305+
yarn lerna version ${{ github.event.inputs.new_version || '' }} \
306+
--conventional-graduate \
307+
--force-conventional-graduate \
308+
--yes \
309+
--exact \
310+
--create-release github
311+
312+
- name: Publish
313+
run: |
314+
yarn lerna publish from-git --yes --dist-tag "v1"

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,38 @@ describe("Accessibility", () => {
17461746
cy.get("[ui5-search]")
17471747
.should("be.focused");
17481748
});
1749+
1750+
it("should have aria-autocomplete='both' on the input element", () => {
1751+
cy.mount(
1752+
<Search>
1753+
<SearchItem text="Item 1" icon={history} />
1754+
</Search>
1755+
);
1756+
1757+
cy.get("[ui5-search]")
1758+
.shadow()
1759+
.find("input")
1760+
.should("have.attr", "aria-autocomplete", "both");
1761+
});
1762+
1763+
it("should have aria-controls pointing to responsive popover", () => {
1764+
cy.mount(
1765+
<Search>
1766+
<SearchItem text="Item 1" icon={history} />
1767+
</Search>
1768+
);
1769+
1770+
cy.get("[ui5-search]")
1771+
.shadow()
1772+
.find("input")
1773+
.invoke("attr", "aria-controls")
1774+
.then((ariaControlsId) => {
1775+
cy.get("[ui5-search]")
1776+
.shadow()
1777+
.find("[ui5-responsive-popover]")
1778+
.should("have.attr", "id", ariaControlsId);
1779+
});
1780+
});
17491781
});
17501782

17511783
describe("Lazy loaded items and autocomplete", () => {

packages/fiori/src/SearchFieldTemplate.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ export default function SearchFieldTemplate(this: SearchField, options?: SearchF
6464
role="searchbox"
6565
aria-description={this.accessibleDescription}
6666
aria-label={this.accessibleName || this._translations.searchFieldAriaLabel}
67+
aria-autocomplete="both"
68+
aria-controls="ui5-search-list"
6769
value={this.value}
6870
placeholder={this.placeholder}
6971
data-sap-focus-ref

packages/fiori/src/SearchItem.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import SearchItemCss from "./generated/themes/SearchItem.css.js";
77
import generateHighlightedMarkup from "@ui5/webcomponents-base/dist/util/generateHighlightedMarkup.js";
88
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
99
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
10-
import { SEARCH_ITEM_DELETE_BUTTON } from "./generated/i18n/i18n-defaults.js";
10+
import {
11+
SEARCH_ITEM_DELETE_BUTTON_TOOLTIP,
12+
} from "./generated/i18n/i18n-defaults.js";
13+
1114
import getActiveElement from "@ui5/webcomponents-base/dist/util/getActiveElement.js";
1215
import { getFirstFocusableElement } from "@ui5/webcomponents-base/dist/util/FocusableElements.js";
1316
import { getTabbableElements } from "@ui5/webcomponents-base/dist/util/TabbableElements.js";
@@ -259,7 +262,7 @@ class SearchItem extends ListItemBase {
259262
}
260263

261264
get _deleteButtonTooltip() {
262-
return SearchItem.i18nBundle.getText(SEARCH_ITEM_DELETE_BUTTON);
265+
return SearchItem.i18nBundle.getText(SEARCH_ITEM_DELETE_BUTTON_TOOLTIP);
263266
}
264267

265268
get hasActions() {

packages/fiori/src/SearchPopoverTemplate.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type { JsxTemplate } from "@ui5/webcomponents-base/dist/index.js";
1717
export default function SearchPopoverTemplate(this: Search, headerTemplate?: JsxTemplate) {
1818
return (
1919
<ResponsivePopover
20+
id="ui5-search-list"
2021
hideArrow={true}
2122
preventFocusRestore={true}
2223
preventInitialFocus={!isPhone()}

packages/fiori/src/i18n/messagebundle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ SHELLBAR_IMAGE_BTN = User Menu
197197
#XACT: ARIA announcement for the search button
198198
SHELLBAR_SEARCH_BTN_OPEN = Open Search
199199

200-
#XACT: ARIA announcement for the search item delete button
201-
SEARCH_ITEM_DELETE_BUTTON=Remove Suggestion
200+
#XACT: ARIA announcement for the search item delete button tooltip
201+
SEARCH_ITEM_DELETE_BUTTON_TOOLTIP=Remove Suggestion
202202

203203
#XACT: ARIA announcement for the more button
204204
SHELLBAR_OVERFLOW = More

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

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,71 @@ describe("Accessibility", () => {
2121
.should("have.attr", "aria-label", expectedLabel);
2222
});
2323

24+
it("should return correct accessibilityInfo object when avatar is interactive", () => {
25+
const INITIALS = "JD";
26+
const hasPopup = "menu";
27+
const customLabel = "John Doe Avatar";
28+
29+
cy.mount(
30+
<Avatar
31+
id="interactive-info"
32+
initials={INITIALS}
33+
interactive
34+
accessibleName={customLabel}
35+
accessibilityAttributes={{hasPopup}}
36+
></Avatar>
37+
);
38+
39+
cy.get("#interactive-info").then($avatar => {
40+
const avatar = $avatar[0] as any;
41+
42+
// Check accessibilityInfo properties
43+
expect(avatar.accessibilityInfo).to.exist;
44+
expect(avatar.accessibilityInfo.role).to.equal("button");
45+
expect(avatar.accessibilityInfo.type).to.equal("Button");
46+
expect(avatar.accessibilityInfo.description).to.equal(customLabel);
47+
});
48+
});
49+
50+
it("should return correct accessibilityInfo object when avatar is not interactive", () => {
51+
cy.mount(
52+
<Avatar
53+
id="non-interactive-info"
54+
initials="JD"
55+
></Avatar>
56+
);
57+
58+
cy.get("#non-interactive-info").then($avatar => {
59+
const avatar = $avatar[0] as any;
60+
61+
// Check that accessibilityInfo is undefined
62+
expect(avatar.accessibilityInfo).to.exist;
63+
expect(avatar.accessibilityInfo.role).to.equal("img");
64+
expect(avatar.accessibilityInfo.type).to.equal("Image");
65+
expect(avatar.accessibilityInfo.description).to.equal("Avatar JD");
66+
});
67+
});
68+
69+
it("should use default label for accessibilityInfo description when no custom label is provided", () => {
70+
const INITIALS = "AB";
71+
72+
cy.mount(
73+
<Avatar
74+
id="default-label-info"
75+
initials={INITIALS}
76+
interactive
77+
></Avatar>
78+
);
79+
80+
cy.get("#default-label-info").then($avatar => {
81+
const avatar = $avatar[0] as any;
82+
83+
// Check that accessibilityInfo uses the default label format that includes initials
84+
expect(avatar.accessibilityInfo).to.exist;
85+
expect(avatar.accessibilityInfo.description).to.equal(`Avatar ${INITIALS}`);
86+
});
87+
});
88+
2489
it("checks if accessible-name is correctly passed to the icon", () => {
2590
const ACCESSIBLE_NAME = "Supplier Icon";
2691
const ICON_NAME = "supplier";
@@ -500,4 +565,4 @@ describe("Avatar Rendering and Interaction", () => {
500565
cy.get("@clickStub")
501566
.should("have.been.calledOnce");
502567
});
503-
});
568+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import CheckBox from "../../src/CheckBox.js";
2+
import Switch from "../../src/Switch.js";
3+
import Link from "../../src/Link.js";
4+
import Label from "../../src/Label.js";
5+
import Text from "../../src/Text.js";
6+
import RatingIndicator from "../../src/RatingIndicator.js";
7+
import StepInput from "../../src/StepInput.js";
8+
import Button from "../../src/Button.js";
9+
import ComboBox from "../../src/ComboBox.js";
10+
import ComboBoxItem from "../../src/ComboBoxItem.js";
11+
import SegmentedButtonItem from "../../src/SegmentedButtonItem.js";
12+
import SegmentedButton from "../../src/SegmentedButton.js";
13+
import Input from "../../src/Input.js";
14+
import DatePicker from "../../src/DatePicker.js";
15+
import RadioButton from "../../src/RadioButton.js";
16+
import RangeSlider from "../../src/RangeSlider.js";
17+
import Slider from "../../src/Slider.js";
18+
import Select from "../../src/Select.js";
19+
import Option from "../../src/Option.js";
20+
import FileUploader from "../../src/FileUploader.js";
21+
22+
describe("Vertical Alignment", () => {
23+
it("tests container height to detect and avoid vertical misalignment", () => {
24+
cy.mount(
25+
<>
26+
<div id="container">
27+
<Input value="value"></Input>
28+
<DatePicker value="today"></DatePicker>
29+
<SegmentedButton accessibleName="Geographic location">
30+
<SegmentedButtonItem>Map</SegmentedButtonItem>
31+
<SegmentedButtonItem selected>Satellite</SegmentedButtonItem>
32+
</SegmentedButton>
33+
<ComboBox value="Bulgaria">
34+
<ComboBoxItem text="Algeria" id="cbi"></ComboBoxItem>
35+
<ComboBoxItem text="Argentina"></ComboBoxItem>
36+
<ComboBoxItem text="Bosnia and Herzegovina"></ComboBoxItem>
37+
<ComboBoxItem text="Brazil"></ComboBoxItem>
38+
<ComboBoxItem text="Bulgaria"></ComboBoxItem>
39+
<ComboBoxItem text="Canada"></ComboBoxItem>
40+
<ComboBoxItem text="Chile"></ComboBoxItem>
41+
</ComboBox>
42+
<Select>
43+
<Option>Option 1</Option>
44+
<Option>Option 2</Option>
45+
<Option>Option 3</Option>
46+
</Select>
47+
</div>
48+
49+
<div id="container2">
50+
<CheckBox text="Check" checked></CheckBox>
51+
<Switch textOn="On" textOff="Off"></Switch>
52+
<RadioButton text="option c" checked></RadioButton>
53+
<Label>Lorem ipsum dolor sit</Label>
54+
<Text>Some text here</Text>
55+
<Button>Click Me</Button>
56+
<Link href="https://ui5webcomponents.github.io" target="_blank">Link</Link>
57+
<StepInput></StepInput>
58+
<FileUploader></FileUploader>
59+
</div>
60+
61+
<div id="container3">
62+
<RatingIndicator></RatingIndicator>
63+
</div>
64+
65+
<div id="container4">
66+
<RangeSlider id="range_slider1" style={{ width: "200px" }}></RangeSlider>
67+
<Slider id="slider1" style={{ width: "200px" }}></Slider>
68+
</div>
69+
</>
70+
);
71+
72+
cy.get("#container").should("have.css", "height", "44px");
73+
cy.get("#container2").should("have.css", "height", "44px");
74+
cy.get("#container3").should("have.css", "height", "48px");
75+
cy.get("#container4").should("have.css", "height", "53px");
76+
});
77+
});

packages/main/src/Avatar.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
55
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
66
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
77
import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
8-
import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js";
8+
import type { AccessibilityAttributes, AriaRole } from "@ui5/webcomponents-base/dist/types.js";
99
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
1010
import type { ITabbable } from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js";
1111
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
@@ -17,7 +17,11 @@ import type { IAvatarGroupItem } from "./AvatarGroup.js";
1717
// Template
1818
import AvatarTemplate from "./AvatarTemplate.js";
1919

20-
import { AVATAR_TOOLTIP } from "./generated/i18n/i18n-defaults.js";
20+
import {
21+
AVATAR_TOOLTIP,
22+
AVATAR_TYPE_BUTTON,
23+
AVATAR_TYPE_IMAGE,
24+
} from "./generated/i18n/i18n-defaults.js";
2125

2226
// Styles
2327
import AvatarCss from "./generated/themes/Avatar.css.js";
@@ -493,6 +497,15 @@ class Avatar extends UI5Element implements ITabbable, IAvatarGroupItem {
493497
}
494498
this._imageLoadError = true;
495499
}
500+
501+
get accessibilityInfo() {
502+
return {
503+
role: this._role as AriaRole,
504+
type: this.interactive ? Avatar.i18nBundle.getText(AVATAR_TYPE_BUTTON) : Avatar.i18nBundle.getText(AVATAR_TYPE_IMAGE),
505+
description: this.accessibleNameText,
506+
disabled: this.disabled,
507+
};
508+
}
496509
}
497510

498511
Avatar.define();

packages/main/src/i18n/messagebundle.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER=Interactive Card Header
1616
#XACT: ARIA announcement for the Avatar default tooltip
1717
AVATAR_TOOLTIP=Avatar
1818

19+
#XACT: ARIA type description for interactive Avatar (when the Avatar is a button)
20+
AVATAR_TYPE_BUTTON=Button
21+
22+
#XACT: ARIA type description for non-interactive Avatar (when the Avatar is an image)
23+
AVATAR_TYPE_IMAGE=Image
24+
1925
#XACT: ARIA announcement for the Avatar default tooltip
2026
AVATAR_GROUP_DISPLAYED_HIDDEN_LABEL={0} displayed, {1} hidden.
2127

0 commit comments

Comments
 (0)