@sapudex/web-components 2.28.0 → 2.30.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 (230) hide show
  1. package/cypress/specs/FilterMenu.cy.tsx +39 -1
  2. package/cypress/specs/List.cy.tsx +171 -0
  3. package/cypress/specs/PromoTile.cy.tsx +16 -2
  4. package/cypress/specs/ReviewItem.cy.tsx +48 -14
  5. package/cypress/specs/Tag.cy.tsx +6 -0
  6. package/cypress/support/component-imports.instrumented.ts +4 -0
  7. package/cypress/support/component-imports.src.ts +5 -1
  8. package/dist/Avatar.d.ts +1 -0
  9. package/dist/Avatar.js +9 -0
  10. package/dist/Avatar.js.map +1 -1
  11. package/dist/FilterMenu.d.ts +2 -0
  12. package/dist/FilterMenu.js +2 -0
  13. package/dist/FilterMenu.js.map +1 -1
  14. package/dist/ImageGridTickerTemplate.js +2 -1
  15. package/dist/ImageGridTickerTemplate.js.map +1 -1
  16. package/dist/List.d.ts +4 -2
  17. package/dist/List.js +42 -9
  18. package/dist/List.js.map +1 -1
  19. package/dist/ListGroupHeader.d.ts +4 -0
  20. package/dist/ListGroupHeader.js +26 -1
  21. package/dist/ListGroupHeader.js.map +1 -1
  22. package/dist/ListGroupHeaderBase.js +1 -1
  23. package/dist/ListGroupHeaderBase.js.map +1 -1
  24. package/dist/ListItem.js +1 -1
  25. package/dist/ListItem.js.map +1 -1
  26. package/dist/ListItemBase.d.ts +40 -1
  27. package/dist/ListItemBase.js +70 -3
  28. package/dist/ListItemBase.js.map +1 -1
  29. package/dist/MastheadCountrySelector.d.ts +16 -0
  30. package/dist/MastheadCountrySelector.js +21 -6
  31. package/dist/MastheadCountrySelector.js.map +1 -1
  32. package/dist/MastheadItem.d.ts +9 -2
  33. package/dist/MastheadItem.js +19 -15
  34. package/dist/MastheadItem.js.map +1 -1
  35. package/dist/MastheadMenu.d.ts +2 -2
  36. package/dist/MastheadMenu.js +9 -9
  37. package/dist/MastheadMenu.js.map +1 -1
  38. package/dist/MessageStrip.d.ts +14 -0
  39. package/dist/MessageStrip.js +7 -1
  40. package/dist/MessageStrip.js.map +1 -1
  41. package/dist/MessageStripTemplate.js +1 -1
  42. package/dist/MessageStripTemplate.js.map +1 -1
  43. package/dist/Pagination.js +1 -1
  44. package/dist/Pagination.js.map +1 -1
  45. package/dist/PromoTile.d.ts +8 -1
  46. package/dist/PromoTile.js +9 -6
  47. package/dist/PromoTile.js.map +1 -1
  48. package/dist/PromoTileTemplate.js +5 -5
  49. package/dist/PromoTileTemplate.js.map +1 -1
  50. package/dist/ReviewItem.d.ts +8 -7
  51. package/dist/ReviewItem.js +35 -36
  52. package/dist/ReviewItem.js.map +1 -1
  53. package/dist/ReviewItemTemplate.js +3 -1
  54. package/dist/ReviewItemTemplate.js.map +1 -1
  55. package/dist/SearchableListBase.d.ts +3 -0
  56. package/dist/SearchableListBase.js +38 -2
  57. package/dist/SearchableListBase.js.map +1 -1
  58. package/dist/SelectBase.js +1 -1
  59. package/dist/SelectBase.js.map +1 -1
  60. package/dist/SelectBox.js +0 -1
  61. package/dist/SelectBox.js.map +1 -1
  62. package/dist/TabNavigation.d.ts +1 -1
  63. package/dist/TabNavigation.js +2 -7
  64. package/dist/TabNavigation.js.map +1 -1
  65. package/dist/Tag.d.ts +7 -1
  66. package/dist/Tag.js +4 -1
  67. package/dist/Tag.js.map +1 -1
  68. package/dist/TagTemplate.js +1 -1
  69. package/dist/TagTemplate.js.map +1 -1
  70. package/dist/TextField.d.ts +1 -1
  71. package/dist/TextField.js.map +1 -1
  72. package/dist/assets/{InputSuggestions-DTdaDbps.js → InputSuggestions-CaAXs3ok.js} +1 -1
  73. package/dist/assets/{ListItemStandardExpandableTextTemplate-DoV7tVwi.js → ListItemStandardExpandableTextTemplate-CPqUBd--.js} +1 -1
  74. package/dist/assets/{bundle.esm-BUg2IPOZ.js → bundle.esm-L-7H6J4f.js} +217 -217
  75. package/dist/assets/messagebundle_en-J-MHTtdL.js +1 -0
  76. package/dist/css/themes/Button.css +1 -1
  77. package/dist/css/themes/FilterMenu.css +1 -1
  78. package/dist/css/themes/ImageGridTicker.css +1 -1
  79. package/dist/css/themes/ListGroupHeader.css +1 -1
  80. package/dist/css/themes/ListItem.css +1 -1
  81. package/dist/css/themes/MastheadCountrySelector.css +1 -1
  82. package/dist/css/themes/MastheadItem.css +1 -1
  83. package/dist/css/themes/MastheadMenuItem.css +1 -1
  84. package/dist/css/themes/MastheadProfileMenu.css +1 -1
  85. package/dist/css/themes/Modal.css +1 -1
  86. package/dist/css/themes/PromoTile.css +1 -1
  87. package/dist/css/themes/RatingIndicator.css +1 -1
  88. package/dist/css/themes/ReviewItem.css +1 -1
  89. package/dist/css/themes/SearchableList.css +1 -1
  90. package/dist/css/themes/Slider.css +1 -1
  91. package/dist/custom-elements-internal.json +1087 -17
  92. package/dist/custom-elements.json +820 -0
  93. package/dist/generated/assets/i18n/messagebundle_en.json +1 -1
  94. package/dist/generated/i18n/i18n-defaults.d.ts +5 -1
  95. package/dist/generated/i18n/i18n-defaults.js +5 -1
  96. package/dist/generated/i18n/i18n-defaults.js.map +1 -1
  97. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js +21 -10
  98. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js.map +1 -1
  99. package/dist/generated/templates/ListItemTemplate.lit.js +21 -19
  100. package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
  101. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js +2 -2
  102. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js.map +1 -1
  103. package/dist/generated/templates/MastheadItemTemplate.lit.js +33 -25
  104. package/dist/generated/templates/MastheadItemTemplate.lit.js.map +1 -1
  105. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js +5 -5
  106. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js.map +1 -1
  107. package/dist/generated/templates/SearchableListBaseTemplate.lit.js +1 -1
  108. package/dist/generated/templates/SearchableListBaseTemplate.lit.js.map +1 -1
  109. package/dist/generated/themes/Button.css.d.ts +1 -1
  110. package/dist/generated/themes/Button.css.js +1 -1
  111. package/dist/generated/themes/Button.css.js.map +1 -1
  112. package/dist/generated/themes/FilterMenu.css.d.ts +1 -1
  113. package/dist/generated/themes/FilterMenu.css.js +1 -1
  114. package/dist/generated/themes/FilterMenu.css.js.map +1 -1
  115. package/dist/generated/themes/ImageGridTicker.css.d.ts +1 -1
  116. package/dist/generated/themes/ImageGridTicker.css.js +1 -1
  117. package/dist/generated/themes/ImageGridTicker.css.js.map +1 -1
  118. package/dist/generated/themes/ListGroupHeader.css.d.ts +1 -1
  119. package/dist/generated/themes/ListGroupHeader.css.js +1 -1
  120. package/dist/generated/themes/ListGroupHeader.css.js.map +1 -1
  121. package/dist/generated/themes/ListItem.css.d.ts +1 -1
  122. package/dist/generated/themes/ListItem.css.js +1 -1
  123. package/dist/generated/themes/ListItem.css.js.map +1 -1
  124. package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
  125. package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
  126. package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
  127. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  128. package/dist/generated/themes/MastheadItem.css.js +1 -1
  129. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  130. package/dist/generated/themes/MastheadMenuItem.css.d.ts +1 -1
  131. package/dist/generated/themes/MastheadMenuItem.css.js +1 -1
  132. package/dist/generated/themes/MastheadMenuItem.css.js.map +1 -1
  133. package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
  134. package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
  135. package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
  136. package/dist/generated/themes/Modal.css.d.ts +1 -1
  137. package/dist/generated/themes/Modal.css.js +1 -1
  138. package/dist/generated/themes/Modal.css.js.map +1 -1
  139. package/dist/generated/themes/PromoTile.css.d.ts +1 -1
  140. package/dist/generated/themes/PromoTile.css.js +1 -1
  141. package/dist/generated/themes/PromoTile.css.js.map +1 -1
  142. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  143. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  144. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  145. package/dist/generated/themes/ReviewItem.css.d.ts +1 -1
  146. package/dist/generated/themes/ReviewItem.css.js +1 -1
  147. package/dist/generated/themes/ReviewItem.css.js.map +1 -1
  148. package/dist/generated/themes/SearchableList.css.d.ts +1 -1
  149. package/dist/generated/themes/SearchableList.css.js +1 -1
  150. package/dist/generated/themes/SearchableList.css.js.map +1 -1
  151. package/dist/generated/themes/Slider.css.d.ts +1 -1
  152. package/dist/generated/themes/Slider.css.js +1 -1
  153. package/dist/generated/themes/Slider.css.js.map +1 -1
  154. package/dist/messagebundle.properties +6 -0
  155. package/dist/messagebundle_en.properties +2 -0
  156. package/dist/types/SearchableListBase.d.ts +1 -0
  157. package/dist/types/SearchableListBase.js.map +1 -1
  158. package/dist/vscode.html-custom-data.json +153 -13
  159. package/dist/web-types.json +336 -12
  160. package/package.json +1 -1
  161. package/src/Avatar.ts +9 -0
  162. package/src/FilterMenu.ts +4 -0
  163. package/src/ImageGridTickerTemplate.tsx +3 -1
  164. package/src/List.ts +48 -11
  165. package/src/ListGroupHeader.hbs +130 -15
  166. package/src/ListGroupHeader.ts +31 -1
  167. package/src/ListGroupHeaderBase.ts +1 -1
  168. package/src/ListItem.hbs +15 -0
  169. package/src/ListItem.ts +1 -1
  170. package/src/ListItemBase.ts +107 -1
  171. package/src/MastheadCountrySelector.hbs +2 -1
  172. package/src/MastheadCountrySelector.ts +36 -6
  173. package/src/MastheadItem.hbs +31 -22
  174. package/src/MastheadItem.ts +20 -18
  175. package/src/MastheadMenu.ts +10 -9
  176. package/src/MastheadMobileMenu.hbs +5 -5
  177. package/src/MessageStrip.ts +19 -1
  178. package/src/MessageStripTemplate.tsx +1 -0
  179. package/src/Pagination.ts +1 -1
  180. package/src/PromoTile.ts +17 -10
  181. package/src/PromoTileTemplate.tsx +18 -14
  182. package/src/ReviewItem.ts +45 -35
  183. package/src/ReviewItemTemplate.tsx +16 -14
  184. package/src/SearchableListBase.hbs +3 -0
  185. package/src/SearchableListBase.ts +53 -2
  186. package/src/SelectBase.ts +1 -1
  187. package/src/SelectBox.ts +0 -1
  188. package/src/TabNavigation.ts +3 -10
  189. package/src/Tag.ts +10 -2
  190. package/src/TagTemplate.tsx +4 -0
  191. package/src/TextField.ts +1 -1
  192. package/src/generated/i18n/i18n-defaults.ts +2 -2
  193. package/src/generated/templates/ListGroupHeaderTemplate.lit.ts +21 -10
  194. package/src/generated/templates/ListItemTemplate.lit.ts +21 -19
  195. package/src/generated/templates/MastheadCountrySelectorTemplate.lit.ts +2 -2
  196. package/src/generated/templates/MastheadItemTemplate.lit.ts +33 -25
  197. package/src/generated/templates/MastheadMobileMenuTemplate.lit.ts +5 -5
  198. package/src/generated/templates/SearchableListBaseTemplate.lit.ts +1 -1
  199. package/src/generated/themes/Button.css.ts +1 -1
  200. package/src/generated/themes/FilterMenu.css.ts +1 -1
  201. package/src/generated/themes/ImageGridTicker.css.ts +1 -1
  202. package/src/generated/themes/ListGroupHeader.css.ts +1 -1
  203. package/src/generated/themes/ListItem.css.ts +1 -1
  204. package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
  205. package/src/generated/themes/MastheadItem.css.ts +1 -1
  206. package/src/generated/themes/MastheadMenuItem.css.ts +1 -1
  207. package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
  208. package/src/generated/themes/Modal.css.ts +1 -1
  209. package/src/generated/themes/PromoTile.css.ts +1 -1
  210. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  211. package/src/generated/themes/ReviewItem.css.ts +1 -1
  212. package/src/generated/themes/SearchableList.css.ts +1 -1
  213. package/src/generated/themes/Slider.css.ts +1 -1
  214. package/src/i18n/messagebundle.properties +6 -0
  215. package/src/i18n/messagebundle_en.properties +2 -0
  216. package/src/themes/Button.css +9 -20
  217. package/src/themes/FilterMenu.css +2 -2
  218. package/src/themes/ImageGridTicker.css +2 -26
  219. package/src/themes/ListGroupHeader.css +103 -8
  220. package/src/themes/ListItem.css +68 -15
  221. package/src/themes/MastheadCountrySelector.css +6 -0
  222. package/src/themes/MastheadItem.css +31 -3
  223. package/src/themes/MastheadMenuItem.css +8 -2
  224. package/src/themes/MastheadProfileMenu.css +3 -9
  225. package/src/themes/Modal.css +2 -1
  226. package/src/themes/PromoTile.css +4 -0
  227. package/src/themes/ReviewItem.css +18 -1
  228. package/src/themes/SearchableList.css +1 -1
  229. package/src/types/SearchableListBase.ts +1 -0
  230. package/dist/assets/messagebundle_en-DfoXjU7o.js +0 -1
@@ -32,6 +32,7 @@ export type Country = {
32
32
  displayTitle: string,
33
33
  countryCode: string,
34
34
  url: string,
35
+ active: boolean,
35
36
  };
36
37
 
37
38
  type UDExMastheadCountrySelectorRegionClickEventDetail = {
@@ -127,6 +128,25 @@ class UDExMastheadCountrySelector extends UI5Element {
127
128
  "country-selector-search": UDExMastheadCountrySelectorSearchEventDetail,
128
129
  "region-item-click": UDExMastheadCountrySelectorRegionClickEventDetail
129
130
  };
131
+
132
+ /**
133
+ * Defines active country code of the regions menu
134
+ *
135
+ * @default ""
136
+ * @public
137
+ */
138
+ @property({ type: String })
139
+ activeCountryCode !: string;
140
+
141
+ /**
142
+ * Defines active country url of the regions menu
143
+ *
144
+ * @default ""
145
+ * @public
146
+ */
147
+ @property({ type: String })
148
+ activeCountryUrl!: string;
149
+
130
150
  /**
131
151
  * Defines title of the regions menu
132
152
  *
@@ -279,11 +299,8 @@ class UDExMastheadCountrySelector extends UI5Element {
279
299
  }
280
300
 
281
301
  handleBackKeyboard(e: KeyboardEvent): void {
282
- if (isLeft(e) && !this.isRtlDirection) {
283
- return this.backToRegions();
284
- }
285
- if (isRight(e) && this.isRtlDirection) {
286
- return this.backToRegions();
302
+ if ((isLeft(e) && !this.isRtlDirection) || (isRight(e) && this.isRtlDirection)) {
303
+ this.backToRegions();
287
304
  }
288
305
  }
289
306
 
@@ -562,6 +579,12 @@ class UDExMastheadCountrySelector extends UI5Element {
562
579
  this.countryListHolder.classList.remove(`${this._countriesListHolderClassName}_scrollable`);
563
580
  }
564
581
 
582
+ isActiveCountry(countryCode: string, url: string): boolean {
583
+ const matchedURL = this.activeCountryUrl?.toUpperCase() === url.toUpperCase();
584
+ const matchedCode = this.activeCountryCode?.toUpperCase() === countryCode.toUpperCase();
585
+ return matchedURL && matchedCode;
586
+ }
587
+
565
588
  get scrollBottomCountriesList(): number {
566
589
  const countriesList = this.countryListHolder;
567
590
  return countriesList.scrollHeight - countriesList.scrollTop - countriesList.clientHeight;
@@ -590,7 +613,14 @@ class UDExMastheadCountrySelector extends UI5Element {
590
613
  }
591
614
 
592
615
  get regionsData(): Array<Region> {
593
- return this.regions ? JSON.parse(this.regions) as Array<Region> : [];
616
+ const regions: Array<Region> = this.regions ? JSON.parse(this.regions) as Array<Region> : [];
617
+ return regions.map(region => ({
618
+ ...region,
619
+ countries: region.countries.map(country => ({
620
+ ...country,
621
+ active: this.isActiveCountry(country.countryCode, country.url),
622
+ })),
623
+ }));
594
624
  }
595
625
 
596
626
  get isRtlDirection(): boolean {
@@ -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,13 +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
- alt="{{imageAlt}}"/>
78
- </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}}
79
84
  {{#if imageAlt}}
80
85
  <span
81
86
  id="image-desc"
@@ -98,13 +103,17 @@
98
103
  {{/inline}}
99
104
 
100
105
  {{#*inline "dropdown"}}
106
+ {{#if isDropdownOpened}}
101
107
  <div
102
108
  id="{{this._id}}_dropdown"
103
109
  class="udex-masthead-item__dropdown"
104
110
  @keydown="{{handleKeyDown}}"
105
111
  @focusout="{{handleFocusout}}">
106
- <div class="udex-masthead-item__dropdown-holder">
107
- <slot name="dropdown"></slot>
108
- </div>
112
+ <div class="udex-masthead-item__dropdown-holder">
113
+ <slot name="dropdown"></slot>
114
+ </div>
109
115
  </div>
116
+ {{else}}
117
+ <div id="{{this._id}}_dropdown"></div>
118
+ {{/if}}
110
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;
@@ -511,13 +519,6 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
511
519
  this.fireDropdownCloseEvent(this.accessibleName || this.eventItemTitle, UDExMastheadDropdownItemAction.Close);
512
520
  }
513
521
 
514
- async applyFocusToFirstElement(): Promise<void> {
515
- const focusedElement = await getFirstFocusableElement(this.dropdownHolder);
516
- if (focusedElement) {
517
- focusedElement.focus();
518
- }
519
- }
520
-
521
522
  getDomElement(selector: string): HTMLElement | undefined | null {
522
523
  return this.shadowRoot?.querySelector(`${selector}`);
523
524
  }
@@ -607,10 +608,6 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
607
608
  return labels.length ? labels.join(" ").trim() : undefined;
608
609
  }
609
610
 
610
- get shouldFocusFirstElement(): boolean {
611
- return this.isDropdownOpened && !this._preventFocusOut;
612
- }
613
-
614
611
  get isDropdownOpened(): boolean {
615
612
  return this.hasDropdownSlot && this.selected;
616
613
  }
@@ -688,9 +685,14 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
688
685
  }
689
686
 
690
687
  get buttonAriaExpanded(): boolean | undefined {
691
- if (!this.isSearchBtn) {
692
- return this.selected;
688
+ if (!this.hasDropdownSlot) {
689
+ return undefined;
693
690
  }
691
+ return this.selected || false;
692
+ }
693
+
694
+ get imageLoadError(): boolean {
695
+ return this._imageLoadError && this.isCountrySelectorBtn;
694
696
  }
695
697
  }
696
698
 
@@ -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,7 +38,7 @@
38
38
  class="udex-masthead-mobile-menu__back-item"
39
39
  @click="{{handleBackToMenuItems}}"
40
40
  label="{{_clickedItem.innerText}}"
41
- aria-has-popup="true"
41
+ aria-haspopup="true"
42
42
  type="Button"
43
43
  is-back
44
44
  has-border
@@ -58,7 +58,7 @@
58
58
  @click="{{handleBackToCategories}}"
59
59
  label="{{_category.category}}"
60
60
  type="Button"
61
- aria-has-popup="true"
61
+ aria-haspopup="true"
62
62
  has-border
63
63
  icon-start
64
64
  is-back
@@ -77,7 +77,7 @@
77
77
  @click="{{handleExploreSapClick}}"
78
78
  @keydown="{{handleLeftRightKeys}}"
79
79
  accessible-role-text="button"
80
- aria-has-popup="true"
80
+ aria-haspopup="true"
81
81
  type="Button"
82
82
  first-level-btn
83
83
  first-level
@@ -96,7 +96,7 @@
96
96
  part="menu-item"
97
97
  @click="{{../handleMenuItemClick}}"
98
98
  label="{{this.innerText}}"
99
- aria-has-popup="true"
99
+ aria-haspopup="true"
100
100
  id="{{this._id}}"
101
101
  type="Button"
102
102
  first-level-btn
@@ -141,7 +141,7 @@
141
141
  @click="{{../handleMenuCategoryClick}}"
142
142
  id="{{@index}}"
143
143
  label="{{this.category}}"
144
- aria-has-popup="true"
144
+ aria-haspopup="true"
145
145
  type="Button"
146
146
  second-level-btn
147
147
  second-level
@@ -64,6 +64,24 @@ class UDExMessageStrip extends MessageStrip {
64
64
  @property({ type: Boolean })
65
65
  hideCloseButton!: boolean;
66
66
 
67
+ /**
68
+ * Defines accessible name for close icon
69
+ *
70
+ * @default ""
71
+ * @public
72
+ */
73
+ @property()
74
+ closeIconAccessibleName!: string;
75
+
76
+ /**
77
+ * Defines tooltip for close icon
78
+ *
79
+ * @default ""
80
+ * @public
81
+ */
82
+ @property()
83
+ closeIconTooltip!: string;
84
+
67
85
  /**
68
86
  * Defines the content of the component.
69
87
  *
@@ -126,7 +144,7 @@ class UDExMessageStrip extends MessageStrip {
126
144
  }
127
145
 
128
146
  get _closeButtonText(): string {
129
- return `${this.textStatus ?? ""} ${this.getTranslation(MESSAGE_STRIP_CLOSE_BUTTON)}`;
147
+ return this.closeIconTooltip || `${this.textStatus ?? ""} ${this.getTranslation(MESSAGE_STRIP_CLOSE_BUTTON)}`;
130
148
  }
131
149
 
132
150
  get isNotIconStatusType(): boolean {
@@ -54,6 +54,7 @@ export default function MessageStripTemplate(this: UDExMessageStrip) {
54
54
  design={UDExButtonDesign.Tertiary}
55
55
  onClick={this._closeClick}
56
56
  tooltip={this._closeButtonText}
57
+ accessibleName={this.closeIconAccessibleName}
57
58
  part="close-button"
58
59
  />
59
60
  )}
package/src/Pagination.ts CHANGED
@@ -364,7 +364,7 @@ class UDExPagination extends UI5Element {
364
364
  return;
365
365
  }
366
366
 
367
- if (!this._pages.length || this._visiblePages.length < this.displayNumber) {
367
+ if (!this._pages.length || this._visiblePages.length !== this.displayNumber) {
368
368
  this._firstPageIndex = 0;
369
369
  this._lastPageIndex = pages > this.displayNumber ? this.displayNumber : pages;
370
370
  this._pageFocusedManually = false;
package/src/PromoTile.ts CHANGED
@@ -16,10 +16,10 @@ import type UDExButton from "./Button.js";
16
16
  import UDExButtonSize from "./types/ButtonSize.js";
17
17
  import UDExButtonDesign from "./types/ButtonDesign.js";
18
18
  import { UDExPromoTileColorScheme, UDExPromoTileMode } from "./types/PromoTile.js";
19
+ import translate from "./utils/translate.js";
19
20
 
20
21
  // Styles
21
22
  import PromoTileCss from "./generated/themes/PromoTile.css.js";
22
- import translate from "./utils/translate.js";
23
23
 
24
24
  export enum UDExOrientation {
25
25
  Vertical = "Vertical",
@@ -72,6 +72,15 @@ class UDExPromoTile extends UI5Element {
72
72
  @slot({ type: HTMLElement, "default": true })
73
73
  content!: Array<HTMLElement>;
74
74
 
75
+ /**
76
+ * Defines the custom pictogram of the Promo Tile.
77
+ *
78
+ * @slot pictogram
79
+ * @public
80
+ */
81
+ @slot({ type: HTMLElement })
82
+ pictogram?: Array<HTMLElement>;
83
+
75
84
  /**
76
85
  * Defines the orientation of the Promo Tile component.
77
86
  *
@@ -199,9 +208,7 @@ class UDExPromoTile extends UI5Element {
199
208
  }
200
209
 
201
210
  getButton(): UDExButton | undefined {
202
- return this.shadowRoot!.querySelector<UDExButton>(
203
- "[udex-button]",
204
- )!;
211
+ return this.shadowRoot!.querySelector<UDExButton>("[udex-button]")!;
205
212
  }
206
213
 
207
214
  applyColorScheme(): void {
@@ -250,6 +257,11 @@ class UDExPromoTile extends UI5Element {
250
257
  return color;
251
258
  }
252
259
 
260
+ handleCTAButtonClick(e: Event) {
261
+ e.preventDefault();
262
+ this.fireDecoratorEvent("button-click");
263
+ }
264
+
253
265
  get isMobile(): boolean {
254
266
  return BreakpointUtils.isAtMost("S");
255
267
  }
@@ -259,7 +271,7 @@ class UDExPromoTile extends UI5Element {
259
271
  }
260
272
 
261
273
  get _showPictogram(): boolean {
262
- return !!this.icon || !!this.logoUrl;
274
+ return !!this.icon || !!this.logoUrl || !!this.pictogram?.length;
263
275
  }
264
276
 
265
277
  get _showLogo(): boolean {
@@ -269,11 +281,6 @@ class UDExPromoTile extends UI5Element {
269
281
  get _imageLabel(): string {
270
282
  return this.imageLabel || translate(UDExPromoTile, PROMO_TILE_ICON);
271
283
  }
272
-
273
- handleCTAButtonClick(e: Event) {
274
- e.preventDefault();
275
- this.fireDecoratorEvent("button-click");
276
- }
277
284
  }
278
285
 
279
286
  UDExPromoTile.define();
@@ -18,22 +18,26 @@ export default function PromoTileTemplate(this: UDExPromoTile) {
18
18
  part="image"
19
19
  class={{
20
20
  "udex-promo-tile__pictogram": true,
21
- "udex-promo-tile__pictogram--logo": this.logoUrl
21
+ "udex-promo-tile__pictogram--logo": this.logoUrl && !this.pictogram?.length
22
22
  }}
23
23
  title={this._imageLabel}>
24
- {this.icon &&
25
- <UI5Icon
26
- class={`${rootClass}__icon`}
27
- name={this.icon?.toLowerCase()}
28
- mode={IconMode.Decorative}
29
- accessibleName={this._imageLabel}>
30
- </UI5Icon>}
31
- {this._showLogo &&
32
- <img
33
- src={this.logoUrl}
34
- class={`${rootClass}__icon`}
35
- aria-label={this._imageLabel}
36
- alt={this._imageLabel} />}
24
+ <slot slot="pictogram" name="pictogram">
25
+ {this.icon &&
26
+ <UI5Icon
27
+ class={`${rootClass}__icon`}
28
+ name={this.icon?.toLowerCase()}
29
+ mode={IconMode.Decorative}
30
+ accessibleName={this._imageLabel}>
31
+ </UI5Icon>
32
+ }
33
+ {this._showLogo &&
34
+ <img
35
+ src={this.logoUrl}
36
+ class={`${rootClass}__icon`}
37
+ aria-label={this._imageLabel}
38
+ alt={this._imageLabel} />
39
+ }
40
+ </slot>
37
41
  </div>
38
42
  }
39
43
  <div part="content" class={`${rootClass}__content`}>
package/src/ReviewItem.ts CHANGED
@@ -8,7 +8,7 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
8
8
  import type { ResizeObserverCallback } from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
9
9
  import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
10
10
  import ReviewItemTemplate from "./ReviewItemTemplate.js";
11
- import { READ_LESS, READ_MORE } from "./generated/i18n/i18n-defaults.js";
11
+ import { SHOW_LESS, SHOW_MORE } from "./generated/i18n/i18n-defaults.js";
12
12
  import translate from "./utils/translate.js";
13
13
 
14
14
  // Styles
@@ -73,14 +73,6 @@ class UDExReviewItem extends UI5Element {
73
73
  @property({ type: String })
74
74
  text!: string;
75
75
 
76
- /**
77
- * Defines whether button for showing truncated text is shown.
78
- * @default 2
79
- * @private
80
- */
81
- @property({ type: Number })
82
- _textLineLimit: number = 2;
83
-
84
76
  /**
85
77
  * Defines whether the text is expanded.
86
78
  * @default false
@@ -123,23 +115,30 @@ class UDExReviewItem extends UI5Element {
123
115
  @slot()
124
116
  date!: Array<HTMLElement>;
125
117
 
118
+ /**
119
+ * Slot for custom content.
120
+ *
121
+ * @slot
122
+ */
123
+ @slot()
124
+ content?: Array<HTMLElement>;
125
+
126
126
  @i18n("@sapudex/web-components")
127
127
  static i18nBundle: I18nBundle;
128
128
 
129
129
  _handleResizeBound: ResizeObserverCallback;
130
130
  _textElement!: HTMLElement;
131
131
  _visibleText!: string;
132
- _maxHeight: number = 48;
132
+ _maxHeight: number = 90;
133
133
  _maxRating: number = 5;
134
134
  _minRating: number = 0;
135
135
 
136
136
  constructor() {
137
137
  super();
138
- this._handleResizeBound = this._checkTextOverflow.bind(this);
138
+ this._handleResizeBound = this._handleResize.bind(this);
139
139
  }
140
140
 
141
141
  onEnterDOM(): void {
142
- this._maxHeight = 48;
143
142
  this._completeText = this.text;
144
143
  ResizeHandler.register(this, this._handleResizeBound);
145
144
  }
@@ -149,19 +148,22 @@ class UDExReviewItem extends UI5Element {
149
148
  }
150
149
 
151
150
  onAfterRendering(): void {
152
- this._textElement = this.getTextElement();
153
- this._checkTextOverflow();
151
+ this._textElement = this.textElement;
152
+ if (this.text) {
153
+ this._checkTextOverflow();
154
+ }
155
+ }
156
+
157
+ _handleResize(): void {
158
+ if (this.text) {
159
+ this._checkTextOverflow();
160
+ }
154
161
  }
155
162
 
156
163
  _toggleText() {
157
164
  this._textExpanded = !this._textExpanded;
158
- if (this._textExpanded) {
159
- this._completeText = this.text;
160
- this._textElement.classList.add("udex-review-item__text-expanded");
161
- } else {
162
- this._textElement.classList.remove("udex-review-item__text-expanded");
163
- this._completeText = this._visibleText;
164
- }
165
+ this._completeText = this._textExpanded ? this.text : this._visibleText;
166
+ this._textElement.classList.toggle("udex-review-item__text-expanded", this._textExpanded);
165
167
  }
166
168
 
167
169
  _checkTextOverflow() {
@@ -169,18 +171,26 @@ class UDExReviewItem extends UI5Element {
169
171
 
170
172
  const canvas = document.createElement("canvas");
171
173
  const context = canvas.getContext("2d")!;
172
- context.font = `16px sans-serif`;
174
+ context.font = "16px sans-serif";
173
175
 
174
- let currentLineWidth = 0;
176
+ const maxWidth = this._textElement.offsetWidth;
175
177
  let visibleText = "";
178
+ const lineHeight = 22; // Approximate line height for 16px font
179
+
180
+ for (let i = 0; i < words.length; i++) {
181
+ const testText = visibleText + (visibleText ? " " : "") + words[i];
182
+ const metrics = context.measureText(testText);
183
+ const textWidth = metrics.width;
184
+
185
+ const estimatedLines = Math.ceil(textWidth / maxWidth);
186
+ const estimatedHeight = estimatedLines * lineHeight;
176
187
 
177
- words.forEach(word => {
178
- const wordWidth = context.measureText(`${word} `).width;
179
- if (currentLineWidth + wordWidth <= 2 * this._textElement.offsetWidth) {
180
- visibleText += `${word} `;
181
- currentLineWidth += wordWidth;
188
+ if (estimatedHeight > this._maxHeight) {
189
+ break;
182
190
  }
183
- });
191
+
192
+ visibleText = testText;
193
+ }
184
194
 
185
195
  this._visibleText = visibleText;
186
196
  if (!this._textExpanded) {
@@ -190,8 +200,13 @@ class UDExReviewItem extends UI5Element {
190
200
  this._showTextExpander = (!this._textExpanded && this._completeText.length < this.text.length) || (this._textExpanded && visibleText.length < this.text.length);
191
201
  }
192
202
 
203
+ get textElement(): HTMLElement {
204
+ const textElement = this.shadowRoot?.getElementById("udex-review-item__text");
205
+ return textElement!;
206
+ }
207
+
193
208
  get buttonText(): string {
194
- return this._textExpanded ? translate(UDExReviewItem, READ_LESS) : translate(UDExReviewItem, READ_MORE);
209
+ return this._textExpanded ? translate(UDExReviewItem, SHOW_LESS) : translate(UDExReviewItem, SHOW_MORE);
195
210
  }
196
211
 
197
212
  get reviewItemClasses(): string {
@@ -210,11 +225,6 @@ class UDExReviewItem extends UI5Element {
210
225
  }
211
226
  return this.rating;
212
227
  }
213
-
214
- getTextElement(): HTMLElement {
215
- const textElement = this.shadowRoot?.getElementById("udex-review-item__text");
216
- return textElement!;
217
- }
218
228
  }
219
229
 
220
230
  UDExReviewItem.define();