@sapudex/web-components 2.29.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/cypress/specs/FilterMenu.cy.tsx +39 -1
  2. package/cypress/specs/List.cy.tsx +171 -0
  3. package/cypress/specs/ListItem.cy.tsx +22 -26
  4. package/cypress/specs/PromoTile.cy.tsx +10 -0
  5. package/cypress/specs/ReviewItem.cy.tsx +48 -14
  6. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +12 -12
  7. package/cypress/specs/SelectBox.cy.tsx +76 -0
  8. package/cypress/support/component-imports.instrumented.ts +4 -0
  9. package/cypress/support/component-imports.src.ts +5 -1
  10. package/dist/Avatar.d.ts +1 -0
  11. package/dist/Avatar.js +9 -0
  12. package/dist/Avatar.js.map +1 -1
  13. package/dist/Breadcrumbs.d.ts +0 -4
  14. package/dist/Breadcrumbs.js +7 -16
  15. package/dist/Breadcrumbs.js.map +1 -1
  16. package/dist/BreadcrumbsTemplate.js +1 -1
  17. package/dist/BreadcrumbsTemplate.js.map +1 -1
  18. package/dist/FilterMenu.d.ts +2 -0
  19. package/dist/FilterMenu.js +2 -0
  20. package/dist/FilterMenu.js.map +1 -1
  21. package/dist/ImageGridTickerTemplate.js +2 -1
  22. package/dist/ImageGridTickerTemplate.js.map +1 -1
  23. package/dist/List.d.ts +4 -2
  24. package/dist/List.js +45 -12
  25. package/dist/List.js.map +1 -1
  26. package/dist/ListGroupHeader.d.ts +4 -0
  27. package/dist/ListGroupHeader.js +26 -1
  28. package/dist/ListGroupHeader.js.map +1 -1
  29. package/dist/ListGroupHeaderBase.js +1 -1
  30. package/dist/ListGroupHeaderBase.js.map +1 -1
  31. package/dist/ListItem.js +1 -1
  32. package/dist/ListItem.js.map +1 -1
  33. package/dist/ListItemBase.d.ts +40 -3
  34. package/dist/ListItemBase.js +70 -9
  35. package/dist/ListItemBase.js.map +1 -1
  36. package/dist/MastheadCountrySelector.d.ts +3 -15
  37. package/dist/MastheadCountrySelector.js +28 -72
  38. package/dist/MastheadCountrySelector.js.map +1 -1
  39. package/dist/MastheadItem.d.ts +10 -2
  40. package/dist/MastheadItem.js +26 -15
  41. package/dist/MastheadItem.js.map +1 -1
  42. package/dist/MastheadMenu.d.ts +2 -2
  43. package/dist/MastheadMenu.js +9 -9
  44. package/dist/MastheadMenu.js.map +1 -1
  45. package/dist/MastheadMenuItem.d.ts +7 -0
  46. package/dist/MastheadMenuItem.js +3 -0
  47. package/dist/MastheadMenuItem.js.map +1 -1
  48. package/dist/MastheadMobileMenu.d.ts +2 -12
  49. package/dist/MastheadMobileMenu.js +31 -116
  50. package/dist/MastheadMobileMenu.js.map +1 -1
  51. package/dist/MastheadProfileMenu.js +1 -1
  52. package/dist/MastheadProfileMenu.js.map +1 -1
  53. package/dist/MastheadShell.d.ts +1 -6
  54. package/dist/MastheadShell.js +7 -44
  55. package/dist/MastheadShell.js.map +1 -1
  56. package/dist/Pagination.d.ts +14 -1
  57. package/dist/Pagination.js +40 -7
  58. package/dist/Pagination.js.map +1 -1
  59. package/dist/PromoTile.d.ts +8 -0
  60. package/dist/PromoTile.js +4 -0
  61. package/dist/PromoTile.js.map +1 -1
  62. package/dist/PromoTileTemplate.js +3 -1
  63. package/dist/PromoTileTemplate.js.map +1 -1
  64. package/dist/ReviewItem.d.ts +8 -7
  65. package/dist/ReviewItem.js +35 -36
  66. package/dist/ReviewItem.js.map +1 -1
  67. package/dist/ReviewItemTemplate.js +3 -1
  68. package/dist/ReviewItemTemplate.js.map +1 -1
  69. package/dist/SearchableListBase.d.ts +3 -0
  70. package/dist/SearchableListBase.js +37 -1
  71. package/dist/SearchableListBase.js.map +1 -1
  72. package/dist/SecondaryNavigationItem.js +7 -1
  73. package/dist/SecondaryNavigationItem.js.map +1 -1
  74. package/dist/SelectBase.js +28 -7
  75. package/dist/SelectBase.js.map +1 -1
  76. package/dist/SelectBox.js +0 -1
  77. package/dist/SelectBox.js.map +1 -1
  78. package/dist/TextField.d.ts +1 -1
  79. package/dist/TextField.js.map +1 -1
  80. package/dist/assets/{InputSuggestions-GMbG8xQ2.js → InputSuggestions-i2kFpCfC.js} +1 -1
  81. package/dist/assets/{ListItemStandardExpandableTextTemplate-IyZB_qzJ.js → ListItemStandardExpandableTextTemplate-C1ceDaxu.js} +1 -1
  82. package/dist/assets/{bundle.esm-Dg7j0PXg.js → bundle.esm-DQ3cxywT.js} +216 -216
  83. package/dist/assets/messagebundle_en-DWAgV5VH.js +1 -0
  84. package/dist/css/themes/BreadcrumbsPopover.css +1 -1
  85. package/dist/css/themes/Dropdown.css +1 -1
  86. package/dist/css/themes/FilterMenu.css +1 -1
  87. package/dist/css/themes/ImageGridTicker.css +1 -1
  88. package/dist/css/themes/Link.css +1 -1
  89. package/dist/css/themes/ListGroupHeader.css +1 -1
  90. package/dist/css/themes/ListItem.css +1 -1
  91. package/dist/css/themes/MastheadCountrySelector.css +1 -1
  92. package/dist/css/themes/MastheadItem.css +1 -1
  93. package/dist/css/themes/MastheadProfileMenu.css +1 -1
  94. package/dist/css/themes/MastheadShell.css +1 -1
  95. package/dist/css/themes/Modal.css +1 -1
  96. package/dist/css/themes/RatingIndicator.css +1 -1
  97. package/dist/css/themes/ReviewItem.css +1 -1
  98. package/dist/css/themes/SecondaryNavigation.css +1 -1
  99. package/dist/css/themes/SecondaryNavigationItem.css +1 -1
  100. package/dist/css/themes/SecondaryNavigationSubItem.css +1 -1
  101. package/dist/css/themes/Slider.css +1 -1
  102. package/dist/custom-elements-internal.json +986 -19
  103. package/dist/custom-elements.json +734 -13
  104. package/dist/generated/assets/i18n/messagebundle_en.json +1 -1
  105. package/dist/generated/i18n/i18n-defaults.d.ts +6 -1
  106. package/dist/generated/i18n/i18n-defaults.js +6 -1
  107. package/dist/generated/i18n/i18n-defaults.js.map +1 -1
  108. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js +17 -10
  109. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js.map +1 -1
  110. package/dist/generated/templates/ListItemTemplate.lit.js +32 -34
  111. package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
  112. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js +3 -3
  113. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js.map +1 -1
  114. package/dist/generated/templates/MastheadItemTemplate.lit.js +33 -25
  115. package/dist/generated/templates/MastheadItemTemplate.lit.js.map +1 -1
  116. package/dist/generated/templates/MastheadMenuItemTemplate.lit.js +1 -1
  117. package/dist/generated/templates/MastheadMenuItemTemplate.lit.js.map +1 -1
  118. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js +5 -5
  119. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js.map +1 -1
  120. package/dist/generated/templates/MastheadShellTemplate.lit.js +9 -10
  121. package/dist/generated/templates/MastheadShellTemplate.lit.js.map +1 -1
  122. package/dist/generated/templates/SearchableListBaseTemplate.lit.js +1 -1
  123. package/dist/generated/templates/SearchableListBaseTemplate.lit.js.map +1 -1
  124. package/dist/generated/themes/BreadcrumbsPopover.css.d.ts +1 -1
  125. package/dist/generated/themes/BreadcrumbsPopover.css.js +1 -1
  126. package/dist/generated/themes/BreadcrumbsPopover.css.js.map +1 -1
  127. package/dist/generated/themes/Dropdown.css.d.ts +1 -1
  128. package/dist/generated/themes/Dropdown.css.js +1 -1
  129. package/dist/generated/themes/Dropdown.css.js.map +1 -1
  130. package/dist/generated/themes/FilterMenu.css.d.ts +1 -1
  131. package/dist/generated/themes/FilterMenu.css.js +1 -1
  132. package/dist/generated/themes/FilterMenu.css.js.map +1 -1
  133. package/dist/generated/themes/ImageGridTicker.css.d.ts +1 -1
  134. package/dist/generated/themes/ImageGridTicker.css.js +1 -1
  135. package/dist/generated/themes/ImageGridTicker.css.js.map +1 -1
  136. package/dist/generated/themes/Link.css.d.ts +1 -1
  137. package/dist/generated/themes/Link.css.js +1 -1
  138. package/dist/generated/themes/Link.css.js.map +1 -1
  139. package/dist/generated/themes/ListGroupHeader.css.d.ts +1 -1
  140. package/dist/generated/themes/ListGroupHeader.css.js +1 -1
  141. package/dist/generated/themes/ListGroupHeader.css.js.map +1 -1
  142. package/dist/generated/themes/ListItem.css.d.ts +1 -1
  143. package/dist/generated/themes/ListItem.css.js +1 -1
  144. package/dist/generated/themes/ListItem.css.js.map +1 -1
  145. package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
  146. package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
  147. package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
  148. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  149. package/dist/generated/themes/MastheadItem.css.js +1 -1
  150. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  151. package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
  152. package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
  153. package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
  154. package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
  155. package/dist/generated/themes/MastheadShell.css.js +1 -1
  156. package/dist/generated/themes/MastheadShell.css.js.map +1 -1
  157. package/dist/generated/themes/Modal.css.d.ts +1 -1
  158. package/dist/generated/themes/Modal.css.js +1 -1
  159. package/dist/generated/themes/Modal.css.js.map +1 -1
  160. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  161. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  162. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  163. package/dist/generated/themes/ReviewItem.css.d.ts +1 -1
  164. package/dist/generated/themes/ReviewItem.css.js +1 -1
  165. package/dist/generated/themes/ReviewItem.css.js.map +1 -1
  166. package/dist/generated/themes/SecondaryNavigation.css.d.ts +1 -1
  167. package/dist/generated/themes/SecondaryNavigation.css.js +1 -1
  168. package/dist/generated/themes/SecondaryNavigation.css.js.map +1 -1
  169. package/dist/generated/themes/SecondaryNavigationItem.css.d.ts +1 -1
  170. package/dist/generated/themes/SecondaryNavigationItem.css.js +1 -1
  171. package/dist/generated/themes/SecondaryNavigationItem.css.js.map +1 -1
  172. package/dist/generated/themes/SecondaryNavigationSubItem.css.d.ts +1 -1
  173. package/dist/generated/themes/SecondaryNavigationSubItem.css.js +1 -1
  174. package/dist/generated/themes/SecondaryNavigationSubItem.css.js.map +1 -1
  175. package/dist/generated/themes/Slider.css.d.ts +1 -1
  176. package/dist/generated/themes/Slider.css.js +1 -1
  177. package/dist/generated/themes/Slider.css.js.map +1 -1
  178. package/dist/messagebundle.properties +9 -0
  179. package/dist/messagebundle_en.properties +3 -0
  180. package/dist/types/List.d.ts +0 -2
  181. package/dist/types/List.js +0 -2
  182. package/dist/types/List.js.map +1 -1
  183. package/dist/types/SearchableListBase.d.ts +1 -0
  184. package/dist/types/SearchableListBase.js.map +1 -1
  185. package/dist/vscode.html-custom-data.json +144 -85
  186. package/dist/web-types.json +303 -83
  187. package/package.json +2 -1
  188. package/src/Avatar.ts +9 -0
  189. package/src/Breadcrumbs.ts +8 -20
  190. package/src/BreadcrumbsTemplate.tsx +1 -1
  191. package/src/FilterMenu.ts +4 -0
  192. package/src/ImageGridTickerTemplate.tsx +3 -1
  193. package/src/List.ts +51 -14
  194. package/src/ListGroupHeader.hbs +128 -17
  195. package/src/ListGroupHeader.ts +31 -1
  196. package/src/ListGroupHeaderBase.ts +1 -1
  197. package/src/ListItem.hbs +15 -2
  198. package/src/ListItem.ts +1 -1
  199. package/src/ListItemBase.ts +105 -7
  200. package/src/MastheadCountrySelector.hbs +6 -3
  201. package/src/MastheadCountrySelector.ts +31 -85
  202. package/src/MastheadItem.hbs +31 -23
  203. package/src/MastheadItem.ts +28 -18
  204. package/src/MastheadMenu.ts +10 -9
  205. package/src/MastheadMenuItem.hbs +1 -0
  206. package/src/MastheadMenuItem.ts +9 -0
  207. package/src/MastheadMobileMenu.hbs +5 -6
  208. package/src/MastheadMobileMenu.ts +34 -130
  209. package/src/MastheadProfileMenu.ts +1 -1
  210. package/src/MastheadShell.hbs +9 -11
  211. package/src/MastheadShell.ts +8 -50
  212. package/src/Pagination.ts +52 -8
  213. package/src/PromoTile.ts +10 -0
  214. package/src/PromoTileTemplate.tsx +4 -1
  215. package/src/ReviewItem.ts +45 -35
  216. package/src/ReviewItemTemplate.tsx +16 -14
  217. package/src/SearchableListBase.hbs +3 -0
  218. package/src/SearchableListBase.ts +52 -1
  219. package/src/SecondaryNavigationItem.ts +1 -2
  220. package/src/SelectBase.ts +33 -7
  221. package/src/SelectBox.ts +0 -1
  222. package/src/TextField.ts +1 -1
  223. package/src/generated/i18n/i18n-defaults.ts +2 -2
  224. package/src/generated/templates/ListGroupHeaderTemplate.lit.ts +17 -10
  225. package/src/generated/templates/ListItemTemplate.lit.ts +32 -34
  226. package/src/generated/templates/MastheadCountrySelectorTemplate.lit.ts +3 -3
  227. package/src/generated/templates/MastheadItemTemplate.lit.ts +33 -25
  228. package/src/generated/templates/MastheadMenuItemTemplate.lit.ts +1 -1
  229. package/src/generated/templates/MastheadMobileMenuTemplate.lit.ts +5 -5
  230. package/src/generated/templates/MastheadShellTemplate.lit.ts +9 -10
  231. package/src/generated/templates/SearchableListBaseTemplate.lit.ts +1 -1
  232. package/src/generated/themes/BreadcrumbsPopover.css.ts +1 -1
  233. package/src/generated/themes/Dropdown.css.ts +1 -1
  234. package/src/generated/themes/FilterMenu.css.ts +1 -1
  235. package/src/generated/themes/ImageGridTicker.css.ts +1 -1
  236. package/src/generated/themes/Link.css.ts +1 -1
  237. package/src/generated/themes/ListGroupHeader.css.ts +1 -1
  238. package/src/generated/themes/ListItem.css.ts +1 -1
  239. package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
  240. package/src/generated/themes/MastheadItem.css.ts +1 -1
  241. package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
  242. package/src/generated/themes/MastheadShell.css.ts +1 -1
  243. package/src/generated/themes/Modal.css.ts +1 -1
  244. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  245. package/src/generated/themes/ReviewItem.css.ts +1 -1
  246. package/src/generated/themes/SecondaryNavigation.css.ts +1 -1
  247. package/src/generated/themes/SecondaryNavigationItem.css.ts +1 -1
  248. package/src/generated/themes/SecondaryNavigationSubItem.css.ts +1 -1
  249. package/src/generated/themes/Slider.css.ts +1 -1
  250. package/src/i18n/messagebundle.properties +9 -0
  251. package/src/i18n/messagebundle_en.properties +3 -0
  252. package/src/themes/BreadcrumbsPopover.css +2 -0
  253. package/src/themes/Dropdown.css +5 -1
  254. package/src/themes/FilterMenu.css +2 -2
  255. package/src/themes/ImageGridTicker.css +2 -26
  256. package/src/themes/Link.css +2 -3
  257. package/src/themes/ListGroupHeader.css +102 -15
  258. package/src/themes/ListItem.css +67 -15
  259. package/src/themes/MastheadCountrySelector.css +3 -1
  260. package/src/themes/MastheadItem.css +88 -3
  261. package/src/themes/MastheadProfileMenu.css +1 -9
  262. package/src/themes/MastheadShell.css +0 -2
  263. package/src/themes/Modal.css +2 -1
  264. package/src/themes/ReviewItem.css +18 -1
  265. package/src/themes/SecondaryNavigation.css +6 -3
  266. package/src/themes/SecondaryNavigationItem.css +11 -10
  267. package/src/themes/SecondaryNavigationSubItem.css +3 -2
  268. package/src/types/List.ts +0 -2
  269. package/src/types/SearchableListBase.ts +1 -0
  270. package/dist/assets/messagebundle_en-DfoXjU7o.js +0 -1
@@ -4,10 +4,16 @@ import property from "@ui5/webcomponents-base/dist/decorators/property.js";
4
4
  import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
5
5
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
6
6
  import { UDExListItemSize, UDExListMode, UDExListStyleType } from "./types/List.js";
7
+ import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
8
+ import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
9
+ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
10
+ import translate from "./utils/translate.js";
11
+ import { COLLAPSE, EXPAND } from "./generated/i18n/i18n-defaults.js";
7
12
 
8
13
  export type UDExListItemBaseEvents = {
9
14
  "first-icon-click": UDExListItemBaseEventDetail,
10
15
  "second-icon-click": UDExListItemBaseEventDetail,
16
+ "accordion-icon-click": UDExListItemBaseAccordionClickEventDetail,
11
17
  }
12
18
 
13
19
  type UDExListItemBaseEventDetail = {
@@ -15,6 +21,10 @@ type UDExListItemBaseEventDetail = {
15
21
  item: HTMLElement,
16
22
  }
17
23
 
24
+ type UDExListItemBaseAccordionClickEventDetail = {
25
+ collapsed: boolean;
26
+ }
27
+
18
28
  /**
19
29
  * @class
20
30
  *
@@ -49,6 +59,14 @@ type UDExListItemBaseEventDetail = {
49
59
  */
50
60
  @event("second-icon-click", { bubbles: true })
51
61
 
62
+ /**
63
+ * Triggered when the user clicks on an accordion item.
64
+ * @public
65
+ * @param { string } name
66
+ * @param { boolean } expanded
67
+ */
68
+ @event("accordion-icon-click", { bubbles: true })
69
+
52
70
  class UDExListItemBase extends UI5Element {
53
71
  eventDetails!: UDExListItemBaseEvents;
54
72
 
@@ -148,6 +166,33 @@ class UDExListItemBase extends UI5Element {
148
166
  @property({ type: String })
149
167
  _icon: string = "";
150
168
 
169
+ /**
170
+ * Defines if grouping header can collapse/expand child elements.
171
+ *
172
+ * @default false
173
+ * @public
174
+ */
175
+ @property({ type: Boolean })
176
+ collapsible!: boolean;
177
+
178
+ /**
179
+ * Defines if collapsible grouping header is collapsed or expanded
180
+ *
181
+ * @default undefined
182
+ * @public
183
+ */
184
+ @property({ type: Boolean })
185
+ collapsed!: boolean;
186
+
187
+ /**
188
+ * Defines if item is part of filtered list
189
+ *
190
+ * @default undefined
191
+ * @private
192
+ */
193
+ @property({ type: Boolean })
194
+ _filtered!: boolean;
195
+
151
196
  /**
152
197
  * Defines the tab index of the component.
153
198
  *
@@ -157,6 +202,45 @@ class UDExListItemBase extends UI5Element {
157
202
  @property({ type: String })
158
203
  _tabIndex: string = "";
159
204
 
205
+ _resizeHandler: () => void;
206
+ contentElement: HTMLElement | null | undefined;
207
+
208
+ constructor() {
209
+ super();
210
+ this._resizeHandler = this._onResize.bind(this);
211
+ this.contentElement = null;
212
+ }
213
+
214
+ @i18n("@sapudex/web-components")
215
+ static i18nBundle: I18nBundle;
216
+
217
+ onEnterDOM() {
218
+ if (!this.collapsible) {
219
+ return;
220
+ }
221
+ this.contentElement = this.shadowRoot?.querySelector(".udex-list__group-list__content") || this.nextElementSibling as HTMLElement;
222
+ if (this.contentElement) {
223
+ ResizeHandler.register(this.contentElement, this._resizeHandler);
224
+ this.setContentHeight();
225
+ }
226
+ }
227
+
228
+ onExitDOM(): void {
229
+ if (this.contentElement && this.collapsible) {
230
+ ResizeHandler.deregister(this.contentElement, this._resizeHandler);
231
+ }
232
+ }
233
+
234
+ setContentHeight() {
235
+ this.style.setProperty("--udex-list-content-max-height", `${this.contentElement?.scrollHeight || 0}px`);
236
+ }
237
+
238
+ _onResize(): void {
239
+ if (this.contentElement && this.collapsible) {
240
+ this.setContentHeight();
241
+ }
242
+ }
243
+
160
244
  _fireIconClickEvent(e: PointerEvent): void {
161
245
  const target = e.target as HTMLElement;
162
246
  const slot = target.getAttribute("slot");
@@ -173,6 +257,16 @@ class UDExListItemBase extends UI5Element {
173
257
  }
174
258
  }
175
259
 
260
+ handleCollapseIconMouseDown(e: MouseEvent) {
261
+ e.stopPropagation();
262
+ }
263
+
264
+ handleCollapseIconClick(e: MouseEvent | KeyboardEvent) {
265
+ e.stopPropagation();
266
+ e.preventDefault();
267
+ this.fireDecoratorEvent("accordion-icon-click", { collapsed: this.collapsed });
268
+ }
269
+
176
270
  get _effectiveTabIndex(): string {
177
271
  if (this.disabled) {
178
272
  return "-1";
@@ -204,18 +298,22 @@ class UDExListItemBase extends UI5Element {
204
298
  return this.modeMultiSelect || this.modeRadioGroup;
205
299
  }
206
300
 
207
- get typeNumber(): boolean {
208
- return this.type === UDExListStyleType.Number;
301
+ get typeIcon(): boolean {
302
+ return this.type === UDExListStyleType.Icon;
209
303
  }
210
304
 
211
- get typeCircle(): boolean {
212
- return this.type === UDExListStyleType.Circle;
305
+ get ariaControlsId(): string {
306
+ return `udex-list-${this._id}__group-content`;
213
307
  }
214
308
 
215
- get typeIcon(): boolean {
216
- return this.type === UDExListStyleType.Icon;
309
+ get expandButtonAccessibleName(): string {
310
+ return this.collapsed ? translate(UDExListItemBase, EXPAND) : translate(UDExListItemBase, COLLAPSE);
311
+ }
312
+
313
+ get expanded(): boolean {
314
+ return !this.collapsed;
217
315
  }
218
316
  }
219
317
 
220
318
  export default UDExListItemBase;
221
- export type { UDExListItemBaseEventDetail };
319
+ export type { UDExListItemBaseEventDetail, UDExListItemBaseAccordionClickEventDetail };
@@ -4,6 +4,8 @@
4
4
  {{#unless this.isSingleMode}}
5
5
  <udex-masthead-menu-item
6
6
  class="udex-masthead-country-selector__region-back-item"
7
+ accessible-role="button"
8
+ _accessible-Name="{{backToRegionListAccessibleName}}"
7
9
  @click="{{backToRegions}}"
8
10
  label="{{_activeRegion?.title}}"
9
11
  type="Button"
@@ -48,15 +50,16 @@
48
50
  </div>
49
51
  {{else}}
50
52
  <span class="udex-masthead-country-selector__title">{{regionTitle}}</span>
51
- <ul class="udex-masthead-country-selector__list" role="menu">
53
+ <ul class="udex-masthead-country-selector__list">
52
54
  {{#each regionsData}}
53
- <li role="none">
55
+ <li>
54
56
  <udex-masthead-menu-item
55
57
  id="{{this._id}}"
56
58
  @click="{{../handleRegionClick}}"
57
59
  index="{{@index}}"
60
+ accessible-role="button"
58
61
  class="udex-masthead-country-selector__item udex-masthead-country-selector__item_region"
59
- aria-has-popup="true"
62
+ aria-haspopup="true"
60
63
  type="Button"
61
64
  part="menu-item"
62
65
  is-nav-item
@@ -9,7 +9,7 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
9
9
  import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
10
10
  import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
11
11
  import {
12
- isUp, isDown, isRight, isLeft, isEnd, isHome,
12
+ isEnd, isHome, isTabNext, isTabPrevious,
13
13
  } from "@ui5/webcomponents-base/dist/Keys.js";
14
14
  import UDExMastheadMenuItem from "./MastheadMenuItem.js";
15
15
  import UDExSearch, { Mode as UDExSearchMode } from "./Search.js";
@@ -17,7 +17,7 @@ import MastheadCountrySelectorTemplate from "./generated/templates/MastheadCount
17
17
  import AnalyticsName from "./types/AnalyticsName.js";
18
18
  import { BreakpointUtils } from "./utils/Breakpoints.js";
19
19
  import type UDExMastheadShell from "./MastheadShell.js";
20
- import { NO_MATCHES_FOUND, RESULT_RETURNED } from "./generated/i18n/i18n-defaults.js";
20
+ import { NO_MATCHES_FOUND, RESULT_RETURNED, BACK_TO_REGION_LIST } from "./generated/i18n/i18n-defaults.js";
21
21
  import translate from "./utils/translate.js";
22
22
 
23
23
  // Styles
@@ -217,14 +217,6 @@ class UDExMastheadCountrySelector extends UI5Element {
217
217
  @property({ type: Boolean })
218
218
  _isMobileMode!: boolean;
219
219
 
220
- /**
221
- * Defines direction of the component.
222
- *
223
- * @private
224
- */
225
- @property({ type: String })
226
- _direction!: string;
227
-
228
220
  @property({ type: Boolean, noAttribute: true })
229
221
  _requestRender = false;
230
222
 
@@ -250,7 +242,6 @@ class UDExMastheadCountrySelector extends UI5Element {
250
242
  this._mastheadShell = this.mastheadShell;
251
243
  this.handleFocusItem();
252
244
  this.setTabIndexForItems();
253
- this.handleDirection();
254
245
  this.handleOutsideClick();
255
246
 
256
247
  if (this.isSingleMode) {
@@ -283,55 +274,23 @@ class UDExMastheadCountrySelector extends UI5Element {
283
274
  handleKeyDown(e: KeyboardEvent): void {
284
275
  const item = e.target as UDExMastheadMenuItem;
285
276
 
286
- if (item.hasAttribute("is-back")) {
287
- this.handleBackKeyboard(e);
288
- return;
289
- }
290
-
291
277
  if (item.hasAttribute("is-nav-item")) {
292
- this.handleUpArrow(e);
293
- this.handleDownArrow(e);
294
- this.handleRightArrow(e);
295
- this.handleLeftArrow(e);
278
+ const isFirstItem = item === this.items[0];
279
+ const isLastItem = item === this.items[this.items.length - 1];
280
+
281
+ if (isTabNext(e) && !isLastItem) {
282
+ e.preventDefault();
283
+ this.focusNextItem(item);
284
+ }
285
+ if (isTabPrevious(e) && !isFirstItem) {
286
+ e.preventDefault();
287
+ this.focusPreviousItem(item);
288
+ }
296
289
  this.handleHomeKey(e);
297
290
  this.handleEndKey(e);
298
291
  }
299
292
  }
300
293
 
301
- handleBackKeyboard(e: KeyboardEvent): void {
302
- if ((isLeft(e) && !this.isRtlDirection) || (isRight(e) && this.isRtlDirection)) {
303
- this.backToRegions();
304
- }
305
- }
306
-
307
- handleRightArrow(e: KeyboardEvent): void {
308
- if (isRight(e) && !this.isRtlDirection) {
309
- this.openCountriesByRegion(e);
310
- this.fireEventRegionItemClick(e);
311
- }
312
- }
313
-
314
- handleLeftArrow(e: KeyboardEvent): void {
315
- if (isLeft(e) && this.isRtlDirection) {
316
- this.openCountriesByRegion(e);
317
- this.fireEventRegionItemClick(e);
318
- }
319
- }
320
-
321
- handleUpArrow(e: KeyboardEvent): void {
322
- if (isUp(e)) {
323
- e.preventDefault();
324
- this.focusPreviousItem(e);
325
- }
326
- }
327
-
328
- handleDownArrow(e: KeyboardEvent): void {
329
- if (isDown(e)) {
330
- e.preventDefault();
331
- this.focusNextItem(e);
332
- }
333
- }
334
-
335
294
  handleSearch(e: CustomEvent): void {
336
295
  const searchTerm = e.detail.value.toLowerCase().trim() as string;
337
296
 
@@ -377,17 +336,6 @@ class UDExMastheadCountrySelector extends UI5Element {
377
336
  this._requestRender = !this._requestRender;
378
337
  }
379
338
 
380
- handleDirection() {
381
- const directionStyles: string = window
382
- .getComputedStyle(this)
383
- .getPropertyValue("direction");
384
- if (!directionStyles) {
385
- this._direction = "ltr";
386
- } else {
387
- this._direction = directionStyles;
388
- }
389
- }
390
-
391
339
  handleOutsideClick(): void {
392
340
  document.addEventListener("mousedown", (e: Event): void => {
393
341
  if (e.target !== this && !this.isMobile) {
@@ -415,21 +363,9 @@ class UDExMastheadCountrySelector extends UI5Element {
415
363
  this._shouldFocusRegionByIndex = true;
416
364
  }
417
365
 
418
- focusPreviousItem(e: KeyboardEvent): void {
419
- const currentIndex = (e.target as UDExMastheadMenuItem).index;
420
- const lastItemIndex = this.items.length - 1;
421
- const prevIndex = currentIndex - 1 < 0 ? lastItemIndex : currentIndex - 1;
422
- const prevItem = this.items[prevIndex];
423
- this.items[currentIndex]._tabIndex = "-1";
424
- prevItem._tabIndex = "0";
425
- prevItem.scrollIntoView({ block: "center" });
426
- prevItem.focus({ preventScroll: true });
427
- }
428
-
429
- focusNextItem(e: KeyboardEvent): void {
430
- const currentIndex = (e.target as UDExMastheadMenuItem).index;
431
- const lastItemIndex = this.items.length - 1;
432
- const nextIndex = currentIndex + 1 > lastItemIndex ? 0 : currentIndex + 1;
366
+ focusNextItem(currentItem: UDExMastheadMenuItem): void {
367
+ const currentIndex = currentItem.index;
368
+ const nextIndex = currentIndex + 1;
433
369
  const nextItem = this.items[nextIndex];
434
370
  this.items[currentIndex]._tabIndex = "-1";
435
371
  nextItem._tabIndex = "0";
@@ -437,6 +373,16 @@ class UDExMastheadCountrySelector extends UI5Element {
437
373
  nextItem.focus({ preventScroll: true });
438
374
  }
439
375
 
376
+ focusPreviousItem(currentItem: UDExMastheadMenuItem): void {
377
+ const currentIndex = currentItem.index;
378
+ const prevIndex = currentIndex - 1;
379
+ const prevItem = this.items[prevIndex];
380
+ this.items[currentIndex]._tabIndex = "-1";
381
+ prevItem._tabIndex = "0";
382
+ prevItem.scrollIntoView({ block: "center" });
383
+ prevItem.focus({ preventScroll: true });
384
+ }
385
+
440
386
  focusLastItem(e: KeyboardEvent): void {
441
387
  const currentIndex = (e.target as UDExMastheadMenuItem).index;
442
388
  const lastItemIndex = this.items.length - 1;
@@ -564,7 +510,7 @@ class UDExMastheadCountrySelector extends UI5Element {
564
510
  }
565
511
 
566
512
  handleCountryListShadowVisible(): void {
567
- if (this.scrollBottomCountriesList === 0) {
513
+ if (this.scrollBottomCountriesList <= 1) {
568
514
  this.removeScrollableClassInCountryList();
569
515
  } else {
570
516
  this.addScrollableClassToCountryList();
@@ -623,10 +569,6 @@ class UDExMastheadCountrySelector extends UI5Element {
623
569
  }));
624
570
  }
625
571
 
626
- get isRtlDirection(): boolean {
627
- return this._direction === "rtl";
628
- }
629
-
630
572
  get homeSearchMode(): UDExSearchMode {
631
573
  return UDExSearchMode.HomeSearch;
632
574
  }
@@ -642,6 +584,10 @@ class UDExMastheadCountrySelector extends UI5Element {
642
584
  get mastheadShell(): UDExMastheadShell {
643
585
  return document.querySelector<UDExMastheadShell>("[udex-masthead-shell]")!;
644
586
  }
587
+
588
+ get backToRegionListAccessibleName(): string {
589
+ return `${this._activeRegion?.title} ${translate(UDExMastheadCountrySelector, BACK_TO_REGION_LIST)}`;
590
+ }
645
591
  }
646
592
 
647
593
  UDExMastheadCountrySelector.define();
@@ -21,23 +21,21 @@
21
21
  </span>
22
22
  {{/if}}
23
23
  {{else if isProfileBtn}}
24
- <span
24
+ <button
25
25
  id="{{this._id}}"
26
- class="udex-masthead-item__btn {{additionalClass}}"
27
- aria-expanded="{{selected}}"
26
+ class="udex-masthead-item__btn udex-masthead-item__profile-btn {{additionalClass}}"
27
+ aria-expanded="{{buttonAriaExpanded}}"
28
28
  aria-describedby="{{ariaDescribedBy}}"
29
29
  aria-controls="{{this._id}}_dropdown"
30
- aria-haspopup="{{hasDropdownSlot}}"
31
30
  aria-label="{{accessibleLabel}}"
32
31
  @keydown="{{handleKeyDown}}"
33
32
  @click="{{handleItemClick}}"
33
+ @click-default="{{handleItemClick}}"
34
34
  @mousedown="{{handleMouseDown}}"
35
35
  @mouseup="{{handleMouseUp}}">
36
36
  {{> content}}
37
- </span>
38
- {{#if isDropdownOpened}}
39
- {{> dropdown}}
40
- {{/if}}
37
+ </button>
38
+ {{> dropdown}}
41
39
  {{else}}
42
40
  <button
43
41
  role="{{accessibleRoleName}}"
@@ -46,7 +44,6 @@
46
44
  aria-expanded="{{buttonAriaExpanded}}"
47
45
  aria-controls="{{this._id}}_dropdown"
48
46
  aria-describedby="{{ariaDescribedBy}}"
49
- aria-haspopup="{{hasDropdownSlot}}"
50
47
  aria-label="{{accessibleLabel}}"
51
48
  @keydown="{{handleKeyDown}}"
52
49
  @mousedown="{{handleMouseDown}}"
@@ -54,9 +51,7 @@
54
51
  @click="{{handleItemClick}}">
55
52
  {{> content}}
56
53
  </button>
57
- {{#if isDropdownOpened}}
58
- {{> dropdown}}
59
- {{/if}}
54
+ {{> dropdown}}
60
55
  {{/if}}
61
56
 
62
57
  {{#*inline "content"}}
@@ -69,14 +64,23 @@
69
64
  mode="Decorative">
70
65
  </ui5-icon>
71
66
  {{else if image}}
72
- <div class="udex-masthead-item__image-wrap">
73
- <img
74
- class="udex-masthead-item__image"
75
- id="{{this._id}}_image-alt"
76
- src="{{image}}"
77
- aria-hidden="{{isCountrySelectorBtn}}"
78
- alt="{{imageAlt}}"/>
79
- </div>
67
+ {{#if imageLoadError}}
68
+ <ui5-icon
69
+ class="udex-masthead-item__icon"
70
+ name="sap-icon://world"
71
+ mode="Decorative">
72
+ </ui5-icon>
73
+ {{else}}
74
+ <div class="udex-masthead-item__image-wrap">
75
+ <img
76
+ class="udex-masthead-item__image"
77
+ id="{{this._id}}_image-alt"
78
+ src="{{image}}"
79
+ aria-hidden="{{isCountrySelectorBtn}}"
80
+ alt="{{imageAlt}}"
81
+ @error="{{handleImageError}}"/>
82
+ </div>
83
+ {{/if}}
80
84
  {{#if imageAlt}}
81
85
  <span
82
86
  id="image-desc"
@@ -99,13 +103,17 @@
99
103
  {{/inline}}
100
104
 
101
105
  {{#*inline "dropdown"}}
106
+ {{#if isDropdownOpened}}
102
107
  <div
103
108
  id="{{this._id}}_dropdown"
104
109
  class="udex-masthead-item__dropdown"
105
110
  @keydown="{{handleKeyDown}}"
106
111
  @focusout="{{handleFocusout}}">
107
- <div class="udex-masthead-item__dropdown-holder">
108
- <slot name="dropdown"></slot>
109
- </div>
112
+ <div class="udex-masthead-item__dropdown-holder">
113
+ <slot name="dropdown"></slot>
114
+ </div>
110
115
  </div>
116
+ {{else}}
117
+ <div id="{{this._id}}_dropdown"></div>
118
+ {{/if}}
111
119
  {{/inline}}
@@ -10,13 +10,13 @@ import "@ui5/webcomponents-icons/dist/search.js";
10
10
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
11
11
  import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
12
12
  import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
13
- import { getFirstFocusableElement } from "@ui5/webcomponents-base/dist/util/FocusableElements.js";
14
13
  import {
15
14
  OPENS_IN_A_NEW_WINDOW, PROFILE, CART, COUNTRY_SELECTOR, SUPPORT, SEARCH,
16
15
  } from "./generated/i18n/i18n-defaults.js";
17
16
  import UDExMastheadMenu from "./MastheadMenu.js";
18
17
  import type UDExAvatar from "./Avatar.js";
19
18
  import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
19
+ import "@ui5/webcomponents-icons/dist/world.js";
20
20
  import type UDExMastheadShell from "./MastheadShell.js";
21
21
  import MastheadItemTemplate from "./generated/templates/MastheadItemTemplate.lit.js";
22
22
  import { UDExTarget } from "./types/common.js";
@@ -315,6 +315,14 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
315
315
  @property({ type: Boolean })
316
316
  _isMenuCloseBtn?: boolean;
317
317
 
318
+ /**
319
+ * Defines if the image failed to load
320
+ *
321
+ * @private
322
+ */
323
+ @property({ type: Boolean })
324
+ _imageLoadError = false;
325
+
318
326
  @i18n("@sapudex/web-components")
319
327
  static i18nBundle: I18nBundle;
320
328
 
@@ -339,10 +347,6 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
339
347
  this.setDropdownInsetStart();
340
348
  }
341
349
 
342
- if (this.shouldFocusFirstElement) {
343
- this.applyFocusToFirstElement();
344
- }
345
-
346
350
  this.handleOutsideClick();
347
351
  }
348
352
 
@@ -432,6 +436,10 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
432
436
  }
433
437
  }
434
438
 
439
+ handleImageError(): void {
440
+ this._imageLoadError = true;
441
+ }
442
+
435
443
  fireDropdownEvents(): void {
436
444
  if (this.hasDropdownSlot) {
437
445
  const { Open, Close } = UDExMastheadDropdownItemAction;
@@ -473,6 +481,14 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
473
481
  }
474
482
  }
475
483
 
484
+ recalculateDropdownPosition(): void {
485
+ const dropdown = this.dropdownHolder;
486
+ if (dropdown) {
487
+ dropdown.style.marginInlineStart = "";
488
+ this.setDropdownInsetStart();
489
+ }
490
+ }
491
+
476
492
  calculateMarginInlineStart(rect: DOMRect): number | null {
477
493
  const { left, right } = rect;
478
494
 
@@ -511,13 +527,6 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
511
527
  this.fireDropdownCloseEvent(this.accessibleName || this.eventItemTitle, UDExMastheadDropdownItemAction.Close);
512
528
  }
513
529
 
514
- async applyFocusToFirstElement(): Promise<void> {
515
- const focusedElement = await getFirstFocusableElement(this.dropdownHolder);
516
- if (focusedElement) {
517
- focusedElement.focus();
518
- }
519
- }
520
-
521
530
  getDomElement(selector: string): HTMLElement | undefined | null {
522
531
  return this.shadowRoot?.querySelector(`${selector}`);
523
532
  }
@@ -607,10 +616,6 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
607
616
  return labels.length ? labels.join(" ").trim() : undefined;
608
617
  }
609
618
 
610
- get shouldFocusFirstElement(): boolean {
611
- return this.isDropdownOpened && !this._preventFocusOut;
612
- }
613
-
614
619
  get isDropdownOpened(): boolean {
615
620
  return this.hasDropdownSlot && this.selected;
616
621
  }
@@ -688,9 +693,14 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
688
693
  }
689
694
 
690
695
  get buttonAriaExpanded(): boolean | undefined {
691
- if (!this.isSearchBtn) {
692
- return this.selected;
696
+ if (!this.hasDropdownSlot) {
697
+ return undefined;
693
698
  }
699
+ return this.selected || false;
700
+ }
701
+
702
+ get imageLoadError(): boolean {
703
+ return this._imageLoadError && this.isCountrySelectorBtn;
694
704
  }
695
705
  }
696
706
 
@@ -9,7 +9,7 @@ import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
9
9
  import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
10
10
  import "@ui5/webcomponents-icons/dist/action.js";
11
11
  import {
12
- isUp, isDown, isTabNext, isTabPrevious, isHome, isEnd,
12
+ isTabNext, isTabPrevious, isHome, isEnd,
13
13
  } from "@ui5/webcomponents-base/dist/Keys.js";
14
14
  import UDExBadge from "./Badge.js";
15
15
  import UDExMastheadMenuItem, { UDExItemType } from "./MastheadMenuItem.js";
@@ -139,11 +139,11 @@ class UDExMastheadMenu extends UI5Element {
139
139
  const isFirstItem = e.target === this.links[0];
140
140
  const isLastItem = e.target === this.links[this.links.length - 1];
141
141
 
142
- if (isUp(e) || (isTabPrevious(e) && !isFirstItem)) {
143
- this.handleUpArrow(e);
142
+ if (isTabPrevious(e) && !isFirstItem) {
143
+ this.handlePreviousItemFocus(e);
144
144
  }
145
- if (isDown(e) || (isTabNext(e) && !isLastItem)) {
146
- this.handleDownArrow(e);
145
+ if (isTabNext(e) && !isLastItem) {
146
+ this.handleNextItemFocus(e);
147
147
  }
148
148
  if (isHome(e)) {
149
149
  this.handleHomeKey(e);
@@ -165,13 +165,13 @@ class UDExMastheadMenu extends UI5Element {
165
165
  lastItem.focus();
166
166
  }
167
167
 
168
- handleUpArrow(e: KeyboardEvent): void {
168
+ handlePreviousItemFocus(e: KeyboardEvent): void {
169
169
  e.preventDefault();
170
170
  const currentItem = e.target as UDExMastheadMenuItem;
171
171
  this.focusPreviousItem(currentItem);
172
172
  }
173
173
 
174
- handleDownArrow(e: KeyboardEvent): void {
174
+ handleNextItemFocus(e: KeyboardEvent): void {
175
175
  e.preventDefault();
176
176
  const currentItem = e.target as UDExMastheadMenuItem;
177
177
  this.focusNextItem(currentItem);
@@ -239,10 +239,11 @@ class UDExMastheadMenu extends UI5Element {
239
239
  return parsedItems.map((mainItem: MenuItem) => {
240
240
  mainItem.subMenuLinkItems = mainItem.subMenuLinkItems.map((subMenu: SubMenuLinkItem) => {
241
241
  subMenu.categoryId = `${id++}`;
242
- subMenu.items = subMenu.items.map((item: Item) => ({
242
+
243
+ subMenu.items = subMenu.items ? subMenu.items.map((item: Item) => ({
243
244
  ...item,
244
245
  ...(item.title === "-" && { isDivider: true }),
245
- }));
246
+ })) : [];
246
247
 
247
248
  return subMenu;
248
249
  });
@@ -38,6 +38,7 @@
38
38
  {{#if isButtonType}}
39
39
  <button
40
40
  _id="{{id}}"
41
+ aria-label="{{_accessibleName}}"
41
42
  class="udex-masthead-menu-item {{rootClass}}"
42
43
  part="menu-item-button"
43
44
  aria-haspopup="{{ariaHasPopup}}"
@@ -162,6 +162,15 @@ class UDExMastheadMenuItem extends UI5Element {
162
162
  @property()
163
163
  target: `${UDExTarget}` = UDExTarget._self;
164
164
 
165
+ /**
166
+ * Defines the accessible name of the item.
167
+ *
168
+ * @default undefined
169
+ * @private
170
+ */
171
+ @property()
172
+ _accessibleName?: string;
173
+
165
174
  /**
166
175
  * Defines the tabindex attribute for the item.
167
176
  *